【问题标题】:CLP(FD)-ying Simultaneous Recursion for Fibonacci Lukas Numbers Possible?斐波那契卢卡斯数的 CLP(FD)-ying 同时递归可能吗?
【发布时间】:2016-03-28 14:29:16
【问题描述】:

在某些instances 中,递归谓词可以是 CLP(FD)-fied,其好处是谓词变成双向的。这种方法的局限性是什么?例如可以如下computationCLP(FD)-fied:

Fn: n-th Fibonacci Number
Ln: n-th Lucas Number (starting with 2)

通过这个加倍递归步骤:

F2n = Fn*Ln
L2n = (5*Fn^2+Ln^2)//2

还有这个递增的递归步骤:

Fn+1 = (Fn+Ln)//2
Ln+1 = (5*Fn+Ln)//2

传统的 Prolog realization 已经从 n 工作到 Fn。这可以变成一个 CLP(FD) 程序,保留快速递归,同时使其双向,例如找出 Fn=377 的索引 n?如果是怎么办?如果不是为什么?

再见

【问题讨论】:

  • fibluc/3 大约是比 fib/2 快 20%。可能不得不这样做 fib/2 正在使用 call/n 和编程 stye 之类的教科书。请参阅您的答案中的评论。但我想这两种算法都会遇到相同的 CLP(FD) 问题。
  • 现在我看得更清楚了,这似乎是不同衣服的相同算法。我将删除我的答案。
  • @Boris 我认为您的 fib/2 确实不同,它是一种众所周知的斐波那契数列算法,它不会在途中生成卢卡斯数。也可以在这里查看:en.wikipedia.org/wiki/Fibonacci_number#Matrix_form 但我猜使用加倍和递增是相似的。
  • 是的,确实,这就是我的意思

标签: prolog clpfd


【解决方案1】:

是的,可以通过限制值来完成。您也可以将递归移动为尾递归,尽管不需要获得解决方案:

fibluc(0, 0, 2).
fibluc(1, 1, 1).
fibluc(N, F, L) :-
    N in 2..1000,        % Pick a reasonable value here for 1000
    [F, L] ins 1..sup,
    N rem 2 #= 1,
    M #= N-1,
    F #= (F1 + L1) // 2,
    L #= (5*F1 + L1) // 2,
    fibluc(M, F1, L1).
fibluc(N, F, L) :-
    N in 2..1000,        % Pick a reasonable value here for 1000
    [F, L] ins 1..sup,
    N rem 2 #= 0,
    M #= N // 2,
    F #= F1 * L1,
    L #= (5*F1*F1 + L1*L1) // 2,
    fibluc(M, F1, L1).

将产生:

?- fibluc(10, X, Y).
X = 55,
Y = 123 ;
false.

?- fibluc(N, 55, Y).
N = 10,
Y = 123 ;
false.

?- fibluc(N, X, 123).
N = 10,
X = 55 ;
false.

?- fibluc(N, 55, 123).
N = 10 ;
false.

?- fibluc(N, 55, 125).
false.

?- fibluc(N, X, Y).
N = X, X = 0,
Y = 2 ;
N = X, X = Y, Y = 1 ;
N = 3,
X = 2,
Y = 4 ;
N = 7,
X = 13,
Y = 29 ;
N = 15,
X = 610,
Y = 1364 ;
N = 31,
X = 1346269,
Y = 3010349 ;
N = 63,
X = 6557470319842,
Y = 14662949395604 ;
...

N 未实例化时,可以修改此设置以生成增加N 值的结果。
这是一个定时复合查询示例,在 Linux 下在 SWI Prolog 7.1.33 中运行:

?- time((fibluc(100, X, Y), fibluc(N, X, Z))).
% 11,337,988 inferences, 3.092 CPU in 3.100 seconds (100% CPU, 3666357 Lips)
X = 354224848179261915075,
Y = Z, Z = 792070839848372253127,
N = 100 ;
% 1,593,620 inferences, 0.466 CPU in 0.468 seconds (100% CPU, 3417800 Lips)
false.

?-

将 SWI Prolog 7.2.3 与上面相同的代码和相同的复合查询一起使用,代码确实会运行很长时间。我等了至少 15 分钟没有终止。它现在还在运行……我可能会在早上检查它。 :)

但是,我确实重新安排了上述代码,将递归调用移回原始代码所在的位置,如下所示:

fibluc(0, 0, 2).
fibluc(1, 1, 1).
fibluc(N, F, L) :-
    N in 2..1000,        % Pick a reasonable value here for 1000
    [F, L] ins 1..sup,
    N rem 2 #= 1,
    M #= N-1,
    fibluc(M, F1, L1),
    F #= (F1 + L1) // 2,
    L #= (5*F1 + L1) // 2.
fibluc(N, F, L) :-
    N in 2..1000,        % Pick a reasonable value here for 1000
    [F, L] ins 1..sup,
    N rem 2 #= 0,
    M #= N // 2,
    fibluc(M, F1, L1),
    F #= F1 * L1,
    L #= (5*F1*F1 + L1*L1) // 2.

在这种情况下,返回了有利的结果:

?- time((fibluc(100, X, Y), fibluc(N, X, Z))).
% 10,070,701 inferences, 3.216 CPU in 3.222 seconds (100% CPU, 3131849 Lips)
X = 354224848179261915075,
Y = Z, Z = 792070839848372253127,
N = 100 ;
% 1,415,320 inferences, 0.493 CPU in 0.496 seconds (100% CPU, 2868423 Lips)
false.

请注意,CLP(FD) 的性能在不同的 Prolog 解释器之间可能会有很大差异。有趣的是,在 SWI Prolog 中,处理尾递归情况的能力在 7.1.33 版本中暂时存在。

【讨论】:

  • @j4nbur53 您使用的是哪个 Prolog 解释器?在 SWI Prolog 中,查询 ?- fibluc(100, X, Y), fibluc(N, X, Z). 在几秒钟内返回一个解决方案(请参阅我更新的答案)。性能不佳可能是由于解释器对 CLP(FD) 的执行效率低下。 sup 相当大。我不确定在结果溢出之前最大的N 是多少。尽管您看到的性能差异与我遇到类似问题的经验一致。对FL 的限制可能促成了这一点。
  • 在早期的 SWI 版本中,您可以使用 (/)/2 而不是 (//)/2 来表示 CLP(FD) 表达式中的下限除法。您看到的不同参数的不同速度可能是由于代数属性(如生成的整数和域边界的素性、可分性等)导致的不同传播,这有时有助于加快传播速度。在 SWI-Prolog 中,sup 表示实际无穷大。您不能超出该边界,只有在数字太大时才会耗尽内存。这取决于全局堆栈的最大大小和可用 RAM。
  • 我是在回答潜伏者的隐含问题,而不是你。
  • 我在 same 评论中解决了你和 lurker 的问题....没有人指望西班牙人在同一评论中解决两个人的问题!
  • @j4nbur53 我的 SWI Prolog 版本是 7.1.33。我下载并编译了适用于 Linux(这是我的平台)的 7.2.3 源代码,并在 7.2.3 上运行了相同的测试,结果与您观察到的相似。但是,如果我将递归的 fibluc 调用移回原来的位置,我会得到有利的结果。
猜你喜欢
  • 2010-12-03
  • 2011-07-27
  • 1970-01-01
  • 1970-01-01
  • 2014-04-02
  • 2012-11-19
  • 1970-01-01
  • 2021-12-01
相关资源
最近更新 更多