Optimization of MiniZinc model - optimization

I have a MiniZinc model which is supposed to find d[1 .. n] and o[1..k, 0 .. n] such that
x[k] = o[k,0] + d[1]*o[k,1] + d[2]*o[k,2] ... d[n]+o[k,n] and the sum of absolute values of o[k,i]'s is minimized.
I have many different x[i] and d[1..n] should remain the same for all of them.
I have a working model which is pasted below, which finds a good solution in the n=2 case really quickly (less than a second) however, if I go to n=3 (num_dims in the code) even after an hour I get no answer except the trivial one (xi=o0), even though the problem is somewhat recursive, in that a good answer for 2 dimensions can serve as a starting point for 3 dimensions by using o0 as xi for a new 2 dimensional problem.
I have used MiniZinc before, however, I do not have a background in OR or Optimization, thus I do not really know how to optimize my model. I would be helpful for any hints on how to do that, either by adding constraints or somehow directing the search. Is there a way to debug such performance problems in MiniZinc?
My current model:
% the 1d offsets
array [1 .. num_stmts] of int : x;
x = [-10100, -10001, -10000, -9999, -9900, -101, -100, -99, -1, 1, 99, 100, 101, 9900, 9999, 10000, 10001, 10100];
int : num_stmts = 18;
% how many dimensions we decompose into
int : num_dims = 2;
% the dimension sizes
array [1 .. num_dims] of var int : dims;
% the access offsets
array [1 .. num_stmts, 1 .. num_dims] of var int : offsets;
% the cost function: make access distance (absolute value of offsets) as small as possible
var int : cost = sum (s in 1 .. num_stmts, d in 1 .. num_dims) (abs(offsets[s,d]));
% dimensions must be positive
constraint forall (d in 1 .. num_dims) (dims[d] >= 0);
% offsets * dimensions must be equal to the original offsets
constraint forall (s in 1 .. num_stmts) (
x[s] = offsets[s,1] + sum(d in 2 .. num_dims) (offsets[s,d] * dims[d-1])
);
% disallow dimension crossing
constraint forall (s in 1 .. num_stmts, d in 1 .. num_dims) (
abs(offsets[s,d]) < dims[d]
);
% all dims together need to match the array size
constraint product (d in 1..num_dims) (dims[d]) = 1300000;
solve minimize cost;
output ["dims = ", show(dims), "\n"] ++
[ if d == 1 then show_int(6, x[s]) ++ " = " else "" endif ++
" " ++ show_int(4, offsets[s, d]) ++ if d>1 then " * " ++ show(dims[d-1]) else "" endif ++
if d == num_dims then "\n" else " + " endif |
s in 1 .. num_stmts, d in 1 .. num_dims];

Are you using the MiniZinc IDE? Have you tried using a different solver?
I was struggling with a problem of dividing n random positive integers into m groups (m < n) where the sum of each group was supposed to be as close as possible to some other number.
When n reached about 100 and m about 10, it took significantly longer time (30 min+) and the result was not satisfying. This was using the default Gecode (bundled) solver. By chance I went through each and everyone of the solvers and found that the COIN-OR CBC (bundled) found an optimal solution within 15 s.

Related

Minizinc "var set of int: x" instead of "set of int: x"

