MiniZinc basic problem. n Workers and n Tasks - artificial-intelligence

I am learning Minizinc for the first time and am kind of stuck on a very basic problem. It involves n workers and n tasks. I am given a 2D-profit matrix where profit[w,t] will give the profit for worker w and task t. The assignment problem's aim is to maximize the profit.
I have tried the following:
include "all_different.mzn";
include "globals.mzn";
int: n = 4;
array [1..n,1..n] of int: profit =
[| 7,1,3,4 |
8,2,5,1 |
4,3,7,2 |
3,1,6,3 |];
set of int: WORKERS = 1..n;
set of int: TASKS = 1..n;
array[WORKERS] of var TASKS: task;
constraint alldifferent(task);
constraint maximize sum(w in WORKERS) (profit[w,task[w]]);
But this does not work, because the maximize function is not set up that way, however I do not know what else to do.
Any tips/solutions?
Thanks :)

You are almost there. The problem is in the last line which should be solve, not constraint:
solve maximize sum(w in WORKERS) (profit[w,task[w]]);
The output is:
task: [4, 1, 2, 3]
----------
==========

Related

Count the number of different elements in an array

I am new to constraint programming and to Minizinc.
I have look for a solution to this not relly hard task but I found nothing.
I want to count the number of different elements that appear in an array:
This is the declaration of my array:
array[1..n,1..n] of var 1..n: countLeft;
I have try to do like this:
constraint
forall(j in 1..n) (
length(array2set([countLeft[i,j]|i in 1..stopCountLeft[j]]) )==left_vision[j]
);
But apparently my array is of type: array[int]of var opt int and is not accept by the function array2set.
Any ideas?
There might be different approaches you could take, but an approach that is similar to what you try would be to split the counting of different elements in an array into two steps:
Counting the occurrence of the values in the domain.
Counting the amount of times the occurrence is higher than zero.
We can use the global global_cardinality constraint to count the occurrences and then use a simply count constraint over its result.
include "global_cardinality_fn";
array[1..n] of var int: occurrences = global_cardinality(YOURARRAY, [i | i in 1..n]);
var int: num_diff = count(o in occurrences) (o > 0);
Note, however, that this might not be the best code for your model. For some solvers global_cardinality might not be perform well enough. Similarly if your stopCountLeft contains variables, then that means that you are creating a array of optional variables, and global_cardinality might not be defined for optional variables.
Instead we can write an implication graph instead. The idea is still the same, but instead of counting the number of a value occurring, we just use a boolean value to signal wether the value is in use.
array[1..n] of var bool: occurs;
constraint forall(i,j in 1..n) (YOURARRAY[i] = j -> occurs[j]);
var int: num_diff = count(occurs);
Note that the problem with this approach is the exponential number of implications posted in the forall loop. However, I suspect that, with implications being small, it would perform reasonably well.
In MiniZinc 2.5.0, you can do something like this:
array[int, int] of int: a =
[| 1, 1,
| 2, 3,
| 3, 4 |];
set of int: Rows = index_set_1of2(a);
set of int: Cols = index_set_2of2(a);
int: values = card({ a[r, c] | r in Rows, c in Cols });
output ["\(values) values in "] ++
[if c == 1 then "\n" else "" endif ++
"\(a[r, c]) " | r in Rows, c in Cols];

Need help optimizing this array builder

