Minizinc strange behaviour - minizinc

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]);

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)]

Hash function that returns the same hash for a sum even if different terms lead to the same sum

let's say I have:
n = 14
n is the result of the following sums of integers:
[5, 2, 7] -> 5 + 2 + 7 = 14 = n
[3, 4, 5, 2] -> 3 + 4 + 5 + 2 = 14 = n
[1, 13] -> 1 + 13 = 14 = n
[13, 1] -> 13 + 1 = 14 = n
[4, 3, 5, 2] -> 4 + 3 + 5 + 2 = 14 = n
...
I would need a hash function h so that:
h([5, 2, 7]) = h([3, 4, 5, 2]) = h([1, 13]) = h([13, 1]) = h([4, 3, 5, 2]) = h(...)
I.e. it doesn't matter the order of the integer terms and as long as their integer sum is the same, their hash should also the same.
I need to do this without computing the sum n, because the terms as well as n can be very high and easily overflow (they don't fit the bits of an int), that's why I am asking this question.
Are you aware or maybe do you have an insight on how I can implement such a hash function?
Given a list/sequence of integers, this hash function must return the same hash if the sum of the integers would be the same, but without computing the sum.
Thank you for your attention.
EDIT: I elaborated on #derpirscher's answer and modified his function a bit further as I had collisions on multiples of BIG_PRIME (this example is in JavaScript):
function hash(seq) {
const BIG_PRIME = 999999999989;
const MAX_SAFE_INTEGER_DIV_2_FLOOR = Math.floor(Number.MAX_SAFE_INTEGER / 2);
let h = 0;
for (i = 0; i < seq.length; i++) {
let value = seq[i];
if (h > MAX_SAFE_INTEGER_DIV_2_FLOOR) {
h = h % BIG_PRIME;
}
if (value > MAX_SAFE_INTEGER_DIV_2_FLOOR) {
value = value % BIG_PRIME;
}
h += value;
}
return h;
}
My question now would be: what do you think about this function? Are there some edge cases I didn't take into account?
Thank you.
EDIT 2:
Using the above function hash([1,2]); and hash([4504 * BIG_PRIME +1, 4504 * BIG_PRIME + 2]) will collide as mentioned by #derpirscher.
Here is another modified of version of the above function, which computes the modulo % BIG_PRIME only to one of the two terms if either of the two are greater than MAX_SAFE_INTEGER_DIV_2_FLOOR:
function hash(seq) {
const BIG_PRIME = 999999999989;
const MAX_SAFE_INTEGER_DIV_2_FLOOR = Math.floor(Number.MAX_SAFE_INTEGER / 2);
let h = 0;
for (let i = 0; i < seq.length; i++) {
let value = seq[i];
if (
h > MAX_SAFE_INTEGER_DIV_2_FLOOR &&
value > MAX_SAFE_INTEGER_DIV_2_FLOOR
) {
if (h > MAX_SAFE_INTEGER_DIV_2_FLOOR) {
h = h % BIG_PRIME;
} else if (value > MAX_SAFE_INTEGER_DIV_2_FLOOR) {
value = value % BIG_PRIME;
}
}
h += value;
}
return h;
}
I think this version lowers the number of collisions a bit further.
What do you think? Thank you.
EDIT 3:
Even though I tried to elaborate on #derpirscher's answer, his implementation of hash is the correct one and the one to use.
Use his version if you need such an hash function.
You could calculate the sum modulo some big prime. If you want to stay within the range of int, you need to know what the maximum integer is, in the language you are using. Then select a BIG_PRIME that's just below maxint / 2
Assuming an int to be 4 bytes, maxint = 2147483647 thus the biggest prime < maxint/2 would be 1073741789;
int hash(int[] seq) {
BIG_PRIME = 1073741789;
int h = 0;
for (int i = 0; i < seq.Length; i++) {
h = (h + seq[i] % BIG_PRIME) % BIG_PRIME;
}
return h;
}
As at every step both summands will always be below maxint/2 you won't get any overflows.
Edit
From a mathematical point of view, the following property which may be important for your use case holds:
(a + b + c + ...) % N == (a % N + b % N + c % N + ...) % N
But yeah, of course, as in every hash function you will have collisions. You can't have a hash function without collisions, because the size of the domain of the hash function (ie the number of possible input values) is generally much bigger than the the size of the codomain (ie the number of possible output values).
For your example the size of the domain is (in principle) infinite, as you can have any count of numbers from 1 to 2000000000 in your sequence. But your codomain is just ~2000000000 elements (ie the range of int)

Produce set of random integers with minimum intervals in Matlab

I would like to randomly produce a set of integers ranging from 1~100. After sorting the integers, the minimum interval between each integer should not be less than a 2. For example
2,4,8,10
satisfies the requirement while the following set
2,4,5,7
does not since the interval between 4 and 5 is less than 2.
Is there any way to achieve this? Thanks!
N = 10; % number of integers required
delta = 2; % minimum difference required
a = randperm(100);
idx = 1;
b = a(idx);
while(length(b) < N && idx < length(a))
idx = idx+1;
c = abs(b - a(idx));
if any(c < delta)
continue;
end
b = [b; a(idx)];
end
b

Counting Number of Specific Outputs of a Function

If I have a matrix and I want to apply a function to each row of the matrix. This function has three possible outputs, either x = 0, x = 1, or x > 0. There's a couple things I'm running into trouble with...
1) The cases that output x = 1 or x > 0 are different and I'm not sure how to differentiate between the two when writing my script.
2) My function isn't counting correctly? I think this might be a problem with how I have my loop set up?
This is what I've come up with. Logically, I feel like this should work (except for the hiccup w/ the first problem I've stated)
[m n] = size(matrix);
a = 0; b = 0; c = 0;
for i = 1 : m
x(i) = function(matrix(m,:));
if x > 0
a = a + 1;
end
if x == 0
b = b + 1;
end
if x == 1
c = c + 1;
end
end
First you probably have an error in line 4. It probably should be i instead of m.
x(i) = function(matrix(i,:));
You can calculate a, b and c out of the loop:
a = sum(x>0);
b = sum(x==0);
c = sum(x==1);
If you want to distinguish x==1 and x>0 then may be with sum(xor(x==1,x>0)).
Also you may have problem with precision error when comparing double values with 0 and 1.