Minizinc constraints from another array - minizinc

I'm attempting my first constraint programming with minizinc. I'm trying to create a schedule, with n slots and n people, with a different person allocated to each slot. I'm using an array of var int to model the schedule, usingalldifferent() to ensure a different person in each slot.
A separate array of size n, names contains their names, as below:
% Pseudo enum
set of int: NameIndex = 1..2;
int: Forename = 1;
int: Surname = 2;
int: n = 4; % Number of slots and people
set of int: slots = 1..n;
array[slots, NameIndex] of string: names = [| "John", "Doe"
| "Ann", "Jones"
| "Fred", "Doe"
| "Barry", "Doe" |];
% The schedule
array[slots] of var slots: schedule;
% Every person is scheduled:
include "alldifferent.mzn";
constraint alldifferent(schedule);
% How to constrain by a value from names, say alphabetic order by forename.
% Want to compare each value in schedule to the next one.
%constraint forall (i in 1..n-1) (names[schedule[i],Forename] < names[schedule[i+1],Forename]);
solve satisfy;
output [show(i) ++ ": " ++ show(names[schedule[i], Forename]) ++ " " ++ show(names[schedule[i], Surname]) ++ "\n"
| i in slots]
% should be:
% | i in schedule]
How can I constrain schdule by values from names? In my (broken) example above, when the forall constraint is uncommented, i get (using the Minizinc IDE):
in call 'forall'
in array comprehension expression
with i = 1
in binary '<' operator expression
in array access
cannot find matching declaration
I follow the error until not understanding which declaration cannot be found. The output block show()s values from names quite happily when I index into array from the schdule value.
What am I missing? Is there a better way to model the names? I'm hoping to extend names to additional 'attributes' of people and create additional constraints. I'm sure both the model and my forall constraint are quite naive!