My current code has two major bottlenecks, one I can improve for sure, but this one has me stuck. It eats up roughly 50% of my run time, and only gets worse.
What should it do?
It should take an array (a walk) from Walks and break it into two new arrays, A and B. The rules look a bit odd, but I'm sure they're straightforward enough.
Each walk should have even-N non-negative integers, and a pair is simply a list of 2 lists of integers, each list also being length N.
L is N/2.
#example pair: [[1,2,5,6,-4,-1],[8,12,-3,7,4,9]]
#example walks:[[1,0,2,5,3,1]] just 1 walk in this example. Could be k many.
#L = 3
newpairs=[]
for walk in walks:
Anew = [0 for j in range(2*L)]
Bnew = [0 for j in range(2*L)]
for r in range(L):
Anew[r] = int((pair[0][r]+walk[r])/2)
Anew[r+L] = int((pair[0][r]-walk[r])/2)
Bnew[r] = int((pair[1][r]+walk[r+L])/2)
Bnew[r+L] = int((pair[1][r]-walk[r+L])/2)
newpair = [Anew,Bnew]
newpairs.append(newpair)
#output:[[[1, 1, 3, 0, 1, 1], [6, 7, -1, 1, 4, -2]]]
I realize this may be a shot in the dark, but I'm happy to answer any questions to further clarify aspects of the code. My project cannot go much further without optimizing this piece. Its blowing up run times by over 50% and will only get worse as I push bigger sets through.
Your algorithm seems simple enough and doesn't have any glaring performance mistakes. You probably won't be reducing the run time by an order of magnitude or anything like it. There are some smaller optimizations you can do, though.
1) Use list multiplication notation for initializing your Anew and Bnew lists. Replace this:
Anew = [0 for j in range(2*L)]
Bnew = [0 for j in range(2*L)]
with this:
Anew = [0]*2*L
Bnew = [0]*2*L
Benchmarking:
>>> timeit.timeit('[0 for x in range(300)]')
7.822149500000023
>>> timeit.timeit('[0]*300')
0.8999562000000196
2) Use floor division. Replace
Anew[r] = int((pair[0][r]+walk[r])/2)
and similar lines, with this:
Anew[r] = (pair[0][r]+walk[r])//2
Benchmark:
>>> timeit.timeit('[int((x+y)/2) for x in range(-5,5) for y in range(-5,5)]')
23.69675469999993
>>> timeit.timeit('[(x+y)//2 for x in range(-5,5) for y in range(-5,5)]')
11.680407500000001
Beyond that, you might want to look into using numpy as it's almost always faster than the standard library for working with lists/arrays.

Find possible solutions for a matrix with known row/column sums and maximum cell values

I am trying to find solutions to a matrix where I know the row and column sums and the maximum value a cell can have. I want to find possible solutions that are within the constraints. I've already tried various things like constructing an array of all cell values and picking picking from each cell in sequence but whatever I try I always run into the problem where I run out of values for a cell.
I also tried a recursive algorithm but that I only managed to get the first result or it failed to get any solution. I think I have to do this with a backtracking algorithm? Not sure...
Any help or pointers would be appreciated.
Row sums A, B, C, column sums X, Y, Z as well as the maximum value for each ? are known. All values are are positive integers.
C1 | C2 | C3
-----------------
R1 | ? | ? | ? | A
-----------------
R2 | ? | ? | ? | B
-----------------
R3 | ? | ? | ? | C
-----------------
X | Y | Z
If you heard about linear programming (LP) and its 'cousins' (ILP, MILP), that could be a good approach to help you solve your problem with a great efficiency.
A linear program consists in a set of variables (your matrix unknowns), constraints (maximum values, sum of rows and columns), and an objective function (here none) to minimize or maximize.
Let's call x[i][j] the values you are looking for.
With the following data:
NxM the dimensions of your matrix
max_val[i][j] the maximum value for the variable x[i][j]
row_val[i] the sum of the values on the row i
col_val[j] the sum of the values on the column j
Then a possible linear program that could solve your problem is:
// declare variables
int x[N][M] // or eventually float x[N][M]
// declare constaints
for all i in 1 .. N, j in 1 .. M, x[i][j] <= max_val[i][j]
for all i in 1 .. N, sum[j in 1 .. M](x[i][j]) == row_val[i]
for all j in 1 .. M, sum[i in 1 .. N](x[i][j]) == col_val[j]
// here the objective function is useless, but you still will need one
// for instance, let's minimize the sum of all variables (which is constant, but as I said, the objective function does not have to be useful)
minimize sum[i in 1 .. N](sum[j in 1 .. M](x[i][j]))
// you could also be more explicit about the uselessness of the objective function
// minimize 0
Solvers such as gurobi or Cplex (but there are much more of them, see here for instance) can solve this kind of problems incredibly fast, especially if your solutions do not need to be integer, but can be float (that makes the problem much, much easier). It also have the advantage to not only be faster t execute, but faster and simpler to code. They have APIs in several common programming languages to ease their use.
For example, you can reasonably expect to solve this kind of problem in less than a minute, with hundreds of thousands of variables in the integer case, millions in the real variables case.
Edit:
In response to the comment, here is a piece of code in OPL (the language Cplex and other LP solvers use) that would solve your problem. We consider a 3x3 case.
// declare your problem input
int row_val[1..3] = [7, 11, 8];
int col_val[1..3] = [14, 6, 6];
int max_val[1..3][1..3] = [[10, 10, 10], [10, 10, 10], [10, 10, 10]];
// declare your decision variables
dvar int x[1..3][1..3];
// objective function
minimize 0;
// constraints
subject to {
forall(i in 1..3, j in 1..3) x[i][j] <= max_val[i][j];
forall(i in 1..3) sum(j in 1..3) x[i][j] == row_val[i];
forall(j in 1..3) sum(i in 1..3) x[i][j] == col_val[j];
}
The concept of a LP solver is that you only describe the problem you want to solve, then the solver solves it for you. The problem must be described according to a certain set of rules. In the current case (Integer Linear Programming, or ILP), the variables must all be integers, and the constraints and objective function must be linear equalities (or inequalities) with regards to the decision variables.
The solver will then work as a black box. It will analyse the problem, and run algorithms that can solve it, with a ton of optimizations, and output the solution.
As you wrote in a comment, that you want to come up an own solution, here's some guideline:
Use a Backtrack algorithm to find a solution. Your value-space consists of 3*3=9 independent values, each of them are between 1 and maxval[i][j]. Your constraints will be the row and column sums (all of them must match)
Intitalize your space with all 1s, then increment them, until they reach the maxval. Evaluate the conditions only after each value is covered for that condition (particularly, after 3 values you can evaluate the first row, after 6 the second row, after 7 the first col, after 8 the second col, and after 9 the third row and the third col)
If you reach the 9th, with all conditions passing, you've got a solution. Otherwise try the values from 1 till maxval, if neither matches, step back. If the first value was iterated through, then there's no solution.
That's all.
More advanced backtracking:
Your moving values are only the top-left 2*2=4 values. The third column is calculated, the condition is that it must be between 1 and the maxval for that particular element.
After defining the [1][1] element, you need to calculate the [2][2] index by using the column sum, and validate its value by the row sum (or vica versa). The same processing rules apply as above: iterate through all possible values, step back if none matches, and check rules only if they can be applied.
It is a way faster method, since you have 5 bound variables (the bottom and right rows), and only 4 unbound. These are optimizations from your particular rules. A bit more complex to implement, though.
PS: 1 is used because you have positive integers. If you have non-negative integers, you need to start with 0.

