Как реализовать тараи в хитрости

Теперь я хотел бы запустить tarai, который читается на Прологе следующим образом. Тестовым примером будет запуск ?- 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.

Меня больше всего интересует, можно ли запустить тестовый пример с полностью декларативной версией некоторого кода miniKanren для tarai. При желании мне было бы интересно запустить некоторые тестовые случаи назад.

Я немного в растерянности. Мне удалось установить guile, вариант схемы, и я могу успешно запустить тестовые примеры miniKanren. Но в miniKanren нет целых чисел, так что же делать?


person Mostowski Collapse    schedule 06.04.2019    source источник


Ответы (6)


Вопрос был перефразирован, чтобы спросить, как реализовать более общую версию функции tarai в спецификации пролога, которая допускает переменные в полях x, y, z. Техника здесь может быть реализована в прологе, например. Решатель конечной области clpfd и что-то подобное необходимо для kanren (см. обсуждения в комментариях выше, например, ссылку на numbers.scm). Ключевым моментом является уничтожение -> и использование охранников для всех случаев, и мы предполагаем, что все операторы >o =o ‹=o определены для переменных (например, для var X, X > 0 будет ограничивать X значениями 1,2 ,3,...). Также будем считать, что '-o' определено и для переменных такого рода с использованием ограничений интервальной арифметики через специальный 'iso'. Используя это, мы можем определить 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))))))
person Stefan    schedule 15.04.2019
comment
Я могу добавить о, если вы действительно хотите отметить, что они относятся к категории «о». - person Stefan; 15.04.2019
comment
У меня нет ссылки на банкомат number.scm, потому что он заблокирован брандмауэром. Я использую гипотетическую библиотеку ограничений, например. хороший должен поддерживать такие, как clpfd - person Stefan; 15.04.2019
comment
Также обратите внимание, что было бы целесообразно ввести ограничения с помощью конструкции iso, как в clpfd. - person Stefan; 15.04.2019
comment
Чтобы позволить x, y, z или w быть переменными, вам нужен решатель конечной области для миниканрена, который вам нужно закодировать самостоятельно, поскольку я не могу найти такую ​​библиотеку в сети, если x, y, z ограничен, вы можете просто используйте мою первую версию. Я надеялся на ваш квест, что неравенства были определены в numbers.scm, но это просто похоже на библиотеку для обычных чисел, сделанных в хорошей книге «аргументированный схематик» из вашего описания. Кстати, я отдаю не за вознаграждение, а за то, что отдаю сообществу, SE — фантастический источник. - person Stefan; 15.04.2019
comment
раньше это было неправильно, гораздо проще, если можно использовать max - person Stefan; 15.04.2019

Я разработчик guile-log — среды логического программирования на схеме хитрости, которая как конструкции миниканрена, так и конструкции пролога, и их можно смешивать. Он также имеет портированную библиотеку clpfd, поэтому здесь вы можете сделать следующее (к сожалению, это не работает (ошибка, над которой я работаю)). Предположим, что clpfd импортирован. (,, ;; чередует kanren как ops). Замена ,, на и ;; с ; вы получаете код, который может работать, например, на прологе swi, используя библиотеку clpfd.

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).
person Stefan    schedule 15.04.2019
comment
По моему личному мнению, хорошо выделять разные идеи и синтаксисы. - person Stefan; 15.04.2019
comment
обратите внимание, что вы можете изменить ,, на и ;; к ; и запустите код на прологе swi, но тогда вы не получите гарантий, которые миниканрен имеет против бесконечной рекурсии. - person Stefan; 15.04.2019
comment
Поиск в глубину в некоторых случаях может привести к бесконечности, и самое замечательное в миниканрене то, что вы можете кодировать и знать, что если есть решение, вы в конечном итоге найдете его, если памяти недостаточно. Но в выборе стратегий поиска не так много разума, и может быть разумно использовать другие методы, чтобы разумно направлять поиск. Вероятно, это то, что вы видите, когда запускаете tarai. Одна вещь, на которую стоит обратить внимание, — это запоминание, которое может ускорить работу. - person Stefan; 15.04.2019
comment
Может быть, на одну величину медленнее. Однако, чтобы знать наверняка, нужно запустить его. Однако компилятор Guile медленный. 15 минут на компиляцию clpfd. - person Stefan; 15.04.2019
comment
Я добавил детерминированный ответ с таймингами в интерфейс макроса схемы guile-log - person Stefan; 15.04.2019
comment
Я могу понять, что поиск очень глубокий и не так просто сдувает стек переменных, и мой лимит на количество переменных дует с этим детерминированным кодом - person Stefan; 15.04.2019
comment
ошибка, исправлю - person Stefan; 15.04.2019

Я пытался запустить, например, tarai(12,X,0,12) с clpfd, но это слишком сложно для него. И мемоизация не работает с атрибутированными переменными для 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).

тогда все решения Y,Z в этом диапазоне с tarai2(12,Y,Z,12) могут быть легко найдены.

person Stefan    schedule 15.04.2019
comment
попросите меня удалить сообщения позже, и мы можем очистить. - person Stefan; 15.04.2019

