Hope someone can help me with this!
The original problem is to generate valid shifts like explained below:
I have arrays like this [m,m,m,o,o,l,l,m,m,m,l,m,m,m] with a fixed length (S) where m is work, o is office and l free. What I need to make sure is that at least every 6m I have two l together (ll). The o does not count as work or as free. Examples:
mmlmmlmmmll is not valid (7 ms without two ls)
mmlmmlmmll is valid
mmomomommll is valid
What I was trying is to create an array with 0 (for ls) and 1 (for ms) but removing from the array all the o and the non consecutive ls. So, for the above examples would be:
mmlmmlmmmll -> 111111100
mmlmmlmmll -> 11111100
mmomomommll -> 11111100
This way I could use a sliding_sum or at_least constraint to solve it. However, I cannot manage to create this new array as it would have a different size than the original (S). A valid option is to pad at the end with 0 the remaining slots until S.
Any help is appreciated
Edit. This is the code so far:
enum TypeOfShift = {l,m,o};
enum Staff = {John, Mike, Mary};
array[Staff, 1..30] of TypeOfShift: Roster=[|
m, m, m, l, l, o, m, m, m, m, l, l, l, m, m, m, m, m, m, l, l, m, m, m, m, m, l, l, l, l|
l, l, l, l, l, m, m, m, o, o, l, l, l, m, m, m, m, m, l, l, l, m, m, m, m, m, l, l, m, m|
m, m, l, l, m, o, m, m, m, m, l, l, l, m, m, m, m, m, m, m, m, m, m, m, m, m, l, l, l, m|];
array[Staff, 1..30] of var 0..2: RosterCalculated = array2d(Staff, 1..30,[if (Roster[i,d]==l) then 0 else (if (Roster[i,d]==o) then 2 else 1 endif) endif | i in Staff, d in 1..30]);
output[if (d==1) then "\n\(i) " ++ " " ++ show(RosterCalculated[i,d]) ++ " " else show(RosterCalculated[i,d]) ++ " " endif | i in Staff, d in 1..30];
This answer provides a simple & effective solution for the problem stated in the question, that is, how to determine if a given shift is valid or not. [Note that in this case it is not necessary (actually, it is counterproductive) to declare the content of any array as
var $T
].One option is to:
ll
in the array (arraydouble_l_pos
)o
in the array (arrayhas_o
)o
in the array from the beginning (arraycum_has_o
)ll
so that it ignores anyo
preceding it (arrayfixed_double_l_pos
)ll
starting positions (arraydouble_l_distance
)6
Example:
Everything here is statically computed, so the model inconsistency can be detected even before the actual solving is started.
Addendum: since this is a roster problem, you may want to read in detail the roster and the on-call-rostering models in the
MiniZinc
benchmarks repository. Those files may contain better approaches for dealing with your problem.This new answer deals with the more general problem of generating a valid schedule. In this case we are dealing with decision variables so the other approach cannot be easily implemented.
My suggestion is to use the regular global constraint to deal with counting the number of
m
andl
. This ensures that the provided solution does not place more than6
sub-sequentm
(ignoringo
and singlel
) in a sequence.Example:
Important Notes:
this can also be used to verify existing solutions;
one should place the regular constraint within a predicate, so that it can be easily applied to all members of the Staff without code duplication;
MiniZinc
prints a trivial answer for this model only because there is no other constraint on theshifts
array (i.e. the minimum number ofm
required in a month).