MiniZinc - Array of (multidimensional) array

I would like to know if it’s possible to have array of (multidimensional) array in MiniZinc language.
Indeed, I would like to resolve a timetabling problem with workers. My goal is to check if they are available at least 1 day per week. Each worker is indexed by an integer and I have their schedule per week.
For me, an array like : [[number_of_week, weekday]] could be a solution.
For example, worker 1 who is available monday/friday in week 1 and tuesday/thursday in week 2 can be modeled by the following array : (« 1 » means that the worker is available)
[[| 1,0,0,0,1,
| 0,1,0,1,0 |],
[...], ...]
If it's possible, how to declare this kind of array ? And I’m also open to any advice on modeling this constraint.
Sorry for my imperfect English and thank you in advance,
Nicolas.
I'm not sure I understand your question fully, but you can have multi dimensional arrays as follows:
array[1..3,1..3] of int: a = array2d(1..3,1..3,
[1,0,0,
0,1,0,
1,1,0]);
or using another syntax:
array[1..3,1..3] of int: a =
[|1,0,0
|0,1,0
|1,1,0|];
However, you cannot have arrays in arrays, i.e. this is not allowed:
% This is NOT valid MiniZinc code!
array[1..3,1..3] of int: a =
[[[1,0,0],[1,0,1]],
[[0,1,0],[0,1,1]],
[[1,1,0],[0,0,0]]];
Note also that one cannot have "ragged" arrays: the number of element in each row and each column must be the same.
Regarding you specific constraint you might - if I understand your description - define a 3D array like this:
int:_num_workers = 2;
int: num_weeks = 3;
int: num_days = 4;
array[1..num_workers,1..num_weeks,1..num_days] of int: a =
array3d(1..num_workers,1..num_weeks,1..num_days,
[
% worker 1
% week1 week2 week3
1,0,0,1, 1,1,0,1, 0,0,1,1,
% worker 2
% week1 week2 week3
1,0,0,0, 0,0,0,1, 1,1,1,0
]);
Note especially the array3d construct which creates a 3D array. So you can access day d of week e for worker w with a[w,e,d].

