MiniZinc Constraint: set of variables = set of associated domains - constraints

I'm very new to MiniZinc and trying to model what I feel should be a simple constraint however I'm really struggling to understand syntax & looking at various documentation left me more confused.
Basically I want to constrain specific sets of variables to specific sets of their associated domains, which in my case is just 0..1. Here's a non-working example of what I want to achieve:
set of int: DOMAIN = 0..1;
var DOMAIN: x11;
var DOMAIN: x12;
var DOMAIN: x13;
var DOMAIN: x21;
var DOMAIN: x22;
var DOMAIN: x23;
% obviously these constraint don't work but this is the gist is what i'm going for
constraint [x11, x12, x13] = [1, 0, 1] \/ [1, 0, 0] \/ [0, 1, 0];
constraint [x11, x21] = [1,0] \/ [1,1];
% ... etc (ultimately every variable will appear in 2 constraints and this situation
% represents a grid of 1's and 0's)
(Then I just want to use solve satisfy; to simply assign variables to 0..1 such that all constraints are satisfied)
I apologise for the sloppy explanation but as you can tell I'm clearly very new to this. If anyone could help me formulate these constraints I'd greatly appreciate - I presume I've vastly oversimplified the syntax, not sure if table constraints would be involved?

As #sascha said, using a table constraint is probably the best option when there are many selections. Your constraints could be written as:
constraint table([x11, x12, x13], [|
1,0,1 |
1,0,0 |
0,1,0 |
|]);
constraint table([x11, x21], [|
1,0 |
1,1 |
|]);
If there are many (small) (Boolean) table constraints, then it might for some solvers be more efficient to use Boolean clauses directly. The syntax for this is actually very similar to your non-working example:
constraint [x11, x12, x13] = [1, 0, 1] \/ [x11, x12, x13] = [1, 0, 0] \/ [x11, x12, x13] = [0, 1, 0];
constraint [x11, x21] = [1,0] \/ [x11, x21] = [1,1];

Related

Need review of scheduling model logic, suggestions for constraint creation and fixes for syntax errors

