Question

I need to create a predicate:

applyConstraints(L)

That applies constraints to the variables in L such that no two contiguous elements in L are both odd or even how can I do that? With a fixed size L it's simple but what about a variable size L? I need that to be done using sicstus-prolog clpfd library.

Was it helpful?

Solution 2

Inspired by @MatsCarlsson's version, I tried to minimize the number of constrained variables involved:

applyConstraints(Xs) :-
   S #\= R,
   applyConstraints(Xs, S, R).

applyConstraints([], _, _).
applyConstraints([X|Xs], S, R) :-
   X mod 2 #= S,
   applyConstraints(Xs, R, S).

Edit: This version has one flaw for the goal applyConstraints([]) which is not readily visible. In fact, one needs to switch to full_answer mode in SICStus like so:

| ?- applyConstraints([]).
yes
| ?- assertz(clpfd:full_answer).
yes
| ?- applyConstraints([]).
clpfd:(_A#\=_B),
_A in inf..sup,
_B in inf..sup ? ;
no

So we have this useless constraint hanging around which might eat up resources. To overcome this deficiency, some special casing is needed:

applyConstraints([]).
applyConstraints([X|Xs]) :-
   X mod 2 #= S,
   S #\= R,
   applyConstraints(Xs, R, S).

Note 1 — in SWI or YAP there is no direct way to switch full answer mode on. The only way to get hold of the problem is to wrap the query around call_residue_vars/2 like so:

?- applyConstraints([]).
true.

?- call_residue_vars(applyConstraints([]),RVs).
RVs = [_G794, _G797],
_G794#\=_G797.

Note 2 — Thanks to @mat, there is similar functionality since SWI 7.3 (remember that SWI 7 needs --traditional for compatibility):

?- set_prolog_flag(toplevel_residue_vars, true).
true.

?- applyConstraints([]).
% with detached residual goals
_G430#\=_G433.

(It is not quite clear what "detached" should mean in this context, after all, the residual goals have to be true, to make the answer true. So there is no detachement involved.)

OTHER TIPS

% SICStus:

applyConstraints([]).
applyConstraints([X|Xs]) :-
    X mod 2 #= R,
    applyConstraints(Xs, R).

applyConstraints([], _).
applyConstraints([X|Xs], R) :-
    X mod 2 #= S,
    S #\= R,
    applyConstraints(Xs, S).

% Query:

| ?- applyConstraints(L), length(L,2), !, domain(L,-2,2), labeling([],L).
L = [-2,-1] ? ;
L = [-2,1] ? ;
L = [-1,-2] ? ;
L = [-1,0] ? ;
L = [-1,2] ? ;
L = [0,-1] ? ;
L = [0,1] ? ;
L = [1,-2] ? ;
L = [1,0] ? ;
L = [1,2] ? ;
L = [2,-1] ? ;
L = [2,1] ? ;
no

Just consider pair of elements

applyConstraints([A,B|R]) :-
    A mod 2 #\= B mod 2,
    applyConstraints([B|R]).
applyConstraints([_]).

test (using SWI-Prolog library(clpfd), maybe you will need to substitute ins/2 with the counterpart from Sicstus)

?- L=[X,Y,Z], applyConstraints(L), L ins 1..4, label(L).
L = [1, 2, 1],
X = Z, Z = 1,
Y = 2 ;
L = [1, 2, 3],
X = 1,
Y = 2,
Z = 3 ;
...
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top