Non-monolithic arrays in Haskell

I have accepted an answer to the question below, but It seemed I misunderstood how Arrays in haskell worked. I thought they were just beefed up lists. Keep that in mind when reading the question below.
I've found that monolithic arrays in haskell are quite inefficient when using them for larger arrays.
I haven't been able to find a non-monolithic implementation of arrays in haskell. What I need is O(1) time look up on a multidimensional array.
Is there an implementation of of arrays that supports this?
EDIT: I seem to have misunderstood the term monolithic. The problem is that it seems like the arrays in haskell treats an array like a list. I might be wrong though.
EDIT2: Short example of inefficient code:
fibArray n = a where
bnds = (0,n)
a = array bnds [ (i, f i) | i <- range bnds ]
f 0 = 0
f 1 = 1
f i = a!(i-1) + a!(i-2)
this is an array of length n+1 where the i'th field holds the i'th fibonacci number. But since arrays in haskell has O(n) time lookup, it takes O(n²) time to compute.
You're confusing linked lists in Haskell with arrays.
Linked lists are the data types that use the following syntax:
[1,2,3,5]
defined as:
data [a] = [] | a : [a]
These are classical recursive data types, supporting O(n) indexing and O(1) prepend.
If you're looking for multidimensional data with O(1) lookup, instead you should use a true array or matrix data structure. Good candidates are:
Repa - fast, parallel, multidimensional arrays -- (Tutorial)
Vector - An efficient implementation of Int-indexed arrays (both mutable and immutable), with a powerful loop optimisation framework . (Tutorial)
HMatrix - Purely functional interface to basic linear algebra and other numerical computations, internally implemented using GSL, BLAS and LAPACK.
Arrays have O(1) indexing. The problem is that each element is calculated lazily. So this is what happens when you run this in ghci:
*Main> :set +s
*Main> let t = 100000
(0.00 secs, 556576 bytes)
*Main> let a = fibArray t
Loading package array-0.4.0.0 ... linking ... done.
(0.01 secs, 1033640 bytes)
*Main> a!t -- result omitted
(1.51 secs, 570473504 bytes)
*Main> a!t -- result omitted
(0.17 secs, 17954296 bytes)
*Main>
Note that lookup is very fast, after it's already been looked up once. The array function creates an array of pointers to thunks that will eventually be calculated to produce a value. The first time you evaluate a value, you pay this cost. Here are a first few expansions of the thunk for evaluating a!t:
a!t -> a!(t-1)+a!(t-2)-> a!(t-2)+a!(t-3)+a!(t-2) -> a!(t-3)+a!(t-4)+a!(t-3)+a!(t-2)
It's not the cost of the calculations per se that's expensive, rather it's the need to create and traverse this very large thunk.
I tried strictifying the values in the list passed to array, but that seemed to result in an endless loop.
One common way around this is to use a mutable array, such as an STArray. The elements can be updated as they're available during the array creation, and the end result is frozen and returned. In the vector package, the create and constructN functions provide easy ways to do this.
-- constructN :: Unbox a => Int -> (Vector a -> a) -> Vector a
import qualified Data.Vector.Unboxed as V
import Data.Int
fibVec :: Int -> V.Vector Int64
fibVec n = V.constructN (n+1) c
where
c v | V.length v == 0 = 0
c v | V.length v == 1 = 1
c v | V.length v == 2 = 1
c v = let len = V.length v
in v V.! (len-1) + v V.! (len-2)
BUT, the fibVec function only works with unboxed vectors. Regular vectors (and arrays) aren't strict enough, leading back to the same problem you've already found. And unfortunately there isn't an Unboxed instance for Integer, so if you need unbounded integer types (this fibVec has already overflowed in this test) you're stuck with creating a mutable array in IO or ST to enable the necessary strictness.
Referring specifically to your fibArray example, try this and see if it speeds things up a bit:
-- gradually calculate m-th item in steps of k
-- to prevent STACK OVERFLOW , etc
gradualth m k arr
| m <= v = pre `seq` arr!m
where
pre = foldl1 (\a b-> a `seq` arr!b) [u,u+k..m]
(u,v) = bounds arr
For me, for let a=fibArray 50000, gradualth 50000 10 aran at 0.65 run time of just calling a!50000 right away.

Resources