如何在guile中实施tarai

时间:2019-04-06 10:56:19

标签: guile

我现在想运行tarai,在Prolog中的内容如下。一个测试案例是运行?- tarai(12,6,0,X)。这是一个相当困难的测试案例,例如,GNU Prolog与此测试案例一起崩溃。

tarai(X, Y, Z, R) :- 
    X > Y -> 
        X1 is max(0,X-1), tarai(X1, Y, Z, Rx),
        Y1 is max(0,Y-1), tarai(Y1, Z, X, Ry),
        Z1 is max(0,Z-1), tarai(Z1, X, Y, Rz),
        tarai(Rx, Ry, Rz, R); 
    R = Y.

我最感兴趣的是测试用例是否可以在tarai的miniKanren代码的完全声明版本上运行。可选地,我会对向后运行一些测试用例感兴趣。

我有点茫然。我设法安装了guile(一种方案变体),并且可以成功运行miniKanren测试用例。但是miniKanren没有整数,那该怎么办?

6 个答案:

答案 0 :(得分:1)

这个问题被问到如何在prolog规范中实现tarai函数的更通用版本,该版本允许x,y,z字段中的变量。此处的技术可以例如以序言形式实现。 clpfd有限域求解器和kanren需要类似的东西(上面的注释讨论,例如对numbers.scm的引用)。关键是在所有情况下使用nuke->并使用防护,我们将假设> o = o <= o均已为变量定义(例如,对于var X,X> 0将约束X为值1,2 ,3,...)。我们还将假设使用间隔算术约束通过特殊的“ iso”为此类变量定义了“ -o”。使用此方法,我们可以将tarai定义为以下代码(如果将max和min也定义为约束,则可以简化,但是这里我们通过不等式和大量案例来实现)。

(define (taray x y z w)
  (lambda ()         
    (conde ((<o x y) 
            (fresh (rx ry rz)
              (conde
               ((conde 
                  ((>o x 0) 
                   (fresh (xx) 
                     (conde
                       ((iso xx (-o x 1)) 
                        (tarai xx y z rx)))))
                  ((== x 0) (tarai 0 y z rx)))
                (conde 
                  ((>o y 0) 
                   (fresh (yy) 
                     (conde
                       ((iso yy (-o y 1)) 
                        (tarai yy z x ry)))))
                  ((== y 0) (tarai 0 z x ry)))
                (conde 
                  ((>o z 0) 
                   (fresh (zz) 
                     (conde
                       ((iso zz (-o z 1)) 
                        (tarai zz x y rz)))))
                  ((== z 0) (tarai 0 x y r<)))
                (tarai rx ry rz r)))))
            ((>=o x y) (== x y))))))

答案 1 :(得分:1)

我是guile-log的开发者,它是一个基于guile方案的逻辑编程环境,该环境同时具有minikanren构造和prolog构造,并且可以将它们混合使用。它还移植了一个clpfd库,因此您可以在此处执行以下操作(不幸的是,atm无法正常工作(我正在研究的错误))。假设已导入clpfd。 (,; ;;像kans一样交错kanren)。用和替换;;;与;您会使用clpfd库获得可以在swi prolog等代码上运行的代码。

