Search code examples
listprologconstraint-programmingclpfd

Prolog CLPFD trying to define domain for lists of list


I am working on a constraints programming problem in Prolog and I am having problems trying to define a domain for lists of list. The initial challenge of the problem is as follows:

   trains([[1,2,0,1], %from station, to station, departs at, arrives at
           [2,3,4,5],
           [2,3,0,1],
           [3,4,5,6],
           [3,4,2,3],
           [3,4,8,9]]).

   threepath(A,D,Ps):-
        Ps = [[A,B, _T0, T1], [B,C, T2, T3], [C,D, T4, _T5]],
        T2 #> T1,
        T4 #> T3,
        trains(Ts),
        tuples_in(Ps, Ts).

After that, I am expected to expand on this to accommodate for any number of trains instead of only 3. Here is my attempt at doing that:

  anypath(A,D,Ps,N):-
        length(Ps,N),
        Ps ins Xs,
        Xs = [A,B,C,D],
        Xs ins 1..9. %How to define the domain for a list of length 4 inside a list of variable length.

However, I am not very sure how to define a domain for lists of list. So far, I have defined length(Ps, N) so that Ps can have any length. Then, I tried to define the variables inside of Ps so that they will be list of length 4 but failed horribly.

Additionally, I am also not sure how to define the constraints for a variable length of Ps like the 3 scenario case where T2 #> T1 and T3 #> T4. The pattern that I am seeing is the last element of the next list should be greater than the third element of the list before it but I am stuck on the syntax to represent this constraint as well.

Right now, I am trying to use recursion to somehow set the Head of Ps to a list of length 4 and to recurse through to do the same with the tails since I won't be able to know how long the list Ps will be.

I would be grateful if someone can shed some light on this.

Update on Progress 25/3/2015

I read on an example of another problem that a maplist was used to produce inner lists. An excerpt of the code is:

length_(Length, List) :- length(List, Length).

child_row(X) :- X ins 1..16 .

ww(X) :-
        write(X),
        write('/').

print_row(Row) :-
        maplist(ww, Row),
        nl.

children(Class) :-
        length(Class, 4),
        maplist(length_(4), Class),
        maplist(child_row , Class),

From what I understand, maplist(length_(4), Class) applies the length_(4) to every element inside Class and creates inner lists of length 4 as a result. So, I tried to apply this to my problem and here is my attempt:

length_(Length, List) :- length(List, Length).
anypath(A,D,Ps,N):-
    length(Ps,N),
    maplist(length_(4), Ps),
    %constraint(Ps),
    trains(Ts),
    tuples_in(Ps, Ts).

However, I get an error message saying "length/2: Type error: list' expected, found4'" regardless of whether N is set to 3 or 4 and I don't quite understand this as well since it should work the same way as the example above and gtrace is a bit messy to detect what's wrong for me.

I am currently stuck at the moment and I will update if I figure anything out.

So, I have another question that I hope can be answered is "What is the normal practice of creating inner lists and how do you normally do it yourself?".

Thanks!


Solution

  • You can flatten the list with

    append(Trains, FlatTrains)
    

    and then constrain the domain of FlatTrains

    FlatTrains ins 1..9