constraint dependents in array of classes - constraints

How can I constraint 2 variables in an array of classes, when there is a dependent between different items of the array?
class X;
rand bit en;
rand int idx;
constraint cnst1{
idx inside {[0:9]};
}
endclass
class Y;
rand X arr_x[100];
constraint cnst2{
???
}
endclass
I want to create cnst2 that will guarantee that:
each idx optional value (0-9) will be set for at least one of the arr_x[i].idx .
for all of the arr_x[i] that have the same value of idx, at least 1 will have en set to 1.
for example:
let's say that only the following have idx == 9:
arr_x[0].idx == 9;
arr_x[13].idx == 9;
arr_x[44].idx == 9;
arr_x[75].idx == 9;
arr_x[81].idx == 9;
arr_x[93].idx == 9;
need to guarantee that:
arr_x[0].en | arr_x[13].en | arr_x[44].en | arr_x[75].en | arr_x[81].en | arr_x[93].en == 1;
and so on for every idx value;

You want the or array reduction method. Also create a helper array so you can iterate from 0-9. This constraint reads: if at least one element has the value 0-9, then one of those elements has to have en set.
bit iterator[10];
constraint cnst2{
foreach(iterator[i])
arr_x.or(x) with (i ==x.idx) -> // needed if idx will not have every value 0-9
arr_x.or(y) with (i == y.idx && y.en);
}
See sections 18.5.8.2 Array reduction iterative constraints and 7.12.3 Array reduction methods in the IEEE 1800-2017 SystemVerilog LRM.

Related

Dynamic array constraint such that 8'h00 value should come in min 4 elements

