Prolog中的反因子

时间:2013-09-26 10:25:32

标签: prolog factorial clpfd

有人可以帮助我找到一种方法来获得Prolog中的反因子...

例如inverse_factorial(6,X) ===> X = 3

我一直在努力工作。

我目前有阶乘,但我必须让它变得可逆。请帮帮我。

4 个答案:

答案 0 :(得分:5)

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).

此定义现在可以双向运作。

?- n_factorial(N,6).
N = 3 ;
false.

?- n_factorial(3,F).
F = 6 ;
false.

由于SICStus 4.3.4和SWI 7.1.25也终止了以下内容:

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

有关详情,请参阅the manual

答案 1 :(得分:2)

作为参考,这是我能提出的声明性factorial谓词的最佳实现。

两个要点与@ false的答案不同:

  • 它使用累加器参数,递归调用增加了我们乘以阶乘的因子,而不是基本情况为0的标准递归实现。当已知阶乘并且初始数字不是时,这使得谓词更快。

  • 它广泛使用if_/3(=)/3来自模块reif,以便在可能的情况下摆脱不必要的选择点。如果我们有两对可用于(#>)/3 (===)/6部分的情况,它还会使用(=)/3if -> then的变体if_ }。

factorial/2

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)
            )
        )
    ).

(#>)/3

#>(X, Y, T) :-
    zcompare(C, X, Y),
    greater_true(C, T).

greater_true(>, true).
greater_true(<, false).
greater_true(=, false).

(===)/6

===(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 ;
...

答案 2 :(得分:0)

一种简单的“低技术”方式:枚举整数直到

  • 你找到了所寻求的因子,然后'找回'数字
  • 正在构建的阶乘大于目标。那你就失败了......

实际上,您可以在现有的阶乘实现,目标和找到的反向中添加2个参数。

答案 3 :(得分:-3)

只需实现factorial(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).