Début du travail sur l'optimiseur de recouvrement.d'horaire pour trouver celle qui conduit au coût minimal.

Ajout d'une classe statique pour calculer les coûts d'employés pour un horaire donné.
Ajout de la librairie java tuples pour avoir des quartets pour stocker des états d'horaire et ainsi faire une fouille dans l'arbre de recouvrement d'horaire.
This commit is contained in:
Francois Berube\frabe 2018-04-04 00:24:31 -04:00
parent 04bfd630f1
commit d1a9072e46
12 changed files with 437 additions and 127 deletions

View file

@ -5,7 +5,7 @@ import jdistlib.rng.RandomEngine;
public class AbsencesVector {
private boolean[] AbsencesVector;
private double probPresence = 0.90;
private double probPresence = 0.80;
private double probReturn = 0.50;
public AbsencesVector(int length, RandomEngine r) {

View file

@ -58,9 +58,9 @@ public class ModelInitialSchedules {
private void createEmployeesVariables() {
this.maxPartTimeEmployee = (int) Math.ceil((double) myScheduleParameters.totalWorkedPeriodsInSchedule
/ myScheduleParameters.minWorkingPeriodsOfPartTimeEmployeesPerSchedule);
/ myScheduleParameters.getMinWorkingPeriodsOfPartTimeEmployeesPerSchedule());
this.maxFullTimeEmployee = (int) Math.ceil((double) myScheduleParameters.totalWorkedPeriodsInSchedule
/ myScheduleParameters.workingPeriodsOfFullTimeEmployeesPerSchedule);
/ myScheduleParameters.getWorkingPeriodsOfFullTimeEmployeesPerSchedule());
}
@ -155,9 +155,9 @@ public class ModelInitialSchedules {
chocoModelInitialSchedules.ifThen(isWorkingEmployee,
chocoModelInitialSchedules.arithm(
this.workingPeriodsPerPartTimeEmployees[employee], ">=",
this.myScheduleParameters.minWorkingPeriodsOfPartTimeEmployeesPerSchedule));
this.myScheduleParameters.getMinWorkingPeriodsOfPartTimeEmployeesPerSchedule()));
chocoModelInitialSchedules.arithm(this.workingPeriodsPerPartTimeEmployees[employee], "<=",
this.myScheduleParameters.maxWorkingPeriodsOfPartTimeEmployeesPerSchedule).post();
this.myScheduleParameters.getMaxWorkingPeriodsOfPartTimeEmployeesPerSchedule()).post();
}
// Constraintes pour compter le nombre d'employes par periode de travail et s'assurer qu'il
@ -237,7 +237,7 @@ public class ModelInitialSchedules {
IntVar PartTimeEmployeesSalary =
chocoModelInitialSchedules.intVar(0, this.maxPartTimeEmployee *
this.myScheduleParameters.workPeriodsPerSchedule *
this.myScheduleParameters.hourlyRateOfPartTimeEmployees, true);
this.myScheduleParameters.regularHourlyRateOfPartTimeEmployees, true);
IntVar FullTimeEmployeesSalary =
chocoModelInitialSchedules.intVar(0, this.maxFullTimeEmployee *
@ -246,13 +246,13 @@ public class ModelInitialSchedules {
this.TotalEmployeesSalary = chocoModelInitialSchedules.intVar(0, this.maxPartTimeEmployee *
this.myScheduleParameters.workPeriodsPerSchedule *
this.myScheduleParameters.hourlyRateOfPartTimeEmployees +
this.myScheduleParameters.regularHourlyRateOfPartTimeEmployees +
this.maxFullTimeEmployee *
this.myScheduleParameters.workPeriodsPerSchedule *
this.myScheduleParameters.regularHourlyRateOfFullTimeEmployees, true);
IntVar HourlyRateOfPartTimeEmployees =
chocoModelInitialSchedules.intVar(this.myScheduleParameters.hourlyRateOfPartTimeEmployees);
chocoModelInitialSchedules.intVar(this.myScheduleParameters.regularHourlyRateOfPartTimeEmployees);
IntVar regularHourlyRateOfFullTimeEmployees =
chocoModelInitialSchedules.intVar(this.myScheduleParameters.regularHourlyRateOfFullTimeEmployees);

View file

@ -11,26 +11,24 @@ public class ParametersInitialSchedules {
int totalWorkedPeriodsInSchedule;
int hoursPerWorkPeriod;
int fixedCostOfPartTimeEmployeesPerSchedule;
int hourlyRateOfPartTimeEmployees;
public int fixedCostOfPartTimeEmployeesPerSchedule;
public int regularHourlyRateOfPartTimeEmployees;
public int overtimeHourlyRateOfPartTimeEmployees;
int minWorkingHoursOfPartTimeEmployeesPerSchedule;
int maxWorkingHoursOfPartTimeEmployeesPerSchedule;
int minWorkingPeriodsOfPartTimeEmployeesPerSchedule;
public int maxConsecutiveWorkingPeriodsOfPartTimeEmployeesPerShiftWork;
public int minConsecutiveNonWorkingPeriodsBetweenShiftWorksOfPartTimeEmployees;
public int maxWorkingPeriodsOfPartTimeEmployeesPerSchedule;
int maxConsecutiveWorkingHoursOfPartTimeEmployeesPerShiftWork;
int minConsecutiveNonWorkingHoursBetweenShiftWorksOfPartTimeEmployees;
int fixedCostOfFullTimeEmployeesPerSchedule;
int regularHourlyRateOfFullTimeEmployees;
int overtimeHourlyRateOfFullTimeEmployees;
int workingHoursOfFullTimeEmployeesPerSchedule;
public int fixedCostOfFullTimeEmployeesPerSchedule;
public int regularHourlyRateOfFullTimeEmployees;
public int overtimeHourlyRateOfFullTimeEmployees;
int maxWorkingHoursOfFullTimeEmployeesPerSchedule;
int workingPeriodsOfFullTimeEmployeesPerSchedule;
public int maxConsecutiveWorkingPeriodsOfFullTimeEmployeesPerShiftWork;
public int minConsecutiveNonWorkingPeriodsBetweenShiftWorksOfFullTimeEmployees;
public int maxWorkingPeriodsOfFullTimeEmployeesPerSchedule;
int workingHoursOfFullTimeEmployeesPerSchedule;
int maxConsecutiveWorkingHoursOfFullTimeEmployeesPerShiftWork;
int minConsecutiveNonWorkingHoursBetweenShiftWorksOfFullTimeEmployees;
int workingHoursPaidAtRegularHourlyRatePerSchedule;
int workingHoursPaidAtRegularHourlyRatePerShiftWork;
public int[] requiredWorkforce;
Tuples enumerationWorkPeriodsSchedulesOfFullTimeEmployees;
@ -54,44 +52,28 @@ public class ParametersInitialSchedules {
this.daysPerSchedule = 14;
this.hoursPerWorkPeriod = 24 / this.workPeriodsPerDay;
this.workPeriodsPerSchedule = this.workPeriodsPerDay * this.daysPerSchedule;
this.workingHoursPaidAtRegularHourlyRatePerSchedule = 80;
this.workingHoursPaidAtRegularHourlyRatePerShiftWork = 8;
}
private void setPartTimeEmployeesParameters() {
this.fixedCostOfPartTimeEmployeesPerSchedule = 50;
this.hourlyRateOfPartTimeEmployees = 12; // To simulate lower productivity
this.regularHourlyRateOfPartTimeEmployees = 12; // To simulate lower productivity
this.overtimeHourlyRateOfPartTimeEmployees = 17; // To simulate lower productivity
this.minWorkingHoursOfPartTimeEmployeesPerSchedule = 32;
this.maxWorkingHoursOfPartTimeEmployeesPerSchedule = 64;
int maxConsecutiveWorkingHoursOfPartTimeEmployeesPerShiftWork = 12;
this.maxConsecutiveWorkingPeriodsOfPartTimeEmployeesPerShiftWork
= (int) (maxConsecutiveWorkingHoursOfPartTimeEmployeesPerShiftWork / this.hoursPerWorkPeriod);
int minConsecutiveNonWorkingHoursBetweenShiftWorksOfPartTimeEmployees = 12;
this.minConsecutiveNonWorkingPeriodsBetweenShiftWorksOfPartTimeEmployees
= (int) (minConsecutiveNonWorkingHoursBetweenShiftWorksOfPartTimeEmployees / this.hoursPerWorkPeriod);
this.minWorkingPeriodsOfPartTimeEmployeesPerSchedule
= (int) (this.minWorkingHoursOfPartTimeEmployeesPerSchedule / this.hoursPerWorkPeriod);
this.maxWorkingPeriodsOfPartTimeEmployeesPerSchedule
= (int) (this.maxWorkingHoursOfPartTimeEmployeesPerSchedule / this.hoursPerWorkPeriod);
this.maxConsecutiveWorkingHoursOfPartTimeEmployeesPerShiftWork = 12;
this.minConsecutiveNonWorkingHoursBetweenShiftWorksOfPartTimeEmployees = 12;
}
private void setFullTimeEmployeesParameters() {
this.fixedCostOfFullTimeEmployeesPerSchedule = 50;
this.regularHourlyRateOfFullTimeEmployees = 10;
this.overtimeHourlyRateOfFullTimeEmployees = 15;
this.workingHoursOfFullTimeEmployeesPerSchedule = 80;
this.maxWorkingHoursOfFullTimeEmployeesPerSchedule = 120;
int maxConsecutiveWorkingHoursOfFullTimeEmployeesPerShiftWork = 12;
this.maxConsecutiveWorkingPeriodsOfFullTimeEmployeesPerShiftWork
= (int) (maxConsecutiveWorkingHoursOfFullTimeEmployeesPerShiftWork / this.hoursPerWorkPeriod);
int minConsecutiveNonWorkingHoursBetweenShiftWorksOfFullTimeEmployees = 12;
this.minConsecutiveNonWorkingPeriodsBetweenShiftWorksOfFullTimeEmployees
= (int) (minConsecutiveNonWorkingHoursBetweenShiftWorksOfFullTimeEmployees / this.hoursPerWorkPeriod);
this.workingPeriodsOfFullTimeEmployeesPerSchedule
= (int) (this.workingHoursOfFullTimeEmployeesPerSchedule / this.hoursPerWorkPeriod);
this.maxWorkingPeriodsOfFullTimeEmployeesPerSchedule
= (int) (this.maxWorkingHoursOfFullTimeEmployeesPerSchedule / this.hoursPerWorkPeriod);
this.workingHoursPaidAtRegularHourlyRatePerSchedule = 80;
this.maxConsecutiveWorkingHoursOfFullTimeEmployeesPerShiftWork = 12;
this.minConsecutiveNonWorkingHoursBetweenShiftWorksOfFullTimeEmployees = 12;
}
private void setRequiredWorkforce() {
@ -163,7 +145,64 @@ public class ParametersInitialSchedules {
this.ValidPartTimeEmployeeShiftTuples = new ValidPartTimeEmployeeShift().makeTuples();
}
public int getWorkingPeriodsPaidAtRegularHourlyRatePerSchedule () {
return (int) (workingHoursPaidAtRegularHourlyRatePerSchedule / this.hoursPerWorkPeriod);
}
public int getWorkingPeriodsPaidAtRegularHourlyRatePerShiftWork () {
return (int) (workingHoursPaidAtRegularHourlyRatePerShiftWork / this.hoursPerWorkPeriod);
}
public int getWorkingPeriodCostOfPartTimeEmployeesPaidAtRegularHourlyRate () {
return (int) (regularHourlyRateOfPartTimeEmployees * this.hoursPerWorkPeriod);
}
public int getWorkingPeriodCostOfFullTimeEmployeesPaidAtRegularHourlyRate () {
return (int) (regularHourlyRateOfFullTimeEmployees * this.hoursPerWorkPeriod);
}
public int getWorkingPeriodCostOfPartTimeEmployeesPaidAtOvertimeHourlyRate () {
return (int) (overtimeHourlyRateOfPartTimeEmployees * this.hoursPerWorkPeriod);
}
public int getWorkingPeriodCostOfFullTimeEmployeesPaidAtOvertimeHourlyRate () {
return (int) (overtimeHourlyRateOfFullTimeEmployees * this.hoursPerWorkPeriod);
}
public int getMaxConsecutiveWorkingPeriodsOfFullTimeEmployeesPerShiftWork () {
return (int) (maxConsecutiveWorkingHoursOfFullTimeEmployeesPerShiftWork / this.hoursPerWorkPeriod);
}
public int getMaxConsecutiveWorkingPeriodsOfPartTimeEmployeesPerShiftWork () {
return (int) (maxConsecutiveWorkingHoursOfPartTimeEmployeesPerShiftWork / this.hoursPerWorkPeriod);
}
public int getMinConsecutiveNonWorkingPeriodsBetweenShiftWorksOfPartTimeEmployees () {
return (int) (minConsecutiveNonWorkingHoursBetweenShiftWorksOfPartTimeEmployees / this.hoursPerWorkPeriod);
}
public int getMinConsecutiveNonWorkingPeriodsBetweenShiftWorksOfFullTimeEmployees () {
return (int) (minConsecutiveNonWorkingHoursBetweenShiftWorksOfFullTimeEmployees / this.hoursPerWorkPeriod);
}
public int getMaxWorkingPeriodsOfPartTimeEmployeesPerSchedule () {
return (int) (this.maxWorkingHoursOfPartTimeEmployeesPerSchedule / this.hoursPerWorkPeriod);
}
public int getMaxWorkingPeriodsOfFullTimeEmployeesPerSchedule () {
return (int) (this.maxWorkingHoursOfFullTimeEmployeesPerSchedule / this.hoursPerWorkPeriod);
}
public int getMinWorkingPeriodsOfPartTimeEmployeesPerSchedule () {
return (int) (this.minWorkingHoursOfPartTimeEmployeesPerSchedule / this.hoursPerWorkPeriod);
}
public int getWorkingPeriodsOfFullTimeEmployeesPerSchedule () {
return (int) (this.workingHoursOfFullTimeEmployeesPerSchedule / this.hoursPerWorkPeriod);
}
// A implementer plus tard si l'on veut travailler avec des fichiers texte
public ParametersInitialSchedules(String fileName) {

View file

@ -24,7 +24,7 @@ public class MainClass {
List<SchedulesArray> absenceSchedulesArrayList = GenerateAbsencesSchedules(initialSchedulesArrayList);
List<SchedulesArray> recoveredSchedulesArrayList = GenerateRecoveredSchedules(absenceSchedulesArrayList);
List<SchedulesArray> recoveredSchedulesArrayList = GenerateOptimalRecoveredSchedules(absenceSchedulesArrayList);
// Algo de recouvrement d'absences. Faire un nouveau package de fonctions.
// Trouver meilleure solution et l'afficher.
}
@ -90,7 +90,7 @@ public class MainClass {
return absenceSchedulesArrayList;
}
private static List<SchedulesArray> GenerateRecoveredSchedules(List<SchedulesArray> absenceSchedulesArrayList) {
private static List<SchedulesArray> GenerateOptimalRecoveredSchedules(List<SchedulesArray> absenceSchedulesArrayList) {
List<SchedulesArray> recoveredSchedulesArrayList = new ArrayList<>();
for (SchedulesArray absenceSchedule : absenceSchedulesArrayList) {

View file

@ -0,0 +1,89 @@
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package ScheduleUtil;
import InitialSchedules.ParametersInitialSchedules;
import SchedulesRecovery.*;
/**
*
* @author frabe
*/
public class EmployeeCostCalculator {
public static int getFullScheduleCost( boolean[][] partTimeEmployeesSchedule , boolean[][] fullTimeEmployeesSchedule, ParametersInitialSchedules myScheduleParameters) {
return 0;
}
public static int getRecoveringActionCost (RecoveringAction action, ParametersInitialSchedules myScheduleParameters) {
int actionCost = 0;
if (action.getClass().getName() == "RecoveringActionPartTimeEmployee") {
actionCost = getPartTimeEmployeeCost(action.employeeScheduleAfterRecoveringAction, myScheduleParameters) -
getPartTimeEmployeeCost(action.employeeScheduleBeforeRecoveringAction, myScheduleParameters);
} else if (action.getClass().getName() == "RecoveringActionFullTimeEmployee") {
actionCost = getFullTimeEmployeeCost(action.employeeScheduleAfterRecoveringAction, myScheduleParameters) -
getFullTimeEmployeeCost(action.employeeScheduleBeforeRecoveringAction, myScheduleParameters);
}
return actionCost;
}
public static int getPartTimeEmployeeCost( boolean[] employeeSchedule, ParametersInitialSchedules myScheduleParameters) {
int consecutiveWorkingPeriods = 0;
int overtimeWorkingPeriods = 0;
int totalWorkingPeriods = 0;
for (int workPeriod = 0; workPeriod < employeeSchedule.length ; workPeriod++) {
if (employeeSchedule[workPeriod]) {
totalWorkingPeriods += 1;
consecutiveWorkingPeriods += 1;
if (consecutiveWorkingPeriods > myScheduleParameters.getWorkingPeriodsPaidAtRegularHourlyRatePerShiftWork()) {
overtimeWorkingPeriods += 1;
}
} else {
consecutiveWorkingPeriods = 0;
}
}
int additionalOvertimeWorkingPeriods = totalWorkingPeriods - myScheduleParameters.getWorkingPeriodsPaidAtRegularHourlyRatePerSchedule();
if ( additionalOvertimeWorkingPeriods > 0 ){
overtimeWorkingPeriods += additionalOvertimeWorkingPeriods;
}
int employeeCost = myScheduleParameters.fixedCostOfPartTimeEmployeesPerSchedule +
overtimeWorkingPeriods * myScheduleParameters.getWorkingPeriodCostOfPartTimeEmployeesPaidAtOvertimeHourlyRate() +
(totalWorkingPeriods - overtimeWorkingPeriods) * myScheduleParameters.getWorkingPeriodCostOfPartTimeEmployeesPaidAtRegularHourlyRate();
return employeeCost;
}
public static int getFullTimeEmployeeCost( boolean[] employeeSchedule, ParametersInitialSchedules myScheduleParameters) {
int consecutiveWorkingPeriods = 0;
int overtimeWorkingPeriods = 0;
int totalWorkingPeriods = 0;
for (int workPeriod = 0; workPeriod < employeeSchedule.length ; workPeriod++) {
if (employeeSchedule[workPeriod]) {
totalWorkingPeriods += 1;
consecutiveWorkingPeriods += 1;
if (consecutiveWorkingPeriods > myScheduleParameters.getWorkingPeriodsPaidAtRegularHourlyRatePerShiftWork()) {
overtimeWorkingPeriods += 1;
}
} else {
consecutiveWorkingPeriods = 0;
}
}
int additionalOvertimeWorkingPeriods = totalWorkingPeriods - myScheduleParameters.getWorkingPeriodsPaidAtRegularHourlyRatePerSchedule();
if ( additionalOvertimeWorkingPeriods > 0 ){
overtimeWorkingPeriods += additionalOvertimeWorkingPeriods;
}
int employeeCost = myScheduleParameters.fixedCostOfFullTimeEmployeesPerSchedule +
overtimeWorkingPeriods * myScheduleParameters.getWorkingPeriodCostOfFullTimeEmployeesPaidAtOvertimeHourlyRate() +
(totalWorkingPeriods - overtimeWorkingPeriods) * myScheduleParameters.getWorkingPeriodCostOfFullTimeEmployeesPaidAtRegularHourlyRate();
return employeeCost;
}
}

View file

@ -57,23 +57,10 @@ public class SchedulesArray {
this.isFullTimeEmployeeActive[employee] = myScheduleArray.isFullTimeEmployeeActive[employee];
}
this.partTimeSchedules = new boolean[this.maxPartTimeEmployee][this.workPeriodsPerSchedule];
this.fullTimeSchedules = new boolean[this.maxFullTimeEmployee][this.workPeriodsPerSchedule];
this.initialPartTimeSchedules = new boolean[this.maxPartTimeEmployee][this.workPeriodsPerSchedule];
this.initialFullTimeSchedules = new boolean[this.maxFullTimeEmployee][this.workPeriodsPerSchedule];
for (int workPeriod = 0; workPeriod < this.workPeriodsPerSchedule; workPeriod++) {
for (int employee = 0; employee < this.maxPartTimeEmployee; employee++) {
this.partTimeSchedules[employee][workPeriod] = myScheduleArray.partTimeSchedules[employee][workPeriod];
this.initialPartTimeSchedules[employee][workPeriod] = myScheduleArray.initialPartTimeSchedules[employee][workPeriod];
}
}
for (int workPeriod = 0; workPeriod < this.workPeriodsPerSchedule; workPeriod++) {
for (int employee = 0; employee < this.maxFullTimeEmployee; employee++) {
this.fullTimeSchedules[employee][workPeriod] = myScheduleArray.fullTimeSchedules[employee][workPeriod];
this.initialFullTimeSchedules[employee][workPeriod] = myScheduleArray.initialFullTimeSchedules[employee][workPeriod];
}
}
this.partTimeSchedules = deepCopyPartTimeEmployeesSchedule(myScheduleArray.partTimeSchedules);
this.initialPartTimeSchedules = deepCopyPartTimeEmployeesSchedule(myScheduleArray.initialPartTimeSchedules);
this.fullTimeSchedules = deepCopyFullTimeEmployeesSchedule(myScheduleArray.fullTimeSchedules);
this.initialFullTimeSchedules = deepCopyFullTimeEmployeesSchedule(myScheduleArray.initialFullTimeSchedules);
this.employeesPerWorkPeriod = new int[this.workPeriodsPerSchedule];
this.workingPeriodsPerPartTimeEmployees = new int[this.maxPartTimeEmployee];
@ -85,6 +72,26 @@ public class SchedulesArray {
}
protected boolean[][] deepCopyPartTimeEmployeesSchedule(boolean[][] partTimeSchedules) {
boolean[][] copyPartTimeSchedules = new boolean[this.maxPartTimeEmployee][this.workPeriodsPerSchedule];
for (int workPeriod = 0; workPeriod < this.workPeriodsPerSchedule; workPeriod++) {
for (int employee = 0; employee < this.maxPartTimeEmployee; employee++) {
copyPartTimeSchedules[employee][workPeriod] = partTimeSchedules[employee][workPeriod];
}
}
return copyPartTimeSchedules;
}
protected boolean[][] deepCopyFullTimeEmployeesSchedule(boolean[][] fullTimeSchedules) {
boolean[][] copyFullTimeSchedules = new boolean[this.maxFullTimeEmployee][this.workPeriodsPerSchedule];
for (int workPeriod = 0; workPeriod < this.workPeriodsPerSchedule; workPeriod++) {
for (int employee = 0; employee < this.maxFullTimeEmployee; employee++) {
copyFullTimeSchedules[employee][workPeriod] = fullTimeSchedules[employee][workPeriod];
}
}
return copyFullTimeSchedules;
}
public SchedulesArray(ModelInitialSchedules m, Solution s) {
this.myModelInitialSchedules = m;
Solution mySolution = s;

View file

@ -6,7 +6,9 @@
package SchedulesRecovery;
import AbsenceSchedules.AbsenceSchedulesArray;
import java.util.*;
import org.javatuples.Triplet;
import ScheduleUtil.*;
/**
*
@ -18,73 +20,151 @@ public class RecoveredSchedulesArray extends AbsenceSchedulesArray{
super(myAbsenceScheduleArray);
}
// public void oldRecoverAbsenceScheduleOptimally() {
// for ( int workPeriod = 0 ; workPeriod < this.workPeriodsPerSchedule ; workPeriod++ ) {
// boolean noEmployeeAvailable = false;
// while (!noEmployeeAvailable && getEmployeesPerWorkPeriod(workPeriod) < getRequiredWorkForce(workPeriod)) {
// boolean absenceRecoveryDone = false;
// int employee = 0;
// while (!absenceRecoveryDone && employee < this.maxFullTimeEmployee) {
// if ( isFullTimeEmployeeAvailableForAbsenceRecovering(employee, workPeriod) ){
// fullTimeSchedules[employee][workPeriod] = true;
// updateEmployeesPerWorkPeriod(workPeriod);
// updateWorkingPeriodsPerFullTimeEmployees(employee);
// absenceRecoveryDone = true;
// }
// employee++;
// }
// employee = 0;
// while (!absenceRecoveryDone && employee < this.maxPartTimeEmployee) {
// if (isPartTimeEmployeeAvailableForAbsenceRecovering(employee, workPeriod) ){
// partTimeSchedules[employee][workPeriod] = true;
// updateEmployeesPerWorkPeriod(workPeriod);
// updateWorkingPeriodsPerPartTimeEmployees(employee);
// absenceRecoveryDone = true;
// }
// employee++;
// }
// if (!absenceRecoveryDone) {
// noEmployeeAvailable = true;
// }
// }
// }
//
// }
public void recoverAbsenceScheduleOptimally() {
for (int workPeriod = 0; workPeriod < this.workPeriodsPerSchedule; workPeriod++) {
boolean noEmployeeAvailable = false;
while (!noEmployeeAvailable && getEmployeesPerWorkPeriod(workPeriod) < getRequiredWorkForce(workPeriod)) {
boolean absenceRecoveryDone = false;
int employee = 0;
while (!absenceRecoveryDone && employee < this.maxFullTimeEmployee) {
if (isFullTimeEmployeeAvailableForAbsenceRecovering(employee, workPeriod) && !isFullTimeEmployeeWorking(employee, workPeriod)){
fullTimeSchedules[employee][workPeriod] = true;
updateEmployeesPerWorkPeriod(workPeriod);
updateWorkingPeriodsPerFullTimeEmployees(employee);
absenceRecoveryDone = true;
}
employee++;
}
employee = 0;
while (!absenceRecoveryDone && employee < this.maxPartTimeEmployee) {
if (isPartTimeEmployeeAvailableForAbsenceRecovering(employee, workPeriod) && !isPartTimeEmployeeWorking(employee, workPeriod)){
partTimeSchedules[employee][workPeriod] = true;
updateEmployeesPerWorkPeriod(workPeriod);
updateWorkingPeriodsPerPartTimeEmployees(employee);
absenceRecoveryDone = true;
}
employee++;
}
if (!absenceRecoveryDone) {
noEmployeeAvailable = true;
int workPeriod = 0;
boolean[][] currentRecoveredScheduleOfPartTimeEmployees = deepCopyPartTimeEmployeesSchedule(partTimeSchedules);
boolean[][] currentRecoveredScheduleOfFullTimeEmployees = deepCopyFullTimeEmployeesSchedule(fullTimeSchedules);
int totalEmployeesCost = EmployeeCostCalculator.getFullScheduleCost(currentRecoveredScheduleOfPartTimeEmployees, currentRecoveredScheduleOfFullTimeEmployees, this.myModelInitialSchedules.myScheduleParameters);
int currentTotalEmployeesCost = totalEmployeesCost;
ScheduleStateComparator totalCostComparator = new ScheduleStateComparator();
// mettre les Schedules dans les Tuples currentRecoveredScheduleOfPartTimeEmployees et currentRecoveredScheduleOfFullTimeEmployees au lieu de previousActions
PriorityQueue< Triplet<RecoveringAction, RecoveringAction, Integer> > priorityQueueScheduleStatesOrderedByTotalCost = new PriorityQueue<>(totalCostComparator);
List< Triplet<RecoveringAction, RecoveringAction, Integer> > listVisitedScheduleStates = new ArrayList<>();
RecoveringAction currentRecoveringAction = null;
RecoveringAction previousRecoveringAction = null;
while ( workPeriod < this.workPeriodsPerSchedule ) {
Stack<RecoveringActionPartTimeEmployee> stackRecoveringActionsOfPartTimeEmployee =
getPossibleActionOfPartTimeEmployees(workPeriod, currentRecoveredScheduleOfPartTimeEmployees);
Stack<RecoveringActionFullTimeEmployee> stackRecoveringActionsOfFullTimeEmployees =
getPossibleActionOfFullTimeEmployees(workPeriod, currentRecoveredScheduleOfFullTimeEmployees);
while ( !stackRecoveringActionsOfPartTimeEmployee.isEmpty() && !stackRecoveringActionsOfFullTimeEmployees.isEmpty() ) {
if (stackRecoveringActionsOfPartTimeEmployee.isEmpty()) {
currentRecoveringAction = stackRecoveringActionsOfFullTimeEmployees.pop();
} else {
currentRecoveringAction = stackRecoveringActionsOfPartTimeEmployee.pop();
}
// On pourrait comparer currentRecoveredScheduleOfPartTimeEmployees pour voir si on ne l'a pas deja visite avec un coût plus faible. Dans ce cas, on ne pousse pas l'etat dans la liste.
int actionCost = EmployeeCostCalculator.getRecoveringActionCost( currentRecoveringAction, this.myModelInitialSchedules.myScheduleParameters );
totalEmployeesCost = currentTotalEmployeesCost + actionCost;
Triplet<RecoveringAction, RecoveringAction, Integer> scheduleState = Triplet.with(previousRecoveringAction, currentRecoveringAction, totalEmployeesCost);
priorityQueueScheduleStatesOrderedByTotalCost.add(scheduleState);
listVisitedScheduleStates.add(scheduleState);
}
Triplet<RecoveringAction, RecoveringAction, Integer> currentScheduleState = priorityQueueScheduleStatesOrderedByTotalCost.poll();
currentTotalEmployeesCost = currentScheduleState.getValue2();
previousRecoveringAction = currentScheduleState.getValue1();
//recalculer les currentRecoveredScheduleOfPartTimeEmployees et ajuster la workPeriod
//en trouvent la workPeriod la plus petite avec une demande incomplète.
//workPeriod++;
}
}
private Stack<RecoveringActionPartTimeEmployee> getPossibleActionOfPartTimeEmployees(int workPeriod, boolean[][] currentRecoveredSchedule) {
// inclure un attribut pour dire si la requiredWorkForce est satifaite avec l'action.
Stack<RecoveringActionPartTimeEmployee> stackRecoveringActionsOfPartTimeEmployee = new Stack<>();
for (int employee = 0 ; employee < this.maxPartTimeEmployee ; employee++) {
boolean[] currentEmployeeSchedule = currentRecoveredSchedule[employee];
if ( isPartTimeEmployeeActive(employee) && isPartTimeEmployeeAvailableForAbsenceRecovering(employee, workPeriod, currentEmployeeSchedule) ){
RecoveringActionPartTimeEmployee recoveringAction =
new RecoveringActionPartTimeEmployee(employee, workPeriod, currentEmployeeSchedule);
stackRecoveringActionsOfPartTimeEmployee.push(recoveringAction);
}
}
return stackRecoveringActionsOfPartTimeEmployee;
}
private boolean isPartTimeEmployeeAvailableForAbsenceRecovering(int employee, int workPeriod){
return isPartTimeEmployeeActive(employee) && !isPartTimeEmployeeAbsent(employee, workPeriod) && isValidPartTimeEmployeeWorkPeriod(employee,workPeriod);
private Stack<RecoveringActionFullTimeEmployee> getPossibleActionOfFullTimeEmployees(int workPeriod, boolean[][] currentRecoveredSchedule) {
Stack<RecoveringActionFullTimeEmployee> stackRecoveringActionsOfFullTimeEmployees = new Stack<>();
for (int employee = 0 ; employee < this.maxFullTimeEmployee ; employee++) {
boolean[] currentEmployeeSchedule = currentRecoveredSchedule[employee];
if ( isFullTimeEmployeeActive(employee) && isFullTimeEmployeeAvailableForAbsenceRecovering(employee, workPeriod, currentEmployeeSchedule) ){
RecoveringActionFullTimeEmployee recoveringAction =
new RecoveringActionFullTimeEmployee(employee, workPeriod, currentEmployeeSchedule);
stackRecoveringActionsOfFullTimeEmployees.push(recoveringAction);
}
}
return stackRecoveringActionsOfFullTimeEmployees;
}
private boolean isValidPartTimeEmployeeWorkPeriod(int employee, int workPeriod){
return isValidWorkingPeriodsOfPartTimeEmployee(employee) &&
isValidConsecutiveWorkingPeriodsOfPartTimeEmployee(employee, workPeriod) &&
isValidConsecutiveNonWorkingPeriodsBetweenShiftWorksOfPartTimeEmployee(employee, workPeriod);
private boolean isPartTimeEmployeeAvailableForAbsenceRecovering(int employee, int workPeriod, boolean[] currentEmployeeSchedule){
return !currentEmployeeSchedule[workPeriod] && !isPartTimeEmployeeAbsent(employee, workPeriod) && isValidPartTimeEmployeeWorkPeriod(currentEmployeeSchedule, workPeriod);
}
private boolean isValidWorkingPeriodsOfPartTimeEmployee(int employee){
return this.workingPeriodsPerPartTimeEmployees[employee] < myModelInitialSchedules.myScheduleParameters.maxWorkingPeriodsOfPartTimeEmployeesPerSchedule;
private boolean isValidPartTimeEmployeeWorkPeriod(boolean[] currentEmployeeSchedule, int workPeriod){
return isValidWorkingPeriodsOfPartTimeEmployeePerSchedule(currentEmployeeSchedule) &&
isValidConsecutiveWorkingPeriodsOfPartTimeEmployee(currentEmployeeSchedule, workPeriod) &&
isValidConsecutiveNonWorkingPeriodsBetweenShiftWorksOfPartTimeEmployee(currentEmployeeSchedule, workPeriod);
}
private boolean isValidWorkingPeriodsOfPartTimeEmployeePerSchedule(boolean[] currentEmployeeSchedule){
int employeeWorkingPeriods = 0;
for ( int workPeriod = 0 ; workPeriod < this.workPeriodsPerSchedule ; workPeriod++ ) {
if (currentEmployeeSchedule[workPeriod]){
employeeWorkingPeriods +=1 ;
}
}
return employeeWorkingPeriods < myModelInitialSchedules.myScheduleParameters.getMaxWorkingPeriodsOfPartTimeEmployeesPerSchedule();
}
private boolean isValidConsecutiveWorkingPeriodsOfPartTimeEmployee(int employee, int workPeriod){
private boolean isValidConsecutiveWorkingPeriodsOfPartTimeEmployee(boolean[] currentEmployeeSchedule, int workPeriod){
int consecutiveWorkingPeriods = 1;
int compteurWorkPeriod = workPeriod - 1;
while ( compteurWorkPeriod >= 0 && isPartTimeEmployeeWorking(employee, compteurWorkPeriod) ){
while ( compteurWorkPeriod >= 0 && currentEmployeeSchedule[compteurWorkPeriod] ){
consecutiveWorkingPeriods += 1;
compteurWorkPeriod--;
}
compteurWorkPeriod = workPeriod + 1;
while ( compteurWorkPeriod < this.workPeriodsPerSchedule && isPartTimeEmployeeWorking(employee, compteurWorkPeriod) ){
while ( compteurWorkPeriod < this.workPeriodsPerSchedule && currentEmployeeSchedule[compteurWorkPeriod] ){
consecutiveWorkingPeriods += 1;
compteurWorkPeriod++;
}
return consecutiveWorkingPeriods <= myModelInitialSchedules.myScheduleParameters.maxConsecutiveWorkingPeriodsOfPartTimeEmployeesPerShiftWork;
return consecutiveWorkingPeriods <= myModelInitialSchedules.myScheduleParameters.getMaxConsecutiveWorkingPeriodsOfPartTimeEmployeesPerShiftWork();
}
private boolean isValidConsecutiveNonWorkingPeriodsBetweenShiftWorksOfPartTimeEmployee(int employee, int workPeriod){
private boolean isValidConsecutiveNonWorkingPeriodsBetweenShiftWorksOfPartTimeEmployee(boolean[] currentEmployeeSchedule, int workPeriod){
int consecutivePreviousNonWorkingPeriods = 0;
int compteurWorkPeriod = workPeriod - 1;
while ( compteurWorkPeriod >= 0 && !isPartTimeEmployeeWorking(employee, compteurWorkPeriod) ){
while ( compteurWorkPeriod >= 0 && !currentEmployeeSchedule[compteurWorkPeriod] ){
consecutivePreviousNonWorkingPeriods += 1;
compteurWorkPeriod--;
}
@ -93,12 +173,12 @@ public class RecoveredSchedulesArray extends AbsenceSchedulesArray{
validConsecutivePreviousNonWorkingPeriods = true;
} else if (consecutivePreviousNonWorkingPeriods == 0) {
validConsecutivePreviousNonWorkingPeriods = true;
} else if (consecutivePreviousNonWorkingPeriods >= myModelInitialSchedules.myScheduleParameters.minConsecutiveNonWorkingPeriodsBetweenShiftWorksOfPartTimeEmployees) {
} else if (consecutivePreviousNonWorkingPeriods >= myModelInitialSchedules.myScheduleParameters.getMinConsecutiveNonWorkingPeriodsBetweenShiftWorksOfPartTimeEmployees()) {
validConsecutivePreviousNonWorkingPeriods = true;
}
int consecutiveNextNonWorkingPeriods = 0;
compteurWorkPeriod = workPeriod + 1;
while ( compteurWorkPeriod < this.workPeriodsPerSchedule && !isPartTimeEmployeeWorking(employee, compteurWorkPeriod) ){
while ( compteurWorkPeriod < this.workPeriodsPerSchedule && !currentEmployeeSchedule[compteurWorkPeriod] ){
consecutiveNextNonWorkingPeriods += 1;
compteurWorkPeriod++;
}
@ -107,46 +187,52 @@ public class RecoveredSchedulesArray extends AbsenceSchedulesArray{
validConsecutiveNextNonWorkingPeriods = true;
} else if (consecutiveNextNonWorkingPeriods == 0) {
validConsecutiveNextNonWorkingPeriods = true;
} else if (consecutiveNextNonWorkingPeriods >= myModelInitialSchedules.myScheduleParameters.minConsecutiveNonWorkingPeriodsBetweenShiftWorksOfPartTimeEmployees) {
} else if (consecutiveNextNonWorkingPeriods >= myModelInitialSchedules.myScheduleParameters.getMinConsecutiveNonWorkingPeriodsBetweenShiftWorksOfPartTimeEmployees()) {
validConsecutiveNextNonWorkingPeriods = true;
}
return validConsecutivePreviousNonWorkingPeriods && validConsecutiveNextNonWorkingPeriods;
}
private boolean isFullTimeEmployeeAvailableForAbsenceRecovering(int employee, int workPeriod){
return isFullTimeEmployeeActive(employee) && !isFullTimeEmployeeAbsent(employee, workPeriod) && isValidFullTimeEmployeeWorkPeriod(employee,workPeriod);
private boolean isFullTimeEmployeeAvailableForAbsenceRecovering(int employee, int workPeriod, boolean[] currentEmployeeSchedule){
return !currentEmployeeSchedule[workPeriod] && !isFullTimeEmployeeAbsent(employee, workPeriod) && isValidFullTimeEmployeeWorkPeriod(currentEmployeeSchedule, workPeriod);
}
private boolean isValidFullTimeEmployeeWorkPeriod(int employee, int workPeriod){
return isValidWorkingPeriodsOfFullTimeEmployee(employee) &&
isValidConsecutiveWorkingPeriodsOfFullTimeEmployee(employee, workPeriod) &&
isValidConsecutiveNonWorkingPeriodsBetweenShiftWorksOfFullTimeEmployee(employee, workPeriod);
private boolean isValidFullTimeEmployeeWorkPeriod(boolean[] currentEmployeeSchedule, int workPeriod){
return isValidWorkingPeriodsOfFullTimeEmployeePerSchedule(currentEmployeeSchedule) &&
isValidConsecutiveWorkingPeriodsOfFullTimeEmployee(currentEmployeeSchedule, workPeriod) &&
isValidConsecutiveNonWorkingPeriodsBetweenShiftWorksOfFullTimeEmployee(currentEmployeeSchedule, workPeriod);
}
private boolean isValidWorkingPeriodsOfFullTimeEmployee(int employee){
return this.workingPeriodsPerFullTimeEmployees[employee] < myModelInitialSchedules.myScheduleParameters.maxWorkingPeriodsOfFullTimeEmployeesPerSchedule;
private boolean isValidWorkingPeriodsOfFullTimeEmployeePerSchedule(boolean[] currentEmployeeSchedule){
int employeeWorkingPeriods = 0;
for ( int workPeriod = 0 ; workPeriod < this.workPeriodsPerSchedule ; workPeriod++ ) {
if (currentEmployeeSchedule[workPeriod]){
employeeWorkingPeriods +=1 ;
}
}
return employeeWorkingPeriods < myModelInitialSchedules.myScheduleParameters.getMaxWorkingPeriodsOfFullTimeEmployeesPerSchedule();
}
private boolean isValidConsecutiveWorkingPeriodsOfFullTimeEmployee(int employee, int workPeriod){
private boolean isValidConsecutiveWorkingPeriodsOfFullTimeEmployee(boolean[] currentEmployeeSchedule, int workPeriod){
int consecutiveWorkingPeriods = 1;
int compteurWorkPeriod = workPeriod - 1;
while ( compteurWorkPeriod >= 0 && isFullTimeEmployeeWorking(employee, compteurWorkPeriod) ){
while ( compteurWorkPeriod >= 0 && currentEmployeeSchedule[compteurWorkPeriod] ){
consecutiveWorkingPeriods += 1;
compteurWorkPeriod--;
}
compteurWorkPeriod = workPeriod + 1;
while ( compteurWorkPeriod < this.workPeriodsPerSchedule && isFullTimeEmployeeWorking(employee, compteurWorkPeriod) ){
while ( compteurWorkPeriod < this.workPeriodsPerSchedule && currentEmployeeSchedule[compteurWorkPeriod] ){
consecutiveWorkingPeriods += 1;
compteurWorkPeriod++;
}
return consecutiveWorkingPeriods <= myModelInitialSchedules.myScheduleParameters.maxConsecutiveWorkingPeriodsOfFullTimeEmployeesPerShiftWork;
return consecutiveWorkingPeriods <= myModelInitialSchedules.myScheduleParameters.getMaxConsecutiveWorkingPeriodsOfFullTimeEmployeesPerShiftWork();
}
private boolean isValidConsecutiveNonWorkingPeriodsBetweenShiftWorksOfFullTimeEmployee(int employee, int workPeriod){
private boolean isValidConsecutiveNonWorkingPeriodsBetweenShiftWorksOfFullTimeEmployee(boolean[] currentEmployeeSchedule, int workPeriod){
int consecutivePreviousNonWorkingPeriods = 0;
int compteurWorkPeriod = workPeriod - 1;
while ( compteurWorkPeriod >= 0 && !isFullTimeEmployeeWorking(employee, compteurWorkPeriod)){
while ( compteurWorkPeriod >= 0 && !currentEmployeeSchedule[compteurWorkPeriod] ){
consecutivePreviousNonWorkingPeriods += 1;
compteurWorkPeriod--;
}
@ -155,12 +241,12 @@ public class RecoveredSchedulesArray extends AbsenceSchedulesArray{
validConsecutivePreviousNonWorkingPeriods = true;
} else if (consecutivePreviousNonWorkingPeriods == 0) {
validConsecutivePreviousNonWorkingPeriods = true;
} else if (consecutivePreviousNonWorkingPeriods >= myModelInitialSchedules.myScheduleParameters.minConsecutiveNonWorkingPeriodsBetweenShiftWorksOfFullTimeEmployees) {
} else if (consecutivePreviousNonWorkingPeriods >= myModelInitialSchedules.myScheduleParameters.getMinConsecutiveNonWorkingPeriodsBetweenShiftWorksOfFullTimeEmployees()) {
validConsecutivePreviousNonWorkingPeriods = true;
}
int consecutiveNextNonWorkingPeriods = 0;
compteurWorkPeriod = workPeriod + 1;
while ( compteurWorkPeriod < this.workPeriodsPerSchedule && !isFullTimeEmployeeWorking(employee, compteurWorkPeriod) ){
while ( compteurWorkPeriod < this.workPeriodsPerSchedule && !currentEmployeeSchedule[compteurWorkPeriod] ){
consecutiveNextNonWorkingPeriods += 1;
compteurWorkPeriod++;
}
@ -169,7 +255,7 @@ public class RecoveredSchedulesArray extends AbsenceSchedulesArray{
validConsecutiveNextNonWorkingPeriods = true;
} else if (consecutiveNextNonWorkingPeriods == 0) {
validConsecutiveNextNonWorkingPeriods = true;
} else if (consecutiveNextNonWorkingPeriods >= myModelInitialSchedules.myScheduleParameters.minConsecutiveNonWorkingPeriodsBetweenShiftWorksOfFullTimeEmployees) {
} else if (consecutiveNextNonWorkingPeriods >= myModelInitialSchedules.myScheduleParameters.getMinConsecutiveNonWorkingPeriodsBetweenShiftWorksOfFullTimeEmployees()) {
validConsecutiveNextNonWorkingPeriods = true;
}
return validConsecutivePreviousNonWorkingPeriods && validConsecutiveNextNonWorkingPeriods;

View file

@ -0,0 +1,33 @@
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package SchedulesRecovery;
/**
*
* @author frabe
*/
public class RecoveringAction {
public int employee;
public int workPeriod;
public boolean[] employeeScheduleBeforeRecoveringAction;
public boolean[] employeeScheduleAfterRecoveringAction;
public RecoveringAction( int employee, int workPeriod, boolean[] employeeSchedule){
this.employee = employee;
this.workPeriod = workPeriod;
this.employeeScheduleBeforeRecoveringAction = new boolean[employeeSchedule.length];
this.employeeScheduleAfterRecoveringAction = new boolean[employeeSchedule.length];
for (int i = 0 ; i < employeeSchedule.length ; i++) {
this.employeeScheduleBeforeRecoveringAction[i] = employeeSchedule[i];
if (i == workPeriod) {
this.employeeScheduleAfterRecoveringAction[i] = true;
} else {
this.employeeScheduleAfterRecoveringAction[i] = employeeSchedule[i];
}
}
}
}

View file

@ -0,0 +1,18 @@
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package SchedulesRecovery;
/**
*
* @author frabe
*/
public class RecoveringActionFullTimeEmployee extends RecoveringAction{
public RecoveringActionFullTimeEmployee( int employee, int workPeriod, boolean[] employeeSchedule){
super(employee, workPeriod, employeeSchedule);
}
}

View file

@ -0,0 +1,19 @@
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package SchedulesRecovery;
/**
*
* @author frabe
*/
public class RecoveringActionPartTimeEmployee extends RecoveringAction{
public RecoveringActionPartTimeEmployee( int employee, int workPeriod, boolean[] employeeSchedule){
super(employee, workPeriod, employeeSchedule);
}
}

View file

@ -0,0 +1,19 @@
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package SchedulesRecovery;
import java.util.Comparator;
import org.javatuples.Triplet;
/**
*
* @author frabe
*/
public class ScheduleStateComparator implements Comparator< Triplet<RecoveringAction, RecoveringAction, Integer> > {
public int compare(Triplet<RecoveringAction, RecoveringAction, Integer> o1, Triplet<RecoveringAction, RecoveringAction, Integer> o2) {
return o1.getValue2().compareTo(o2.getValue2());
}
}

Binary file not shown.