Prolog - 简化导数 [英] Prolog - simplify derivative

查看:76
本文介绍了Prolog - 简化导数的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

所以我这个学期刚开始使用 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(A, B) :-iwhen(ground(A), xpr_simplr(A,B)).xpr_simplr(A, B) :-( 原子 (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 包罗万象地图列表(xpr_simplr,Xs0,Xs),B =.. [F|X]).

让我们看看它对您提供的表达式有何作用.我们应用 expr_simplified/2 直到我们到达一个固定点:

<预>?- 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. % 固定点达到

尽管简化器并不完美,但表达式变得更具可读性.

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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