Search code examples
lambdaprologconstraint-programmingclpfd

Prolog: iteration


Good evening, i have a simple problem, and i warn you that i am very new with prolog. Suppose to have three lists of the same size, each containing only 1s, 0s or -1s. I want to verify that for all i, of the i-th elements of the three lists, one and only one is nonzero.

This code does it for a fixed i:

:- use_module(library(clpfd)).

compat1(V1,V2,V3,I) :-
    length(V1,G),
    nth1(I,V1,X),
    nth1(I,V2,Y),
    nth1(I,V3,Z),
    W is X*X+Y*Y+Z*Z,
    W is 1,
    I in 1..G.

how can I tell "for ALL I, compat1(V1,V2,V3,I)"? I tried to define

compat2(V1,V2,V3,1) :- compat1(V1,V2,V3,1).
compat2(V1,V2,V3,K) :- compat2(V1,V2,V3,J), compat1(V1,V2,V3,K), K is J+1.

so that I could call it with K=maximum value i'm interested in. But compat2 doesn't work: gives true, then, after ";" runs indefinitely.

Thanks!


Solution

  • Some remarks: Mixing library(clpfd) and (is)/2 is mostly not a good idea. You can write X #= Y + 1 in place of X is Y + 1 with almost the same efficiency (in SWI) but enjoying its increased generality.

    The relation you are interested in, relates the i-th elements of three lists. That is, we can write: maplist(r, Xs, Ys, Zs) where r/3 is the relation you are interested in. So we have to define r(X,Y,Z).

    What about abs(X)+abs(Y)+abs(Z) #= 1?

    With library(lambda) you can put it all into a single line:

    maplist(\X^Y^Z^(abs(X)+abs(Y)+abs(Z) #= 1), Xs, Ys, Zs).