int: n;
set of int: PERSON = 1..n;
enum GENDER = { M, F, O };
array[PERSON] of GENDER: g;
set of int: POSN = 1..n;
array[int] of int: pos;
array[POSN] of var PERSON: who;
int: _objective;
test alldifferent(array[int] of int: x) =
forall(i,j in index_set(x) where i < j)(x[i] != x[j]);
include "inverse.mzn";
constraint if alldifferent(pos) then inverse(pos,who)
else forall(i in 1..n)(who[i] = 1) endif;
output [if
check_array(pos, n, POSN, "pos") /\
check_alldifferent(pos,"pos") /\
check_array(fix(pos), n, PERSON, "who") /\
forall(i in 1..n-2)
(check(g[fix(who[i])] != g[fix(who[i+1])] \/
g[fix(who[i+1])] != g[fix(who[i+2])],
"three people of the same gender \(g[fix(who[i])]) in positions \(i)..\(i+2)\n")) /\
let { int: obj = sum(i in 1..n-1)(abs(pos[i] - pos[i+1])); } in
check(obj = _objective, "calculated objective \(obj) does not agree with objective from the model (\(_objective))\n")
then
"CORRECT: All constraints hold"
else
"INCORRECT"
endif];
test check(bool: b,string: s) =
if b then true else trace_stdout("ERROR: "++s++"\n",false) endif;
test check_alldifferent(array[int] of int: x, string: name) =
forall(i, j in index_set(x) where i < j)
(check(x[i] != x[j], name ++ "[\(i)] = \(x[i]) = " ++
name ++ "[\(j)] " ++
"when they should be different\n"));
test check_int(int: x, set of int: vals, string: name) =
check(x in vals, "integer \(name) is not in values \(vals)\n");
function bool: check_array(array[int] of int: x, int: length, set of int: vals, string: name) =
check(length(x) = length, "array \(name) is not of length \(length)\n") /\
forall(i in index_set(x))
(check(x[i] in vals, "element \(i) of array \(name), \(x[i]) is not in values \(vals)\n"));