Обратите внимание, что этот алгоритм имеет только одно решение, если оно существует и является детерминированным. Вы можете передавать переменные схемы как x, y, z непосредственно в функцию kanren tarai, для них нет унификации, поэтому реализация логики для X, Y, Z может быть выполнена без переменных kanren. Однако значения R должны быть логическими переменными, и вам нужно получить ограниченные значения в форме tarai (Rx, Ry, Rz, R), например. найдите значение Rx, Ry, Rz и введите их в функцию tarai. Также вам нужно убедиться, что эта форма выполняется после завершения первых трех форм (что легко сделать, потому что нет чистого множественного выбора), чтобы вы знали, что Rx, Ry, Rz ограничены. Также обратите внимание, что этот алгоритм может зависеть от порядка выполнения, чтобы быть эффективным, но опять же детерминизм означает, что этот пункт легко удовлетворить. Обратите внимание, что А -> В ; 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)))))
person Stefan    schedule 12.04.2019
comment
Я разговариваю по телефону в эти выходные, так что просто короткие ответы. нет, код пролога также необратим. но если вам нужна обратимость, вам нужно защищать каждое предложение с помощью меньше, больше или равно. После этого вам понадобится wsy для ограничения переменных и выполнения арифметических операций с переменными. в прологе вы бы сделали это с чем-то вроде постоянного решателя, такого как clpfd или как он называется, и, возможно, numbers.scm предоставит то же самое. - person Stefan; 12.04.2019
comment
Если у вас нет max и min, вы можете погрузиться в дела, используя охранники x › 0 и x = 0. - person Stefan; 15.04.2019
comment
Если у вас нет conda, попробуйте использовать conde в приведенном выше примере. - person Stefan; 15.04.2019

Чтобы сделать детерминированную версию в макроинтерфейсе схемы guile-log, см. ссылки на этом сайте, вы можете реализовать это с мемоизацией как (без мемоизации решение сносит стек переменных на 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)> 
person Stefan    schedule 15.04.2019
comment
Комментарии не для расширенного обсуждения; этот разговор был перемещен в чат. - person Samuel Liew♦; 15.04.2019

Это медленная декларативная реализация, использующая numbers.scm ( как предлагает автор вопроса) и минканрен.

(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].
person Stefan    schedule 15.04.2019
comment
похоже, что когда вы переворачиваете вывод, он начинает подсчитывать элементы, и количество случаев взрывается, а алгоритм поиска работает вечно. Ограничение числа препятствует этому, и это немного отличается от поиска между, потому что порядок поиска другой. - person Stefan; 16.04.2019
comment
да, он использует немного макросов guile-log, чтобы по существу включить табличное отображение и сделать его работоспособным из приглашения пролога. - person Stefan; 16.04.2019
comment
aha ‹o чередуется, что означает, что они работают иначе, чем между - person Stefan; 16.04.2019
comment
Просто скажи мне, кем ты хочешь остаться, и мы позволим этому быть! - person Stefan; 16.04.2019
comment
ваш пример - tarai (12,6,0, R), может быть обратным, если вы можете запросить tarai (12, Y, 0,12), например. вы можете решить для любого количества переменных, это приведет к нескольким решениям. Если вы не хотите составлять таблицы, у вас есть решение minikanren в приведенном выше сообщении довольно легко, которое является декларативным, хотя оно будет использовать чередование между, например, ‹o и друзья и не будет основываться на решателе ограничений. - person Stefan; 16.04.2019
comment
Хорошо, я просто переписал это в стиле канрен, это будет то, о чем вы просили. Это проверено (возможно, несколько неправильных скобок), чтобы дать правильные ответы. Но я подозреваю, что когда вы запустите тестовый пример, он взорвется. Мне удалить остальные посты? - person Stefan; 16.04.2019
comment
Это весело, но нам нужно получить постоянный запас в этом вопросе. Давайте просто ответим на вопрос и отложим вопросы о таблицах и о том, как это эффективно решить, до другого вопроса. В нынешнем виде люди получат пример того, как кодировать с помощью minikanren. Я действительно думаю, что ссылки на guile-log — это излишество, это просто моя игрушка. Для развлечения загляните на c-lambda.se/interleaving-tables.html. - person Stefan; 16.04.2019
comment
Если в решении нет ни одной точки, вам нужна метка или маркировка. Guile использует тот же исходный код от Triska, что и swipl. - person Stefan; 16.04.2019
comment
Запрос: схема@(guile-user)[4]›(run 1(x)(tarai '(0 0 1 1) '(0 1 1) '() x)) выполняется уже минуту, результата нет. - person Mostowski Collapse; 17.04.2019
comment
Я получил результат при использовании таблицы в guile-log. Для ванильного канрена вам нужно запускать меньшие кейсы - person Stefan; 17.04.2019
comment
Обратите внимание, что у вас будет то же пространство поиска с kanren, что и с пролог-версией, только поиск kanren будет намного медленнее из-за 1) общего более медленного механизма выполнения, 2) сохранения assoc, который значительно увеличивает привязки переменных. - person Stefan; 17.04.2019
comment
возможно, github.com/webyrd/table может вам помочь, я не могу открыть этот файл в банкомате. - person Stefan; 17.04.2019
comment
Хорошо, я уточнил ваш ответ и добавил, что для второго примера предполагается таблица. Если у меня будет время, я также проверю, работает ли первый пример, то есть tarai(4,2,Z,4). - person Mostowski Collapse; 17.04.2019