Prolog中的可逆数值计算

Prolog中的可逆数值计算,prolog,factorial,clpfd,Prolog,Factorial,Clpfd,在阅读SICP时,我遇到了逻辑编程第4.4章。然后我开始研究Prolog编程语言,并试图理解Prolog中的一些简单赋值。我发现Prolog似乎在数值计算方面有问题 以下是标准Prolog中阶乘的计算: f(0, 1). f(A, B) :- A > 0, C is A-1, f(C, D), B is A*D. 我发现的问题是,我需要引入两个辅助变量(C和D),一个新语法(是),并且问题是不可逆的(即,f(5,X)按预期工作,但f(X,120)没有) 天真地说,我希望至少C是A-1,上

在阅读SICP时,我遇到了逻辑编程第4.4章。然后我开始研究Prolog编程语言,并试图理解Prolog中的一些简单赋值。我发现Prolog似乎在数值计算方面有问题

以下是标准Prolog中阶乘的计算:

f(0, 1).
f(A, B) :- A > 0, C is A-1, f(C, D), B is A*D.
我发现的问题是,我需要引入两个辅助变量(
C
D
),一个新语法(
),并且问题是不可逆的(即,
f(5,X)
按预期工作,但
f(X,120)
没有)

天真地说,我希望至少
C是A-1,上面的f(C,D)
可以被
f(A-1,D)
取代,但即使这样也不行

我的问题是:为什么我需要在数值计算中做这些额外的“东西”,而不是在其他查询中


我确实理解(SICP对此非常清楚),关于“做什么”的一般信息不足以回答“如何做”的问题。所以(至少在一些)数学问题中的陈述性知识不足以实际解决这些问题。但这引出了下一个问题:Prolog中的这个额外的“东西”如何帮助我将公式限制在那些“做什么”就足以回答“如何做”的问题上呢?

忘记变量,认为
A
B
-只是可以放入该子句
(X:-Y)中的值的名称.
以使其可访问。以表示数学表达式的数据结构的方式考虑
X=(2+(3*4))
。如果你要求prolog实现目标,它会试图找到这样的原子,或者一条规则,它将统一为“成功”。
is/2
尝试将第一个参数与将第二个参数解释为表达式的结果统一起来。考虑<代码> EVA/2 作为<代码>的变体:/2 < <代码>:

eval(0, 1-1). eval(0, 2-2). eval(1,2-1).
eval(Y, X-0):- eval(Y, X).
eval(Y, A+B):- eval(ValA, A), eval(ValB, B), eval(Y, ValA + ValB).
eval(4, 2*2).
eval(0, 0*_). eval(0, _*0).
eval(Y, X*1):- eval(Y, X).
eval(Y, 1*X):- eval(Y, X).
eval(Y, A*B):- eval(ValA, A), eval(ValB, B), eval(Y, ValA * ValB).
:- use_module(library(clpfd)).

n_factorial(0, 1).
n_factorial(N, F) :- N #> 0, N1 #= N - 1, F #= N * F1, n_factorial(N1, F1).
n_fac(N_expr,F_expr) :-
   N #= N_expr,                 % eval arith expr
   F #= F_expr,                 % eval arith expr
   n_facAux(N,F).
f(X,120)
不起作用的原因很简单
>/2
仅在其参数被绑定时起作用(即,您无法将尚未定义的对象,如
X
与任何其他对象进行比较)。要解决此问题,您必须将该规则拆分为:

f(A,B) :- nonvar(A), A > 0, C is A-1, f(C, D), B is A*D.
f(A,B) :- nonvar(B), f_rev(A, B, 1, 1).

% f_rev/4 - only first argument is unbound.
f_rev(A, B, A, B). % solution 
f_rev(A, B, N, C):- C < B, NextN is (N+1), NextC is (C*NextN), f_rev(A, B, NextN, NextC).
f(A,B):-nonvar(A),A>0,C是A-1,f(C,D),B是A*D。
f(A,B):-无表决权(B),f_修订版(A,B,1,1)。
%f_rev/4-只有第一个参数未绑定。
f_修订版(A、B、A、B)。%解决方案
f_rev(A,B,N,C):-C
更新:(已修复
f_rev/4

您可能对有限域解算器感兴趣。使用这些东西有一个很大的困难。通过使用
#>/2
#=/2
可以描述一些公式和限制,然后解决它们。但这些谓词使用了一些prolog系统的特殊功能,允许将名称与一些属性相关联,这可能有助于通过限制的交集缩小可能的值集。其他一些系统(通常相同)允许您重新排列处理目标的顺序(“暂停”)。
另外
成员(X[1,2,3,4,5,6,7]),f(X,120)
可能正在做与“其他查询”相同的事情


如果您一般对逻辑语言感兴趣,您也可以看看Curry语言(所有非纯函数在统一定义值之前都是“挂起的”。

是/2
是非常低级和有限的。正如你正确观察到的,它不能在所有方向上使用,因此不是真正的关系

对于可逆算法,请使用Prolog系统的约束解算器

例如,SWI Prolog包含以下
n_factorial/2
的定义:

eval(0, 1-1). eval(0, 2-2). eval(1,2-1).
eval(Y, X-0):- eval(Y, X).
eval(Y, A+B):- eval(ValA, A), eval(ValB, B), eval(Y, ValA + ValB).
eval(4, 2*2).
eval(0, 0*_). eval(0, _*0).
eval(Y, X*1):- eval(Y, X).
eval(Y, 1*X):- eval(Y, X).
eval(Y, A*B):- eval(ValA, A), eval(ValB, B), eval(Y, ValA * ValB).
:- use_module(library(clpfd)).

n_factorial(0, 1).
n_factorial(N, F) :- N #> 0, N1 #= N - 1, F #= N * F1, n_factorial(N1, F1).
n_fac(N_expr,F_expr) :-
   N #= N_expr,                 % eval arith expr
   F #= F_expr,                 % eval arith expr
   n_facAux(N,F).
以下示例查询表明,它可以在所有方向上使用:

?- n_factorial(47, F).
F = 258623241511168180642964355153611979969197632389120000000000 ;
false.

?- n_factorial(N, 1).
N = 0 ;
N = 1 ;
false.

?- n_factorial(N, 3).
false.
当然,这个定义仍然依赖于统一,因此不能插入任意整数表达式。像
2-2
(前缀表示法中的
-(2,2)
)这样的术语不适合
0
。但如果您将其改写为:

:- use_module(library(clpfd)).

n_factorial(N, F) :- N #= 0, F #= 1.
n_factorial(N, F) :- N #> 0, N1 #= N - 1, F #= N * F1, n_factorial(N1, F1).
示例查询及其结果:

?- n_factorial(2-2, -4+5).
true .

在阅读序言时,您必须记住以下几点:

  • 调用谓词时没有隐式返回值。如果要从调用中获取值,需要添加额外的参数,这些参数可用于“返回”值,
    f/2
    谓词中的第二个参数。虽然更加详细,但它的好处是可以轻松返回许多值

  • 这意味着在调用中自动“评估”参数实际上是毫无意义的,因为没有返回值,也没有完成。因此没有嵌套调用,在这方面Prolog是扁平的。因此,当调用
    f(A-1,D)
    时,
    f/2
    的第一个参数是结构
    A-1
    ,或者实际上是
    -(A,1)
    ,因为
    -
    是中缀运算符。因此,如果要将调用
    foo
    的值转换为调用
    bar
    的值,则必须显式使用变量,如下所示:

    foo(…,X),bar(X,…),

  • 因此需要一个特殊的谓词来强制算术求值,
    is/2
    。它的第二个参数是一个表示算术表达式的结构,它解释、计算并将结果与第一个参数统一起来,第一个参数可以是变量,也可以是数值

  • 而在原则上,你可以用大多数你做不到的东西来倒转。通常情况下,只有简单的谓词才能处理可能的结构,尽管也有一些非常有用的情况
    is/2
    不能反向工作,如果它能反向工作,那将是一个例外

这就是为什么您需要额外的变量
C
D
,并且不能用
f(A)替换
C是A-1,f(C,D)
?- n_factorial(47,F).
  F = 258623241511168180642964355153611979969197632389120000000000
; false.
?- n_fac(47,F).
  F = 258623241511168180642964355153611979969197632389120000000000
; false.

?- n_factorial(N,1).
  N = 0
; N = 1
; false.
?- n_fac(N,1).
  N = 0
; N = 1
; false.

?- member(F,[3,1_000_000]), ( n_factorial(N,F) ; n_fac(N,F) ).
false.                          % both predicates agree
?- time((F1 #\= F2,n_factorial(N,F1),n_fac(N,F2))). % 57,739,784 inferences, 6.415 CPU in 7.112 seconds (90% CPU, 9001245 Lips) % Execution Aborted ?- time((F1 #\= F2,n_fac(N,F2),n_factorial(N,F1))). % 52,815,182 inferences, 5.942 CPU in 6.631 seconds (90% CPU, 8888423 Lips) % Execution Aborted ?- time((N1 #> 1,N2 #> 1,N1 #\= N2,n_fac(N1,F),n_factorial(N2,F))). % 99,463,654 inferences, 15.767 CPU in 16.575 seconds (95% CPU, 6308401 Lips) % Execution Aborted ?- time((N1 #> 1,N2 #> 1,N1 #\= N2,n_factorial(N2,F),n_fac(N1,F))). % 187,621,733 inferences, 17.192 CPU in 18.232 seconds (94% CPU, 10913552 Lips) % Execution Aborted
?- n_factorial(N,N), false.
false.
?- n_fac(N,N), false.
false.
?- N #< 5, n_factorial(N,_), false.
false.
?- N #< 5, n_fac(N,_), false.
false.

?- F in 10..100, n_factorial(_,F), false.
false.
?- F in 10..100, n_fac(_,F), false.
false.
?- F in inf..10, n_factorial(_,F), false. ... % Execution Aborted % does not terminate universally ?- F in inf..10, n_fac(_,F), false. false. % terminates universally ?- member(Exp,[6,7,8,9]), F #= 10^Exp, time(n_factorial(N,F)) ; true. % 328,700 inferences, 0.043 CPU in 0.043 seconds (100% CPU, 7660054 Lips) % 1,027,296 inferences, 0.153 CPU in 0.153 seconds (100% CPU, 6735634 Lips) % 5,759,864 inferences, 1.967 CPU in 1.967 seconds (100% CPU, 2927658 Lips) % 22,795,694 inferences, 23.911 CPU in 23.908 seconds (100% CPU, 953351 Lips) true. ?- member(Exp,[6,7,8,9]), F #= 10^Exp, time(n_fac(N,F)) ; true. % 1,340 inferences, 0.000 CPU in 0.000 seconds ( 99% CPU, 3793262 Lips) % 1,479 inferences, 0.000 CPU in 0.000 seconds (100% CPU, 6253673 Lips) % 1,618 inferences, 0.000 CPU in 0.000 seconds (100% CPU, 5129994 Lips) % 1,757 inferences, 0.000 CPU in 0.000 seconds (100% CPU, 5044792 Lips) true. ?- member(U,[10,100,1000]), time((N in 1..U,n_factorial(N,_),false)) ; true. % 34,511 inferences, 0.004 CPU in 0.004 seconds (100% CPU, 9591041 Lips) % 3,091,271 inferences, 0.322 CPU in 0.322 seconds (100% CPU, 9589264 Lips) % 305,413,871 inferences, 90.732 CPU in 90.721 seconds (100% CPU, 3366116 Lips) true. ?- member(U,[10,100,1000]), time((N in 1..U,n_fac(N,_),false)) ; true. % 3,729 inferences, 0.001 CPU in 0.001 seconds (100% CPU, 2973653 Lips) % 36,369 inferences, 0.004 CPU in 0.004 seconds (100% CPU, 10309784 Lips) % 362,471 inferences, 0.036 CPU in 0.036 seconds (100% CPU, 9979610 Lips) true.