git-subtree-dir: software/mza git-subtree-split: f970a59b177c13ca3dd8aaef8cc6681d83b7e813
87 lines
3.0 KiB
MiniZinc
87 lines
3.0 KiB
MiniZinc
/* 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";
|
|
|
|
/** @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 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.");
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
%-----------------------------------------------------------------------------%
|