一次删除不正确的后续解决方案

时间:2016-07-23 15:50:12

标签: prolog dcg clpfd

我有一个谓词,找到正确的解决方案,但接着找到不正确的解决方案。

?- data(D),data_threshold_nonredundantbumps(D,5,Bs),write(D).
[3,6,7,8,2,4,5,6,9,4,7,3]
D = [3, 6, 7, 8, 2, 4, 5, 6, 9|...],
Bs = [bump([11], [7]), bump([8, 9], [6, 9]), bump([2, 3, 4], [6, 7, 8])] ;
[3,6,7,8,2,4,5,6,9,4,7,3]
D = [3, 6, 7, 8, 2, 4, 5, 6, 9|...],
Bs = [bump([8, 9], [6, 9]), bump([2, 3, 4], [6, 7, 8])] ;
[3,6,7,8,2,4,5,6,9,4,7,3]
D = [3, 6, 7, 8, 2, 4, 5, 6, 9|...],
Bs = [bump([8], [6]), bump([2, 3, 4], [6, 7, 8])] ;
[3,6,7,8,2,4,5,6,9,4,7,3]
D = [3, 6, 7, 8, 2, 4, 5, 6, 9|...],
Bs = [bump([9], [9]), bump([2, 3, 4], [6, 7, 8])] ;
[3,6,7,8,2,4,5,6,9,4,7,3]
D = [3, 6, 7, 8, 2, 4, 5, 6, 9|...],
Bs = [bump([11], [7]), bump([2, 3, 4], [6, 7, 8])] ;
[3,6,7,8,2,4,5,6,9,4,7,3]
D = [3, 6, 7, 8, 2, 4, 5, 6, 9|...],
Bs = [bump([2, 3, 4], [6, 7, 8])] ;

这个想法是它会找到数据中的所有非冗余颠簸,其中凹凸是data的连续子列表,高于threshold,返回{的有序(按大小)列表{ {1}}其中bump / 2的第一个arg是来自数据的标记列表,第二个arg是值列表。所以bump/2s意味着在数据索引2,3和4高于5时,它们是6,7,8。

如何添加条件以便找不到这些额外的解决方案? - 没有使用bump([2, 3, 4], [6, 7, 8])

如果我的代码可以通过其他方式简化,请告诉我。这似乎有点复杂,它正在尝试做什么。

所以:

这是我的代码:

once/1

2 个答案:

答案 0 :(得分:7)

我的印象是你稍微过度思考。对于超过阈值的运行数字有一个直接的表达式,可以通过在列表的单个遍历中从头到尾考虑从头到尾的元素来定义。特别是,我们需要append/3来执行此操作。

在Prolog中描述列表时,请始终考虑使用 DCG表示法)。在这种情况下,需要花一点时间来决定如何最好地应用DCG,因为我们正在描述两个列表:

  • 运行列表(连续元素超过阈值)
  • 在运行中,索引列表和

然而,除了一些技巧和扩展之外,DCG基本上只允许我们描述单个列表,而不是同时单独的列表。因此,我们可以使用这种功能强大且可能非常合适的机制,并且必须选择我们要应用的列表主要是

在下文中,我展示了一个使用DCG来描述 bump / 1 术语列表的解决方案,也就是说,我“专用”该机制来描述上面提到的第一种列表,并使用另一个DCG来描述第二个类型的列表,我从第一个DCG中通过phrase/2调用。

data_threshold_bumps(Ds, T, Bs) :-
        phrase(bumps(Ds, 1, T), Bs).

bumps([], _, _) --> [].
bumps([D|Ds0], I0, T) -->
        { D #> T,
          phrase(bump(D, T, Ds0, Ds, I0, I), Bs) },
        [bump(Bs)],
        bumps(Ds, I, T).
