clpfd - ограничение верхней связи домена максимумом списка элементов

Учитывая следующий код:

solve(G,L) :-
    G = [A0,B0,C0,D0],
    L = [A1,B1,C1,D1,A2,B2,C2,D2,A3,B3,C3,D3,A4,B4,C4,D4],
    G ins 0..4,
    L ins 0..max(G).

Я хочу, чтобы ограничение L не содержало значений, превышающих максимальное значение, содержащееся в G, но при использовании этого синтаксиса я получаю «ошибку домена». Есть ли другой способ выразить это?


person The Coding Monk    schedule 14.04.2015    source источник
comment
Всегда ли G имеет длину четыре?   -  person repeat    schedule 14.04.2015
comment
Да, максимальное значение в G равно 4 и является фиксированным.   -  person The Coding Monk    schedule 15.04.2015


Ответы (1)


По сути вы были на правильном пути. Но L ins 0..max(G) не работает, потому что границы, которые вы передаете ins/2, должны быть целыми числами или inf или sup.

страница руководства SWI-Prolog clpfd поддерживает max в арифметических выражениях с конечным доменом, поэтому мы сначала укажите, что MaxG является максимальным из A0, B0, C0 и D0. Затем мы утверждаем, что MaxG больше или равно каждому элементу в списке L.

Собираем все вместе:

:- use_module(library(clpfd)).

gte_than(X,Y) :-
    X #>= Y.

solve(G,L) :-
    G = [A0,B0,C0,D0],
    L = [A1,B1,C1,D1,A2,B2,C2,D2,A3,B3,C3,D3,A4,B4,C4,D4],
    G ins 0..4,
    L ins 0..sup,
    MaxG #= max(max(A0,B0),max(C0,D0)),
    maplist(gte_than(MaxG),L).

Вот несколько запросов:

?- solve([0,1,2,1], [0,1,2,1,1,2,1,2,1,0,1,2,1,1,1,2]).
true.

?- solve([0,1,2,1], [0,3,2,1,1,2,1,2,1,0,1,2,1,1,1,2]).
false.

?- solve([0,3,2,1], [0,3,2,1,1,2,1,2,1,0,1,2,1,1,1,2]).
true.

?- solve([0,3,2,1], [0,3,2,1,1,2,4,4,1,0,1,2,1,1,1,2]).
false.

?- solve([4,3,2,1], [0,3,2,1,1,2,4,4,1,0,1,2,1,1,1,2]).
true.

Примечание: SICStus Prolog имеет специализированное арифметическое ограничение с именем maximum/2 мы могли бы использовать здесь, но это ограничение (пока) недоступно в clpfd с SWI-Prolog.

person repeat    schedule 14.04.2015
comment
Забыл указать, что использую SWI-Prolog. Это все еще применимо? - person The Coding Monk; 15.04.2015
comment
+1! Если в вашей системе нет maximum/2, я предлагаю следующее определение list_max/2: Вспомогательный предикат: max_(L, Max0, Max) :- Max #= max(L, Max0). и основной предикат: list_max([L|Ls], Max) :- foldl(max_, Ls, L, Max).. Это дает вам list_max/2, связывающий список выражений CLP(FD) с его максимальным значением в каждой системе, поддерживающей max/2. - person mat; 15.04.2015
comment
Спасибо, решение работает! Я просто получаю это предупреждение: Warning: c:/.../strata.pro:10: Test is always true: var(MaxG) и мне интересно, о чем это? - person The Coding Monk; 15.04.2015