A set of benchmarks to compare a new prototype MiniZinc implementation
at develop 9.7 kB view raw
1% NOTE: the formulation of this problem that was used in the 2009 2% MiniZinc challenge is in the file roster_model.old. (That formulation 3% is not compatible with MiniZinc 1.1 and above.) 4 5%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 6% FIT3022 7% Assignment 1 8% Rostering Problem 9% Example Solution 10% 6th May 2008 11%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 12 13% This model should be paired with a data file, viz. 14% mzn_run(chicroster,data_A, fzn_ic) 15 16% An example data file data_A is as follows: 17 % reqt = [3,2,1,0,1,1,5, 18 % 1,0,1,0,1,2,0, 19 % 1,2,0,1,1,1,0, 20 % 0,1,2,2,2,1,0, 21 % 0,0,1,2,0,0,0] ; 22 % 23 % weeks = 5 ; 24 25 26%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 27% Model 28%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 29 30% Import predicates 'exactly', at_most', 'at_least' 31include "exactly.mzn"; 32include "at_most.mzn"; 33include "at_least.mzn"; 34 35%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 36% Parameters 37%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 38 39% "weeks" and "reqt" are imported from the data file. 40% "flatsize" is a constant computed from the parameter "weeks", which is used 41% in the model. 42% 43int: weeks ; 44int: flatsize = 7 * weeks ; 45array [1..5,1..7] of int: reqt ; 46int: minobj; 47 48% The following parameters aid readability of the model. 49% 50int:Rest=1; 51int:Morn=2; 52int:Day=3; 53int:Eve=4; 54int:Joker=5; 55 56% The following two variables will hold the costs due to violated soft 57% constraints. 58% 59var 0..flatsize: evemorn ; 60var 0..flatsize: isolated ; 61 62var minobj..2*flatsize: objective = evemorn + isolated; 63 64% The roster is an array of decision variables: each variable has domain 1..5 65% representing possible shifts Rest,Morn,Day,Eve or Joker roster is a 66% two-dimensional array with a row for each week 67array [1..weeks,1..7] of var 1..5: roster; 68 69% flatroster is a one-dimensional array, which will contain exactly the same set of variables 70array [1..flatsize] of var 1..5: flatroster ; 71array [1..flatsize+6] of var 1..5: longflatroster ; 72 73%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 74% Constraints 75%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 76 77constraint 78 forall (d in 1..6) (longflatroster[flatsize+d] = flatroster[d]); 79 80%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 81% Hard Constraints 82%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 83 84%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 85%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 86% Roster Flat-Roster constraint 87% 88% Description: 89% This constraint ensures that roster and flatroster contain the same set of 90% variables. The first seven variables in flatroster correspond to the first 91% row (week) in roster. The 8th to the 14th variables in flatroster correspond 92% to the second row in roster, etc. The total number of variables is the 93% number of weeks times 7. 94% 95% Example violation: 96% This constraint is violated if a variable in flatroster is different from the corresponding 97% variable in roster, e.g. 98% 99% flatroster = [1,2,2,2,2,2,2,2,2,2,2,2,2,2] 100% roster = [2,2,2,2,2,2,2, 101% 2,2,2,2,2,2,2] 102% 103% The first day of week one is different in flatroster and roster 104% 105%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 106 107constraint 108 forall (w in 1..weeks, d in 1..7) (flatroster[7*(w-1)+d] = roster[w,d]) ; %:: defines_var(roster) ; 109 110%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 111%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 112% Requirement Constraint 113% 114% Description: 115% The roster shifts must meet the requirement specified in the data 116% Each day of the week, the sum of the sifts of each type must match the 117% required number for the given shift type on the given day of the week 118% 119% Example violation: 120% 121% % M T W T F S S 122 % reqt = [0,0,0,0,0,2,2, 123 % 1,1,0,1,1,0,0, 124 % 1,1,0,1,1,0,0, 125 % 0,0,2,0,0,0,0, 126 % 0,0,0,0,0,0,0] ; 127 % 128 % weeks = 2 ; 129% 130% 131% 132% roster = [3,2,4,2,2,1,1, 133% 3,3,4,3,3,1,1] 134% This solution does not match the requirement for Monday 135% (two Day shifts instead of a Morning and a Day shift). 136% 137%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 138 139constraint 140 forall (shift in 1..5) 141 (forall (day in 1..7) 142 (exactly(reqt[shift,day],[roster[week,day] | week in 1..weeks],shift)) 143 ); 144 145%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 146%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 147% Enough Rest Constraint 148% 149% Description: 150% Ensure that in any sequence of 7 days, at least one of them is a Rest day. 151% 152% Example violation: 153% roster = [1,2,4,2,2,2,2, 154% 3,3,4,3,3,1,1] 155% This solution has 11 working days in a row, starting on Tuesday in week 1 156% and ending on Saturday in week 2 157%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 158 159constraint 160 forall (d in 1..flatsize) 161 (at_least(1,[longflatroster[d2]|d2 in d..d+6],Rest)) ; 162 163%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 164% Too Much Rest Constraint 165% 166% Description: 167% Ensure that there is no sequence of three Rest days in a row 168% 169% Example violation: 170% roster = [1,2,4,2,2,2,2, 171% 3,3,4,3,3,1,1] 172% This solution has three Rest days in a row, starting on the Saturday of 173% week 2 and ending on the Monday of week 1 174%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 175 176constraint 177 forall (d in 1..flatsize) 178 (at_most(3,[longflatroster[d2]|d2 in d..d+3],Rest)) ; 179 180%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 181% Soft Constraints 182%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 183 184 185%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 186% Not Evening before Morning Constraint 187% 188% Description: 189% For every occurrence in the roster of an Eve shift (4) followed by a Morn 190% shift (2) incur a cost of 1. Sum up these costs over the whole roster 191% 192% Example Violation: 193% roster = [1,2,4,2,2,2,2, 194% 3,3,4,3,3,1,1] 195% 196% On Tuesday of week 1 there is an Eve shift followed by a Morn shift on 197% Wednesday. 198% 199%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 200 201% The proposition condition 202% flatroster[d]=Eve /\ flatroster[(d mod flatsize)+1] = Morn 203% is true whenever an Eve is followed by a Morn. 204% bool2int converts true to a cost of 1. If the proposition is false 205% (i.e. the constraint is not violated), then bool2int returns 0. 206% The sum over all sequences is therefore the number of violations 207constraint 208 evemorn = sum(d in 1..flatsize) 209 (bool2int(flatroster[d]=Eve /\ 210 longflatroster[d+1] = Morn ) 211 ); 212 213%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 214%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 215% No Isolated Rest Day Constraint 216% 217% Description: 218% An isolated Rest day is a Rest day with a non-Rest-day on the day before and 219% on the day after. Each such isolated Rest day incurs a cost of 1, and the 220% costs are summed up over the whole roster. 221% 222% Example Violation: 223% roster = [1,2,4,2,2,2,2, 224% 1,3,4,3,3,1,1] 225% The Monday of week 2 is preceded by a Morn shift and followed by a Day shift. 226%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 227 228% Using the syntax != for 'not-equals', the propositional formula 229% flatroster[d-1] != Rest /\ flatroster[d] = Rest /\ flatroster[d+1] != Rest 230% holds if and only if d is an isolated Rest day. 231 232constraint 233 isolated = sum(d in 1..flatsize) 234 (bool2int( (longflatroster[d+1] = Rest /\ 235 not(flatroster[d] = Rest \/ longflatroster[d+2] = Rest))) 236 ) ; 237 238%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 239 240%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 241% Solve Item 242%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 243% A solution with minimal cost (evemorn+isolated) due to violations is sought. 244% There may be different solutions with the same, minimal, cost. 245% Only one solution is found by this model 246 247% Unfortunately the facilities for controlling search, which are necessary for 248% getting good solving performance on most problems, have not been covered in FIT3022 249% This model works well on all the data instances provided, but unfortunately 250% small changes to the model can unpredictably, and dramatically, impact performance. 251 252solve 253 :: int_search(flatroster, first_fail, indomain_min, complete) 254 minimize objective; 255 256%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 257% Output of the solution 258%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 259% The roster is displayed as numbers - not unfortunately shift type names - with 260% one row for each week. 261% The number of isolated rests and morning after evening violations is also shown. 262 263output [ 264 "roster = array2d(1..\(weeks), 1..7, \(roster));\n", 265 "evemorn = \(evemorn);\n", 266 "isolated = \(isolated);\n", 267 "objective = \(objective);\n" 268] ++ [ 269 "% Roster: \n", 270 "% Week: M T W T F S S\n" 271] ++ [ 272 if j = 1 then "% \(i): " else "" endif ++ 273 "\(roster[i,j])" ++ 274 if j = 7 then "\n" else " " endif 275| i in 1..weeks, j in 1..7 276]; 277