A set of benchmarks to compare a new prototype MiniZinc implementation
1% Cardinality-constrained Multi-cycle Problem (CCMCP)
2%
3% This problem appears as one of the main optimization problems modelling
4% kidney exchange. The problem consists of the prize-collecting assignment
5% problem and an addition constraint stipulating that each subtour in the graph
6% has a maximum length K. If K = 2 or K = infinity, the problem is
7% polynomially-solvable. Otherwise, it is NP-hard.
8%
9% Further details on the problem can be found in:
10% On the kidney exchange problem: cardinality constrained cycle and chain
11% problems on directed graphs: a survey of integer programming approaches.
12% Vicky Mak-Hau, J Comb Optim (2017) 33:35–59
13%
14% Edward Lam <edward.lam@monash.edu>
15% Vicky Mak-Hau <vicky.mak@deakin.edu.au>
16
17include "all_different.mzn";
18include "bin_packing.mzn";
19include "seq_precede_chain.mzn";
20
21int: V; % Number of vertices
22int: K; % Maximum length of each subtour
23
24set of int: VERTICES = 1..V; % Set of vertices
25array[VERTICES,VERTICES] of int: edge_weight; % Weight of each edge
26
27array[VERTICES] of var VERTICES: succ; % Successor variable indicating next vertex in the cycle
28array[VERTICES] of var VERTICES: cycle; % Index of a cycle
29
30int: obj_ub = sum(i in VERTICES)(max(j in VERTICES)(edge_weight[i,j]));
31var 0..obj_ub: objective; % Objective variable
32
33% Check
34constraint forall(i in VERTICES)(assert(edge_weight[i,i] == 0, "Loop must have zero cost"));
35
36% Path in a cycle
37constraint alldifferent(succ); % Out-degree of two
38constraint forall(i in VERTICES)(cycle[i] == cycle[succ[i]]); % Connectivity
39constraint forall(i in VERTICES, j in VERTICES where i != j)(edge_weight[i,j] < 0 -> succ[i] != j); % Disable infeasible edges
40
41% Maximum cycle length
42constraint bin_packing(K, cycle, [1 | i in VERTICES]);
43
44% Objective function
45constraint objective = sum(i in VERTICES)(edge_weight[i,succ[i]]);
46
47% Symmetry-breaking
48constraint symmetry_breaking_constraint(seq_precede_chain(cycle));
49
50% Search strategy
51solve
52 :: seq_search([
53 int_search(succ, first_fail, indomain_median, complete)
54 ])
55 maximize objective;
56
57% Output
58output [
59 "succ = array1d(1..\(V), \(succ));\n",
60 "cycle = array1d(1..\(V), \(cycle));\n",
61 "objective = \(objective);\n"
62];