## ams_version=1.0 Model Main_Employee_Training_Problem { Comment: { "An implementation of the Employee Training Problem of Chapter 8 of the AIMMS Optimization Modeling book. Keywords: Linear Program, Integer Program, Control-State variables, Rounding Heuristic, Probabilistic Constraint." } DeclarationSection Flight_Attendant_Requirement_Declarations { Set Months { Definition: data { November, December, January, February, March, April, May, June }; } Horizon TimePeriods { SubsetOf: Months; Index: t; Parameter: StartPeriod; CurrentPeriod: StartPeriod; IntervalLength: 6; Definition: Months; Comment: { "The months \'November\' and \'December\' are only used to initialize the model. By using an HORIZON that spans the months \'January\' .. \'June\', the model will automatically assume all variables that are defined over periods outside the planning interval to be initial data (i.e. fixed). So, instead of introducing special model identifier to store the initial data, the initial data is stored in the model variables itself." } } Parameter MonthlyAttendantCost { Range: nonnegative; Comment: "Corresponds to parameter \'c\' in \'AIMMS, Optimization Modeling\'."; } Parameter MonthlyTraineeCost { Range: nonnegative; Comment: "Corresponds to parameter \'d\' in \'AIMMS, Optimization Modeling\'."; } Parameter MonthlyAttendantFlightHours { Range: nonnegative; Comment: "Corresponds to parameter \'u\' in \'AIMMS, Optimization Modeling\'."; } Parameter MonthlyTraineeFlightHours { Range: nonnegative; Comment: "Corresponds to parameter \'v\' in \'AIMMS, Optimization Modeling\'."; } Parameter MonthlyMaximumTrainees; Parameter RequiredFlightHours { IndexDomain: t; Range: nonnegative; Comment: "Corresponds to parameter \'r\' in \'AIMMS, Optimization Modeling\'."; } Parameter AttendantsResigning { IndexDomain: t; Range: { {0..inf} } Comment: "Corresponds to parameter \'l\' in \'AIMMS, Optimization Modeling\'."; } ElementParameter ACase { Range: AllCases; } } Section Deterministic_Model_Formulation { DeclarationSection Determistic_Model_Declarations { Variable Attendants { IndexDomain: t; Range: integer; Definition: Attendants(t-1) - AttendantsResigning(t-1) + TraineesHired(t-2); Comment: { "Corresponds to constraint \'x(t) = x(t-1) - l(t-1) + y(t-2)\' in \'AIMMS, Optimization Modeling\'. Note that this attribute form constains both the declarayion of the \'Attendent\' variable as well as the definition of the \'Attendant balance\' constraint." } } Variable TraineesHired { IndexDomain: t; Range: { {0..MonthlyMaximumTrainees} } Comment: "Corresponds to variable \'y\' in \'AIMMS, Optimization Modeling\'."; } Variable TotalPersonnelCost { Definition: { Sum[ t, MonthlyAttendantCost * Attendants(t) + MonthlyTraineeCost * (TraineesHired(t) + TraineesHired(t-1)) ] } Comment: { "An extra free model variable is needed by AIMMS to represent the objective function of the mathematical program." } } Constraint PersonnelRequirementConstraint { IndexDomain: t; Definition: { MonthlyAttendantFlightHours * Attendants(t) + MonthlyTraineeFlightHours * (TraineesHired(t) + TraineesHired(t-1)) >= RequiredFlightHours(t) } Comment: { "Corresponds to constraint \'u x(t) + v (y(t) + y(t-1)) >= r(t)\' in \'AIMMS, Optimization Modeling\'." } } Set DeterministicConstraints { SubsetOf: AllConstraints; Definition: data { Attendants, TotalPersonnelCost, PersonnelRequirementConstraint }; } MathematicalProgram DeterministicModel { Objective: TotalPersonnelCost; Direction: minimize; Constraints: DeterministicConstraints; Variables: AllVariables; Type: MIP; } } Procedure SolveIntegerModel { Body: { ! solve IP solve DeterministicModel; SolutionAttendants(t in TimePeriods,'Integer') := Attendants(t); SolutionTraineesHired(t in TimePeriods,'Integer') := TraineesHired(t); SolutionTotalPersonnelCost('Integer') := TotalPersonnelCost; empty Rounding_Heuristics; } } } Section Rounding_Heuristics { Section Rounding_Up { Procedure SolveLinearModelAndRoundUp { Body: { ! Solve LP solve DeterministicModel where type := 'rmip'; ! Store LP solution SolutionAttendants(t in TimePeriods,'LP') := Attendants(t); SolutionTraineesHired(t in TimePeriods,'LP') := TraineesHired(t); SolutionTotalPersonnelCost('LP') := TotalPersonnelCost; ! Compute and store rounded solution SolutionAttendants(t in TimePeriods.Past,'Rounded Up') := Attendants(t); SolutionTraineesHired(t in TimePeriods.Past,'Rounded Up') := TraineesHired(t); SolutionTraineesHired(t,'Rounded Up') := Ceil(TraineesHired(t)); SolutionAttendants(t,'Rounded Up') := SolutionAttendants(t-1,'Rounded Up') - AttendantsResigning(t-1) + SolutionTraineesHired(t-2,'Rounded Up'); SolutionTotalPersonnelCost('Rounded Up') := Sum[ t, MonthlyAttendantCost * SolutionAttendants(t,'Rounded Up') + MonthlyTraineeCost * (SolutionTraineesHired(t,'Rounded Up') + SolutionTraineesHired(t-1,'Rounded Up')) ]; } } } Section Rounding_with_Reserves { Procedure SolveLinearModelAndRoundWithReserves { Body: { ! Solve LP solve DeterministicModel where type := 'rmip'; ! Store LP solution SolutionAttendants(t in TimePeriods,'LP') := Attendants(t); SolutionTraineesHired(t in TimePeriods,'LP') := TraineesHired(t); SolutionTotalPersonnelCost('LP') := TotalPersonnelCost; !Compute and store rounded solution SolutionAttendants(t in TimePeriods.Past,'Rounded with Reserves') := Attendants(t); SolutionTraineesHired(t in TimePeriods.Past,'Rounded with Reserves') := TraineesHired(t); Reserve := 0; for (t) do SolutionTraineesHired(t,'Rounded with Reserves') := if ( Reserve < 1 ) then Ceil(TraineesHired(t)) else Floor(TraineesHired(t)) endif; SolutionAttendants(t,'Rounded with Reserves') := SolutionAttendants(t-1,'Rounded with Reserves') - AttendantsResigning(t-1) + SolutionTraineesHired(t-2,'Rounded with Reserves'); Reserve += SolutionTraineesHired(t,'Rounded with Reserves') - TraineesHired(t); endfor; SolutionTotalPersonnelCost('Rounded with Reserves') := Sum[ t, MonthlyAttendantCost * SolutionAttendants(t,'Rounded with Reserves') + MonthlyTraineeCost * (SolutionTraineesHired(t,'Rounded with Reserves') + SolutionTraineesHired(t-1,'Rounded with Reserves')) ]; } Parameter Reserve; } } } Section Probablistic_Model_Formulation { DeclarationSection Probablistic_Model_Declarations { Parameter Alpha { InitialData: 0.01; } Parameter NormalMean { IndexDomain: (t); } Parameter NormalVariance { IndexDomain: (t); } Parameter CriticalValueAttendantsResigning { IndexDomain: (t); } Constraint ProbablisticAttendantBalance { IndexDomain: (t); Definition: { Attendants(t) <= Attendants(t-1) - CriticalValueAttendantsResigning(t-1) + TraineesHired(t-2) } } Set ProbablisticConstraints { SubsetOf: AllConstraints; Definition: data { TotalPersonnelCost, PersonnelRequirementConstraint, ProbablisticAttendantBalance }; } MathematicalProgram ProbablisticModel { Objective: TotalPersonnelCost; Direction: minimize; Constraints: ProbablisticConstraints; Variables: AllVariables; Type: MIP; } } Procedure ComputeCriticalValues { Body: { if ( ( Alpha < 0 ) or ( Alpha > 1 ) ) then DialogMessage( "Invalid value for alpha." ); return; endif; CriticalValueAttendantsResigning(t) := if ( NormalMean(t) or NormalVariance(t) ) then InverseCumulativeDistribution( Normal( NormalMean(t), NormalVariance(t) ), 1 - Alpha ) else 0 endif; } } Procedure SolveProbabilisticModel { Body: { ! Display AIMMS Progress Window ShowProgressWindow(1); ! Temporarily release upper bound on number of trainees per month TemporaryMonthlyMaximumTrainees := MonthlyMaximumTrainees; MonthlyMaximumTrainees := inf; ! solve IP solve ProbablisticModel; ! restore upper bound on number of trainees per month MonthlyMaximumTrainees := TemporaryMonthlyMaximumTrainees; SolutionAttendants(t in TimePeriods,'Probablistic') := Attendants(t); SolutionTraineesHired(t in TimePeriods,'Probablistic') := TraineesHired(t); SolutionTotalPersonnelCost('Probablistic') := TotalPersonnelCost; } Parameter TemporaryMonthlyMaximumTrainees; } } Section Solution_Reporting { DeclarationSection Solution_Reporting_Declarations { Set SolutionMethods { Index: s; Definition: data { 'Integer', 'LP', 'Rounded Up', 'Rounded with Reserves', 'Probablistic' }; } Parameter SolutionAttendants { IndexDomain: (t,s); } Parameter SolutionTraineesHired { IndexDomain: (t,s); } Parameter SolutionTotalPersonnelCost { IndexDomain: (s); } Parameter NumberOfDecimals { IndexDomain: (s); Definition: data { LP : 2 }; } } Procedure ClearSolution { Body: { empty Solution_Reporting_Declarations; } } } Procedure MainInitialization { Body: { read from file ":data.txt"; ComputeCriticalValues; } } Procedure MainTermination { Body: { return 1; } } Procedure SolveModelInteger { Body: { SolveIntegerModel; } } Procedure SolveModelWithRoundingUp { Body: { SolveLinearModelAndRoundUp ; } } Procedure SolveModelWithRoundingAndReserves { Body: { SolveLinearModelAndRoundWithReserves ; } } Procedure SolveModelWithProbabilistic { Body: { SolveProbabilisticModel ; } } }