/* Linearized version
 * Uses a predicate which constructs a subcircuit which always includes an extra dummy vertex
 * Is worse than the just slightly adapted standard variant...
*/
include "alldifferent.mzn";

%% Linear version
predicate 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),
          constraint forall(i in S)(x[i] in l..u),
          array[l..u+1] of var l..u+1: xx,
          constraint forall(i in S)(xx[i] in dom(x[i]) union {u+1}),         
    } in
    alldifferent(x) /\  
    subcircuit_wDummy(xx) /\
    forall( i in S, j in dom(x[i]) )(   %% also when i==j?
      eq_encode(x[i])[j] >= 2*eq_encode(xx[i])[j]
                            + eq_encode(xx[i])[u+1] + eq_encode(xx[u+1])[j] - 1      %% -1
      /\
      eq_encode(x[i])[j] >= eq_encode(xx[i])[j]
      /\
      eq_encode(x[i])[j] <= eq_encode(xx[i])[j] + eq_encode(xx[i])[u+1]
      /\
      eq_encode(x[i])[j] <= eq_encode(xx[i])[j] + eq_encode(xx[u+1])[j]
    )
    /\
    forall( i in S )(
      eq_encode(x[i])[i] == eq_encode(xx[i])[i]
    )
    ;

%% Should include at least 2 nodes if >0?
%% xx[n] is dummy
predicate subcircuit_wDummy(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),
          set of int: S__ = S diff {u},   %% the real nodes
          array[S__] of var 2..n: order,
%%          constraint order[n]==1,           %% fix the dummy
%%          var bool: empty = (firstin == u+1),  no, break 2-cycles with dummy
    } in
    alldifferent(x) /\  
 % NO   alldifferent(order) /\
    
      %%% MTZ model. Note that INTEGER order vars seem better!:
    forall( i in S__, j in dom(x[i]) where i!=j /\ j!=u )(
        order[i] - order[j] + (n-1)*eq_encode(x[i])[j]
  %      + (n-3)*bool2int(x[j]==i)     %% the Desrochers & Laporte '91 term
  %  --- strangely enough it is much worse on vrp-s2-v2-c7_vrp-v2-c7_det_ADAPT_1_INVERSE.mzn!
        <= n-2 ) /\

    %% Break 2-cycles with dummy:
    forall( i in S__ )(
      eq_encode(x[i])[u] + eq_encode(x[u])[i] <= 1
      /\
        %% Ensure dummy is in:
      if i in dom(x[i]) then
        eq_encode(x[i])[i] >= eq_encode(x[u])[u]
      else
        true
      endif
                 )
    /\
        
       % Symmetry? Each node that is not in is numbered after the lastin node.
       forall(i in S) (
    true
%           (not ins[i]) <-> (n == order[i])
       )
    ;

predicate subcircuit_reif(array[int] of var int: x, var bool: b) = 
    abort("Reified subcircuit/1 is not supported.");

%-----------------------------------------------------------------------------%
%-----------------------------------------------------------------------------%
