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
和do
N0=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 ;
...