I am creating a scheduling model for a blending facility in Mini Zinc. I have asked a similar question earlier but I have since progressed. I will summarize what I think my existing model should do, it would be super helpful if someone could correct any logical or syntax errors I have made. The model currently errors, with several instances of "expecting end of file". It seems way to simplistic in comparison to several other sequence dependent scheduling models I have found. Below you will find the model code commented with my understanding of each line.
Besides an overview of the logic and syntax, I am looking for help with the "missing constraint" in this model, which needs to require that the array of blends [y] contain no more than the declared integer quantity of each blend.
Notable future goals for this model include automatic generation of the blendcost matrix, output the schedule array given a starting day into a 5 column matrix representing weekdays, and showing the blend name as opposed to blend number.
enum Blends = { A, B, C, D, E, F};
%Establish names for each blend and link them to their order number.
int: nb = count([Blends])
%Count the number of blends, plan to use later.
int: qA; %Error: syntax error, unexpected int, expecting end of file
int: qB;
int: qC;
int: qD;
int: qE;
int: qF;
int: sb;
%Call for inputs of the quantity of each of the blends needed, as well as the number/letter of the blend currently in the machine.
int: mc = qA + qB + qC + qD + qE + qF;
%Sum the blend quantities to determine total number of blends
[Blendcost] : [|1,2,2,2,2,2,|1,1,1,1,1,1,|1,1,1,1,1,1,|2,2,2,1,2,2,|1,1,1,1,1,1,|1,1,1,1,1,1,|]; %Error: syntax error, unexpected [|, expecting identifier
%Establishes a blend cost matrix, 6X6 depicting the transition costs from any blend A-F to any other blend A-F
array [Blends] of int: 1..6;
%Is this line needed to establish the link between A/1, B/2, C/3 etc;? Or is that taken care of when Blends is enumerated?
array [0..mc] of var 1..6: y;
%Create an array from 0 to the number of blends with potential values from 1-6, corresponding to the blend numbers.
%Missing constraint: [y] can contain no more than the quantity of each blend declared above, except for the blend declared in the starting blend, which will be allowed that blend quantity + 1
constraint y(0) = sb
%y(0) is set equal to the starting blend Letter/Number Defined earlier, used to determine the first transitionary cost.
array [1..mc] of int: x(i); %Error: syntax error, unexpected array, expecting end of file
%Create an array from 1 to number of blends, which will be filled with the transition costs in response to variations in y
constraint forall(i in x)(x(i) = Blendcost(y(i-1),y(i)))
%For each space in x, x will equal the blend cost value obtained from the previous blend in the y array vs the next blend in the y array
solve minimize sum (x); %Error: syntax error, unexpected solve, expecting end of file
%Solves this model attempting to minimize the sum of the x array, which should be filled with the transition costs.
show(y):
%Print the final array of blend numbers that has minimized blend cost transition.
%Error: unexpected end of file, expecting identifier.
Here is a basic version of your CP-model that runs (assuming some demand q):
enum BLEND = { A, B, C, D, E, F};
array[BLEND] of int: q = [1, 2, 4, 6, 8, 1];
array[BLEND, BLEND] of int: Blendcost =
[|1,2,2,2,2,2|1,1,1,1,1,1|1,1,1,1,1,1|2,2,2,1,2,2|1,1,1,1,1,1|1,1,1,1,1,1|];
int: mc = sum(q);
array[1..mc] of var BLEND: y;
include "global_cardinality.mzn";
constraint global_cardinality(y, BLEND, q);
var int: obj = sum(p in 1..mc-1)(Blendcost[y[p],y[p+1]]) + 1;
array[int] of var opt BLEND: day = [y[p] | p in 1..mc-1, q in 1..max(Blendcost) where q <= Blendcost[y[p],y[p+1]]] ++ [y[mc]];
array[int] of var opt int: wash = [bool2int(q > 1) | p in 1..mc-1, q in 1..max(Blendcost) where q <= Blendcost[y[p],y[p+1]]] ++ [0];
solve minimize obj;
output ["obj=\(obj)\n"] ++
["day=\n"] ++ [
show(day[d]) ++ if fix(wash[d]) > 0 then "W" else "" endif ++ " " ++
if d mod 5 = 0 then "\n" else "" endif | d in 1..length(day)
] ++ ["\nmc=\(mc)\n"] ++ ["y=\(y)\n"] ++ ["wash=\(wash)\n"]
Have a look at https://www.minizinc.org/doc-2.2.3/en/lib-globals.html#counting-constraints for alternative versions of the counting constraint.
For larger instances a MIP-model might show better performance.

Schedule minizinc no overlapping

I want to do a schedule with no overlapping only 1 teacher can be booked at 1 timeslot. I want to create a 2darray like teachers a rows and timeslot is coloumns.
The general constraints to use for these kind of constraints ("something should be distinct") are the two global constraints all_different or alldifferent_except_0.
Note: I changed to 3 teachers, 3 timeslots, and 5 presentations to make a more general point of using alldifferent_except_0, since there can be assignments where there are no teacher/timeslot for a presentation.
Also, I'm not sure I would use the specific representation as you did, since it the representation depends on further constraints (if any) in the model.
Here are some approaches that might be useful.
1) Simple model with just a "timetable" matrix
If you only want to assign T teachers, TS timeslots, and P presentations with no further constraints, then a single constraint "all_different_except_0" on a timetable matrix will suffice (together with a sum explained below). The dimension of "timetable" is T x TS (Teachers x Timeslots) where we assign the presentation, or 0 if there is no presentation for this teacher and timeslot.
include "globals.mzn";
set of int: Timeslots = 1..3;
set of int: Teachers = 1..3;
set of int: Presentations = 1..5;
solve satisfy;
% Decision variables
array[Teachers, Timeslots] of var {0} union Presentations: timetable;
constraint
alldifferent_except_0(array1d(timetable))
% ensure that there are 5 assigned presentations
/\ sum([timetable[t,ts]>0 | t in Teachers, ts in Presentations]) = card(Presentations)
;
% output [....];
The drawback of this model is that it's not easy to state further constraints that might be needed, and also that we have to count the number of non-0 assignments in the "timetable" matrix to ensure that there are exactly 5 presentations assigned.
So we will expand with more decision variables.
2) Adding decision variables
This model connects the original presentation with the "timetable" matrix and its constraint shown above. This means that we can keep the constraint on "timetable" to ensure unicity and we can work with constraint on the other decision variables as well. Here's a model with the two original arrays "presentation_teacher" and "presentation_time" and their constraints.
include "globals.mzn";
set of int: Timeslots = 1..3;
set of int: Teachers = 1..3;
set of int: Presentations = 1..5;
% Decision variables
% Which teacher has this presentation
array[Presentations] of var Teachers: presentation_teacher;
% Which timeslot for this presentation
array[Presentations] of var Timeslots: presentation_time;
% Which combination of teacher and timeslot for a presentation, if any
array[Teachers, Timeslots] of var {0} union Presentations: timetable;
solve satisfy;
constraint
alldifferent_except_0(array1d(timetable))
% This constraint is not needed now
% /\ sum([timetable[t,ts]>0 | t in Teachers, ts in Presentations]) = card(Presentations)
/\ % connect timetable and presentation_teacher and presentation_time
forall(p in Presentations) (
timetable[presentation_teacher[p],presentation_time[p]] = p
)
;
The constraint "forall(p in Presentations) ( ... ) " connects the two representations: the "timetable" representation and the two added arrays.
3) Alternative version
An alternative version of ensuring distinct timeslots and presentations for the teachers is to add constraints on the "presentation_teacher", "presentation_time". This don't really need a timetable matrix so it's skipped here. (One can add these constraints with the timetable approach might be faster.)
include "globals.mzn";
set of int: Timeslots = 1..3;
set of int: Teachers = 1..3;
set of int: Presentations = 1..5;
% Decision variables
% Which teacher has this presentation
array[Presentations] of var Teachers: presentation_teacher;
% Which timeslot for this presentation
array[Presentations] of var Timeslots: presentation_time;
solve satisfy;
constraint
% variant A
forall(t in Teachers) (
% the time for this teacher is distinct (or 0)
alldifferent_except_0([presentation_time[p] * (presentation_teacher[p]=t) | p in Presentations])
)
/\
% variant B
forall(t in Teachers) (
% combination of (time + teacher) for this teacher is unique
alldifferent([presentation_time[p]+(presentation_teacher[p]*card(Presentations)) | p in Presentations])
)
;
This model has two variants, where the first ("A") use alldifferent_except_0 to ensure that the presentations for each teacher are distinct.
For each teacher it loops through all the presentations ("p") and picks those time assigned for "this" teacher and ensures that they are distinct.
The second variant ("B") is kind of a hack, though quite useful sometimes: It builds an list of integers for which the teacher is assigned ( time + teacher_id * number of presentations) and ensure that these are distinct.
Since this model don't have an explicit timetable one have to extract the timetable in the output. Here is one way:
output [
"Teacher " ++ show(t) ++ " has these presentations" ++ show([p | p in Presentations where fix(presentation_teacher[p]) = t]) ++ "\n"
| t in Teachers
]
;
As mentioned above, the representation of the model (which decision variables to select) depends much on what one want to do further.