bumps([D|Ds0], I0, T) -->
        { D #=< T,
          I #= I0 + 1 },
        bumps(Ds0, I, T).


bump(D, T, Ds0, Ds, I0, I) --> [I0-D],
        { I1 #= I0 + 1 },
        run(Ds0, Ds, T, I1, I).

run([], [], _, I, I) --> [].
run([D|Ds0], Ds, T, I0, I) --> [I0-D],
        { D #> T,
          I1 #= I0 + 1 },
        run(Ds0, Ds, T, I1, I).
run([D|Ds0], [D|Ds0], T, I, I) -->
        { D #=< T }.

示例查询和回答:

?- data_threshold_bumps([3,6,7,8,2,4,5,6,9,4,7,3], 5, Bs).
Bs = [bump([2-6, 3-7, 4-8]), bump([8-6, 9-9]), bump([11-7])] ;
false.

请注意,这不是完全您需要的完全相同的数据表示形式,但将其转换为该数据表示是微不足道的。

以下是一些改进此解决方案的想法,从容易到难度:

  • 使用if_/3
  • 摆脱不必要的选择点
  • 在上面的代码中对bumps//3run//5使用DCG表示法真的有意义吗?在这里使用DCG比常规谓词有什么好处和缺点?
  • 使用不同的问题视图播放:您可以转换DCG视图吗?例如,如何用DCG描述实际的数据,而不是颠簸?
  • 在您发布的代码中追踪不需要的解决方案的来源。

顺便说一下,要否定一个(可再生的)CLP(FD)约束,你需要使用(#/\)/2来表示一个连词。它(,)/2一起使用。

答案 1 :(得分:2)

在以下代码中,您将找到许多以

括起来的部分
:- if(false).
...
:- endif.

所有这些部分都得到相同的结果

?- data_threshold_bumps([3,6,7,8,2,4,5,6,9,4,7,3], 5, Bs).
Bs = [bump([11], [7]), bump([8, 9], [6, 9]), bump([2, 3, 4], [6, 7, 8])] ;
false.

代码本身它只是一个模式匹配的应用程序,并且,从最后到第一个,显示了一种可能的方法来重构相同的基本bump / 5谓词以获得更好的可读性(但是,确实,我的首选它是它的最后一个......)

data_threshold_bumps(Es, T, Sorted) :-
    bumps(Es, 1, T, Bs),
    predsort(by_len, Bs, Sorted).

bumps([], _, _, []).
bumps([E|Es], P, T, Bs) :-
    succ(P, Q),
    bumps(Es, Q, T, Cs),
    bump(E, P, T, Cs, Bs).

by_len(<, bump(Xs,_), bump(Ys,_)) :-
    length(Xs, Xl),
    length(Ys, Yl), Xl < Yl.
by_len(>, _, _).

:- use_module(library(clpfd)).

bump(E, _, T, Bs, Bs) :- E #=< T.
bump(E, P, T, Cs, Bs) :- E #> T, elem_placed(E, P, Cs, Bs).

elem_placed(E, P, [], [bump([P], [E])]).
elem_placed(E, P, [X|Bs], [Y|Bs]) :-
    X = bump([Q|Ps], [F|Es]),
    P #= Q-1,
    Y = bump([P,Q|Ps], [E,F|Es]).
elem_placed(E, P, [X|Bs], [bump([P],[E]), X|Bs]) :-
    X = bump([Q|_Ps], _Es),
    P #\= Q-1.

:- if(false).

bump(E, _, T, Bs, Bs) :- E =< T.
bump(E, P, T, Cs, Bs) :- E > T, elem_placed(E, P, Cs, Bs).

% first stored: tail
elem_placed(E, P, [], [bump([P], [E])]).
% extend current
elem_placed(E, P, [X|Bs], [Y|Bs]) :-
    X = bump([Q|Ps], [F|Es]),
    succ(P, Q),
    Y = bump([P,Q|Ps], [E,F|Es]).
% place new
elem_placed(E, P, [X|Bs], [bump([P],[E]), X|Bs]) :-
    X = bump([Q|_Ps], _Es),
    \+ succ(P, Q).

:- endif.

:- if(false).

bump(E, _, T, Bs, Bs) :- E =< T.
bump(E, P, T, Cs, Bs) :- E > T, enabled(E, P, Cs, Bs).

enabled(E, P, [], [bump([P], [E])]).
enabled(E, P, [bump([Q|Ps], [F|Es])|Bs], [bump([P,Q|Ps], [E,F|Es])|Bs]) :- succ(P, Q).
enabled(E, P, [bump([Q|Ps], [F|Es])|Bs], [bump([P],[E]), bump([Q|Ps],[F|Es])|Bs]) :- \+ succ(P, Q).

:- endif.

:- if(false).

bump(E, _, T, Bs, Bs) :- E =< T.
bump(E, P, T, [], [bump([P], [E])]) :- E > T.
bump(E, P, T, [bump([Q|Ps], [F|Es])|Bs], [bump([P,Q|Ps], [E,F|Es])|Bs]) :- E > T, succ(P, Q).
bump(E, P, T, [bump([Q|Ps], [F|Es])|Bs], [bump([P],[E]), bump([Q|Ps],[F|Es])|Bs]) :- E > T, \+ succ(P, Q).

:- endif.