谓词有效,但不能自动填空

时间:2018-05-31 02:15:52

标签: prolog

我编写了一个谓词,它带有两个列表,一个列出link个列表,另一个列表按有效顺序使用link个列表。链接写为link(a, b),其中的部分可以按任何顺序排列,结果应该相同。有效的链接订单为[link(a, b), link(b, c), link(c, a)]。这形成了一个link的环,它与至少一个元素相连。

% Can two links be adjacent?
adjacent(link(Elem, _), link(Elem, _)).
adjacent(link(_, Elem), link(Elem, _)).
adjacent(link(_, Elem), link(_, Elem)).
adjacent(link(Elem, _), link(_, Elem)).

% Swap the parts in a link.
swapped(link(A, B), link(B, A)).

% Is each item unique in the list?
unique(List) :- \+ (select(Elem, List, Res), memberchk(Elem, Res)).

% Can the list form a loop using only the provided links?
ring(List, Ring) :-
    length(Ring, Length),
    Length > 2, % List is at least of length 3.
    Ring = [First|_],
    last(Ring, Last),
    adjacent(First, Last), % First and last have to be able to be adjacent.
    unique(Ring), % No repeated items.
    linked(List, Ring). % Are the middle links adjacent?

% Are any of the two elements in a list?
member_or(Elem, _, List) :- member(Elem, List).
member_or(_, Elem, List) :- member(Elem, List).

% Is the list able to be linked using only the provided links?

linked(_, []).
linked(List, [Elem]) :-
    swapped(Elem, Alt),
    member_or(Elem, Alt, List). % Is the item valid?
linked(List, [First|Ring]) :-
    swapped(First, Alt),
    member_or(First, Alt, List), % Is the first item valid?
    Ring = [Second|_],
    adjacent(First, Second), % Can the next item be adjacent?
    linked(List, Ring). % Is the same operation true with one less item?

当它用作ring([link(a, b), link(b, c), link(a, c), link(f, r)], [link(a, b), link(b, c), link(c, a)]).(放置所有参数)时,它总是返回正确的布尔值(在本例中为true)。理想情况下,我想写ring([link(a, b), link(b, c), link(c, a), link(f, r)], Ring).并且会给出所有可能的Ring,但这会冻结解释器(我使用SWI-Prolog,以防万一)并且从不吐出任何东西。这是一些无限循环还是只是错误的逻辑? (或其他什么?)

1 个答案:

答案 0 :(得分:2)

让我们检查一下痕迹:

?- trace, ring([link(a, b), link(b, c), link(c, a), link(f, r)], Ring).
   Call: (9) ring([link(a, b), link(b, c), link(c, a), link(f, r)], _452) ? creep
   Call: (10) length(_452, _828) ? creep
   Exit: (10) length([], 0) ? creep
   Call: (10) 0>2 ? creep
   Fail: (10) 0>2 ? creep
   Redo: (10) length(_452, _828) ? creep
   Exit: (10) length([_812], 1) ? creep
   Call: (10) 1>2 ? creep
   Fail: (10) 1>2 ? creep
   Redo: (10) length([_812|_814], _840) ? creep
   Exit: (10) length([_812, _824], 2) ? creep
   Call: (10) 2>2 ? creep
   Fail: (10) 2>2 ? creep

