Want caculate the n-th largest value in an array Use Minizinc - 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.

Related

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

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)

How to Create Autocorrelation Function without any buit-in functions like xcorr

I want to auto-correlate a random noise vector with out any built-in MATLAB functions.
My auto correlation equation that is given is:
Rxx[L] = ∑ from n = 1 to N-1 [x(n)*x(n+L)]
L = [0:200]
I have written the code below but the plot Rxx vs L plot is not what I am expecting.
I am expecting my plot to start at some maximum at L = 0 or L = 1 since MATLAB starts its index at 1. Then exponentially decrease and saturates at a min of zero.
clc
clear all
randn('seed',2496132);
n = randn(1,1024);
upperbound = numel(n)-1;
for L = 1:200
for j = 1 : upperbound
n1(j) = n(j)+L;
Rxx(j) = (n(j)*n1(j));
end
Rxx_sum(L) = sum(Rxx);
Rxx = 0;
end
plot([1:200], Rxx_sum)
You have error in inner loop: you need to use n1(j) = n(j+L); instead n1(j) = n(j)+L;. E.g. you need add L to index instead value.
Second error is following: if you want to use upperbound = numel(n)-1 than you should use L equal to 0 or 1 only. E.g. you outer loop will be
for L = 0:1
...
Rxx_sum(L+1) = sum(Rxx);
...
Instead of this you can also correct upperbound value:
upperbound = numel(n) - maxL;
There maxL is maximal value of L that will used in next loop.
One more tip: it is possible to increase calculation speed if you replace inner loop with scalar product, e.g.
for L = 1:200
Rxx_sum(L) = n(1:upperbound) * n(1+L:upperbound+L)';
end
I ended up fixing my script with the help of the above code.
clc
clear all
randn('seed',2496132);
z = randn(1,1024);
n = [z zeros(1,200)];
upperbound = numel(z)-1;
for L = 0:200
for j = 1 : upperbound
Rxx(j) = (n(j)*n(j+L));
>end
Rxx_sum(L+1) = sum(Rxx);
Rxx = 0;
end
plot([0:200],Rxx_sum)