I have an array of set in the Golfers problem (in each week there should be formed groups, such that no two players play together more than once, and everybody plays exactly one time each week):
int: gr; %number of groups
set of int: G=1..gr;
int: sz; %size of groups
set of int: S=1..sz;
int: n=gr*sz; %number of players
set of int: P=1..n;
int: we; % number of weeks
set of int: W=1..we;
include "globals.mzn";
array[G,W] of var set of P: X; %X[g,w] is the set of people that form group g in week w
My constraints are as follow (I'm not sure if everything works correctly yet):
constraint forall (g in G, w in W) (card (X[g,w]) = sz); %Each group should have size sz
constraint forall (w in W, g,h in G where g > h) (disjoint(X[g,w], X[h,w])); % Nobody plays twice in one week
constraint forall (w,u in W where w > u) (forall (g,h in G) (card(X[g,w] intersect X[h,u]) <= 1 )); % Two players never meet more than once
constraint forall (w in 2..we) (w+sz-1 in X[1,w] /\ 1 in X[1,w]); %Symmetries breaking: week permutations
constraint forall (w in W, g in 1..gr-1) ( min(X[g,w]) < min(X[g+1,w]) ); %Symmetries breaking: group permutations
constraint forall (g in G, s in S) ( s+sz*(g-1) in X[g,1]);
solve satisfy;
output [ show(X[i,j]) ++ if j == we then "\n" else " " endif | i in 1..gr, j in 1..we ];
My problem lies in constraint number 5. I cannot use min on "var set of int: x", I should use it on "set of int: x". Unfortunately, I do not understand the difference between those two (from what I've read this may be connected to defining the size of each set, but I'm not sure).
Could someone explain the problem to me and propose a solution? I would be very very grateful. Thanks!
First of all: A var is a decision variable. The goal of all Minizinc programs are to decide the the value of all decision variables. You don't know what the values are and you are trying to find the values. Anything that is not a var is simply a known number. (disregarding the use of sets)
Doing min(X[g,w]) of a decision variable (var) is simply not implemented in Minizinc. The reason would be that using X[g,w] < X[g+1,w] without the min makes more sense. Why only constrain the lowest number in both sets insted of all numbers. I.e {1,3,5} < {1,4} insted of 1 < 1
(I hope MiniZinc has < on sets so I don't lie, I am not sure)
I have found out the solution - we should make an array of elements of the set to make the max function possible in this case.
constraint forall (w in 2..we) ( max([i | i in X[1,w-1]]) < max([i | i in X[1,w]])); %Symmetries breaking: week permutations
constraint forall (w in W, g in 1..gr-1) ( min([i | i in X[g,w]]) < min([i | i in X[g+1,w]]));% Symmetries breaking: group permutations (I have been trying to speed up the constraint above, but it does not work with var set of int..)

Max number of consecutive values (Minizinc)

I'm trying to model the next constraint in Minizinc:
Suppose S is an array of decision variables of size n. I want my decision variables to take a value between 1-k, but there is a maximum 'Cons_Max' on the number of consecutive values used.
For example, suppose Cons_Max = 2, n = 8 and k = 15, then the sequence [1,2,4,5,7,8,10,11] is a valid sequence , while e.g. [1,2,3,5,6,8,9,11] is not a valid sequence because the max number of consecutive values is equal to 3 here (1,2,3).
Important to mention is that sequence [1,3,5,7,9,10,12,14] is also valid, because the values don't need to be consecutive but the max number of consectuive values is fixed to 'Cons_Max'.
Any recommendations on how to model this in Minizinc?
Here's a model with a approach that seems to work. I also added the two constraints all_different and increasing since they are probably assumed in the problem.
include "globals.mzn";
int: n = 8;
int: k = 15;
int: Cons_Max = 2;
% decision variables
array[1..n] of var 1..k: x;
constraint
forall(i in 1..n-Cons_Max) (
x[i+Cons_Max]-x[i] > Cons_Max
)
;
constraint
increasing(x) /\
all_different(x)
;
%% test cases
% constraint
% % x = [1,2,4,5,7,8,10,11] % valid solution
% % x = [1,3,5,7,9,10,12,14] % valid valid solution
% % x = [1,2,3,5,6,8,9,11] % -> not valid solution (-> UNSAT)
% ;
solve satisfy;
output ["x: \(x)\n" ];
Suppose you use array x to represent your decision variable.
array[1..n] of var 1..k: x;
then you can model the constraint like this.
constraint not exists (i in 1..n-1)(
forall(j in i+1..min(n, i+Cons_Max))
(x[j]=x[i]+1)
);

Set partitioning

I'm trying to get a good grasp with this problem but I'm struggling.
Let's say that I have a S={1,2,3,4,5}, an L={(1,3,4),(2,3),(4,5),(1,3),(2),(5)} and an other tuple with the costs of L like C={10,20,12,15,4,10}
I want to make a constraint program in Prolog so as to take the solution that solves the problem with the minimum cost.(in this occasion it is the total sum of the costs of the subsets i will get)
My problem is that I cannot understand the way I'll make my modelisation. What I know is that I should choose a modelisation of binary variables {0,1} but I hardly understand how i will manage to express it via Prolog.
There is an easy way to do it: You can use Boolean indicators to denote which elements comprise a subset. For example, in your case:
subsets(Sets) :-
Sets = [[1,0,1,1,0]-10, % {1,3,4}
[0,1,1,0,0]-20, % {2,3}
[0,0,0,1,1]-12, % {4,5}
[1,0,1,0,0]-15, % {1,3}
[0,1,0,0,0]-4, % {2}
[0,0,0,0,1]-10]. % {5}
I now use SICStus Prolog and its Boolean constraint solver to express set covers:
:- use_module(library(lists)).
:- use_module(library(clpb)).
setcover(Cover, Cost) :-
subsets(Sets),
keys_and_values(Sets, Rows, Costs0),
transpose(Rows, Cols),
same_length(Rows, Coeffs),
maplist(cover(Coeffs), Cols),
labeling(Coeffs),
phrase(coeff_is_1(Coeffs, Rows), Cover),
phrase(coeff_is_1(Coeffs, Costs0), Costs),
sumlist(Costs, Cost).
cover(Coeffs, Col) :-
phrase(coeff_is_1(Col,Coeffs), Cs),
sat(card([1],Cs)).
coeff_is_1([], []) --> [].
coeff_is_1([1|Cs], [L|Ls]) --> [L], coeff_is_1(Cs, Ls).
coeff_is_1([0|Cs], [_|Ls]) --> coeff_is_1(Cs, Ls).
For each subset, a Boolean variable is used to denote whether that subset is part of the cover. Cardinality constraints make sure that each element is covered exactly once.
Example query and its result:
| ?- setcover(Cover, Cost).
Cover = [[0,0,0,1,1],[1,0,1,0,0],[0,1,0,0,0]],
Cost = 31 ? ;
Cover = [[1,0,1,1,0],[0,1,0,0,0],[0,0,0,0,1]],
Cost = 24 ? ;
no
I leave picking a cover with minimum cost as an easy exercise.
Maybe an explicit model for your problem instance makes things a bit clearer:
cover(SetsUsed, Cost) :-
SetsUsed = [A,B,C,D,E,F], % a Boolean for each set
SetsUsed #:: 0..1,
A + D #= 1, % use one set with element 1
B + E #= 1, % use one set with element 2
A + B + D #= 1, % use one set with element 3
A + C #= 1, % use one set with element 4
C + F #= 1, % use one set with element 5
Cost #= 10*A + 20*B + 12*C + 15*D + 4*E + 10*F.
You can solve this e.g. in ECLiPSe:
?- cover(SetsUsed,Cost), branch_and_bound:minimize(labeling(SetsUsed), Cost).
SetsUsed = [1, 0, 0, 0, 1, 1]
Cost = 24
Yes (0.00s cpu)

Solving and producing and equation with variables indexed by a given set (Haskell)

I want to solve the following problem in Haskell:
Let n be a natural number and let A = [d_1 , ..., d_r] be a set of positive numbers.
I want to find all the positive solutions of the following equation:
n = Sum d_i^2 x_i.
For example if n= 12 and the set A= [1,2,3]. I would like to solve the following equation over the natural numbers:
x+4y+9z=12.
It's enough to use the following code:
[(x,y,z) | x<-[0..12], y<-[0..12], z<-[0..12], x+4*y+9*z==12]
My problem is if n is not fixed and also the set A are not fixed. I don't know how to "produce" a certain amount of variables indexed by the set A.
Instead of a list-comprehension you can use a recursive call with do-notation for the list-monad.
It's a bit more tricky as you have to handle the edge-cases correctly and I allowed myself to optimize a bit:
solve :: Integer -> [Integer] -> [[Integer]]
solve 0 ds = [replicate (length ds) 0]
solve _ [] = []
solve n (d:ds) = do
let maxN = floor $ fromIntegral n / fromIntegral (d^2)
x <- [0..maxN]
xs <- solve (n - x * d^2) ds
return (x:xs)
it works like this:
It's keeping track of the remaining sum in the first argument
when there this sum is 0 where are obviously done and only have to return 0's (first case) - it will return a list of 0s with the same length as the ds
if the remaining sum is not 0 but there are no d's left we are in trouble as there are no solutions (second case) - note that no solutions is just the empty list
in every other case we have a non-zero n (remaining sum) and some ds left (third case):
now look for the maximum number that you can pick for x (maxN) remember that x * d^2 should be <= n so the upper limit is n / d^2 but we are only interested in integers (so it's floor)
try all from x from 0 to maxN
look for all solutions of the remaining sum when using this x with the remaining ds and pick one of those xs
combine x with xs to give a solution to the current subproblem
The list-monad's bind will handle the rest for you ;)
examples
λ> solve 12 [1,2,3]
[[0,3,0],[3,0,1],[4,2,0],[8,1,0],[12,0,0]]
λ> solve 37 [2,3,4,6]
[[3,1,1,0],[7,1,0,0]]
remark
this will fail when dealing with negative numbers - if you need those you gonna have to introduce some more cases - I'm sure you figure them out (it's really more math than Haskell at this point)
Some hints:
Ultimately you want to write a function with this signature:
solutions :: Int -> [Int] -> [ [Int] ]
Examples:
solutions 4 [1,2] == [ [4,0], [0,1] ]
-- two solutions: 4 = 4*1^2 + 0*2^2, 4 = 0*1^2 + 1*2^2
solutions 22 [2,3] == [ [1,2] ]
-- just one solution: 22 = 1*2^2 + 2*3^2
solutions 10 [2,3] == [ ]
-- no solutions
Step 2. Define solutions recursively based on the structure of the list:
solutions x [a] = ...
-- This will either be [] or a single element list
solutions x (a:as) = ...
-- Hint: you will use `solutions ... as` here

k consecutive integers constraint

How can I state the following constraint in Constraint Programming? (Preferably in Gurobi or Comet).
S is an array of integers of size n. The set of integers that I can use to fill the array are in the range 1-k. There is a constraint ci for each of the integers that can be used. ci denotes the minimum number of consecutive integers i.
For example if c1 = 3, c2 = 2 then 1112211112111 is not a valid sequence since there must be two consecutive 2's, whereas 1112211122111 is a valid sequence.
Perhaps using the regular constraint (automaton in Comet) would be the best approach.
However, here is a straightforward solution in MiniZinc which use a lot of reifications. It should be possible to translate it to Comet at least (I don't think Gurobi support reifications).
The decision variables (the sequences) are in the array "x". It also use a helper array ("starts") which contains the start positions of each sequences; this makes it easier to reason about the sequences in "x". The number of sequences is in "z" (e.g. for optimization problems).
Depending on the size of x and other constraints, one can probably add more (redundant) constraints on how many sequences there can be etc. This is not done here, though.
Here's the model: http://www.hakank.org/minizinc/k_consecutive_integers.mzn
It's also shown below.
int: n;
int: k;
% number of consecutive integers for each integer 1..k
array[1..k] of int: c;
% decision variables
array[1..n] of var 1..k: x;
% starts[i] = 1 -> x[i] starts a new sequence
% starts[i] = 0 -> x[i] is in a sequence
array[1..n] of var 0..k: starts;
% sum of sequences
var 1..n: z = sum([bool2int(starts[i] > 0) | i in 1..n]);
solve :: int_search(x, first_fail, indomain_min, complete) satisfy;
constraint
forall(a in 1..n, b in 1..k) (
(starts[a] = b ) ->
(
forall(d in 0..c[b]-1) (x[a+d] = b )
/\
forall(d in 1..c[b]-1) (starts[a+d] = 0 )
/\
(if a > 1 then x[a-1] != b else true endif) % before
/\
(if a <= n-c[b] then x[a+c[b]] != b else true endif) % after
)
)
/\
% more on starts
starts[1] > 0 /\
forall(i in 2..n) (
starts[i] > 0 <-> ( x[i]!=x[i-1] )
)
/\
forall(i in 1..n) (
starts[i] > 0 -> x[i] = starts[i]
)
;
output [
"z : " ++ show(z) ++ "\n" ++
"starts: " ++ show(starts) ++ "\n" ++
"x : " ++ show(x) ++ "\n"
];
%
% data
%
%% From the question above:
%% It's a unique solution.
n = 13;
k = 2;
c = [3,2];