Difference between similar MiniZinc constraints - minizinc

In the solution of the Zebra puzzle (http://rosettacode.org/wiki/Zebra_puzzle#MiniZinc) there's a constraint stating that one of the pets must be a zebra:
var 1..5: n;
constraint Gz[n]=Zebra;
Has the expression below a different meaning? They yield different results.
constraint exists(n in 1..5)(Gz[n]=Zebra);

These constraints are indeed equivalent. There is however a different in the way MiniZinc will translate these constraint for the solver.
The first option will be translated as a element constraint:
var 1..5: n;
constraint array_int_element(n, Gz, Zebra);
While the second one will result in an big clause constraint:
constraint bool_clause([Gz[1]=Zebra, Gz[2]=Zebra, Gz[3]=Zebra, Gz[3]=Zebra, Gz[5]=Zebra], [])
Although the constraints are equivalent it might depend on the solver which form will be more efficient during solving.
A better approach is to use the global count_leq(array [int] of var int: x, int: y, int: c) which enforces c to be less or equal to the number of occurences of y in x. Expressing the constraint as:
include "count_leq.mzn";
constraint count_leq(Gz, Zebra, 1);
directly conveys the meaning of the constraint and allows the solver used to use whichever form of the constraint would be best suited for its solving mechanism

If the declaration var 1..5: n is removed, then there is no global n that can be used in the output section, and this will yield an error: MiniZinc: type error: undefined identifier n'`.
It you keep var 1..5: n then the variable n in the exists loop don't have any effect of the global defined variable n, with the result that (the global) n will take any of the values 1..5 (which is shown if all solutions are printed).

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.

Conditional output minizinc

I'm messing arround with minizinc and I'm trying to achieve a conditional output where, if an array element has value 'true', the program outputs information concerning these element's array indexes. This is what I have:
include "globals.mzn";
int: time=5;
int: n=3;
int: l=n*n;
array[1..4,0..time,1..l] of var bool: X;
constraint X[1,5,7]=true;
constraint X[2,5,3]=true;
constraint X[3,5,9]=true;
constraint X[4,5,7]=true;
solve satisfy;
I attempted to solve this problem using concat, like so:
output ["X_"++concat(["\(r)_\(t)_\(pos)"
| pos in 1..l, r in 1..4, t in 0..time, where X[r,t,pos]==true])++"\n"];
However I am not allowed,
"MiniZinc: type error: no function or predicate with this signature found: `concat(array[int] of var opt string)'"
What I want is something like,
for pos in 1..l, r in 1..4, t in 0..time
if X[r,t,pos]==true
output ["X_\(r)_\(pos)_\(t)"]
How can I achieve it?
Try using fix(...) around the decision variable in the where clause, e.g.
output ["X_"++concat(["\(r)_\(t)_\(pos)"
| pos in 1..l, r in 1..4, t in 0..time, where fix(X[r,t,pos])==true])++"\n"];
fix is (often) needed when one use the actual values of decision variables, e.g. for comparing its values etc.
(The message about var opt string is perhaps misleading in this context.)

Initialize only certain elements of array in dzn file

I'm messing arround with minizinc and I want to have a static mzn file where I make the solving using only the dzn.
For a better understanding of the question, here's a sample:
include "globals.mzn";
include "data.dzn";
int: time;
int: n;
int: l=n*n;
array[1..4,0..time,1..l] of var bool: X;
solve satisfy;
I now want to initialize only few elements of X using the dzn file (the other elements should be vars).
The dzn would look like this
time=1;
n=3;
X[4,1,7]=true;
Since this initialization is impossible, I also tried using X=array3d(1..4,0..time,1..l,[false,...,false] where every element other than the element in position (4,1,7) is false. However this initializes every element and I cannot obtain the result I wish since it cannot satisfy the constraints I have.
Is there a way to initialize only one or some elements of this array using the dzn file?
One way to do this is to use the anonymous variable (_) in the data matrix in the dzn file. Here is a simple example:
% mzn file
include "data.dzn";
int: time;
int: n;
array[1..time,1..n] of var bool: X;
solve satisfy;
And the data file:
% data.dzn
time=3;
n=2;
X = array2d(1..3,1..2,
[_,_,
_,_,
_,false
]);
Note that this approach requires at least one non-anonymous value, otherwise this message is thrown: array literal must contain at least one non-anonymous variable.

MiniZinc: how to sum equal-length subarrays?

The problem I encountered is how to add variables in a[0..9] to b[10..19].
My code is:
array[0..19] of int: a=array1d(0..19,[0,1,2,3,4,5,6,7,8,9,9,8,7,6,5,4,3,2,1,0]);
array[0..19] of int: b=array1d(0..19,[9,8,7,6,5,4,3,2,1,0,0,1,2,3,4,5,6,7,8,9]);
array[0..9] of var int: c;
constraint
forall(i in 0..9, j in 10..19)
(
c[i]=a[i]+b[j]
);
solve satisfy;
output[show(c[i]) | i in 0..9];
However, MiniZinc gives me the warning "model inconsistency detected, in call 'forall' in array comprehension expressionwith i = 0 with j = 11" and outputs "=====UNSATISFIABLE=====".
How do I get this to work?
(Extracts the answer from my comments.)
Your forall loop tries to assign c[i] many times with different values, which is not allowed. In MiniZinc, unlike traditional programming languages, a decision variables cannot be reassigned.
I guess that you mean addition in a parallel loop:
constraint
forall(i in 0..9) ( c[i]=a[i]+b[i+10])
;

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