Search code examples
prologswi-prologclpfd

How to use tuple_in from clpfd?


I am following along the clpfd exercises here: http://www.pathwayslms.com/swipltuts/clpfd/clpfd.html

I have the following solution for example 5 number 1

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


allpaths(From,To,Route):-
  trains(Ts),
  length(Ts,Max_Trains),
  between(2,Max_Trains,Length_Of_Route),
  Route=[_,_|_],length(Route,Length_Of_Route),
  maplist(same_length([_,_,_,_]),Route),
  create_chain(Route,TimeChain,1),
  train_chain(Route),
  chain(TimeChain, #<),
  tuples_in(Route,Ts),
  nth1(1,Route,[From|_]),
  nth1(Length_Of_Route,Route,[_,To|_]).

create_chain([],[],_).
create_chain(List_of_Lists,[First,Second|Chain],1):-
  List_of_Lists =[Item|T],
  Item =[_T1,_T2,First,Second],
  create_chain(T,Chain,2).
create_chain(List_of_Lists,[First,Second|Chain],2):-
  List_of_Lists =[Item|T],
  Item =[_T1,_T2,First,Second],
  create_chain(T,Chain,1).

train_chain([_]).
train_chain(List_Of_Lists):-
  List_Of_Lists =[First,Second|T],
  First = [_One,Two,_,_],
  Second =[Two,_Three,_,_],
  train_chain([Second|T]).

I am not sure if I have done this in the 'intended' way but it works and seems okay. I basically create lists of variables that are across trains and then apply the constraint to. I am not sure if I have done this in the 'intended' way because I am only using clpfd for the times of the trains not the trains.

Now for the next exercise with employees, the constraints are on individual employees, not across the employees, unlike the train exercise.
I don't understand how to use tuples_in in this case, It seems simple to complete the exercise with findall. How would it be implemented using constraints and tuples_in and what are the advantages?

employees([
 [1, 75, 0, 30, 25],
 [2, 83, 0, 45, 25],
 [3, 90, 1, 45, 50],
 [4, 45, 3, 75, 25],
 [5, 89, 0, 52, 50]
 ]).

promotions(Es,Promotions):-
  employees(Es),
  findall([Id,Score,V,T,RT],
    (member([Id,Score,V,T,RT],Es),Score>80,V=<1,T>RT),
  Promotions).

Solution

  • I think should be as simple as

    ex2(EmployeeId) :-
     employees(Es),
     tuples_in([[EmployeeId, LastReviewScore, NumOfSafetyViolations, TimeInGrade, RequiredTimeForPromotion]], Es),
     LastReviewScore #> 80, NumOfSafetyViolations #=< 1, TimeInGrade #> RequiredTimeForPromotion,
     label([EmployeeId]).
    

    The advantage, is that the relation among values that are used to identify candidates can be left unspecified until something interesting is known about the problem.

    The simple example doesn't show such advantages... I have found tuple_in useful solving crosswords, where it allowed to drastically shorten the solution time.