对于QuasiGroup完成问题,我实现了两个模型。其中之一是仅基于渠道约束的模型(基于Dotu的研究)。另一个是基于以下事实的模型:每个值都必须出现在每行/每列中。这是一个小脚本:
flag :- fail.
:- lib(ic).
:- import occurrences/3 from ic_global.
test :-
O is 9, % Order of the puzzle
dim(Variables, [O,O]), Variables :: 1..O,
6 is Variables[1,1], 8 is Variables[6,2],
dim(Dual1, [O,O]), Dual1 :: 1..O,
dim(Dual2, [O,O]), Dual2 :: 1..O,
(flag ->
(multifor([I,V], 1, O), param(Variables, O) do
ic_global:occurrences(V, Variables[I,1..O], 1),
ic_global:occurrences(V, Variables[1..O,I], 1)
)
;
(multifor([I,J,K], 1, O), param(Variables, Dual1, Dual2) do
#=(Variables[I,J], K, Bool),
#=(Dual1[I,K], J, Bool),
#=(Dual2[J,K], I, Bool)
)
),
search(Variables, 0, input_order, indomain, complete, [backtrack(Backtracks)]),
write(Variables), nl,
write('Backtracks : '), write(Backtracks), nl.
我在一系列基准测试(超过10个难题)上进行了尝试。回溯的总数大于500,但令我惊讶的是,两种型号的回溯数均相同。集中每个问题的回溯次数也相同。
上面的小脚本也报告了相同数量的回溯。我很好奇为什么会这样。 ic_global:occurrences/
的作用是什么使它表现得如此相似(尽管速度稍慢一些)?
答案 0 :(得分:1)
occurrences/3约束达到arc-consistency,即它急切地从其自变量变量的域中删除了在对该约束的任何解中都没有出现的所有值。
如果您可以为整个问题建立弧线一致性,那么任何搜索过程都将找到回溯绝对数量最小的解决方案:第一个具有0个回溯的解决方案,第二个在1个回溯之后的解决方案,在N-1个回溯之后的第N个解决方案。这通常无法实现,因为即使您使用所有都分别实现弧一致性的约束条件对问题进行建模,也并不意味着您在整个问题上都具有弧一致性。
这些全局约束的存在的一个主要原因是,与许多小约束的结合相比,它们通常可以实现更高的一致性。因此,您的“双重”表述似乎与基于事件的表述相同。
我对您的程序进行了一些扩展,并研究了可以使用全局约束轻松编写的许多替代公式:
:- lib(ic).
:- lib(ic_global).
:- lib(ic_global_gac).
test(Model) :-
O is 9, % Order of the puzzle
dim(Variables, [O,O]), Variables :: 1..O,
6 is Variables[1,1], 8 is Variables[6,2],
(Model=occ ->
(multifor([I,V], 1, O), param(Variables, O) do
ic_global:occurrences(V, Variables[I,1..O], 1),
ic_global:occurrences(V, Variables[1..O,I], 1)
)
;Model=gcc ->
(for(V, 1, O), foreach(gcc(1,1,V),Bounds) do true ),
(for(I, 1, O), param(Variables, O, Bounds) do
ic_global_gac:gcc(Bounds, Variables[1..O,I]),
ic_global_gac:gcc(Bounds, Variables[I,1..O])
)
;Model=gcm ->
(for(V, 1, O), foreach(gcc(1,1,V),Bounds) do true ),
(for(_, 1, O), foreach(Bounds,RowColBounds), param(Bounds) do true ),
ic_global_gac:gcc_matrix(RowColBounds, RowColBounds, Variables)
;Model=ad(Strength) ->
(for(I, 1, O), param(Variables,O,Strength) do
Strength:alldifferent(Variables[1..O,I]),
Strength:alldifferent(Variables[I,1..O])
)
;Model=adm ->
ic_global:alldifferent_matrix(Variables)
;Model=dual ->
dim(Dual1, [O,O]), Dual1 :: 1..O,
dim(Dual2, [O,O]), Dual2 :: 1..O,
(multifor([I,J,K], 1, O), param(Variables, Dual1, Dual2) do
#=(Variables[I,J], K, Bool),
#=(Dual1[I,K], J, Bool),
#=(Dual2[J,K], I, Bool)
)
),
search(Variables, 0, input_order, indomain, complete, [backtrack(Backtracks)]),
( foreacharg(Row,Variables) do writeln(Row) ),
write('Backtracks : '), write(Backtracks), nl.
在您的小型测试实例中,它们的行为如下:
Goal #backtracks until first solution
test(occ) 3
test(gcc) 0
test(gcm) 0
test(ad(ic)) 29
test(ad(ic_global)) 0
test(ad(ic_global_gac)) 0
test(adm) 0
test(dual) 3
对于更大的问题实例,您可能会发现更多有趣的差异。但是,adm
和gcm
模型(其中整个问题都由一个约束表示)应该始终表现出最小的回溯行为。