MiniZinc: type error: expected `array[int] of int', actual `array[int] of var opt int - minizinc

I am trying to write a predicate that performs the same operation as circuit, but ignores zeros in the array, and I keep getting the following error:
MiniZinc: type error: initialisation value for 'x_without_0' has invalid type-inst: expected 'array[int] of int', actual 'array[int] of var opt int'
in the code:
% [0,5,2,0,7,0,3,0] -> true
% [0,5,2,0,4,0,3,0] -> false (no circuit)
% [0,5,2,0,3,0,8,7] -> false (two circuits)
predicate circuit_ignoring_0(array[int] of var int: x) =
let {
array[int] of int: x_without_0 = [x[i] | i in 1..length(x) where x[i] != 0],
int: lbx = min(x_without_0),
int: ubx = max(x_without_0),
int: len = length(x_without_0),
array[1..len] of var lbx..ubx: order
} in
alldifferent(x_without_0) /\
alldifferent(order) /\
order[1] = x_without_0[1] /\
forall(i in 2..len) (
order[i] = x_without_0[order[i-1]]
)
/\ % last value is the minimum (symmetry breaking)
order[ubx] = lbx
;
I am using MiniZinc v2.0.11
Edit
Per Kobbe's suggestion that it was an issue with having a variable length array, I used "the usual workaround" of keeping the order array the same size as the original array x, and using a parameter, nnonzeros, to keep track of the part of the array I care about:
set of int: S = index_set(x),
int: u = max(S),
var int: nnonzeros = among(x, S),
array[S] of var 0..u: order

This kind of answers your question:
The problem you are experiencing is that your array size is dependent on a var. This means that MiniZinc can not really know the size of the array is should create and the opt type is used. I would suggest that you stay away from the opt type if you do not know how to handle it.
Generally the solution is to make some workaround where your arrays are not dependent of the size of an var. My solution is most often to pad the array, i.e [2,0,5,0,8] -> [2,2,5,5,8], if the application allows it, or
var int : a;
[i * bool2int(i == a) in 1..5]
if you are okay with zeroes in your answer (I guess not in this case).
Furthermore, the alldifferent_except_0 could be in interest for you, or at least you can look how alldifferent_except_0 solves the problem with zeroes in the answer.
predicate alldifferent_except_0(array [int] of var int: vs) =
forall ( i, j in index_set(vs) where i < j ) (
vs[i]!=0 /\ vs[j]!=0 -> vs[i]!=vs[j]
)
from MiniZinc documentation

Related

Hash function for custom type

I'm trying to define a custom equality method for a new type I've constructed. This is a MWE getting at what I'm trying to do.
mutable struct a
first_num::Int
second_num::Int
end
import Base.==
import Base.hash
function hash(obj::a, h=33141651)
return hash((obj.first_num, obj.second_num), h)
end
function ==(obj1::a, obj2::a)
if hash(obj1) == hash(obj2)
return true
else
return false
end
end
a1 = a(2,3)
a2 = a(2,3)
a1 == a2
I then get an error like ERROR: TypeError: ==: in typeassert, expected UInt64, got Int64
Is h becoming Int64?
In addition, if hashing the tuple of attributes is simply not the correct way to do this, let me know.
Edit: Actually, I ran this and I'm getting MethodError: no method matching hash(::Tuple{Int64,Int64}, ::Int64). Is h being promoted to Int64?
The problem is that your literal value for h (33141651) is an Int rather than a UInt. Thus, when you call hash with the tuple h is an Int, but the internal tuple hash function expects a UInt. I don't think you have to specify a value for h at all, and something like this should be enough:
function Base.hash(obj::a, h::UInt)
return hash((obj.first_num, obj.second_num), h)
end
Full example for completeness:
mutable struct A
first::Int
second::Int
end
function Base.hash(obj::A, h::UInt)
return hash((obj.first, obj.second), h)
end
function Base.:(==)(obj1::A, obj2::A)
return hash(obj1) == hash(obj2)
end
With the following behaviour
julia> a = A(2,3); b = A(2,3)
A(2, 3)
julia> hash(a)
0x965b43497b212144
julia> hash(b)
0x965b43497b212144
julia> a == b
true

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

Minizinc constraints from another array

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

Ocaml error with if statement

I have a list of lists, eg [[1;2;3];[2];[3;4;5;6]; [7;8;9;10]
I want to place these in a Hashtbl where the key is the length of the list and the value is list of lists, which contains all sublists of the given length.
So for the example above the hash will look like as follows
Key Value
1 [[2]]
3 [[1;2;3]]
4 [[3;4;5;6];[7;8;9;10]]
In addition I am also trying to keep track of the length of the longest list and that number is what is returned by the function
The code that does this is as follows.
let hashify lst =
let hash = Hashtbl.create 123456 in
let rec collector curmax lst =
match lst with
[] -> curmax
| h::t -> let len = (List.length h) in
(if ((Hashtbl.mem hash len)=true)
then ( let v = (Hashtbl.find hash len) in Hashtbl.add hash len v#[h] ) (* Line 660 *)
else ( Hashtbl.add hash len [h]));
(collector (max len curmax) t)
in
collector 0 lst
;;
Now when I do this I get the following error for the code above
File "all_code.ml", line 600, characters 50-72:
Error: This expression has type unit but an expression was expected of type
'a list
Why does Ocaml require a return type of 'a list and how do I fix this.
Thanks in advance
Puneet
You probably should add parenthesis in (v#[h]) to avoid have it parsed as (Hashtbl.add hash len v)#[h]
And you probably should not pass 123456 to Hashtbl.create but a reasonable prime number like 307 or 2017
You are almost there: # has a lower priority than apply, and thus, as Basil said, Hashtbl.add hash len v#[h] is parsed as (Hashtbl.add hash len v)#[h]. Moreover, you are using way too much parenthesis and if ((Hashtbl.mem hash len)=true) is unnecessary verbose. So a possible good way to write your function is:
let hashify lst =
let hash = Hashtbl.create 307 in
let rec collector curmax = function
| [] -> curmax
| h::t ->
let len = List.length h in
if Hashtbl.mem hash len then
let v = Hashtbl.find hash len in
Hashtbl.add hash len (v#[h])
else
Hashtbl.add hash len [h];
collector (max len curmax) t in
collector 0 lst
Most heavy work on hash tables in OCaml hugely benefits from an update primitive. There are actually two versions, which do different things depending on whether the value exists in the table. This is the one you wish to use:
(* Binds a value to the key if none is already present, and then updates
it by applying the provided map function and returns the new value. *)
let update hashtbl key default func =
let value = try Hashtbl.find hashtbl key with Not_found -> default in
let value' = func value in
Hashtbl.remove hashtbl key ; Hashtbl.add hashtbl key value' ; value'
With these primitives, it becomes simple to manage a hashtable-of-lists:
let prepend hashtbl key item =
update hashtbl key [] (fun list -> item :: list)
From there, traversing a list and appending everything to a hashtable is quite simple:
let hashify lst =
let hash = Hashtbl.create 607 in
List.fold_left (fun acc list ->
let l = List.length list in
let _ = prepend hash l list in
max acc l
) 0 lst