I want to randomize dynamic array such that a particular value should come in min N elements.
For example, in the following case here are the constraints
Array size should be min 20, max 50
All elements should be either 8'h0a, 8'ha0, 8'hff, 8'h62
All elements should come min 5 times in array.
No 2 same elements should be side by side (a[0] = 8'h0a then a[1] can't be 8'h0a)
Here is the code for that.
class trans;
rand bit [7:0] a [];
// For 1st Constraint
constraint c_size {a.size() inside {[20:50]};}
// For 2nd Constraint
constraint c_element {foreach(a[i]) a[i] inside {8'h0a, 8'ha0, 8'hff, 8'h62};}
// For 3rd Constraint
constraint c_min {
// Only valid if 20 entries and all values exact 5 times
// a.sum() with (int'(item)) == ((10*5)+(160*5)+(255*5)+(98*5));
}
// For 4th Constraint
constraint c_side {foreach (a[i]) (i > 0) -> (a[i] != a[i-1]);}
endclass
I am not sure, how to write for min 5 times.
You can do the following to get a count of how many times an expression is true
a.sum() with (int'(item==value))
It would make it easier if you put the value set into an array. Then you could write
int values[]='{8'h0a, 8'ha0, 8'hff, 8'h62};
// For 2nd Constraint
constraint c_element {foreach(a[i]) a[i] inside {values};}
// For 3rd Constraint
constraint c_min {foreach(values[i]
a.sum() with (int'(item==values[i])) >= 5;
}

minizinc sitting-friends-at-a-table-far-from-furius ones

1.we have cycling table
2.a man must be sit next to a woman and a woman next to a man
3. guests must share hobbies (at least one common between their hobbies)
4. there are couples of furious guests. they must not sit near to next to each other
5. nobody of list o furious guests must sit at start(seat 1) or end (seat N)
-pR is the number of furious couples
my model:
int :N;
set of int: GUESTS = 1..N;
set of int: POSITIONS = 1..N;
array[GUESTS] of 1..2 : gender;
array[GUESTS] of set of int: hobbies;
enum PAIR = {first,second};
int : pR;
set of int: LIST = 1..pR;
array[LIST,PAIR] of GUESTS : furious;
array[POSITIONS] of var GUESTS : guest_at;
array[POSITIONS] of var 1..2: table_gender;
constraint forall(i in 1..length(table_gender)-1)(
table_gender[i]!=table_gender[i+1]
/\
table_gender[1]!=table_gender[length(table_gender)]
)
;
include "alldifferent.mzn";
constraint alldifferent(guest_at);
constraint forall(i in 2..N-1)(card(hobbies[guest_at[i+1]] intersect hobbies[guest_at[i]]) >0);
constraint card(hobbies[guest_at[N]] intersect hobbies[guest_at[1]]) >0;
constraint forall(i in 2..N-1,l in LIST, p in PAIR)(if guest_at[i]=furious[i,first] then guest_at[i+1]!=furious[i,second] /\ guest_at[i-1]!=furious[i,second] else true endif);
constraint forall(l in LIST, p in PAIR)(guest_at[1]!=furious[l,p] /\ guest_at[N]!=furious[l,p]);
solve satisfy;
output
["guest_at = \(guest_at);"]
++ ["\ntable_gender = \(table_gender); \n" ]
++ ["Furious Placement\n"]
++ [show_int(4,furious[i,j]) | i in LIST, j in PAIR] ++["\n"]
++ [if fix(guest_at[p]) = furious[i,j] then show_int(4,p) else "" endif | i in LIST, j in PAIR, p in POSITIONS]
;
my model's bugs:
C:/Users/�������/Documents/������/����������/Gala/gala.mzn:36:
in call 'forall'
in array comprehension expression
with i = 4
with l = 3
with p = 1
in if-then-else expression
in binary '=' operator expression
in array access
WARNING: Further warnings have been suppressed.
This constraint, where there errors are referring to, contains a couple of strange things:
constraint
forall(i in 2..N-1,l in LIST, p in PAIR) (
if guest_at[i]=furious[i,first] then
guest_at[i+1]!=furious[i,second] /\
guest_at[i-1]!=furious[i,second]
else
true
endif
);
1) The second and third loop parameters l in List and p in PAIR is never used, so they are meaningless.
2) The main reason for the warning is that the furious matrix is just two rows, but in the loop variable i goes from 2 to 16. The error (array access out of bounds) indicates that when i is larger than 2 it's out of bound of the furious matrix.

Index of string value in MiniZinc array

The question
Given a MiniZinc array of strings:
int: numStats;
set of int: Stats = 1..numStats;
array[Stats] of string: statNames;
... with data loaded from a MiniZinc data file:
numStats = 3;
statNames = ["HEALTH", "ARMOR", "MANA"];
How can one look up the index of a specific string in the array? For example, that ARMOR is located at position 2.
The context
I need to find an optimal selection of items with regard to some constraints on their stats. This information is stored in a 2D array declared as follows:
int: numItems;
set of int: Items = 1..numItems;
array[Items, Stats] of float: itemStats;
So in order to write a constraint on, say, the minimum amount of ARMOR obtained through the selected items, I need to know that ARMOR has index 2 in the inner array.
Since the data file is generated by an external program, and the number and order of stats are dynamic, I cannot hardcode the indices in the constraints.
One solution (that won't work in my case)
The MiniZinc tutorial uses an interesting trick to achieve something similar:
set of int: Colors = 1..3;
int: red = 1;
int: yellow = 2;
int: blue = 3;
array[Colors] of string: name = ["red", "yellow", "blue"];
var Colors: x;
constraint x != red;
output [ name[fix(x)] ];
Unfortunately, as variable declarations are not allowed in MiniZinc data files, this trick won't work in my case.
You can write your own custom function to get the index of a string within a string array:
function int: getIndexOfString(string: str,
array[int] of string: string_array) =
sum( [ if str = string_array[i]
then i
else 0 endif
| i in index_set(string_array) ]
);
In this function I create an array of integers where the integer at position i either equals the index of str if string_array[i]=str and 0 otherwise. For instance, for your sample string array ["HEALTH", "ARMOR", "MANA"] and str ARMOR the resulting int array will be [0,2,0].
This is why I can simply sum over the int array to get the index of the string. If the string does not occur, the return value is 0, which is fine since indices in MiniZinc start with 1 by default.
Here is how you can call the function above for your first example:
int: numStats;
set of int: Stats = 1..numStats;
array[Stats] of string: statNames;
numStats = 3;
statNames = ["HEALTH", "ARMOR", "MANA"];
var int: indexOfArmor;
constraint
indexOfArmor = getIndexOfString("ARMOR",statNames);
solve satisfy;
Note however that the function above is limited and has some flaws. First, if you have multiple occurrences of the string in the array, then you will receive an invalid index (the sum of all indices where str occurred). Also, if you have your own index set for your string array (say (2..6)), then you will need to adapt the function.
Another, cleaner option is to write a function that uses a recursive helper function:
% main function
function int: index_of(string: elem, array[int] of string: elements) =
let {
int: index = length(elements);
} in % calls the helper function with the last index
get_index(elem, elements, index)
;
% recursive helper function
function int: get_index(string: elem, array[int] of string: elements, int: index) =
if index == 0
then -1 % the element was not found (base case of recursion)
elseif elements[index] == elem
then index % the element was found
else
get_index(elem, elements, index - 1) % continue searching
endif
;
The helper function iterates recursively over the array, starting from the last element, and when it finds the element, it returns the index. If the element was not found in the array, then -1 is returned. Alternatively, you can also throw an assertion following the suggestion of Patrick Trentin by replacing then -1 with then assert(false, "unknown element: " + elem).
An example of calling this function:
set of int: Customers = 1..5;
array[Customers] of string: ids = ["a-1", "a-2", "a-3", "a-4", "a-5"];
var int: index = index_of("a-3", ids);
var int: unknown_index = index_of("x-3", ids);
where index will be assigned 3 and unknown_index will be -1.
An alternative approach to that presented by Andrea Rendl-Pitrey, is the following one:
array[int] of string: statNames = array1d(10..12, ["HEALTH", "ARMOR", "MANA"]);
var int: indexOfArmor =
sum([i | i in index_set(statNames) where statNames[i] = "ARMOR"]);
solve satisfy;
output [
"indexOfArmor=", show(indexOfArmor), "\n",
];
which outputs:
~$ mzn2fzn example.mzn ; flatzinc example.fzn
indexOfArmor = 11;
----------
note: that var can be dropped from the declaration of indexOfArmor, since the index can be statically computed. I kept it here only for output purposes.
A better solution is to declare a new predicate:
predicate index_of_str_in_array(var int: idx,
string: str,
array[int] of string: arr) =
assert(
not exists(i in index_set(arr), j in index_set(arr))
(i != j /\ arr[i] = str /\ arr[j] = str),
"input string occurs at multiple locations",
assert(
exists(i in index_set(arr))
(arr[i] = str),
"input string does not occur in the input array",
exists(i in index_set(arr))
(arr[i] = str /\ i = idx)
));
which enforces both of the following conditions:
str occurs at least once in arr
str does not occur multiple times in arr
e.g
predicate index_of_str_in_array(var int: idx,
string: str,
array[int] of string: arr) =
...
array[10..13] of string: statNames =
array1d(10..13, ["HEALTH", "ARMOR", "MANA", "ATTACK"]);
var int: indexOfArmor;
constraint index_of_str_in_array(indexOfArmor, "ARMOR", statNames);
solve satisfy;
output [
"indexOfArmor=", show(indexOfArmor), "\n",
];
outputs
~$ mzn2fzn example.mzn ; flatzinc example.fzn
indexOfArmor = 11;
----------
If one changes statNames in the following way
array[10..13] of string: statNames =
array1d(10..13, ["HEALTH", "ARMOR", "MANA", "ARMOR"]);
then mzn2fzn detects an assertion violation:
~$ mzn2fzn example.mzn ; flatzinc example.fzn
MiniZinc: evaluation error:
example.mzn:24:
in call 'index_of_str_in_array'
example.mzn:4:
in call 'assert'
Assertion failed: input string occurs at multiple locations
flatzinc:
example.fzn: cannot open input file: No such file
A similar result would be obtained by searching for the index of a string that does not occur in the array. This condition can of course be removed if not necessary.
DISCLAIMER: older versions of mzn2fzn don't seem to check that the declared index-set of an array of strings variable matches the index-set of an array of strings literal that is being assigned to it. This rule is enforced on newer versions, as it is also valid for other data types.
According to this other post on Stackoverflow there is no way of converting strings to integers in MiniZinc, only the other way around. You need to first pre process your data in some other language and turn it into integers. You can however turn those integers into string once you are done in MiniZinc.
You can however load MiniZinc files instead of data files if you would like. Use the include syntax to include any .mzn file.

How to use predicate exactly in MiniZinc

New MiniZinc user here ... I'm having a problem understanding the syntax of the counting constraint:
predicate exactly(int: n, array[int] of var int: x, int: v)
"Requires exactly n variables in x to take the value v."
I want to make sure each column in my 10r x 30c array has at least one each of 1,2 and 3, with the remaining 7 rows equal to zero.
If i declare my array as
array[1..10,1..30] of var 0..3: s;
how can I use predicate exactly to populate it as I need? Thanks!
Well, the "exactly" constraint is not so useful here since you want at least one occurrence of 1, 2, and 3. It's better to use for example the count function:
include "globals.mzn";
array[1..10,1..30] of var 0..3: s;
solve satisfy;
constraint
forall(j in 1..30) (
forall(c in 1..3) (
count([s[i,j] | i in 1..10],c) >= 1
)
)
;
output [
if j = 1 then "\n" else " " endif ++
show(s[i,j])
| i in 1..10, j in 1..30
];
You don't have do to anything about 0 since the domain is 0..3 and all values that are not 1, 2, or 3 must be 0.
Another constraint is "at_least", see https://www.minizinc.org/2.0/doc-lib/doc-globals-counting.html .
If you don't have read the MiniZinc tutorial (https://www.minizinc.org/downloads/doc-latest/minizinc-tute.pdf), I strongly advice you to. The tutorial teaches you how to think Constraint Programming and - of course - MiniZinc.

How many valid parenthesis combinations?

We have:
n1 number of {} brackets ,
n2 number of () brackets ,
n3 number of [] brackets ,
How many different valid combination of these brackets we can have?
What I thought: I wrote a brute force code in java (which comes in the following) and counted all possible combinations, I know it's the worst solution possible,
(the code is for general case in which we can have different types of brackets)
Any mathematical approach ?
Note 1: valid combination is defined as usual, e.g. {{()}} : valid , {(}){} : invalid
Note 2: let's assume that we have 2 pairs of {} , 1 pair of () and 1 pair of [], the number of valid combinations would be 168 and the number of all possible (valid & invalid) combinations would be 840
static void paranthesis_combination(char[] open , char[] close , int[] arr){
int l = 0;
for (int i = 0 ; i < arr.length ; i++)
l += arr[i];
l *= 2;
paranthesis_combination_sub(open , close , arr , new int[arr.length] , new int[arr.length], new StringBuilder(), l);
System.out.println(paran_count + " : " + valid_paran_count);
return;
}
static void paranthesis_combination_sub(char[] open , char[] close, int[] arr , int[] open_so_far , int[] close_so_far, StringBuilder strbld , int l){
if (strbld.length() == l && valid_paran(open , close , strbld)){
System.out.println(new String(strbld));
valid_paran_count++;
return;
}
for (int i = 0 ; i < open.length ; i++){
if (open_so_far[i] < arr[i]){
strbld.append(open[i]);
open_so_far[i]++;
paranthesis_combination_sub(open , close, arr , open_so_far , close_so_far, strbld , l);
open_so_far[i]--;
strbld.deleteCharAt(strbld.length() -1 );
}
}
for (int i = 0 ; i < open.length ; i++){
if (close_so_far[i] < open_so_far[i]){
strbld.append(close[i]);
close_so_far[i]++;
paranthesis_combination_sub(open , close, arr , open_so_far , close_so_far, strbld , l);
close_so_far[i]--;
strbld.deleteCharAt(strbld.length() -1 );
}
}
return;
}
Cn is the nth Catalan number, C(2n,n)/(n+1), and gives the number of valid strings of length 2n that use only (). So if we change all [] and {} into (), there would be Cn1+n2+n3 ways. Then there are C(n1+n2+n3,n1) ways to change n1 () back to {}, and C(n2+n3,n3) ways to change the remaining () into []. Putting that all together, there are C(2n1+2n2+2n3,n1+n2+n3)C(n1+n2+n3,n1)C(n2+n3,n3)/(n1+n2+n3+1) ways.
As a check, when n1=2, n2=n3=1, we have C(8,4)C(4,2)C(2,1)/5=168.
In general, infinitely. However I assume, that you meant to find how many combinations are there provided limited string length. For simplicity lets assume that the limit is an even number. Then, lets create an initial string:
(((...()...))) with length equal to the limit.
Then, we can switch any instance of () pair with [] or {} parenthesis. However, if we change an opening brace, then we ought to change the matching closing brace. So, we can look only at the opening braces, or at pairs. For each parenthesis pair we have 4 options:
leave it unchanged
change it to []
change it to {}
remove it
So, for each of (l/2) objects we choose one of four labels, which gives:
4^(l/2) possibilities.
EDIT: this assumes only "concentric" parenthesis strings (contained in each other), as you've suggested in your edit. Intuitively however, a valid combination is also: ()[]{} - this solution does not take this into account.

Resources