include "alldifferent.mzn"; /** @group globals Constrains the elements of \a x to define a subcircuit where \a x[\p i] = \p j means that \p j is the successor of \p i and \a x[\p i] = \p i means that \p i is not in the circuit. */ %% Linear version predicate fzn_subcircuit(array[int] of var int: x) = let { set of int: S = index_set(x), int: l = min(S), int: u = max(S), int: n = card(S), array[S] of var 1..n: order, array[S] of var bool: ins = array1d(S,[ x[i] != i | i in S]), var l..u+1: firstin = min([ u+1 + bool2int(ins[i])*(i-u-1) | i in S]), %% ... var S: lastin, var bool: empty = (firstin == u+1), } in alldifferent(x) /\ % NO alldifferent(order) /\ % If the subcircuit is empty then each node points at itself. % (empty <-> forall(i in S)(not ins[i])) /\ % If the subcircuit is non-empty then order numbers the subcircuit. % ((not empty) <-> %% Another way to express minimum. % forall(i in l..u+1)( % i==firstin <-> ins[i] % /\ forall(j in S where j firstin /\ % The lastin node points at firstin. x[lastin] = firstin /\ % And both are in ins[lastin] /\ ins[firstin] /\ % The successor of each node except where it is firstin is % numbered one more than the predecessor. % forall(i in S) ( % (ins[i] /\ x[i] != firstin) -> order[x[i]] = order[i] + 1 % ) /\ %%% MTZ model. Note that INTEGER order vars seem better!: forall (i,j in S where i!=j) ( order[i] - order[j] + n*bool2int( x[i]==j /\ i!=lastin ) % + (n-2)*bool2int(x[j]==i) %% the Desrochers & Laporte '91 term <= n-1 ) /\ % Each node that is not in is numbered after the lastin node. forall(i in S) ( true % (not ins[i]) <-> (n == order[i]) ) ); %-----------------------------------------------------------------------------%