int: n; % number of components per device
int: m; % number of devices
int: t; % number of types of components
array [1..t,1..t] of bool: conflict; % pairs of components that can't appear together
array [1..t] of int: num_comp; % number of each type of component
array [1..t,1..m] of int: u; % utility of each type in each device
array [1..t,1..m] of var bool: x :: is_output; % whether component i is used in device j
constraint forall (i in 1..t) (
sum (j in 1..m) (bool2int(x[i,j])) = num_comp[i]
);
constraint forall (i in 1..m) (
sum (j in 1..t) (bool2int(x[j,i])) = n
);
constraint forall (i in 1..m, j, k in 1..t where j < k /\ conflict[j,k]) (
x[j,i] /\ x[k,i] -> false
);
% Dominance breaking constraints
array [1..t,1..m] of var bool: allowed; % whether we can swap component i into device j
constraint forall (i in 1..t, j in 1..m) (
exists (k in 1..t where conflict[i,k]) (x[k,j]) \/ allowed[i,j]
);
constraint forall (c1, c2 in 1..m, t1, t2 in 1..t where c1 < c2 /\ t1 < t2) (
if (u[t1,c1] + u[t2,c2] - u[t1,c2] - u[t2,c1] >= 0) then
allowed[t1,c1] /\ allowed[t2,c2] /\ x[t2,c1] /\ x[t1,c2] -> false
else
allowed[t1,c2] /\ allowed[t2,c1] /\ x[t1,c1] /\ x[t2,c2] -> false
endif
);
solve maximize sum (i in 1..t, j in 1..m) (bool2int(x[i,j])*u[i,j]);