tarai(X,Y,Z,W) :-
 (
   X #> Y , 
   (
     (
       ((X #> 0 , XX #= X - 1, tarai(XX,Y,Z,RX)) ;;
        (X  = 0 , tarai(0,Y,Z,RX))) ,,
       ((Y #> 0 , YY #= Y - 1, tarai(YY,Z,X,RY)) ;;
        (Y =  0 , tarai(0,Z,X,RY))) ,,
       ((Z #> 0 , ZZ #= Z - 1, tarai(ZZ,X,Y,RZ)) ;;
        (Z =  0 , tarai(0,X,Y,RZ)))
     ) ,,
     tarai(RX,TY,RZ,R)
   )
 ) ;;
 (X #=< Y, R=Y).

答案 2 :(得分:0)

例如,我尝试使用clpfd运行tarai(12,X,0,12),但这很复杂。记忆功能不适用于swipl的属性变量。因此,我能找到的最佳解决方案是将确定性的记住的tarai与类似的东西一起使用

tarai2(X,Y,Z,W) :-
  (var(X)->between(0,20,X);true),
  (var(Y)->between(0,20,Y);true),
  (var(z)->between(0,20,Z);true),
  tarai(X,Y,Z,W).

然后可以容易地找到该范围内具有tarai2(12,Y,Z,12)的所有解Y,Z。

答案 3 :(得分:-1)

请注意,此算法只有一种解决方案(如果存在)并且是确定性的。您可以将方案变量x,y,z直接传递给kanren tarai函数,因为它们没有统一性,因此无需kanren变量就可以实现X,Y,Z的逻辑。但是R值必须是逻辑变量,您需要以tarai(Rx,Ry,Rz,R)的形式获取有界值,例如查找Rx,Ry,Rz的值,并将其输入tarai函数。另外,您还需要确保在前三个表单完成后执行此表单(这很容易完成,因为没有纯粹的多重选择),因此您知道Rx,Ry,Rz是有界的。还要注意,该算法可能依赖于执行顺序才能有效执行,但是确定性又意味着这一点很容易满足。注意A-> B; C在这里简单地转换为方案(如果A B C的话),因为A = X> Y是确定性的。因此代码可能看起来像是伪代码

(define (tarai x y z r)
  (lambda ()
    (fresh (rx ry rz)
       (if (> x y)
           (conda
             ( (conda ((tarai (- x 1) y z rx) 
                       (tarai (- y 1) z x ry)
                       (tarai (- z 1) x y rz)))
               (project (rx ry rz) (tarai rx ry rz r))))
           (== r y)))))

答案 4 :(得分:-1)

要在guile-log方案宏接口see links on this site中进行确定性验证,您可以通过备忘实现,因为(没有备忘,解决方案将变量栈吹到guile-log上)

(define tarai 
  (memo 
    (<lambda> (x y z r) 
       (if (> x y) 
           (<var> (rx ry rz) 
              (<and> 
                 (tarai (max (- x 1) 0) y z rx) 
                 (tarai (max (- y 1) 0) z x ry) 
                 (tarai (max (- z 1) 0) x y rz) 
                 (tarai (<lookup> rx) (<lookup> ry) (<lookup> rz) r))) 
           (<=> r y)))))

scheme@(guile-user)> ,time (<run> 1 (r) (tarai 12 6 0 r))
$13 = (12)
;; 0.293411s real time, 0.290711s run time.  0.000000s spent in GC.
scheme@(guile-user)> 

答案 5 :(得分:-1)

这是一个缓慢的实现,它是声明性的,并使用numbers.scm(由问题的作者建议)和minkanren。

(load "minkanren.scm)
(load "numbers.scm")

(define one  (build-num 1))
(define zero (build-num 0))
(define (tarai x y z r)
    (conde
        ((<=o x y) (== r y))
        ((<o y x)
         (fresh (rx ry rz)
          (conde
           ((fresh (xx)
            (conde
             ((<o zero x) (minuso x one xx) (tarai xx y z rx))
             ((== zero x) (tarai zero y z rx))))
           (fresh (yy)
            (conde
             ((<o zero y) (minuso y one yy) (tarai yy z x ry))
             ((== zero y) (tarai zero z x ry))))
           (fresh (zz)
            (conde
             ((<o zero z) (minuso z one zz) (tarai zz x y rz))
             ((== zero z) (tarai zero x y rz))))
           (tarai rx ry rz r)))))))

如果推导方向相反(因此我们要加上数字),由于声明式的样式,我们仍然可以解决

tarai(4,2,Z,4):, (you need to make binaries of the number) will lead to
Y = [0, 1],
W = [0, 0, 1],
Z = [0, 0, 1],
X = [0, 0, 1].

并且应该添加制表符:

tarai(12,6,0,W):
Z = (),
X = [0, 0, 1, 1],
Y = [0, 1, 1],
W = [0, 0, 1, 1].