Search code examples
prologswi-prologclpfdgnu-prolog

How to convert from tuples_in/2 in SWI-Prolog to fd_relation/2 in GNU Prolog?


The following example code uses SWI-Prolog

% example from https://github.com/Anniepoo/swiplclpfd/blob/master/clpfd.adoc
:- use_module(library(clpfd)).

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).

Gnu Prolog has a built in clp(fd) solver. The syntax is mostly identical, but we don't need to include a library, and the tuples_in/2 predicate is instead handled by fd_relation/2, a GNU Prolog predicate.

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),
        fd_relation(Ts, Ps).

This will not work as written because fd_relation/2 expects a list of Vars. I get a type_error(fd_variable), presumably because Ps is a list of lists of vars.

The example as show should produce this

?- threepath(1, 4, Ps).
Ps = [[1, 2, 0, 1], [2, 3, 4, 5], [3, 4, 8, 9]].

How can that be achieved in GNU Prolog?


Solution

  • The answer is to use maplist/2

    % example from https://github.com/Anniepoo/swiplclpfd/blob/master/clpfd.adoc
    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),
            maplist(fd_relation(Ts), Ps).
    

    This will now yield the expected solution.

    ?- threepath(1, 4, Ps).
    
    Ps = [[1,2,0,1],[2,3,4,5],[3,4,8,9]]