繁体   English   中英

循环升序列表的 Prolog 约束

[英]Prolog constraint for cyclical ascending list

我想在 SWI-Prolog 中制定一个约束,使用 CLP(特别是 FD),一个列表是一个循环升序列表。

我的意思是一个常规的 Prolog 列表,它被用来表示一个循环列表,这样列表和它的所有旋转代表相同的循环列表。 并且限制是这些轮换之一是严格升序的列表。

例如,对于 8 个变量,我可以这样表示:

cyclical_ascending([A,B,C,D,E,F,G,H]) :-
    B #> A,
    C #> B,
    D #> C,
    E #> D,
    F #> E,
    G #> F,
    H #> G,
    A #> H.

除了这些约束之一必然不成立,而所有其他约束都成立。 我不知道/不在乎,是哪一个。

如何才能做到这一点?

我想到了几种定义cyclical_ascending规则的方法:

  • 名单cyclical_ascending如果列表的旋转的一个是上升
  • 名单cyclical_ascending如果或者(a)不存在相邻的一对X, Y ,其中X >= Y ,或(b)仅存在一个这样的一对和Head > Tail

我认为第二个定义会带来更有效的解决方案,所以我会尝试一下。 我们将跟踪列表的头部,并计算是否有一个

:- use_module(library(clpfd)).

cyclical_ascending([]).     % Empty list is a degenerate cyclical ascending list
cyclical_ascending([H|T]) :-
    cyclical_ascending([H|T], H, 0).

cyclical_ascending([_], _, 0).      % List is ascending
cyclical_ascending([X], H, 1) :-    % A cycle of list is ascending
    X #< H.
cyclical_ascending([X,Y|T], H, C) :-
    X #< Y,
    cyclical_ascending([Y|T], H, C).
cyclical_ascending([X,Y|T], H, C) :-
    X #>= Y,
    C #< 1,
    C1 #= C + 1,
    cyclical_ascending([Y|T], H, C1).

或者另一种写法是避免计数器但使用另一个辅助谓词:

cyclical_ascending([]).     % Empty list is a degenerate cyclical ascending list
cyclical_ascending([H|T]) :-
    cyclical_ascending([H|T], H).

cyclical_ascending([_], _).
cyclical_ascending([X,Y|T], H) :-
    X #< Y,
    cyclical_ascending([Y|T], H).
cyclical_ascending([X,Y|T], H) :-
    X #>= Y,
    cyclical_ascending1([Y|T], H).

cyclical_ascending1([X], H) :-
    X #< H.
cyclical_ascending1([X,Y|T], H) :-
    X #< Y,
    cyclical_ascending1([Y|T], H).

尝试一个简单的查询:

2 ?- length(L, 4), L ins 1..4, cyclical_ascending(L).
L = [1, 2, 3, 4] ;
L = [2, 3, 4, 1] ;
L = [3, 4, 1, 2] ;
L = [4, 1, 2, 3] ;
false.

3 ?-

这是 ECLiPSe 的解决方案,但您可以对 SWI/clpfd 使用相同的想法。 对于相邻列表元素的每一对X,Y ,我们计算一个布尔值B ,如果该对是升序的,则为 0,否则为 1。 为了满足您的“循环上升”条件, Bs一个必须为 1。

:- lib(ic).

cycasc(Xs) :-
    Xs = [X1|_], append(Xs, [X1], Xs1),                      % for convenience, append the first element to the end of the list
    ( fromto(Xs1,[X,Y|Xs2],[Y|Xs2],[_]), foreach(B,Bs) do    % make a list of booleans that indicate non-ascending pairs
        B #= (X#>=Y)
    ),
    sum(Bs) #= 1.                                            % there must be exactly one

示例运行:

?- length(Xs, 4), Xs #:: 1..4, cycasc(Xs), labeling(Xs).
Xs = [1, 2, 3, 4]
Yes (0.00s cpu, solution 1, maybe more)
Xs = [2, 3, 4, 1]
Yes (0.00s cpu, solution 2, maybe more)
Xs = [3, 4, 1, 2]
Yes (0.00s cpu, solution 3, maybe more)
Xs = [4, 1, 2, 3]
Yes (0.00s cpu, solution 4)

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM