Continuing with the other post ( Minizinc: generate a valid shift ). I am trying to have a maximum of 2 im between double ls. Doing this with a regular constraint is quite hard as the transition table would be quite big (too many paths). Is there any way to solve it? I have tried this, but it is giving me errors:
include "globals.mzn";
enum TypeOfShift = {l,m,o,im};
enum Staff = {John, Mike, Mary};
%array[1..30] of TypeOfShift: Roster=[m, m, m, l, l, o, im, m, m, m, l, l, l, im, m, m, m, m, im, l, l, m, m, m, m, m, l, l, l, l];
array[Staff,1..30] of var TypeOfShift: Roster;
array[Staff, 1..30] of var 1..4: RosterForIm = array2d(Staff, 1..30,[if (Roster[i,d]==l) then 1
else (if (Roster[i,d]==o) then 2 else (if (Roster[i,d]==im) then 3 else 4 endif) endif) endif| i in Staff, d in 1..30]);
predicate TwoOsPerCycle(array[int] of int: shifts) =
let {
array[int] of var opt int: double_l_pos = [ i - 1 | i in index_set(shifts) where
i > 1 /\
shifts[i-1] == l /\
shifts[i] == l];
array[int] of var opt int: double_l_distance = [double_l_pos[1]] ++
[double_l_pos[i] - double_l_pos[i-1] - 1 - 1
| i in index_set(double_l_pos) where i > 1];
} in
(forall(j in double_l_pos)
(at_most(2,[shifts[ciclo] | ciclo in j..j+1],3))); %3 code for im, 2 number of max permited in a cycle
constraint forall(i in Staff) (TwoOsPerCycle([RosterForIm[i,j] | j in 1..30]));
solve satisfy;
Hi Patrick ... I'm stuck again... I continued developing the regular expression but I went up to 55 states... then I stopped. I was trying a different approach which is to build up an array of resting hours between consecutive working days. For example: mmmtnllmmlttlnnlllm (m1 eary morning 6 to 13; m morning start at 7 to 14; t evening 14 to 21; night 22 to 7am; l resting day; o office 10 to 14; im on call morning 6 to 14; it on call evening 13 to 22; ino on call night 21 to 7) should create an array like 17,17,24,24,48,48,17,48,48,16... which is StartTime of shift [day+1] - (StartTime of shift [day] + Duration of shift[day]). This is coded. Between consecutive working shifts has to be 12 hours or more.
When there is a resting day (l) I intend to repit the last resting period (48,48 in the example). This I donĀ“t know how to do it. The idea then is to count the working days in between cycles to check the following: - At least 12 hours between consecutive working shifts - Cycle before a 48h or more rest has a maximum of 5 working days. - Cycle before a 54h rest or more has a maximum of 6 working days.
The restrictions of the nights (48h after a night except if it is another night o rest day, 54h after two nights) I have done it with constraints or I can do it with regular expressions... that's fine
Any ideas?
include "globals.mzn";
%Definitions
enum TypeOfShift = {l,m1,m,t,n,im,it,ino,o}; %Types of shifts
array[TypeOfShift] of float: StartTypeOfShift=[10, 6, 7, 14, 22, 5, 13, 21, 10]; %Starting hour
array[TypeOfShift] of float: DurationTypeOfShift=[1, 7, 7, 7, 9, 8, 8, 10, 4]; %Duration of shifts (hours)
enum Staff={AA,BB,CC,DD,EE,FF,GG,HH,II,JJ,KK,LL,MM,NN,OO,PP,QQ,RR,SS,TT,UU,VV};
int: NumberWorkers = card(Staff);
array[int] of int: DaysInRoster=[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15];
array[1..NumDaysInRoster,TypeOfShift] of int: Configuration = array2d(1..NumDaysInRoster,TypeOfShift,[1 | d in 1..NumDaysInRoster, shift in TypeOfShift ]);
int: NumDaysInRoster=length(DaysInRoster);
% Variables
array[Staff, 1..NumDaysInRoster] of var TypeOfShift: RosterCalculated;
array[Staff, 1..NumDaysInRoster-1] of var float: RosterCalculatedRests = array2d(Staff, 1..NumDaysInRoster-1,[(24*(d)+StartTypeOfShift[RosterCalculated[i,d+1]]) - (24*(d-1)+StartTypeOfShift[RosterCalculated[i,d]] + DurationTypeOfShift[RosterCalculated[i,d]]) | i in Staff, d in 1..NumDaysInRoster-1]);
% Satisfy configuration
constraint forall(d in 1..NumDaysInRoster)
(((sum(i in Staff) (RosterCalculated[i,d] == m)) == Configuration[d,m]) /\ ((sum(i in Staff) (RosterCalculated[i,d] == m1)) == Configuration[d,m1]) /\
((sum(i in Staff) (RosterCalculated[i,d] == t)) == Configuration[d,t]) /\ ((sum(i in Staff) (RosterCalculated[i,d] == n)) == Configuration[d,n]));
% Time between two shifts >= 12h
constraint forall(i in Staff, d in 1..NumDaysInRoster-1)
((RosterCalculated[i,d+1] != l ) -> (24*(d-1)+StartTypeOfShift[RosterCalculated[i,d]] + DurationTypeOfShift[RosterCalculated[i,d]] + 12 <= 24*d+StartTypeOfShift[RosterCalculated[i,d+1]]));
% Rest after night or on call night (could be changed by regular constraint) 48h or more
constraint forall(i in Staff, d in 1..NumDaysInRoster-3)
(((RosterCalculated[i,d] == n) \/ (RosterCalculated[i,d] == ino)) -> ((RosterCalculated[i,d+1]==l \/ RosterCalculated[i,d+1]==n \/ RosterCalculated[i,d+1]==ino) /\
(RosterCalculated[i,d+2]==l \/ RosterCalculated[i,d+2]==n \/ RosterCalculated[i,d+2]==ino) /\
(StartTypeOfShift[RosterCalculated[i,d+3]] >= 7.5 \/ RosterCalculated[i,d+3]==l)));
% Rest after double night has to be 54h or more (could be changed by regular constraint)
constraint forall(i in Staff, d in 1..NumDaysInRoster-4)
((((RosterCalculated[i,d] == n) \/ (RosterCalculated[i,d] == ino)) /\ ((RosterCalculated[i,d+1] == n) \/ (RosterCalculated[i,d+1] == ino))) -> ((RosterCalculated[i,d+2]==l) /\
(RosterCalculated[i,d+3]==l) /\
(StartTypeOfShift[RosterCalculated[i,d+4]] >= 13.5 \/ RosterCalculated[i,d+4]==l)));
% Rest after a night free night has to be 54h or more (could be changed by regular constraint)
constraint forall(i in Staff, d in 1..NumDaysInRoster-5)
((((RosterCalculated[i,d] == n) \/ (RosterCalculated[i,d] == ino)) /\ (RosterCalculated[i,d+1] == l) /\ ((RosterCalculated[i,d+2] == n) \/ (RosterCalculated[i,d+2] == ino))) -> ((RosterCalculated[i,d+3]==l) /\
(RosterCalculated[i,d+4]==l) /\
(StartTypeOfShift[RosterCalculated[i,d+5]] >= 13.5 \/ RosterCalculated[i,d+5]==l)));
predicate Max6WorkingDays(array[int] of var TypeOfShift: shift) =
let {
array[1..35, 1..6] of 0..35: transition_relation = % Complex matrix and not coping with all possibilities!! mlt has 48 hours rest; tln as well
[|
1, 1, 2, 2, 7, 17
|13, 2, 3, 3, 8, 17
|14, 3, 4, 4, 9, 17
|15, 4, 5, 5, 10, 17
|16, 5, 6, 6, 11, 17
|24, 6, 0, 0, 12, 18
|13, 7, 0, 0, 8, 17
|14, 8, 0, 0, 9, 17
|15, 9, 0, 0, 10, 17
|16, 10, 0, 0, 11, 17
|35, 11, 0, 0, 12, 18
|23, 12, 0, 0, 0, 0
|1, 29, 25, 25, 8, 17
|1, 30, 26, 26, 9, 17
|1, 31, 27, 27, 10, 17
|1, 32, 28, 28, 11, 17
|21, 0, 0, 0, 0, 18
|19, 0, 0, 0, 0, 0
|20, 0, 0, 0, 0, 0
|1, 0, 0, 0, 7, 17
|22, 0, 0, 0, 0, 18
|1, 1, 2, 0, 7, 17
|1, 12, 0, 0, 0, 0
|1, 34, 0, 0, 12, 18
|14, 25, 26, 26, 9, 17
|15, 26, 27, 27, 10, 17
|16, 27, 28, 28, 11, 17
|35, 28, 33, 33, 12, 18
|13, 29, 25, 25, 8, 17
|14, 30, 26, 26, 9, 17
|15, 31, 27, 27, 10, 17
|16, 32, 28, 28, 11, 18
|23, 33, 0, 0, 0, 0
|24, 34, 0, 0, 12, 18
|1, 28, 33, 33, 12, 18|];
} in
regular(
[ if (s == l) then 1 else
if (s == o) then 2 else
if (s == m) then 3 else
if ((s == m1) \/ (s == im)) then 4 else
if ((s == t) \/ (s == it)) then 5 else
6 endif %n, in
endif
endif
endif
endif
| s in shift], % sequence of input values
35, % number of states
6, % number of different input values of state machine
transition_relation, % transition relation
1, % initial state
1..35, % final states
);
constraint forall(i in Staff)
(Max6WorkingDays([RosterCalculated[i,j] | j in 1..NumDaysInRoster]));
% Two on calls per cycle as max
/*predicate Max2OnCall(array[int] of var TypeOfShift: shift) =
let {
array[1..5, 1..4] of 0..5: transition_relation =
[| 1, 2, 1, 1 % im0 (start)
| 2, 4, 2, 3 % im1_l0
| 2, 4, 2, 1 % im1_l1
| 4, 0, 4, 5 % im2_l0
| 4, 0, 4, 1 % im2_l1
|];
} in
regular(
[ if ((s == m1) \/ (s == m) \/ (s == t) \/ (s == n)) then 1 else
if ((s == im) \/ (s == it) \/ (s == ino)) then 2 else
if s == o then 3 else
4 endif
endif
endif
| s in shift], % sequence of input values
5, % number of states
4, % number of different input values of state machine
transition_relation, % transition relation
1, % initial state
1..5, % final states
);
constraint forall(i in Staff)
(Max2OnCall([RosterCalculated[i,j] | j in 1..NumDaysInRoster]));
*/
% Maximo de 5Ms seguidas . NO NECESARIOS CON MATRIZ V4 (MAS LENTO)
/*predicate MaxMsPerCycle(array[int] of var TypeOfShift: shift) =
let {
array[1..13, 1..4] of 0..13: transition_relation =
[|
2, 7, 1, 1|
3, 7, 8, 2|
4, 7, 9, 3|
5, 7, 10, 4|
6, 7, 11, 5|
0, 7, 12, 6|
7, 7, 13, 7|
3, 7, 1, 2|
4, 7, 1, 3|
5, 7, 1, 4|
6, 7, 1, 5|
0, 7, 1, 6|
7, 7, 1, 7
|];
} in
regular(
[ if ((s == m1) \/ (s == m) \/ (s == im)) then 1 else
if ((s == t) \/ (s == it) \/ (s == n) \/ (s == ino)) then 2 else
if ((s == l)) then 3 else
4 endif
endif
endif
| s in shift], % sequence of input values
13, % number of states
4, % number of different input values of state machine
transition_relation, % transition relation
1, % initial state
1..13, % final states
);
constraint forall(i in Staff)
(MaxMsPerCycle([RosterCalculated[i,j] | j in 1..NumDaysInRoster]));
*/
solve satisfy;
output[if (d==1) then "\n\(i) " ++ " " ++ show(RosterCalculatedRests[i,d]) ++ " " else show(RosterCalculatedRests[i,d]) ++ " " endif | i in Staff, d in 1..NumDaysInRoster-1]++["\n"]; % Inamovibles
output[";;"]++["\(DaysInRoster[d]);" | d in 1..NumDaysInRoster];
output[if (d==1) then "\n"++"O3;\(i) " ++ ";" ++ show(RosterCalculated[i,d]) ++ ";" else show(RosterCalculated[i,d]) ++ ";" endif | i in Staff, d in 1..NumDaysInRoster]; % Roster calculado
It is actually still possible to use the regular global constraint for this task, since the DFA requires only 5 states:
Here,
im0
is the initial state and all states are also final states:im0
: noim
since the lastll
or since the startim1_l0
: received oneim
im1_l1
: received onel
after anim
; Here, we see if thisl
belongs to a resettingll
sequence or not.im2_l0
: received twoim
, from now onim
cannot be an input up untilll
is receivedim2_l1
: received twoim
and onel
; Here, we see if thisl
belongs to a resettingll
sequence or not.The encoding of the constraint as a predicate follows:
MiniZinc Example:
Here, I include an extended version of the MiniZinc example with the regular global constraint I provided in my answer to your previous question. I fixed the previous constraint to be compatible with the new
im
value, and I added the new part. In order to make the problem interesting, I included some additional constraints.I was unable to use
Gecode
to solve this model within a reasonable time limit. However,OptiMathSAT
returns an answer pretty quickly:(note: the
mzn2fzn
translation maps the enum values into numbers, soOptiMathSAT
can only print the numbers associated withm
,im
,o
andl
)