/*********************************************************** nurse_rostering2.pi from Constraint Solving and Planning with Picat, Springer by Neng-Fa Zhou, Hakan Kjellerstrand, and Jonathan Fruhman ***********************************************************/ import sat. main => Day = 1, % day shift Night = 2, % night shift Off = 3, % off % valid 7 day schedules Valid1 = [ [Day,Day,Day,Day,Day,Off,Off], [Night,Off,Night,Off,Day,Day,Off], [Night,Night,Off,Off,Day,Day,Off] ], % create all rotational variants Valid = [], foreach (V in Valid1, R in 0..V.length-1) Rot = rotate_left(V,R).to_array(), Valid := Valid ++ [Rot] end, NumNurses = 14, NumDays = Valid[1].length, X = new_array(NumNurses,NumDays), X :: Day..Off, % ensure a valid scheme for each nurse foreach (Nurse in 1..NumNurses) table_in([X[Nurse,D] : D in 1..NumDays].to_array(),Valid) end, foreach (D in 1..NumDays) sum([X[Nurse,D] #= Day : Nurse in 1..NumNurses]) #>= 3, sum([X[Nurse,D] #= Night : Nurse in 1..NumNurses]) #>= 2 end, Vars = X.vars(), solve(Vars). rotate_left(L) = rotate_left(L,1). rotate_left(L,N) = slice(L,N+1,L.length) ++ slice(L,1,N).