Smullyan数值机器的解决方案

Cel*_*ibi 6 prolog constraint-programming

在这里,我建议找到这里定义的 Smullyan数值机器的解决方案.

问题陈述

它们是将数字列表作为输入的机器,并根据输入模式将其转换为遵循某些规则的另一个数字列表.以下是上面链接中给出的机器规则,更正式地表达了一下.假设M是机器,M(X)是X的变换.我们定义了一些这样的规则:

M(2X) = X
M(3X) = M(X)2M(X)
M(4X) = reverse(M(X)) // reverse the order of the list.
M(5X) = M(X)M(X)
Run Code Online (Sandbox Code Playgroud)

任何与任何规则都不匹配的内容都会被拒绝.这里有一些例子:

  • M(245)= 45
  • M(3245)= M(245)2M(245)= 45245
  • M(43245)=反向(M(3245))=反向(45245)= 54254
  • M(543245)= M(43245)M(43245)= 5425454254

问题是,找到X这样:

  • M(X)= 2
  • M(X)= X.
  • M(X)= X2X
  • M(X)=反向(X)
  • M(X)=反向(X2X)反向(X2X)

这是第二个例子,与穷举搜索相比有点复杂(特别是如果我想要前10或100个解决方案).

M(1X2) = X
M(3X) = M(X)M(X)
M(4X) = reverse(M(X))
M(5X) = truncate(M(X)) // remove the first element of the list truncate(1234) = 234. Only valid if M(X) has at least 2 elements.
M(6X) = 1M(X)
M(7X) = 2M(X)
Run Code Online (Sandbox Code Playgroud)

问题:

  • M(X)= XX
  • M(X)= X.
  • M(X)=反向(X)

(非)解决方案

在Prolog中编写求解器非常简单.除了它只是详尽的探索(又名蛮力),可能需要一些时间来制定一些规则.

我试过但是无法用CLP(FD)的逻辑约束来表达这个问题,所以我尝试用CHR(约束处理规则)来表达对列表的约束(特别是append约束),但无论我如何表达它,它总是归结为详尽的搜索.

知道我可以采取什么方法在合理的时间内解决这类问题吗?理想情况下,我希望能够生成比某些绑定更短的所有解决方案.

fal*_*lse 5

让我们来看看你的"更复杂"的问题.详尽的搜索功能非常出色!

这是与Сергей的解决方案的比较,通过考虑共同的目标可以显着改善:

m([1|A], X) :-
    A = [_|_],
    append(X, [2], A).
m([E | X], Z) :-
    m(X, Y),
    (  E = 3,
       append(Y, Y, Z)
    ;  E = 4,
       reverse(Y, Z)
    ;  E = 5,
       Y = [_ | Z]
    ;  E = 6,
       Z = [1 | Y]
    ;  E = 7,
       Z = [2 | Y]
    ).
Run Code Online (Sandbox Code Playgroud)

对于查询,time(findall(_, (question3(X), write(X), nl), _)).我得到B 8.1,SICStus 4.3b8:

??????? B tabled   104.542s
??????? B          678.394s
false  B           16.013s
false  B tabled    53.007s
??????? SICStus    439.210s
false  SICStus      7.990s
??????? SWI       1383.678s, 5,363,110,835 inferences
false  SWI         44.743s,   185,136,302 inferences
Run Code Online (Sandbox Code Playgroud)

其他问题并不难回答.只有SICStus以上m/2call_nth/2:

| ?- time(call_nth( (
        length(Xs0,N),append(Xs0,Xs0,Ys),m(Xs0,Ys),
          writeq(Ys),nl ), 10)).