Prolog: Multiplying 2 lists with 1 of them not instantiated?

I am trying to write a rule that can return the sum of the product of each element from two lists (same length).
Here is what I have right now:
sum(0, _, []).
sum(Result, [H1|T1], [H2|T2]) :-
sum(Remaining,T1, T2),
Remaining is Result - (H1*H2).
It won't work when one of the list is not instantiated. What changes I need to make in order to make the following possible?
sum([1,2],X,3).
X = [3,0].
Thanks.
What you are calculating is commonly referred to as a dot product (also known as scalar product or inner product).
You write you are not allowed to use libraries. That surely refers to external libraries---not to the standard library that is part of SWI Prolog, right?
The following predicate list_list_dotProduct/3 roughly corresponds to the code you implemented. It uses finite domain constraints (#>=)/2 and (#=)/2 to allow for non-unidirectional integer arithmetic:
:- use_module(library(clpfd)).
list_list_dotProduct([],[],0).
list_list_dotProduct([X|Xs],[Y|Ys],Sum) :-
X #>= 0,
Y #>= 0,
Sum #= X*Y + Sum0,
list_list_dotProduct(Xs,Ys,Sum0).
Consider the following query:
?- list_list_dotProduct([1,2],Xs,3), label(Xs).
Xs = [1, 1] ;
Xs = [3, 0].
As an added bonus, here's an alternative implementation that is based on the predefined predicates same_length/2, ins/2, and scalar_product/4:
list_list_dotProduct(Xs,Ys,Prod) :-
same_length(Xs,Ys),
Xs ins 0..sup,
Ys ins 0..sup,
scalar_product(Xs,Ys,#=,Prod).

Random tree with specific branching factor in Mathematica

Do you know if it's possible to somehow generate a random tree graph with a specific branching factor? I don't want it to be a k-ary tree.
It would be also great if I could define both the branching factor and the maximum depth. I want to randomly generate a bunch of trees that would differ in branching factor and depth.
TreePlot with random integer input returns something that's almost what I want:
TreePlot[RandomInteger[#] -> # + 1 & /# Range[0, 100]]
but I can't figure out a way to get a tree with a specific branching factor.
Thanks!
I guess I'm a bit late, but I like the question. Instead of creating a tree in the form
{0 -> 1, 0 -> 5, 1 -> 2, 1 -> 3, 1 -> 4}
I will use the following form of nested calls, where every argument is a child, which represents another node
0[1[2, 3, 4], 5]
Both forms are equivalent and can be transformed into each other.
Row[{
TreeForm[0[1[2, 3, 4], 5]],
TreePlot[{0 -> 1, 0 -> 5, 1 -> 2, 1 -> 3, 1 -> 4}]
}]
Here is how the algorithm works: As arguments we need a function f which gives a random number of children and is called when we create a node. Additionally, we have a depth d which defines the maximum depth a (sub-)tree can have.
[Choose branching] Define a branching function f which can be called like f[] and returns a random number of children. If you want a tree with either 2 or 4 children, you could use e.g. f[] := RandomChoice[{2, 4}]. This function will be called for each created node in the tree.
[Choose tree-depth] Choose a maximum depth d of the tree. At this point, I'm not sure what you want the randomness to be incorporated into the generation of the tree. What I do here is that when a new node is created, the depth of the tree below it is randomly chosen between the depth of its parent minus one and zero.
[Create ID Counter] Create a unique counter variable count and set it to zero. This will give us increasing node ID's. When creating a new node, it is increased by 1.
[Create a node] Increase count and use it as node-ID. If the current depth d is zero, give back a leaf with ID count, otherwise call f to decide how many children the node should get. For every new child chose randomly the depth of its sub-tree which can be 0,...,d-1 and call 4. for each new child. When all recursive calls have returned, the tree is built.
Fortunately, in Mathematica-code this procedure is not so verbose and consists only of a few lines. I hope you can find in the code what I have described above
With[{counter = Unique[]},
generateTree[f_, d_] := (counter = 0; builder[f, d]);
builder[f_, d_] := Block[
{nodeID = counter++, childs = builder[f, #] & /# RandomInteger[d - 1, f[]]},
nodeID ## childs
];
builder[f_, 0] := (counter++);
]
Now you can create a random tree like follows
branching[] := RandomChoice[{2, 4}];
t = generateTree[branching, 6];
TreeForm[t]
Or if you like you can use the next function to convert the tree into what is accepted by TreePlot
transformTree[tree_] := Module[{transform},
transform[(n_Integer)[childs__]] := (Sow[
n -> # & /# ({childs} /. h_Integer[__] :> h)];
transform /# {childs});
Flatten#Last#Reap[transform[tree]
]
and use it to create many random trees
trees = Table[generateTree[branching, depth], {depth, 3, 7}, {5}];
GraphicsGrid[Map[TreePlot[transformTree[#]] &, trees, {2}]]

Mathematica Index Equation (basic algebra)

I am currently working on a Mathematica project to calculate Riemann's sums and put them in a table. I am having trouble printing the row numbers (intervals). (The row numbers are also parameters to the secondary functions). I don't know of any way to just access the index of the iterator in a Mathematica Table, so I am trying to compute them using the function parameters.
Here is an example of what I'd like to print, for the integral of x^2 over the range {0, 1}, with 10 subdivisions.
tableRiemannSums[#^2 &, {0, 1}, 10]
I need to figure out what the index of each iteration is, based on the value of the current
subdivision k, the range of the integral {a, b}, and the number of subdivisions, n. Below is the main piece of code.
tableRiemannSums[fct_, {a_, b_}, n_] := Table[{'insert index here',
leftRiemannSum[fct, {a, b}, 'insert index here'],
rightRiemannSum[fct, {a, b}, 'insert index here']},
{k, a, b - (N[b - a]/n), N[b - a]/n}]
In the above equation, the line
{k, a, b - (N[b - a]/n), N[b - a]/n}]
means the range of the table is k as k goes from 'a' to 'b - ((b - a)/n)' in steps of size '(b - a)/n'.
In each of the places where my code says 'insert index here,' I need to put the same equation. Right now, I am using 'n * k + 1' to calculate the index, which is working for positive ranges, but breaks when I have a range like {a,b} = {-1, 1}.
I think this is a fairly straightforward algebra problem, but I have been racking my brain for hours and can't find a general equation.
(I apologize if this is a duplicate question - I tried searching through the Stack overflow archives, but had a hard time summarizing my question into a few key words.)
I finally figured out how to solve this. I was over thinking the range, rather than relying on the inner functions to control it. I rewrote the function as:
tableRiemannSums[fct_, {a_, b_}, n_] := Table[{k,
leftRiemannSum[fct, {a, b}, k],
rightRiemannSum[fct, {a, b}, k]},
{k, 1, n}}]
For reference, here are the left and right sums (for anyone interested!):
leftRiemannSum[fct_, {a_, b_}, n_] :=
N[b - a]/n* Apply[Plus, Map[fct, Range[a, b - N[b - a] / n, N[b - a]/n]]]
rightRiemannSum[fct_, {a_, b_}, n_] :=
N[b - a]/n* Apply[Plus, Map[fct, Range[a + (N[b - a]/n), b, N[b - a]/n]]]
What you may want to consider is creating a function to make each line of the table. One argument to this function would be the row number.
Execute this function using MapIndexed, which will provide you a way to traverse your range as required while providing an incrementing row number.
(Create a list with the range of values, then apply your MapIndexed function to this list.)

Resources