Error message in MiniZinc when specifying a decision variable - minizinc

I am running the first MiniZinc example in the Handbook, coloring the states and territories of Australia. It runs fine as written.
% Colouring Australia using nc colours
int: nc = 3;
var 1..nc: wa; var 1..nc: nt; var 1..nc: sa; var 1..nc: q;
var 1..nc: nsw; var 1..nc: v; var 1..nc: t;
constraint wa != nt;
constraint wa != sa;
constraint nt != sa;
constraint nt != q;
constraint sa != q;
constraint sa != nsw;
constraint sa != v;
constraint q != nsw;
constraint nsw != v;
solve satisfy;
output ["wa=\(wa)\t nt=\(nt)\t sa=\(sa)\n",
"q=\(q)\t nsw=\(nsw)\t v=\(v)\n",
"t=", show(t), "\n"];
But when I change nc (the number of colors) to be a decision variable (change int: nc = 3; to be var 1..10: nc;) and change solve satisfy; to be solve minimize nc; I get an error message saying
MiniZinc: type error: type-inst must be par set but is `var set of int'
I was hoping that MiniZinc would tell me the minimum number of colors needed.
What should I do to get the minimum number of colors?
UPDATE: I found one way to get the answer I want. I added the following.
array[1..7] of var int: ts = [wa, nt, sa, q, nsw, v, t];
var int: min_nc = max(ts);
solve minimize min_nc;
Is there a better way?

This issue occurs because of the declaration of the other variable declarations. They are declared as var 1..nc: X;. However, now that nc is a variable, the set 1..nc becomes a variable as well.
In MiniZinc, it is not allowed to declare an integer variable using a variable set as its domain. (Maybe this feature will be added in the future). What we can do instead is add all variables using the largest domain possible and then restrict it to be within the allowed values. The full model would look like this:
% Colouring Australia using nc colours
var 1..10: nc;
var 1..ub(nc): wa; var 1..ub(nc): nt; var 1..ub(nc): sa; var 1..ub(nc): q;
var 1..ub(nc): nsw; var 1..ub(nc): v; var 1..ub(nc): t;
constraint wa <= nc; % or "wa in 1..nc"
constraint nt <= nc;
constraint sa <= nc;
constraint q <= nc;
constraint nsw <= nc;
constraint v <= nc;
constraint t <= nc;
constraint wa != nt;
constraint wa != sa;
constraint nt != sa;
constraint nt != q;
constraint sa != q;
constraint sa != nsw;
constraint sa != v;
constraint q != nsw;
constraint nsw != v;
solve minimize nc;
output ["colours=\(nc)\nwa=\(wa)\t nt=\(nt)\t sa=\(sa)\n",
"q=\(q)\t nsw=\(nsw)\t v=\(v)\n",
"t=", show(t), "\n"];
Note that ub(nc) is the upper bound of nc, the highest possible value nc will take, in this case 10.

Related

Want caculate the n-th largest value in an array Use Minizinc

Any boys can help me write a function to caculate the n-th largest value in an array ?
for example :
array[1..10] of 1..200 : t=[30,20,30,40,50,50,70,10,90,100];
var int : nth_largest;
In general to determine the nth largest numbers you first have to determine the n-1 larger numbers. If there is only 1 or 2, then you might be able to do something smarter, but in general I think the best supported solution is to use the arg_sort function to determine the order of all elements, and then choose the nth largest one.
This can be written as the following function:
function var int: nth_largest(array[$$E] of $$V: x, var int: n) =
let {
any: perm = arg_sort(x);
} in x[perm[length(x)-n]];
In your fragment this can be used as:
array[1..10] of 1..200: t= [30,20,30,40,50,50,70,10,90,100];
var int: nth_largest ::output = nth_largest(t, 2);
function var int: nth_largest(array[$$E] of $$V: x, var int: n) =
let {
any: perm = arg_sort(x);
} in x[perm[length(x)-n]];
Although you might want to find a more meaningful name for the variable, since shadowing names of variables and functions is generally frowned upon.
Reading #Dekker1's solution, here's what I had in mind. Instead of sort(x,y) the function y = sort(x) is used.
include "globals.mzn";
int: n = 10;
int: nth = 3;
array[1..n] of 1..200: t = [30,20,30,40,50,50,70,10,90,100];
var 1..200: nth_largest;
constraint
nth_largest = sort(t)[n-nth+1]
;
Same idea using a function:
include "globals.mzn";
int: n = 10;
int: nth = 3;
array[1..n] of 1..200: t = [30,20,30,40,50,50,70,10,90,100];
var 1..200: nth_largest;
function var int: nth_largest_val(array[int] of var int: a, var int: m) =
sort(a)[length(a)-m+1]
;
constraint
nth_largest = nth_largest_val(t,nth)
;
Both give:
nth_largest = 70;
Update: Ignoring duplicates
Here is a variant which ignores duplicate values. nthis here a decision variable so we can see all solutions (and it makes it possible to "reverse" the constraint, see below).
include "globals.mzn";
int: n = 10;
var 1..n: nth; % : nth = 4;
array[1..n] of 1..200: t = [30,20,30,40,50,50,70,10,90,100];
var 1..200: nth_largest;
% Skipping duplicates
function var int: nth_largest_skip_dups(array[int] of var int: a, var int: nth) =
let {
var lb_array(a)..ub_array(a): v;
constraint
% count the number of larger values in the unique set
sum([ k > v | k in {a[j] | j in index_set(a) } ]) = nth -1
% ensure that v is in a
/\ exists(i in index_set(a)) (
v = a[i]
);
} in
v
;
constraint
nth_largest = nth_largest_skip_dups(t,nth)
;
output ["nth:\(nth)\nlargest: \(nth_largest)\n" ];
Here's the output:
nth:8
largest: 10
----------
nth:7
largest: 20
----------
nth:1
largest: 100
----------
nth:2
largest: 90
----------
nth:3
largest: 70
----------
nth:4
largest: 50
----------
nth:5
largest: 40
----------
nth:6
largest: 30
----------
Note about reversibility: If the following constraint is added the the constraint is reversed, i.e. we get what rank of the number 50:
constraint nth_largest = 50;
The output:
nth:4
largest: 50
A drawback is that it might be costly for large arrays, and it's better to use the first suggestion if you can ensure that the array has no duplicates.

MiniZinc MILP constraint to restrict a certain for at most 3 contiguous in an array

I have the next MiniZinc code
array [0..5] of var 0..1: a;
constraint sum(a) = 3;
output [show(a)]
And I need to add two constraints to ensure that at most I have 3 contiguous 1's. I thought that adding constraint sum(a) = 3; helps but how can I add a constraint to make sure I have 3-contiguous 1s for example 111000 or 011100?
Another alternative is to constrain the distance between first and last 1:
int: n = 5;
set of int: N = 1..n;
array [N] of var 0..1: a;
var N: first = n + 1 - max(i in N)(i * a[n - i + 1]);
var N: last = max(i in N)(i * a[i]);
constraint sum(a) == 3;
constraint (last - first + 1) == 3;
output [show(a)]
Here is one way by constraining the sum of each block of 4 consecutive elements to 3:
array [0..5] of var 0..1: a;
int: MAX_CONTIGUOUS_ONES = 3;
constraint forall(start in 0..5-MAX_CONTIGUOUS_ONES)
(sum([a[i] | i in start..start+MAX_CONTIGUOUS_ONES]) <= MAX_CONTIGUOUS_ONES);
output [show(a)]

Minizinc strange behaviour

I have recently started studying minizinc, but I have got this strange behaviour in my program.
.dzn
n = 5;
c = 2;
.mzn
include "globals.mzn";
int: n;
int: c;
set of int: num_deliveries = 1..n-1;
int: headquarter = 1;
set of int: num_places = 1..n;
set of int: deliveries = 2..n;
set of int: couriers = 1..c;
set of int: num_max_deliveries = 1..n+2;
set of int: schedule_domain = 0..n;
int: first_place_idx = 1;
int: last_place_idx = n+2;
array[couriers,num_max_deliveries] of var schedule_domain: schedule;
array[1..2*n] of int: total = [schedule[i,j]|i,j in num_max_deliveries where i<=2 /\ j != first_place_idx /\ j!= last_place_idx];
output ["len_without_variable = \(length([ k | k in total where k != 0]))"];
var int: len_cleaned = length([ k | k in total where k != 0]);
output ["len_with_variable = \(len_cleaned)\n"];
In particular, from these lines of code I have different results, even if they are equal.
output ["len_without_variable = \(length([ k | k in total where k != 0]))"];
var int: len_cleaned = length([ k | k in total where k != 0]);
output ["len_with_variable = \(len_cleaned)\n"];
Why does it happen?
Here is one output of the model is this (with total added):
len_without_variable = 2
len_with_variable = 10
total: [3, 3, 0, 0, 0, 0, 0, 0, 0, 0]
To be honest, I'm not sure if the two calculations of the number of non zero elements in total should be the same or not. Perhaps this is a bug in how length operates on decision variables (with a where condition), and it should be 2 (in this example). Until this is settled, you should probably avoid using length like this.
The output of len_without_variable - the one defined in the output section - operates on the actual and known values of the solution. So this might not be the exact thing as using length in a constraint/variable definition.
To calculate the number of non zero values you can use sum instead:
var 0..n num_non_zeros = sum([ 1 | k in total where k != 0]);
However, the construct ... where k != 0 creates temporary variables which makes the model larger than necessary so it's better to use the following:
var 0..n num_non_zeros = sum([ total[i] != 0 | i in 1..n]);

minizinc gramma error can not Dynamic calculation

Anyone can help me to slove this gramma error?
I do know how to rewrite this code
constraint
forall(i in 1..LINENUMBER,j in 1..DAYSETNUMBER )
( PACKOUTCAP[i,j] -( sum(k in 1..j)(INPUTCAP[i,k] * rate[i,k,j-k+1])) >0 );
As mentioned in the comment: What is your full model (with some explanation what it should do). What error do you get? Which MiniZinc version?
The following model is your code with some fictive data added. It don't give any errors, and yield a lot of solutions.
int: LINENUMBER = 3;
int: DAYSETNUMBER = 3;
array[1..LINENUMBER,1..DAYSETNUMBER] of var 1..10: PACKOUTCAP;
array[1..LINENUMBER,1..DAYSETNUMBER] of var 1..10: INPUTCAP;
array[1..LINENUMBER,1..DAYSETNUMBER,1..LINENUMBER] of var 1..10: rate;
constraint
forall(i in 1..LINENUMBER,j in 1..DAYSETNUMBER )
( PACKOUTCAP[i,j] -( sum(k in 1..j)(INPUTCAP[i,k] * rate[i,k,j-k+1])) >0 );
Regarding cumulative sum, here's a simple model where the array y contains the cumulative sum of the values in the array x. Perhaps that help you?
int: n = 5;
array[1..n] of var 1..10: x;
array[1..n] of var 1..100: y; % cumulative sum
constraint
y[1] = x[1] /\
forall(i in 2..n) (
y[i] = y[i-1] + x[i]
)
;

Minizinc Objective Function For Gaps in Schedule

I have a working Miniznic model to schedule individual lessons of 1 professor having n students (Optimization Problem of a Single Lessons Scheduling Model). The model considers availability (hard constraint)
and the time preferences (objective function) of the professor as well
as of the students.
Now, I want to extend the model and optimize the schedule such that
gaps between lessons are minimized.
Example:
Schedule : p L p p L L . . p p L L p L L p L p p . L p L L . L p L
Real Gaps : . L p p L L . . . . L L p L L p L . . . L p L L . L p L
where
`p` = 0 == Teacher available, but no Lesson
`L` = 1 == Teacher gives lesson (to student)
`.` = -1 == Teacher not available
Obviously, the p in slot 1 must not be counted as a gap. Similarly,
slots 9 and 10 are no gaps, neither. Eliminating all false gaps, the
Schedule should finally look like the Real Gaps array (Note: false gaps are marked with .; the same as not available).
The result would be a gap array [2, 1, 1, 1, 1] (for each gap showing the number of slots it lasts). Based on such an array one could then e.g. formulate an objective to minimize the overall gap slots.
In ruby I was able to formulate an algorithm that does what I want:
def gap_array(schedule_arr)
# initialize variables
start_search = false # flag for break start
break_slots = 0 # counter of break slots
res_arr = [] # resulting array
schedule_arr.each do |slot|
if slot == 1 # start watching for break
start_search = true
end
#
if start_search
if slot == 0 # == break
break_slots += 1
elsif slot == 1 # == consecutive lesson slot
if break_slots > 0 # number of break_slots > 0
res_arr.append(break_slots)
break_slots = 0
end
else # == not available
break_slots = 0 # any break so far is discarded
start_search = false
end
end
end
return res_arr
end
How can I formulate such an algorithm in Minizinc?
Thanks!
One way to this in MiniZinc would be to extend the model at Optimization Problem of a Single Lessons Scheduling Model in the following way:
Initially calculate teacher_free as the slots where the teacher is not available combined with adjacent slots where no lesson takes place (this is done in two steps, going from the left teacher_free_left and the right teacher_free_right, respectively, and then combining the results to form teacher_free).
In the next step the real_gap is calculated as slots where the teacher is not free and no lesson takes place.
In the objective a penalty term for real_gap is then introduced like (k2 being the gap penalty weight):
int: k2 = 1;
var int: obj = sum(s in STUDENT, t in TIME)
(active[s,t] * (prio_time[s,t] + k*prioTeacher_time[t])) - k2*sum(real_gap);
Here all the other extensions to the model (with some further comments):
array[DAY,SLOT] of var 0..1: lesson = array2d(DAY, SLOT, [sum(s in STUDENT)(active[s,time(d,z)]) | d in DAY, z in SLOT]);
array[DAY,SLOT] of var 0..1: teacher_free_left;
array[DAY,SLOT] of var 0..1: teacher_free_right;
array[DAY,SLOT] of var 0..1: teacher_free;
array[DAY,SLOT] of var 0..1: real_gap;
predicate equals_and(var 0..1: z, var 0..1: x, var 0..1: y) =
(z <= x /\ z <= y /\ z >= x + y - 1);
predicate equals_or(var 0..1: z, var 0..1: x, var 0..1: y) =
(z >= x /\ z >= y /\ z <= x + y);
% calculate teacher free left
% first slot -> teacher free = no lesson in the slot
% other slots -> teacher free = teacher out or (left slot teacher free and no lesson in slot)
array[DAY,SLOT] of var 0..1: teacher_free_left_temp;
constraint forall(d in DAY)
(teacher_free_left_temp[d,1]=1-lesson[d,1]);
constraint forall(d in DAY, z in 2..maxSlots)
(equals_and(teacher_free_left_temp[d,z], teacher_free_left[d,z-1], 1-lesson[d,z]));
constraint forall(d in DAY, z in SLOT)
(equals_or(teacher_free_left[d,z], 1 - bool2int(z in teacher[d]), teacher_free_left_temp[d,z]));
% calculate teacher free right
% last slot -> teacher free = no lesson in the slot
% other slots -> teacher free = teacher out or (right slot teacher free and no lesson in slot)
array[DAY,SLOT] of var 0..1: teacher_free_right_temp;
constraint forall(d in DAY)
(teacher_free_right_temp[d,maxSlots]=1-lesson[d,maxSlots]);
constraint forall(d in DAY, z in 1..maxSlots-1)
(equals_and(teacher_free_right_temp[d,z], teacher_free_right[d,z+1], 1-lesson[d,z]));
constraint forall(d in DAY, z in SLOT)
(equals_or(teacher_free_right[d,z], 1 - bool2int(z in teacher[d]), teacher_free_right_temp[d,z]));
% teacher free when teacher free left or teacher free right
constraint forall(d in DAY, z in SLOT)
(equals_or(teacher_free[d,z], teacher_free_left[d,z], teacher_free_right[d,z]));
% real gap when teacher not free and no lesson
constraint forall(d in DAY, z in SLOT)
(equals_and(real_gap[d,z], 1-teacher_free[d,z], 1-lesson[d,z]));