直到我们到达这里才感兴趣:

   Redo: (10) length([_812, _824|_826], _852) ? creep
   Exit: (10) length([_812, _824, _836], 3) ? creep
   Call: (10) 3>2 ? creep
   Exit: (10) 3>2 ? creep
   Call: (10) [_812, _824, _836]=[_848|_850] ? creep
   Exit: (10) [_812, _824, _836]=[_812, _824, _836] ? creep
   Call: (10) lists:last([_812, _824, _836], _870) ? creep
   Exit: (10) lists:last([_812, _824, _836], _836) ? creep
   Call: (10) adjacent(_812, _836) ? creep
   Exit: (10) adjacent(link(_854, _856), link(_854, _862)) ? creep
   Call: (10) unique([link(_854, _856), _824, link(_854, _862)]) ? creep
   Call: (11) lists:select(_880, [link(_854, _856), _824, link(_854, _862)], _884) ? creep
   Exit: (11) lists:select(link(_854, _856), [link(_854, _856), _824, link(_854, _862)], [_824, link(_854, _862)]) ? creep
   Call: (11) memberchk(link(_854, _856), [_824, link(_854, _862)]) ? creep
   Exit: (11) memberchk(link(_854, _856), [link(_854, _856), link(_854, _862)]) ? creep
   Fail: (10) unique([link(_854, _856), _824, link(_854, _862)]) ? creep
   Redo: (10) adjacent(_812, _836) ? creep
   Exit: (10) adjacent(link(_854, _856), link(_856, _862)) ? creep
   Call: (10) unique([link(_854, _856), _824, link(_856, _862)]) ? creep
   Call: (11) lists:select(_880, [link(_854, _856), _824, link(_856, _862)], _884) ? creep
   Exit: (11) lists:select(link(_854, _856), [link(_854, _856), _824, link(_856, _862)], [_824, link(_856, _862)]) ? creep
   Call: (11) memberchk(link(_854, _856), [_824, link(_856, _862)]) ? creep
   Exit: (11) memberchk(link(_854, _856), [link(_854, _856), link(_856, _862)]) ? creep
   Fail: (10) unique([link(_854, _856), _824, link(_856, _862)]) ? creep
   Redo: (10) adjacent(_812, _836) ? creep
   Exit: (10) adjacent(link(_854, _856), link(_860, _856)) ? creep
   Call: (10) unique([link(_854, _856), _824, link(_860, _856)]) ? creep
   Call: (11) lists:select(_880, [link(_854, _856), _824, link(_860, _856)], _884) ? creep
   Exit: (11) lists:select(link(_854, _856), [link(_854, _856), _824, link(_860, _856)], [_824, link(_860, _856)]) ? creep
   Call: (11) memberchk(link(_854, _856), [_824, link(_860, _856)]) ? creep
   Exit: (11) memberchk(link(_854, _856), [link(_854, _856), link(_860, _856)]) ? creep
   Fail: (10) unique([link(_854, _856), _824, link(_860, _856)]) ? creep
   Redo: (10) adjacent(_812, _836) ? creep
   Exit: (10) adjacent(link(_854, _856), link(_860, _854)) ? creep
   Call: (10) unique([link(_854, _856), _824, link(_860, _854)]) ? creep
   Call: (11) lists:select(_880, [link(_854, _856), _824, link(_860, _854)], _884) ? creep
   Exit: (11) lists:select(link(_854, _856), [link(_854, _856), _824, link(_860, _854)], [_824, link(_860, _854)]) ? creep
   Call: (11) memberchk(link(_854, _856), [_824, link(_860, _854)]) ? creep
   Exit: (11) memberchk(link(_854, _856), [link(_854, _856), link(_860, _854)]) ? creep
   Fail: (10) unique([link(_854, _856), _824, link(_860, _854)]) ? creep
   Redo: (10) length([_812, _824, _836|_838], _864) ? creep
   Exit: (10) length([_812, _824, _836, _848], 4) ? creep
   Call: (10) 4>2 ? creep
   Exit: (10) 4>2 ? creep
   Call: (10) [_812, _824, _836, _848]=[_860|_862] ? creep
   Exit: (10) [_812, _824, _836, _848]=[_812, _824, _836, _848] ? 

这里有两个值得注意的重要事实:

  1. 你确实转到了长度为4的列表,所以这里确实存在某种逻辑错误。
  2. 我觉得你几次都在产生相同的可能性,所以你很难努力不产生答案。乍一看,看起来adjacent/2正在帮助您生成相同排列变量的四个版本以进行检查。这似乎效率低下。
  3. 追踪中遗漏了什么? linked/2。为什么?因为我们从未成功统一unique/1!实际上,这几乎总是失败:

    ?- unique([A,B]).
    false.
    
    ?- unique([A,B,C]).
    false.
    
    ?- unique([A]).
    true.
    

    我认为这是你的问题。使用dif/2,有更好的方法,尽管不那么便携。有趣的是,最近有人询问了这个问题,@ false链接到this answer,显示了一个实际适用于像你这样的案例的良好实现。让我们用这个定义代替,看看会发生什么:

    unique([]).
    unique([E|Es]) :-
       maplist(dif(E), Es),
       unique(Es).
    
    ?- ring([link(a, b), link(b, c), link(c, a), link(f, r)], Ring).
    Ring = [link(a, b), link(b, c), link(a, c)] ;
    Ring = [link(a, b), link(b, a), link(a, c)] ;
    Ring = [link(a, b), link(c, b), link(a, c)] ;
    Ring = [link(a, b), link(c, a), link(a, c)] ;
    Ring = [link(a, b), link(c, a), link(a, c)] ;
    Ring = [link(a, b), link(b, a), link(a, c)] ;
    Ring = [link(b, c), link(c, a), link(b, a)] ;
    

    似乎可以公平地说这已经解决了你的第一个问题。我看到了很多重复的解决方案,所以我认为你还没有完全走出困境,我认为你仍然需要重新考虑你的adjacent/2谓词,或者你对它的使用;我得到了长度为3的列表的192个解决方案,但只有120个独特的解决方案,看起来更像是我希望看到的那些因子/组合数字之一而不是192。