/* Global constraint distance_between in Picat. http://www.emn.fr/x-info/sdemasse/gccat/Cdistance_between.html """ Let Ui and Vi be respectively the ith and jth variables (i!=j) of the collection VARIABLES1. In a similar way, let Xi and Yi be respectively the ith and jth variables (i!=j) of the collection VARIABLES2. DIST is equal to the number of times one of the following mutually incompatible conditions are true: * Ui CTR Vi holds and Xi CTR Yi does not hold, * Xi CTR Yi holds and Ui CTR Vi does not hold. Example (2, <3, 4, 6, 2, 4>, <2, 6, 9, 3, 6>, <) The distance_between constraint holds since the following DIST=2 conditions are verified: * VARIABLES1[4].var=2 < VARIABLES1[1].var=3 /\ VARIABLES2[4].var=3 >= VARIABLES2[1].var=2 * VARIABLES2[1].var=2 < VARIABLES2[4].var=3 /\ VARIABLES1[1].var=3 >= VARIABLES1[4].var=2 """ TODO: I have problem negating the call/3 constraints. This Picat model was created by Hakan Kjellerstrand, hakank@gmail.com See also my Picat page: http://www.hakank.org/picat/ */ import cp. main => go. % Experiment: % Picat> Op=$#<,[A,B]::1..4,call(Op,A,B), solve_all([A,B])=All % Op = #< % A = DV_0159a8_1..3 % B = DV_0159f8_2..4 % All = [[1,2],[1,3],[1,4],[2,3],[2,4],[3,4]] % yes go ?=> N = 5, X = new_list(N), X :: 1..9, Y = new_list(N), Y :: 1..9, D :: 0..N*N, % the distance X = [3,4,6,2,4], Y = [2,6,9,3,6], distance_between(D, X, Y, #<), % distance_between(D, X, Y, -2), % D #= 2, Vars = X++Y++[D], solve(Vars), println(x=X), println(y=Y), println(d=D), nl, fail, nl. go => true. distance_between(D, X, Y, Op) => println(op=Op), N = X.len, S = 0, foreach (I in 1..N, J in 1..N, I != J) % As suggested by NFZ C1 = my_call(Op,X[I],X[J]), C2 = my_neg_call(Op,Y[I],Y[J]), % variant: % my_call(Op,X[I],X[J],C1), % my_neg_call(Op,Y[I],Y[J],C2), E1 = C1 #/\ C2, % C3 = my_call(Op,Y[I],Y[J]), % C4 = my_neg_call(Op,X[I],X[J]), % E2 = C3 #/\ C4, % Sum := $(Sum + E1 +E2) Sum := $(Sum + E1) end, D #= sum(S). my_call(#<, X, Y) = X #< Y. % my_call(#<, X, Y, C) => C = $(X #< Y). my_neg_call(#<, X, Y) = #~ X #< Y. % my_neg_call(#<, X, Y) = $(#~ X #< Y). % my_neg_call(#<, X, Y, C) => C = $(#~ X #< Y).