The problem is that MiniZinc don't have much support for strings; and specific for your example: there's no support for comparing strings ("<").
That said, there are some plans to support var strings (i.e. using strings as decision variables), but I don't know the exact status when it will be released.
Here's a very simple fix but it requires some preprocessing:
1) Create a new array which includes the (ordering) index of each name:
array[slots] of int: names_ix = [4, % John Doe
1, % Ann Jones
3, % Fred Doe
2, % Barry Doe
];
2) Change the ordering constraint to use this new array
constraint
forall (i in 1..n-1) (
names_ix[schedule[i]] <= names_ix[schedule[i+1]]
);
[There's a more complex variant that requires that you convert each character in the names to integers (in a matrix of "var int"), and then require that the words - as collection of integers - are ordered. Note that this tends to be quite messy, for example to handle strings of different lengths etc.]

Related

Minizinc: declare explicit set in decision variable

I'm trying to implement the 'Sport Scheduling Problem' (with a Round-Robin approach to break symmetries). The actual problem is of no importance. I simply want to declare the value at x[1,1] to be the set {1,2} and base the sets in the same column upon the first set. This is modelled as in the code below. The output is included in a screenshot below it. The problem is that the first set is not printed as a set but rather some sort of range while the values at x[2,1] and x[3,1] are indeed printed as sets and x[4,1] again as a range. Why is this? I assume that in the declaration of x that set of 1..n is treated as an integer but if it is not, how to declare it as integers?
EDIT: ONLY the first column of the output is of importance.
int: n = 8;
int: nw = n-1;
int: np = n div 2;
array[1..np, 1..nw] of var set of 1..n: x;
% BEGIN FIX FIRST WEEK $
constraint(
x[1,1] = {1, 2}
);
constraint(
forall(t in 2..np) (x[t,1] = {t+1, n+2-t} )
);
solve satisfy;
output[
"\(x[p,w])" ++ if w == nw then "\n" else "\t" endif | p in 1..np, w in 1..nw
]
Backend solver: Gecode
(Here's a summarize of my comments above.)
The range syntax is simply a shorthand for contiguous values in a set: 1..8 is a shorthand of the set {1,2,3,4,5,6,7,8}, and 5..6 is a shorthand for the set {5,6}.
The reason for this shorthand is probably since it's often - and arguably - easier to read the shorthand version than the full list, especially if it's a long list of integers, e.g. 1..1024. It also save space in the output of solutions.
For the two set versions, e.g. {1,2}, this explicit enumeration might be clearer to read than 1..2, though I tend to prefer the shorthand version in all cases.

find in range of a IDL array?

I am trying to find all indices in an array A, where the value larger than time0 and less than time1. In matlab I can do:
[M,F] = mode( A((A>=time0) & (A<=time1)) ) %//only interested in range
I have something similar in IDL but really slow:
tmpindex0 = where(A ge time0)
tmpindex1 = where(A lt time1)
M = setintersection(tmpindex0,tmpindex1)
where setintersection() is function find the intersected elements between two arrays. What is the fast alternative implementation?
You can combine your conditions:
M = where(A ge time0 and A lt time1, count)
Then M will contain indices into time0 and time1 while count will contain the number of indices. Generally, you want to check count before using M.
This works (slight modification from mgalloy answer):
M = where( (A ge time0) and (A lt time1), n_match, complement=F, n_complement=ncomp)
The parenthetical separation is not necessary but adds clarity. n_match contains the number of matches to your conditions whereas the complement F will contain the indices for the non-matches and ncomp will contain the number of non-matches.

Confused by the `m..n` notation in MiniZinc

I have seen the "dot-dot" notation (..) in different places. In the following example, 0..n tells us the domain of the decision variable (which in this case, are the entries of the array s).
int: n;
array[0..n-1] of var 0..n: s;
Another example would be in the for-loop:
constraint forall(i in 0..sequence_length)(
t[i] = sum(k in 0..sequence_length)((bool2int(t[k] == i)))
);
In fact, we can even do something like
par var 1..5: x
My feeling is that the expression m..n is generally used when we define a variable (instead of a parameter), and we want to specify the domain of the variable. But in the second case, we are not defining any variable. So when do we use m..n? What is it exactly (e.g. does it have a type?)?
m..n denotes the set of (consecutive) integers from m to n. It could also be written explicitly as {m,m+1,m+2,...,n-1,n}.
Using a set as the domain, e.g.
var 0..5: x;
could be written as
var {0,1,2,3,4,5}: x;
or (which is probably a weird style):
var {1,5,2,3,0,4}: x;
but both represents the set 0..5.
When using m..n in a forall(i in m..n) ( .... ) loop it means that i is assigned from m to n.
A set is always ordered as this little model shows:
solve satisfy;
constraint
forall(i in {0,4,3,1,2,5}) (
trace("i: \(i)\n")
)
;
The trace function prints the following, i.e. ordered:
i: 0
i: 1
i: 2
i: 3
i: 4
i: 5

Matlab; Structure field name with valuable ( = number)

I am trying to assign valuable, which is number and given by for loop, to the name of structure field. For example, I would like to do as following,
A.bx, where A is name of structure(= char), b is part of field name ( = char) and x is valuable given by for loop. A and b is fixed or predefined.
Any comment is appreciated !
genvarname(str,list) generates a valid variable name in str [a string] in which at each iteration value in str is different from the exclusion list
And fieldname(S) returns a list of all the names of the field already in the structure S (use it to create a exclusion list)
Here is a code for what you want:
A = struct ();
for i = 1:5
A.(genvarname ('b', fieldnames (A))) = i;
end
Read about 1. genvarname(str,list) 2. fieldnames(S)
You can name you struct fields using simple sprintf
A = struct()
for ii = 1:10
fn = sprintf('b%d', ii );
A.(fn) = ii; % use the struct
end
I tend to agree with sebastian that suggested using arrays or cells over this type of field naming. In addition to cells and arrays you might find containers.Map to be very versatile and useful.

MATLAB: is fieldnames' order defined?

For the same input structure, will fieldnames always return the same cell array, even on different computers, different OS's, and different MATLAB versions? Or could it order the field names differently? E.g.:
myStructure = load myStructure;
x = fieldnames(myStructure);
% days later, diff computer, diff OS, and diff version of MATLAB...
y = fieldnames(myStructure);
x == y %?
The documentation for fieldnames does not seem to promise that the same order is returned every time. But on the other hand, the existence of orderfields seems to imply that fieldnames predictably returns an underlying, normally unchanging order.
I believe the structure fields are ordered as they created. If you save the structure into mat-file and open it later with another MATLAB, the order will be kept. You can always reorder fields with ORDERFIELDS function. You can order in many different ways (sort alphabetically, using a cell arrays, another structure or permutation vector), see the documentation for more details.
By the way, fields order does not affect structures comparison.
s1 = struct('a',0,'b',1)
s1 =
a: 0
b: 1
s2 = struct('b',1,'a',0)
s2 =
b: 1
a: 0
isequal(s1,s2)
ans =
1
s1=orderfields(s1,s2)
s1 =
b: 1
a: 0
UPDATE:
Here is the quote from the MATLAB documentation for structure data type under "Listing the Fields of a Structure" subtitle:
The fields appear in the order in which they were created.
Hope this answers your question.