[4,3,7,4,3,1,4,3,7,4,3,1,2,4,3,7,4,3,1,4,3,7,4,3,1,2]
[3,4,7,4,3,1,3,4,7,4,3,1,2,3,4,7,4,3,1,3,4,7,4,3,1,2]
[4,3,7,3,4,1,4,3,7,3,4,1,2,4,3,7,3,4,1,4,3,7,3,4,1,2]
[3,4,7,3,4,1,3,4,7,3,4,1,2,3,4,7,3,4,1,3,4,7,3,4,1,2]
[3,5,4,5,3,1,2,2,1,3,5,4,5,3,1,2,3,5,4,5,3,1,2,2,1,3,5,4,5,3,1,2]
[3,5,5,3,4,1,2,1,4,3,5,5,3,4,1,2,3,5,5,3,4,1,2,1,4,3,5,5,3,4,1,2]
[5,4,7,4,3,3,1,2,5,4,7,4,3,3,1,2,5,4,7,4,3,3,1,2,5,4,7,4,3,3,1,2]
[4,7,4,5,3,3,1,2,4,7,4,5,3,3,1,2,4,7,4,5,3,3,1,2,4,7,4,5,3,3,1,2]
[5,4,7,3,4,3,1,2,5,4,7,3,4,3,1,2,5,4,7,3,4,3,1,2,5,4,7,3,4,3,1,2]
[3,5,4,7,4,3,1,_2735,3,5,4,7,4,3,1,2,3,5,4,7,4,3,1,_2735,3,5,4,7,4,3,1,2]
196660ms

| ?- time(call_nth( (
        length(Xs0,N),m(Xs0,Xs0),
          writeq(Xs0),nl ), 10)).
[4,7,4,3,1,4,7,4,3,1,2]
[4,7,3,4,1,4,7,3,4,1,2]
[5,4,7,4,3,1,_2371,5,4,7,4,3,1,2]
[4,7,4,5,3,1,_2371,4,7,4,5,3,1,2]
[5,4,7,3,4,1,_2371,5,4,7,3,4,1,2]
[3,5,4,7,4,1,2,3,5,4,7,4,1,2]
[4,3,7,4,5,1,2,4,3,7,4,5,1,2]
[3,4,7,4,5,1,2,3,4,7,4,5,1,2]
[4,7,5,3,6,4,1,4,7,5,3,6,4,2]
[5,4,7,4,3,6,1,5,4,7,4,3,6,2]
6550ms

| ?- time(call_nth( (
        length(Xs0,N),reverse(Xs0,Ys),m(Xs0,Ys),
          writeq(Ys),nl ), 10)).
[2,1,3,4,7,1,3,4,7]
[2,1,4,3,7,1,4,3,7]
[2,1,3,5,4,7,_2633,1,3,5,4,7]
[2,1,5,4,7,3,2,1,5,4,7,3]
[2,4,6,3,5,7,1,4,6,3,5,7]
[2,6,3,5,4,7,1,6,3,5,4,7]
[2,_2633,1,5,3,4,7,_2633,1,5,3,4,7]
[2,_2633,1,5,4,3,7,_2633,1,5,4,3,7]
[2,1,3,4,4,4,7,1,3,4,4,4,7]
[2,1,3,4,5,6,7,1,3,4,5,6,7]
1500ms
Run Code Online (Sandbox Code Playgroud)

  • 不错的优化!在最后一个问题查询中,应该有`writeq(Xs0)`,因为现在顺序是颠倒的(并不重要,但可能会令人困惑). (2认同)

fal*_*lse 3

这是@Celelibi 改进版本的另一项改进 ( cele_n)。粗略地说,它通过限制第一个参数的长度获得了两倍,通过预先测试两个版本获得了另一个两倍。

cele_n SICStus  2.630s
cele_n SWI     12.258s 39,546,768 inferences
cele_2 SICStus  0.490s
cele_2 SWI      2.665s  9,074,970 inferences
Run Code Online (Sandbox Code Playgroud)
appendh([], [], Xs, Xs).
appendh([_, _ | Ws], [X | Xs], Ys, [X | Zs]) :-
   appendh(Ws, Xs, Ys, Zs).

m([H|A], X) :-
   A = [_|_],                 % New
   m(H, X, A).

m(1, X, A) :-
   append(X, [2], A).
m(3, X, A) :-
   appendh(X, B, B, X),
   m(A, B).
m(4, X, A) :-
   reverse(X, B),
   m(A, B).
m(5, X, A) :-
   X = [_| _],
   m(A, [_|X]).
m(H1, [H2 | B], A) :-
   \+ \+ ( H2 = 1 ; H2 = 2 ),  % New
   m(A, B),
   (  H1 = 6, H2 = 1
   ;  H1 = 7, H2 = 2
   ).

answer3(X) :-
   between(1, 13, N),
   length(X, N),
   reverse(X, A),
   m(X, A).

run :-
   time(findall(X, (answer3(X), write(X), nl), _)).
Run Code Online (Sandbox Code Playgroud)