001: // -------------------------------------------------------------------------- 002: // Licensed Materials - Property of IBM 003: // 004: // 5725-A06 5725-A29 5724-Y48 5724-Y49 5724-Y54 5724-Y55 005: // Copyright IBM Corporation 1998, 2013. All Rights Reserved. 006: // 007: // Note to U.S. Government Users Restricted Rights: 008: // Use, duplication or disclosure restricted by GSA ADP Schedule 009: // Contract with IBM Corp. 010: // -------------------------------------------------------------------------- 011: 012: {string} Weekdays = ...; 013: tuple nurse { 014: key string name; 015: int seniority; 016: int qualification; 017: int payRate; 018: } 019: 020: tuple shift { 021: key string departmentName; 022: key string day; 023: key int startTime; 024: key int endTime; 025: int minRequirement; 026: int maxRequirement; 027: } 028: 029: tuple nurseCouple { 030: nurse Nurse1; 031: nurse Nurse2; 032: } 033: 034: tuple departmentIncompat { 035: nurse Nurse; 036: string department; 037: } 038: 039: //tuple workTimeByNurse { 040: // string Nurse; 041: // int minTime; 042: // int maxTime; 043: //} 044: 045: tuple skillRequirement { 046: key string department; 047: key string skill; 048: int number; 049: } 050: 051: int MaxWorkTime = ...; 052: {nurse} Nurses = ...; 053: {shift} Shifts = ...; 054: {string} Departments = ...; 055: 056: {skillRequirement} SkillRequirements = ...; 057: 058: {nurseCouple} NurseAssoc 059: with Nurse1 in Nurses,Nurse2 in Nurses = ...; 060: {nurseCouple} NurseIncompat 061: with Nurse1 in Nurses, Nurse2 in Nurses = ...; 062: {departmentIncompat} DepartmentIncompat 063: with Nurse in Nurses, department in Departments = ...; 064: 065: int Vacations[Nurses][Weekdays] = ...; 066: //{WorkTimeByNurse} WorkTimeByNurses = ...; 067: 068: {string} Skills = ...; 069: int NurseSkill[Nurses][Skills] = ...; 070: 071: int RequiredAssignments[Nurses][Shifts] = ...; 072: 073: int AbsStartTime[s in Shifts]= s.startTime + ord(Weekdays,s.day)*24; 074: int AbsEndTime[s in Shifts] = 075: s.endTime + ord(Weekdays,s.day)*24 076: +(( s.startTime > s.endTime )?24:0); 077: 078: int Duration[s in Shifts] = AbsEndTime[s] - AbsStartTime[s]; 079: 080: int incompatShifts[Shifts][Shifts] = [ s1 : [ s2 : 1 ] | s1,s2 in Shifts: AbsStartTime[s2]>=AbsStartTime[s1] && AbsStartTime[s2]<AbsEndTime[s1] ]; 081: 082: dvar int NurseAssignments[Nurses][Shifts] in 0..1; 083: dvar float+ NurseWorkTime[Nurses]; 084: dvar float+ NurseAvgHours; 085: dvar float+ NurseMoreThanAvgHours[Nurses]; 086: dvar float+ NurseLessThanAvgHours[Nurses]; 087: dvar float+ Fairness; 088: dvar int CostByDepartments[Departments]; 089: dvar int AllocationByDepartments[Departments]; 090: 091: 092: minimize 093: sum(d in Departments) 094: CostByDepartments[d]; 095: 096: subject to { 097: // cost by department 098: forall( d in Departments ) 099: CostByDepartments[d] == 100: sum( s in Shifts , n in Nurses : s.departmentName == d ) 101: NurseAssignments[n][s] * Duration[s] * n.payRate; 102: 103: // allocation by department 104: forall(d in Departments) 105: AllocationByDepartments[d] == sum(s in Shifts, n in Nurses : s.departmentName == d) NurseAssignments[n][s]; 106: 107: // a shift require between min and max Nurses 108: forall(s in Shifts) 109: s.minRequirement <= sum(n in Nurses) NurseAssignments[n][s] <= s.maxRequirement; 110: 111: forall(n in Nurses) { 112: // time worked by a Nurse 113: NurseWorkTime[n] == sum( s in Shifts ) 114: NurseAssignments[n][s]*Duration[s]; 115: 116: // two shifts at the same time are incompatible 117: forall( s in Shifts ) 118: sum( s2 in Shifts : incompatShifts[s,s2]==1 ) 119: NurseAssignments[n][s2] <=1; 120: } 121: // respect required assignments 122: forall( n in Nurses, s in Shifts : RequiredAssignments[n][s] == 1 ) 123: ctRequiredAssignmentConstraints: 124: NurseAssignments[n][s] == 1; 125: //global max worked time 126: forall(n in Nurses) 127: ctNurseMaxTimeConstraints: 128: NurseWorkTime[n] <= MaxWorkTime; 129: 130: // Nurse-Nurse incompatibility 131: forall( < n1 , n2 > in NurseIncompat , s in Shifts ) 132: ctNurseIncompatConstraints: 133: NurseAssignments[n1][s] + NurseAssignments[n2][s] <= 1; 134: 135: // Nurse association 136: forall( < n1 , n2 > in NurseAssoc, s in Shifts) 137: ctNurseAssocConstraints: 138: NurseAssignments[n1][s] == NurseAssignments[n2][s]; 139: 140: // Nurse-shift incompatibility 141: forall(s in Shifts, <n, s.departmentName > in DepartmentIncompat) 142: NurseAssignments[n][s] == 0; 143: 144: // max worked time 145: // forall( t in workTimeByNurses , n in Nurses : n.name == t.Nurse ) 146: // WorkTimeByNurseConstraints[n]=t.minTime <= NurseWorkTime[n] <= t.maxTime; 147: 148: // Nurse vacations 149: forall( n in Nurses , d in Weekdays : Vacations[n][d] == 1 ) 150: ctNurseVacationConstraints: 151: sum(s in Shifts : s.day == d) NurseAssignments[n][s] == 0; 152: 153: // skills 154: forall(r in SkillRequirements, s in Shifts : r.department == s.departmentName) 155: ctSkillRequirementConstraints: 156: sum(n in Nurses : NurseSkill[n][r.skill] == 1) NurseAssignments[n][s] >= r.number; 157: 158: forall( n in Nurses ) 159: NurseWorkTime[n] == NurseAvgHours + NurseMoreThanAvgHours[n] - NurseLessThanAvgHours[n]; 160: 161: Fairness == sum(n in Nurses) (NurseMoreThanAvgHours[n] + NurseLessThanAvgHours[n]); 162: NurseAvgHours == ((card(Nurses) == 0) ? 0 : sum(n in Nurses) NurseWorkTime[n] / card(Nurses)); 163: } 164: 165: 166: tuple CostByDepartmentsSolutionT{ 167: string Departments; 168: int value; 169: }; 170: {CostByDepartmentsSolutionT} CostByDepartmentsSolution = {<i0,CostByDepartments[i0]> | i0 in Departments}; 171: tuple NurseAssignmentsSolutionT{ 172: nurse Nurses; 173: shift Shifts; 174: int value; 175: }; 176: {NurseAssignmentsSolutionT} NurseAssignmentsSolution = {<i0,i1,NurseAssignments[i0][i1]> | i0 in Nurses,i1 in Shifts}; 177: tuple AllocationByDepartmentsSolutionT{ 178: string Departments; 179: int value; 180: }; 181: {AllocationByDepartmentsSolutionT} AllocationByDepartmentsSolution = {<i0,AllocationByDepartments[i0]> | i0 in Departments}; 182: tuple NurseWorkTimeSolutionT{ 183: nurse Nurses; 184: float value; 185: }; 186: {NurseWorkTimeSolutionT} NurseWorkTimeSolution = {<i0,NurseWorkTime[i0]> | i0 in Nurses}; 187: tuple NurseMoreThanAvgHoursSolutionT{ 188: nurse Nurses; 189: float value; 190: }; 191: {NurseMoreThanAvgHoursSolutionT} NurseMoreThanAvgHoursSolution = {<i0,NurseMoreThanAvgHours[i0]> | i0 in Nurses}; 192: tuple NurseLessThanAvgHoursSolutionT{ 193: nurse Nurses; 194: float value; 195: }; 196: {NurseLessThanAvgHoursSolutionT} NurseLessThanAvgHoursSolution = {<i0,NurseLessThanAvgHours[i0]> | i0 in Nurses}; 197: