Prolog中的逆阶乘
有人能帮我找到一种方法,在序言中得到逆阶乘 例如,Prolog中的逆阶乘,prolog,factorial,clpfd,Prolog,Factorial,Clpfd,有人能帮我找到一种方法,在序言中得到逆阶乘 例如,inverse\u factorial(6,X)==>X=3 我一直在做这件事 我现在有阶乘,但我必须使它可逆。请帮助我。只需实现阶乘(X,XFact),然后交换参数 factorial(X, XFact) :- f(X, 1, 1, XFact). f(N, N, F, F) :- !. f(N, N0, F0, F) :- succ(N0, N1), F1 is F0 * N1, f(N, N1, F1, F). Prolog的谓词是关系
inverse\u factorial(6,X)
==>X=3
我一直在做这件事
我现在有阶乘,但我必须使它可逆。请帮助我。只需实现阶乘(X,XFact),然后交换参数
factorial(X, XFact) :- f(X, 1, 1, XFact).
f(N, N, F, F) :- !.
f(N, N0, F0, F) :- succ(N0, N1), F1 is F0 * N1, f(N, N1, F1, F).
Prolog的谓词是关系,所以定义阶乘后,也隐式定义了逆。但是,常规算术是在Prolog中建模的,也就是说,必须在运行时知道
(is)/2
或(>)/2
中的整个表达式,如果不知道,则会发生错误。这些限制克服了这一缺点:
:- use_module(library(clpfd)).
n_factorial(0, 1).
n_factorial(N, F) :-
N #> 0, N1 #= N - 1, F #= N * F1,
n_factorial(N1, F1).
有关详细信息,请参阅。一种简单的“低技术”方法:枚举整数直到
- 找到寻求的阶乘,然后“返回”数字
- 正在生成的阶乘大于目标。那么你可能会失败
实际上,您只需向现有的阶乘实现添加两个参数,即目标和找到的逆。作为参考,这里是我能想到的声明性
阶乘
谓词的最佳实现
@false的回答有两个要点不同:
- 它使用累加器参数,递归调用递增我们乘以阶乘的因子,而不是基本情况为
的标准递归实现。当阶乘已知而初始数未知时,这使得谓词速度更快0
- 它广泛使用模块中的
和if_u3
,尽可能消除不必要的选择点。它还使用了(=)/3
和具体化的(#>)/3
,这是(==)/6
的一个变体,用于我们有两对夫妇可以用于(=)/3
的if->then
部分
factorial/2
(==)/6
一些疑问
你觉得我的解决方案怎么样?@SergeiLodyagin:如果XFact不是阶乘,将循环。在递归调用之前添加一个测试。我已经添加了示例。@false。在SWI中使用clpfd时,查询将终止。怎么会这样?@错。我复制它,但是使用
?-n_阶乘(n,n)。
我得到n=1;N=2;false。
事实上,当运行查询?-n\u fac(n,n),false时,我确实在其他地方编码了n\u fac的其他变体,但没有终止。
。。。但是在这里?不,错。很高兴知道!当然,我毫不怀疑你的观察是正确的。我简直无法复制它。因此,感谢您对多个版本的额外研究。此定义在两个方向上都有效,并且是实现它的最自然和可读的方式,但是在搜索逆阶乘时,它的速度非常慢,例如n_阶乘(Y,100000000)
在我的机器上回答false
大约需要20秒。n_factorial(n,n)。
应该在昨天发布的SICStus Prolog 4.3.4中终止。到目前为止,您发现“简单迭代变量”(缺少更好的名称)的优化只适用于列表长度/2
等更简单的情况。我想知道这是否可以自动化@你说的“算术和语法相等的混合”是什么意思?不,我不知道(#)/1
。当X=1+0,X=1
成功时,X=1,X=1+0
失败。看来你已经设法消除了所有这些相关的问题,这确实令人惊讶。至少我给出的定义有这个缺陷:N=1+1,N_阶乘(N,2)。
成功,但N_阶乘(N,2),N=1+1。
失败。有一个函子#/1可以克服这个问题:#(X)#=1,X=0+1
失败,而X=0+1,#(X)#=1
是一个错误。参见clpfd/clpz手册。这在某种程度上仍然是试探性的,理想情况下是一个优先级非常低的前缀运算符,然后可以这样写:\X+\Y#=#Z
@false,当N
接地且F
空闲时,或者当两者都空闲时,则可以在then部分使用(=)/3
和doN0=F
。但是当F
接地而N
不接地时,在N
上使用(=)/3
将留下一个不必要的选择点(如果F=N0
是if部分,我们就不会得到的最后一部分(=)/3
和dif
)。因此,(==)/6
允许融合这两种情况,同时如果N
和F
都是免费的,则仍具有正确的行为。为X2,Y2
添加=
和dif
部分是不需要的,实际上会产生多余的结果。您需要生成声明性构建块。否则,你绝不会比纯粹的程序性解决方案更好。
?- n_factorial(N,6).
N = 3 ;
false.
?- n_factorial(3,F).
F = 6 ;
false.
?- n_factorial(N,N).
N = 1
; N = 2
; false.
factorial(N, F) :-
factorial(N, 0, 1, F).
factorial(N, I, N0, F) :-
F #> 0,
N #>= 0,
I #>= 0,
I #=< N,
N0 #> 0,
N0 #=< F,
if_(I #> 2,
( F #> N,
if_(===(N, I, N0, F, T1),
if_(T1 = true,
N0 = F,
N = I
),
( J #= I + 1,
N1 #= N0*J,
factorial(N, J, N1, F)
)
)
),
if_(N = I,
N0 = F,
( J #= I + 1,
N1 #= N0*J,
factorial(N, J, N1, F)
)
)
).
#>(X, Y, T) :-
zcompare(C, X, Y),
greater_true(C, T).
greater_true(>, true).
greater_true(<, false).
greater_true(=, false).
===(X1, Y1, X2, Y2, T1, T) :-
( T1 == true -> =(X1, Y1, T)
; T1 == false -> =(X2, Y2, T)
; X1 == Y1 -> T1 = true, T = true
; X1 \= Y1 -> T1 = true, T = false
; X2 == Y2 -> T1 = false, T = true
; X2 \= Y2 -> T1 = false, T = false
; T1 = true, T = true, X1 = Y1
; T1 = true, T = false, dif(X1, Y1)
).
?- factorial(N, N).
N = 1 ;
N = 2 ;
false. % One could probably get rid of the choice point at the cost of readability
?- factorial(N, 1).
N = 0 ;
N = 1 ;
false. % Same
?- factorial(10, N).
N = 3628800. % No choice point
?- time(factorial(N, 93326215443944152681699238856266700490715968264381621468592963895217599993229915608941463976156518286253697920827223758251185210916864000000000000000000000000)).
% 79,283 inferences, 0.031 CPU in 0.027 seconds (116% CPU, 2541106 Lips)
N = 100. % No choice point
?- time(factorial(N, 93326215443944152681699238856266700490715968264381621468592963895217599993229915608941463976156518284253697920827223758251185210916864000000000000000000000000)).
% 78,907 inferences, 0.031 CPU in 0.025 seconds (125% CPU, 2529054 Lips)
false.
?- F #> 10^100, factorial(N, F).
F = 11978571669969891796072783721689098736458938142546425857555362864628009582789845319680000000000000000,
N = 70 ;
F = 850478588567862317521167644239926010288584608120796235886430763388588680378079017697280000000000000000,
N = 71 ;
F = 61234458376886086861524070385274672740778091784697328983823014963978384987221689274204160000000000000000,
N = 72 ;
...