Prolog - 简化导数 [英] Prolog - simplify derivative
问题描述
所以我这个学期刚开始使用 Prolog,并得到了实现一个非常基本的 d(function, variable,derivative)
的作业,我是这样做的:
d(X,X,1) :- !.d(C,X,0) :- 原子 (C).%,(C \ = X).d(X**E,X,E*X**(E-1)).d(U+V,X,A+B) :- d(U,X,A), d(V,X,B).d(U-V,X,A-B) :- d(U,X,A), d(V,X,B).d(U*V,X,DU*V+U*DV) :- d(U,X,DU), d(V,X,DV).d(U/V,X,(DU*V-U*DV)/(V*V)) :- d(U,X,DU), d(V,X,DV).
我知道这并不完整,但它涵盖了练习中所需的所有任务.
然而,?- d((x*x+2*x+3)/(3*x),x,R).
导致
R = ((1*x+x*1+ (0*x+2*1)+0)* (3*x)- (x*x+2*x+3)* (0*x+3*1))/(3*x* (3*x)).
这看起来一点也不漂亮.is/2 不幸的是不喜欢我的 x 因为它不是数字...
是否有一个简单的解决方案来获得更清晰的结果?
我宁愿将其视为两个独立的问题:
首先,正确推导(根据您的具体要求,您可能已经接近了).
然后,在代数层面上简化表达式.利用代数恒等式,看看在某些子表达式上应用交换律/结合律/分配律是否能够将它们重写为等价的(但更简单/更紧凑).
作为起点,您可能想看一些相关的问题替换序言中的表达部分".
<小时>这是一个简单的草图,您可以如何进行简化—使用 iwhen/2
防止实例化不足:
让我们看看它对您提供的表达式有何作用.我们应用 expr_simplified/2
直到我们到达一个固定点:
尽管简化器并不完美,但表达式变得更具可读性.
so I just got started with Prolog this semester, and got the homework to implement a pretty basic d(function, variable, derivative)
which I did like this:
d(X,X,1) :- !.
d(C,X,0) :- atomic(C). %, (C \= X).
d(X**E,X,E*X**(E-1)).
d(U+V,X,A+B) :- d(U,X,A), d(V,X,B).
d(U-V,X,A-B) :- d(U,X,A), d(V,X,B).
d(U*V,X,DU*V+U*DV) :- d(U,X,DU), d(V,X,DV).
d(U/V,X,(DU*V-U*DV)/(V*V)) :- d(U,X,DU), d(V,X,DV).
I know this is not complete, but it covers all the tasks required in the exercise.
However,
?- d((x*x+2*x+3)/(3*x),x,R).
leads to
R = ((1*x+x*1+ (0*x+2*1)+0)* (3*x)- (x*x+2*x+3)* (0*x+3*1))/ (3*x* (3*x)).
which doesn't look pretty at all. is/2 unfortunately doesn't like my x as it is not a number...
Is there a simple solution to achieve a cleaner result?
I would rather see this as two separate problems:
First, get derivation right (you're probably getting close, depending on your concrete requirements).
Then, work on simplifying expressions on an algebraic level. Exploit algebraic identities, see if applying the laws of commutativity / associativity / distributivity on some subexpressions enable their rewriting into something equivalent (but simpler / more compact).
As a starting point, you may want to look at the somewhat related question "Replacing parts of expression in prolog".
Here's a simplistic sketch how you could do the simplification—using iwhen/2
to safeguard against insufficient instantiation:
expr_simplified(A, B) :- iwhen(ground(A), xpr_simplr(A,B)). xpr_simplr(A, B) :- ( atomic(A) -> A = B ; ( A = X+0 ; A = 0+X ; A = 1*X ; A = X*1 ) -> xpr_simplr(X, B) ; ( A = 0*_ ; A = _*0 ) -> B = 0 ; A = X+X -> B = X*2 ; A = X*X -> B = X**2 ; A = X**1 -> B = X ; A =.. [F|Xs0], % defaulty catch-all maplist(xpr_simplr, Xs0, Xs), B =.. [F|Xs] ).
Let's see what it does with the expression you gave. We apply expr_simplified/2
until we reach a fixed point:
?- A = ((1*x+x*1+(0*x+2*1)+0)*(3*x)-(x*x+2*x+3)*(0*x+3*1))/(3*x*(3*x)), expr_simplified(A,B), expr_simplified(B,C), expr_simplified(C,D). A = ((1*x+x*1+(0*x+2*1)+0)*(3*x)-(x*x+2*x+3)*(0*x+3*1))/(3*x*(3*x)), B = ((x+x+(0+2))*(3*x)-(x**2+2*x+3)*(0+3))/(3*x)**2, C = ((x*2+2)*(3*x)-(x**2+2*x+3)*3)/(3*x)**2, D = C. % fixed point reached
As imperfect as the simplifier is, the expression got a lot more readable.
这篇关于Prolog - 简化导数的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!