Ограничение вхождения / 3 достигает согласованности дуги , т. Е. Оно охотно удаляет из доменов своих аргументных переменных все значения, которые не встречаются ни в одном решении ограничения.
Если вы можете установить согласованность дуги для всей вашей проблемы, то любая процедура поиска найдет решения с абсолютным минимальным числом возвратов: первое решение с 0 возвратами, второе решение после 1 возврата, N-е после N-1 возврат.Это не часто достигается, потому что даже если вы моделируете проблему с помощью совокупности ограничений, которые все достигают согласованности по дуге по отдельности, это не означает, что вы имеете согласованность по дуге по всей проблеме в целом.
Одна из основных причин существования этих глобальных ограничений заключается в том, что они обычно могут достигать более высоких уровней согласованности, чем совокупность многих небольших ограничений.В этом свете примечательно, что ваша «двойная» формулировка, по-видимому, ведет себя идентично основанной на вхождениях.
Я немного расширил вашу программу и рассмотрел ряд альтернативных формулировок, которые могут быть легкозаписанные с использованием доступных глобальных ограничений:
:- 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
(где вся проблема представлена одним ограничением) всегда должны демонстрировать минимальное поведение при возврате.