我使用CLP(FD)和SWI-Prolog编写了一个CSP程序。
有些约束看起来像
Xi mod N #= 0
,所以我必须为每个变量Xi调用res(Xi,Li)
(与res(X,L) :- setof(X, indomain(X), L)
)来进行回溯并获得有效解决方案列表。如果我不这样做,我就会得到剩余目标。
现在在同一个调用中,我想将 Xi 的解决方案列表转换为连续间隔列表。 我怎样才能做到这一点 ?是否有任何现有谓词可以做到这一点?
我尝试使用
fd_dom(Li,Di), dom_intervals(Di,Ii)
但没有成功,因为 Li 需要是原子的,而不是列表。
dom_intervals 定义如下,请参阅使用 CLP 获取间隔:
dom_intervals(Dom, Intervals) :-phrase(dom_intervals1(Dom), Intervals).
dom_intervals1(I) --> {integer(I)}, [I].
dom_intervals1(L..U) --> [L..U].
dom_intervals1(D1 \/ D2) --> dom_intervals1(D1), dom_intervals1(D2).
我还尝试在
member(Xtmpi, Li)
之前调用 fd_dom(Xtmpi,Di), dom_intervals(Di,Ii)
,但是 member
枚举结果,因此我得到了单例列表。
预先感谢您的想法。
生成完整序列然后再次将其压缩回来似乎有点浪费,但我没有找到一种方法来解析 fd_domain 而不这样做,所以这里有一个数字到连续范围的语法。
用途:
?- phrase(ranges(Rs), [2, 4,5,6, 10, 22,23,24,25,26,27,28,29,30]).
Rs = [2, 4-6, 10, 22-30]
代码:
:- use_module(library(dcg/basics)).
ranges([R|Rs]) --> % a list of ranges:
[A], range(A,B), % a number A begins a range from A to B,
{(A=B -> R=A ; R=A-B)}, % output single values as 2, ranges as 2-9
ranges(Rs). % then more ranges up to ...
ranges([]) --> eos. % ... end of stream.
range(A,Z) --> % a range continues if:
{succ(A,B)}, % the next number should be B,
[B], % and yes, B is next in the list,
range(B,Z). % and the range continues from B..end.
range(A,A), [C] --> % a range ends if:
{succ(A,B)}, % the next number should be B
[C], {dif(B,C)}. % the next number is C, which is different.
range(A,A) --> eos. % or a range ends at the end of stream.