Prolog扩展欧几里德算法

时间:2017-05-27 14:31:11

标签: prolog

我已经在一些prolog代码上苦苦挣扎了几天,但我无法找到解决方法。我正在尝试编写扩展的欧几里德算法,并在以下位置找到值ps

a*p + b*s = gcd(a,b)
等式,这是我试过的:`

 common(X,X,X,_,_,_,_,_,_).
 common(0,Y,Y,_,_,_,_,_,_).
 common(X,0,X,_,_,_,_,_,_).

 common(X,Y,_,1,0,L1,L2,SF,TF):-
                                  append(L1,1,[H]),
                                  append(L2,0,[A]),
                                  SF is H ,
                                  TF is A,
                                  common(X,Y,_,0,1,[H],[A],SF,TF).

 common(X,Y,_,0,1,L1,L2,SF,TF):-
                                  append(L1,0,[_,S2]),
                                  append(L2,1,[_,T2]),
                                  Q is truncate(X/Y),
                                  S is 1-Q*0,T is 0-Q*1 ,
                                  common(X,Y,_,S,T,[S2,S],
                                  [T2,T],SF,TF).

 common(X,Y,N,S,T,[S1,S2],[T1,T2],SF,TF):-
                                  Q is truncate(X/Y),
                                  K is X-(Y*Q),
                                  si_finder(S1,S2,Q,SF),
                                  ti_finder(T1,T2,Q,TF),

common(Y,K,N,S,T,[S2,S],[T2,T],SF,TF).


si_finder(PP,P,Q,C):- C is  PP - Q*P.

ti_finder(P2,P1,QA,C2):- C2 is P2 - QA*P1.

经过一番搜索后,我发现s和p系数从1和0开始,它们的第二个值分别为0和1.然后它继续使用我在si_finder和ti_finder谓词中完成的模式。常见谓词是我试图递归控制模式的地方。但是,常见谓词在每次调用时都会返回false。任何人都可以帮我在Prolog中实现这个算法。

提前致谢。

1 个答案:

答案 0 :(得分:2)

首先让我们考虑谓词的arity。显然,您希望将数字A和B以及Bézout系数P和S作为参数。由于该算法无论如何都在计算GCD,因此将其作为参数也是恰当的。这让我们留下了arity 5.当我们谈论扩展的欧几里德算法时,让我们'调用谓词eeuclid/5。接下来,考虑一个例子:让我们使用算法来计算A = 242和B = 69的P,S和GCD:

quotient (Q) | remainder    (B1) |   P   |   S
-------------+-------------------+-------+-------
             |              242  |   1   |   0
             |              69   |   0   |   1
242/69 = 3   | 242 − 3*69 = 35   |   1   |  -3
69/35  = 1   | 69 − 1*35  = 34   |  -1   |   4
35/34  = 1   | 35 − 1*34  = 1    |   2   |  -7
34/1   = 34  | 34 − 34*1  = 0    | -69   | 242

我们可以观察到以下内容:

  • 如果余数变为0

  • ,算法将停止
  • 最后一行之前的行包含剩余列中的GCD(在此示例中为1)和P和S列中的Bézout系数(在此示例中为2和-7)

    < / LI>
  • 商是从前一个余数计算出来的。因此,在下一次迭代中,A变为B,B变为B1。

  • P和S是从它们各自的前辈计算出来的。例如:P3 = P1-3 * P2 = 1-3 * 0 = 1且S3 = S1-3 * S2 = 0-3 * 1 = -3。并且因为它具有前两个P和S的足够,所以我们也可以将它们作为成对传递,例如, P1-P2和S1-S2。

  • 算法从对P:1-0和S:0-1

  • 开始
  • 算法以较大的数字

  • 开头

把所有这些放在一起,调用谓词必须确保A是一个更大的数字,除了它的五个参数之外,它还必须将起始对1-0和0-1传递给描述实际的谓词关系,这里a_b_p_s_/7

:- use_module(library(clpfd)).

eeuclid(A,B,P,S,GCD) :-
   A #>= B,
   GCD #= A*P + B*S,                % <- new
   a_b_p_s_(A,B,P,S,1-0,0-1,GCD).
eeuclid(A,B,P,S,GCD) :-
   A #< B,
   GCD #= A*P + B*S,                % <- new
   a_b_p_s_(B,A,S,P,1-0,0-1,GCD).

a_b_p_s_/7的第一条规则描述了基本情况,其中B = 0且算法停止。然后A是GCD,P1,S1是Bézout系数。否则,计算商Q,余数B1和P和S的新值,并使用这些新值调用a_b_p_s_/7

a_b_p_s_(A,0,P1,S1,P1-_P2,S1-_S2,A).
a_b_p_s_(A,B,P,S,P1-P2,S1-S2,GCD) :-
   B #> 0,
   A #> B,                          % <- new
   Q #= A/B,
   B1 #= A mod B,
   P3 #= P1-(Q*P2),
   S3 #= S1-(Q*S2),
   a_b_p_s_(B,B1,P,S,P2-P3,S2-S3,GCD).

使用上面的示例查询会产生所需的结果:

?- eeuclid(242,69,P,S,GCD).
P = 2,
S = -7,
GCD = 1 ;
false.

确实:gcd(242,69)= 1 = 2 * 242 - 7 * 69

编辑:我想建议添加两个约束。首先是在a_b_p_s_/7之前调用Bézout的身份,然后在A #> B的第一个目标之后调用a_b_p_s_/7。我编辑了上面的谓词并标记了新的目标。这些添加使eeuclid/5更加通用。例如,您可以询问数字A和B具有Bézout系数2和-7和1作为gcd。此查询没有唯一的答案,Prolog将为您提供每个潜在解决方案的剩余目标。但是,您可以要求A和B的有限范围,比如介于0和50之间,然后使用label/1来获取实际数字:

?-  [A,B] ins 0..50, eeuclid(A,B,2,-7,1), label([A,B]).
A = 18,
B = 5 ;
A = 25,
B = 7 ;
A = 32,
B = 9 ;
A = 39,
B = 11 ;
A = 46,
B = 13 ;
false.       % <- previously loop here

如果没有新添加的约束,查询将不会在第五个解决方案后终止。然而,随着Prolog能够确定的新约束,在0到50之间没有更多的解决方案。