diff --git a/.gitignore b/.gitignore index 254f95d..e362fba 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ choco-4.0.6 +/tp/code/TP/Travail_de_session/nbproject/private/ \ No newline at end of file diff --git a/tp/code/TP/Travail_de_session/InitialSchedules/ModelInitialSchedules.java b/tp/code/TP/Travail_de_session/InitialSchedules/ModelInitialSchedules.java new file mode 100644 index 0000000..e596bbd --- /dev/null +++ b/tp/code/TP/Travail_de_session/InitialSchedules/ModelInitialSchedules.java @@ -0,0 +1,152 @@ +package InitialSchedules; + +import org.chocosolver.solver.Model; +import org.chocosolver.solver.variables.BoolVar; +import org.chocosolver.solver.variables.IntVar; + +public class ModelInitialSchedules { + +// private final int HEURISTIQUE_DEFAUT = 0; +// private final int HEURISTIQUE_DOMOVERWDEG = 1; +// private final int HEURISTIQUE_IMPACT_BASED_SEARCH = 2; +// private final int HEURISTIQUE_ACTIVITY = 3; +// private final String COHERENCE_BORNES = "BC"; +// private final String COHERENCE_DOMAINES = "AC"; +// private final int RESTART_AUCUN = 0; +// private final int RESTART_LUBY = 1; +// private final int RESTART_GEOMETRIQUE = 2; + private ParametersInitialSchedules myScheduleParameters; + + public int maxPartTimeEmployee; + public int maxFullTimeEmployee; + + public IntVar workPeriodsSchedulesOfPartTimeEmployees[][]; + private IntVar transposeWorkPeriodsSchedulesOfPartTimeEmployees[][]; + public IntVar workPeriodsSchedulesOfFullTimeEmployees[][]; + private IntVar transposeWorkPeriodsSchedulesOfFullTimeEmployees[][]; + + public IntVar workingPeriodsPerPartTimeEmployees[]; + public IntVar partTimeEmployeesPerWorkPeriods[]; + public IntVar workingPeriodsPerFullTimeEmployees[]; + public IntVar fullTimeEmployeesPerWorkPeriods[]; + public IntVar employeesPerWorkPeriods[]; + + public Model chocoModelInitialSchedules; + public IntVar scheduleProfit; + + public ModelInitialSchedules(ParametersInitialSchedules myScheduleParameters) { + + this.myScheduleParameters = myScheduleParameters; + + this.chocoModelInitialSchedules = new Model("Model Initial Schedules"); + + this.createEmployeesVariables(); + this.createScheduleVariables(); + + this.createModelConstraints(); + + this.createModelObjectiveFunction(); + + } + + private void createEmployeesVariables() { + + this.maxPartTimeEmployee = (int) Math.ceil((double) myScheduleParameters.totalWorkedPeriodsInSchedule + / myScheduleParameters.minWorkingPeriodsOfPartTimeEmployeesPerSchedule); + this.maxFullTimeEmployee = (int) Math.ceil((double) myScheduleParameters.totalWorkedPeriodsInSchedule + / myScheduleParameters.workingPeriodsOfFullTimeEmployeesPerSchedule); + + } + + private void createScheduleVariables() { + + // Variable pour l'horaire des employes + this.workPeriodsSchedulesOfPartTimeEmployees = chocoModelInitialSchedules.intVarMatrix(this.maxPartTimeEmployee, this.myScheduleParameters.workPeriodsPerSchedule, 0, 1); + this.workPeriodsSchedulesOfFullTimeEmployees = chocoModelInitialSchedules.intVarMatrix(this.maxFullTimeEmployee, this.myScheduleParameters.workPeriodsPerSchedule, 0, 1); + + // Variable pour faire le compte du nombre d'heures des employes + this.workingPeriodsPerPartTimeEmployees = chocoModelInitialSchedules.intVarArray(this.maxPartTimeEmployee, 0, this.myScheduleParameters.workPeriodsPerSchedule, true); + this.workingPeriodsPerFullTimeEmployees = chocoModelInitialSchedules.intVarArray(this.maxFullTimeEmployee, 0, this.myScheduleParameters.workPeriodsPerSchedule, true); + + // Creer la transpose des horaires pour compter les elements des colonnes + this.transposeWorkPeriodsSchedulesOfPartTimeEmployees = chocoModelInitialSchedules.intVarMatrix(this.myScheduleParameters.workPeriodsPerSchedule, this.maxPartTimeEmployee, 0, 1); + for (int workPeriod = 0; workPeriod < this.myScheduleParameters.workPeriodsPerSchedule; workPeriod++) { + for (int employee = 0; employee < this.maxPartTimeEmployee; employee++) { + this.transposeWorkPeriodsSchedulesOfPartTimeEmployees[workPeriod][employee] + = this.workPeriodsSchedulesOfPartTimeEmployees[employee][workPeriod]; + } + } + this.transposeWorkPeriodsSchedulesOfFullTimeEmployees = chocoModelInitialSchedules.intVarMatrix(this.myScheduleParameters.workPeriodsPerSchedule, this.maxFullTimeEmployee, 0, 1); + for (int workPeriod = 0; workPeriod < this.myScheduleParameters.workPeriodsPerSchedule; workPeriod++) { + for (int employee = 0; employee < this.maxFullTimeEmployee; employee++) { + this.transposeWorkPeriodsSchedulesOfFullTimeEmployees[workPeriod][employee] + = this.workPeriodsSchedulesOfFullTimeEmployees[employee][workPeriod]; + } + } + + // Variable pour faire le compte du nombre d'employes par periode de travail + this.partTimeEmployeesPerWorkPeriods = chocoModelInitialSchedules.intVarArray(this.myScheduleParameters.workPeriodsPerSchedule, 0, this.maxPartTimeEmployee, true); + this.fullTimeEmployeesPerWorkPeriods = chocoModelInitialSchedules.intVarArray(this.myScheduleParameters.workPeriodsPerSchedule, 0, this.maxFullTimeEmployee, true); + this.employeesPerWorkPeriods = chocoModelInitialSchedules.intVarArray(this.myScheduleParameters.workPeriodsPerSchedule, + 0, this.maxPartTimeEmployee + this.maxFullTimeEmployee, true); + + } + + private void createModelConstraints() { + + // Constrainte tableau pour choisir un type d'horaire dans les horaires possibles + for (int employee = 0; employee < this.maxFullTimeEmployee; employee++) { + chocoModelInitialSchedules.table(this.workPeriodsSchedulesOfFullTimeEmployees[employee], + this.myScheduleParameters.enumerationWorkPeriodsSchedulesOfFullTimeEmployees).post(); + } + + // Constraintes pour compter le nombre d'heures travaillees par les differents employes + for (int employee = 0; employee < this.maxPartTimeEmployee; employee++) { + chocoModelInitialSchedules.count(chocoModelInitialSchedules.intVar(1), + this.workPeriodsSchedulesOfPartTimeEmployees[employee], + this.workingPeriodsPerPartTimeEmployees[employee]).post(); + } + for (int employee = 0; employee < this.maxFullTimeEmployee; employee++) { + chocoModelInitialSchedules.count(chocoModelInitialSchedules.intVar(1), + this.workPeriodsSchedulesOfFullTimeEmployees[employee], + this.workingPeriodsPerFullTimeEmployees[employee]).post(); + } + + // Constraintes pour borner le nombre d'heures travaillees par les employes a temps partiel + for (int employee = 0; employee < this.maxPartTimeEmployee; employee++) { + BoolVar isWorkingEmployee = chocoModelInitialSchedules.arithm( + this.workingPeriodsPerPartTimeEmployees[employee], ">", 0).reify(); + chocoModelInitialSchedules.ifThen(isWorkingEmployee, + chocoModelInitialSchedules.arithm( + this.workingPeriodsPerPartTimeEmployees[employee], ">=", + this.myScheduleParameters.minWorkingPeriodsOfPartTimeEmployeesPerSchedule)); + chocoModelInitialSchedules.arithm(this.workingPeriodsPerPartTimeEmployees[employee], "<=", + this.myScheduleParameters.maxWorkingPeriodsOfPartTimeEmployeesPerSchedule).post(); + } + + // Constraintes pour compter le nombre d'employes par periode de travail et s'assurer qu'il + // satisfait la demande en employes + for (int workPeriod = 0; workPeriod < this.myScheduleParameters.workPeriodsPerSchedule; workPeriod++) { + chocoModelInitialSchedules.count(chocoModelInitialSchedules.intVar(1), + transposeWorkPeriodsSchedulesOfPartTimeEmployees[workPeriod], + this.partTimeEmployeesPerWorkPeriods[workPeriod]).post(); + chocoModelInitialSchedules.count(chocoModelInitialSchedules.intVar(1), + transposeWorkPeriodsSchedulesOfFullTimeEmployees[workPeriod], + this.fullTimeEmployeesPerWorkPeriods[workPeriod]).post(); + chocoModelInitialSchedules.arithm(this.partTimeEmployeesPerWorkPeriods[workPeriod], "+", + this.fullTimeEmployeesPerWorkPeriods[workPeriod], "=", + this.myScheduleParameters.requiredWorkforce[workPeriod]).post(); + chocoModelInitialSchedules.arithm(this.partTimeEmployeesPerWorkPeriods[workPeriod], "+", + this.fullTimeEmployeesPerWorkPeriods[workPeriod], "=", + this.employeesPerWorkPeriods[workPeriod]).post(); + } + + } + + private void createModelObjectiveFunction() { + +// this.scheduleProfit = chocoModelInitialSchedules.intVar("TOTAL_COST", 0, 20 * N * p, true); +// chocoModelInitialSchedules.scalar(perte , coeffs , "=", this.scheduleProfit).post(); + } + +} diff --git a/tp/code/TP/Travail_de_session/InitialSchedules/ParametersInitialSchedules.java b/tp/code/TP/Travail_de_session/InitialSchedules/ParametersInitialSchedules.java new file mode 100644 index 0000000..07251a4 --- /dev/null +++ b/tp/code/TP/Travail_de_session/InitialSchedules/ParametersInitialSchedules.java @@ -0,0 +1,211 @@ +package InitialSchedules; + +import org.chocosolver.solver.constraints.extension.Tuples; + +public class ParametersInitialSchedules { + + int workPeriodsPerDay; + int shiftWorkPerDay; + int daysPerSchedule; + int workPeriodsPerSchedule; + int totalWorkedPeriodsInSchedule; + double hoursPerWorkPeriod; + + double fixedCostOfPartTimeEmployeesPerSchedule; + double hourlyRateOfPartTimeEmployees; + double minWorkingHoursOfPartTimeEmployeesPerSchedule; + double maxWorkingHoursOfPartTimeEmployeesPerSchedule; + int minWorkingPeriodsOfPartTimeEmployeesPerSchedule; + int maxWorkingPeriodsOfPartTimeEmployeesPerSchedule; + + double fixedCostOfFullTimeEmployeesPerSchedule; + double regularHourlyRateOfFullTimeEmployees; + double overtimeHourlyRateOfFullTimeEmployees; + double workingHoursOfFullTimeEmployeesPerSchedule; + double maxWorkingHoursOfFullTimeEmployeesPerSchedule; + int workingPeriodsOfFullTimeEmployeesPerSchedule; + int maxWorkingPeriodsOfFullTimeEmployeesPerSchedule; + + double workingHoursPaidAtRegularHourlyRatePerSchedule; + + public int[] requiredWorkforce; + Tuples enumerationWorkPeriodsSchedulesOfFullTimeEmployees; + + public ParametersInitialSchedules() { + + this.setGeneralParameters(); + this.setPartTimeEmployeesParameters(); + this.setFullTimeEmployeesParameters(); + this.setRequiredWorkforce(); + this.setWorkPeriodsSchedulesOfFullTimeEmployees(); + + } + + private void setGeneralParameters() { + this.workPeriodsPerDay = 6; + this.shiftWorkPerDay = 3; + this.daysPerSchedule = 14; + this.hoursPerWorkPeriod = 4; + this.workPeriodsPerSchedule = this.workPeriodsPerDay * this.daysPerSchedule; + } + + private void setPartTimeEmployeesParameters() { + this.fixedCostOfPartTimeEmployeesPerSchedule = 50; + this.hourlyRateOfPartTimeEmployees = 12; // To simulate lower productivity + this.minWorkingHoursOfPartTimeEmployeesPerSchedule = 32; + this.maxWorkingHoursOfPartTimeEmployeesPerSchedule = 64; + this.minWorkingPeriodsOfPartTimeEmployeesPerSchedule + = (int) (this.minWorkingHoursOfPartTimeEmployeesPerSchedule / this.hoursPerWorkPeriod); + this.maxWorkingPeriodsOfPartTimeEmployeesPerSchedule + = (int) (this.maxWorkingHoursOfPartTimeEmployeesPerSchedule / this.hoursPerWorkPeriod); + } + + private void setFullTimeEmployeesParameters() { + this.fixedCostOfFullTimeEmployeesPerSchedule = 50; + this.regularHourlyRateOfFullTimeEmployees = 10; + this.overtimeHourlyRateOfFullTimeEmployees = 15; + + this.workingHoursOfFullTimeEmployeesPerSchedule = 80; + this.maxWorkingHoursOfFullTimeEmployeesPerSchedule = 120; + this.workingPeriodsOfFullTimeEmployeesPerSchedule + = (int) (this.workingHoursOfFullTimeEmployeesPerSchedule / this.hoursPerWorkPeriod); + this.maxWorkingPeriodsOfFullTimeEmployeesPerSchedule + = (int) (this.maxWorkingHoursOfFullTimeEmployeesPerSchedule / this.hoursPerWorkPeriod); + + this.workingHoursPaidAtRegularHourlyRatePerSchedule = 80; + } + + private void setRequiredWorkforce() { + + this.requiredWorkforce = new int[this.daysPerSchedule * this.workPeriodsPerDay]; + this.totalWorkedPeriodsInSchedule = 0; + for (int day = 0; day < this.daysPerSchedule; day++) { + // A ameliorer + this.requiredWorkforce[day * this.workPeriodsPerDay + 0] = 2; + this.requiredWorkforce[day * this.workPeriodsPerDay + 1] = 2; + this.requiredWorkforce[day * this.workPeriodsPerDay + 2] = 4; + this.requiredWorkforce[day * this.workPeriodsPerDay + 3] = 4; + this.requiredWorkforce[day * this.workPeriodsPerDay + 4] = 3; + this.requiredWorkforce[day * this.workPeriodsPerDay + 5] = 3; + this.totalWorkedPeriodsInSchedule += (2 * 2 + 2 * 4 + 2 * 3); + } + + } + + private void setWorkPeriodsSchedulesOfFullTimeEmployees() { + + int[][] dailySchedulesOfFullTimeEmployees = new int[][]{ + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 1, 1, 1, 1, 0, 0, 1, 0, 1, 1, 1, 1, 1}, + {0, 1, 1, 1, 1, 0, 0, 1, 1, 0, 1, 1, 1, 1}, + {0, 1, 1, 1, 1, 0, 0, 1, 1, 1, 0, 1, 1, 1}, + {0, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 0, 1, 1}, + {1, 0, 1, 1, 1, 0, 0, 1, 1, 0, 1, 1, 1, 1}, + {1, 0, 1, 1, 1, 0, 0, 1, 1, 1, 0, 1, 1, 1}, + {1, 0, 1, 1, 1, 0, 0, 1, 1, 1, 1, 0, 1, 1}, + {1, 1, 0, 1, 1, 0, 0, 1, 1, 1, 0, 1, 1, 1}, + {1, 1, 0, 1, 1, 0, 0, 1, 1, 1, 1, 0, 1, 1}, + {1, 1, 1, 0, 1, 0, 0, 1, 1, 1, 1, 0, 1, 1}, + {1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 0, 0}, + {1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 0, 0}, + {1, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 0, 0}, + {1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 1, 0, 0}, + {1, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 1, 0, 0}, + {1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 0, 0}, + {1, 1, 1, 1, 0, 1, 1, 0, 1, 1, 1, 1, 0, 0}, + {1, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 0}, + {1, 1, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 0, 0}, + {1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 1, 0, 0},}; + + int possibleDailyScheduleOfFullTimeEmployees = dailySchedulesOfFullTimeEmployees.length; + + int[][] workPeriodsSchedulesOfFullTimeEmployees + = new int[possibleDailyScheduleOfFullTimeEmployees * this.shiftWorkPerDay][this.workPeriodsPerSchedule]; + + // Cette fonction sera a ameliorer avec des sous-fonctions, car elle n'est pas tres explicite. + for (int scheduleNumber = 0; scheduleNumber < possibleDailyScheduleOfFullTimeEmployees; scheduleNumber++) { + for (int day = 0; day < this.daysPerSchedule; day++) { + for (int shiftNumber = 0; shiftNumber < this.shiftWorkPerDay; shiftNumber++) { + if (dailySchedulesOfFullTimeEmployees[scheduleNumber][day] == 1 && shiftNumber == 0) { + workPeriodsSchedulesOfFullTimeEmployees[scheduleNumber * this.shiftWorkPerDay + shiftNumber][day * this.workPeriodsPerDay + 0] = 1; + workPeriodsSchedulesOfFullTimeEmployees[scheduleNumber * this.shiftWorkPerDay + shiftNumber][day * this.workPeriodsPerDay + 1] = 1; + workPeriodsSchedulesOfFullTimeEmployees[scheduleNumber * this.shiftWorkPerDay + shiftNumber][day * this.workPeriodsPerDay + 2] = 0; + workPeriodsSchedulesOfFullTimeEmployees[scheduleNumber * this.shiftWorkPerDay + shiftNumber][day * this.workPeriodsPerDay + 3] = 0; + workPeriodsSchedulesOfFullTimeEmployees[scheduleNumber * this.shiftWorkPerDay + shiftNumber][day * this.workPeriodsPerDay + 4] = 0; + workPeriodsSchedulesOfFullTimeEmployees[scheduleNumber * this.shiftWorkPerDay + shiftNumber][day * this.workPeriodsPerDay + 5] = 0; + } else if (dailySchedulesOfFullTimeEmployees[scheduleNumber][day] == 1 && shiftNumber == 1) { + workPeriodsSchedulesOfFullTimeEmployees[scheduleNumber * this.shiftWorkPerDay + shiftNumber][day * this.workPeriodsPerDay + 0] = 0; + workPeriodsSchedulesOfFullTimeEmployees[scheduleNumber * this.shiftWorkPerDay + shiftNumber][day * this.workPeriodsPerDay + 1] = 0; + workPeriodsSchedulesOfFullTimeEmployees[scheduleNumber * this.shiftWorkPerDay + shiftNumber][day * this.workPeriodsPerDay + 2] = 1; + workPeriodsSchedulesOfFullTimeEmployees[scheduleNumber * this.shiftWorkPerDay + shiftNumber][day * this.workPeriodsPerDay + 3] = 1; + workPeriodsSchedulesOfFullTimeEmployees[scheduleNumber * this.shiftWorkPerDay + shiftNumber][day * this.workPeriodsPerDay + 4] = 0; + workPeriodsSchedulesOfFullTimeEmployees[scheduleNumber * this.shiftWorkPerDay + shiftNumber][day * this.workPeriodsPerDay + 5] = 0; + } else if (dailySchedulesOfFullTimeEmployees[scheduleNumber][day] == 1 && shiftNumber == 2) { + workPeriodsSchedulesOfFullTimeEmployees[scheduleNumber * this.shiftWorkPerDay + shiftNumber][day * this.workPeriodsPerDay + 0] = 0; + workPeriodsSchedulesOfFullTimeEmployees[scheduleNumber * this.shiftWorkPerDay + shiftNumber][day * this.workPeriodsPerDay + 1] = 0; + workPeriodsSchedulesOfFullTimeEmployees[scheduleNumber * this.shiftWorkPerDay + shiftNumber][day * this.workPeriodsPerDay + 2] = 0; + workPeriodsSchedulesOfFullTimeEmployees[scheduleNumber * this.shiftWorkPerDay + shiftNumber][day * this.workPeriodsPerDay + 3] = 0; + workPeriodsSchedulesOfFullTimeEmployees[scheduleNumber * this.shiftWorkPerDay + shiftNumber][day * this.workPeriodsPerDay + 4] = 1; + workPeriodsSchedulesOfFullTimeEmployees[scheduleNumber * this.shiftWorkPerDay + shiftNumber][day * this.workPeriodsPerDay + 5] = 1; + } else if (dailySchedulesOfFullTimeEmployees[scheduleNumber][day] == 0) { + workPeriodsSchedulesOfFullTimeEmployees[scheduleNumber * this.shiftWorkPerDay + shiftNumber][day * this.workPeriodsPerDay + 0] = 0; + workPeriodsSchedulesOfFullTimeEmployees[scheduleNumber * this.shiftWorkPerDay + shiftNumber][day * this.workPeriodsPerDay + 1] = 0; + workPeriodsSchedulesOfFullTimeEmployees[scheduleNumber * this.shiftWorkPerDay + shiftNumber][day * this.workPeriodsPerDay + 2] = 0; + workPeriodsSchedulesOfFullTimeEmployees[scheduleNumber * this.shiftWorkPerDay + shiftNumber][day * this.workPeriodsPerDay + 3] = 0; + workPeriodsSchedulesOfFullTimeEmployees[scheduleNumber * this.shiftWorkPerDay + shiftNumber][day * this.workPeriodsPerDay + 4] = 0; + workPeriodsSchedulesOfFullTimeEmployees[scheduleNumber * this.shiftWorkPerDay + shiftNumber][day * this.workPeriodsPerDay + 5] = 0; + } + } + } + } + + // Creation des tuples a partir du tableau pour creer les 3 types de quart de travail (nuit, jour soir). + this.enumerationWorkPeriodsSchedulesOfFullTimeEmployees + = new Tuples(workPeriodsSchedulesOfFullTimeEmployees, true); + } + + // A implementer plus tard si l'on veut travailler avec des fichiers texte + public ParametersInitialSchedules(String fileName) { + +// String line = null; +// try { +// FileReader fileReader = +// new FileReader(fileName); +// +// BufferedReader bufferedReader = +// new BufferedReader(fileReader); +// +// if((line = bufferedReader.readLine()) != null) { +// String[] arrayLine= line.split("\\s+"); +// PARAMETRES_HORAIRE[0] = Integer.parseInt(arrayLine[0]); +// PARAMETRES_HORAIRE[1] = Integer.parseInt(arrayLine[1]); +// PARAMETRES_HORAIRE[2] = Integer.parseInt(arrayLine[2]); +// PARAMETRES_HORAIRE[3] = Integer.parseInt(arrayLine[3]); +// } +// if((line = bufferedReader.readLine()) != null) { +// String[] arrayLine= line.split("\\s+"); +// for (int i = 0 ; i < p ; i++) { +// NBR_EMPLOYES_REQUIS[i] = Integer.parseInt(arrayLine[i]); +// } +// } +// if((line = bufferedReader.readLine()) != null) { +// String[] arrayLine= line.split("\\s+"); +// for (int i = 0 ; i < p ; i++) { +// NBR_EMPLOYES_SOUHAITES[i] = Integer.parseInt(arrayLine[i]); +// } +// } +// bufferedReader.close(); +// } +// catch(FileNotFoundException ex) { +// System.out.println( +// "Unable to open file '" + +// fileName + "'"); +// } +// catch(IOException ex) { +// System.out.println( +// "Error reading file '" +// + fileName + "'"); +// } + } + +} diff --git a/tp/code/TP/Travail_de_session/InitialSchedules/UtilInitialSchedules.java b/tp/code/TP/Travail_de_session/InitialSchedules/UtilInitialSchedules.java new file mode 100644 index 0000000..4705b5c --- /dev/null +++ b/tp/code/TP/Travail_de_session/InitialSchedules/UtilInitialSchedules.java @@ -0,0 +1,97 @@ +package InitialSchedules; + +// classe statique pour mettre fonction utilitaire +public class UtilInitialSchedules { + + private UtilInitialSchedules() { + } + + public static void refineInitialSchedules() { + // A implementer si on veut rafiner la banque d'horaires initiales + } + + public static void printSolutionResults(ModelInitialSchedules myModelInitialSchedules, ParametersInitialSchedules myScheduleParameters) { + // Cette fonction sera a ameliorer avec des sous-fonctions, car elle n'est pas tres explicite. + System.out.print("Schedule Day "); + for (int day = 1; day <= myScheduleParameters.daysPerSchedule; day++) { + System.out.print(day); + System.out.print(" "); + if (day < 10) { + System.out.print(" "); + } + System.out.print("|"); + } + System.out.print("Worked Periods"); + System.out.println(""); + System.out.println("Part-Time Employees"); + int partTimeemployeeNo = 1; + for (int employee = 0; employee < myModelInitialSchedules.maxPartTimeEmployee; employee++) { + if (myModelInitialSchedules.workingPeriodsPerPartTimeEmployees[employee].getValue() != 0) { + System.out.print("Employee "); + System.out.print(partTimeemployeeNo); + System.out.print(" "); + if (partTimeemployeeNo < 10) { + System.out.print(" "); + } + for (int workPeriod = 0; workPeriod < myScheduleParameters.workPeriodsPerSchedule; workPeriod++) { + if (myModelInitialSchedules.workPeriodsSchedulesOfPartTimeEmployees[employee][workPeriod].getValue() == 1) { + System.out.print("1"); + } else { + System.out.print("0"); + + } + if (workPeriod % 6 == 5 && workPeriod != 0) { + System.out.print("|"); + } + } + System.out.print(myModelInitialSchedules.workingPeriodsPerPartTimeEmployees[employee].getValue()); + System.out.println(""); + partTimeemployeeNo++; + } + } + int fullTimeemployeeNo = 1; + System.out.println("Full-Time Employees"); + for (int employee = 0; employee < myModelInitialSchedules.maxFullTimeEmployee; employee++) { + if (myModelInitialSchedules.workingPeriodsPerFullTimeEmployees[employee].getValue() != 0) { + System.out.print("Employee "); + System.out.print(fullTimeemployeeNo); + System.out.print(" "); + if (fullTimeemployeeNo < 10) { + System.out.print(" "); + } + for (int workPeriod = 0; workPeriod < myScheduleParameters.workPeriodsPerSchedule; workPeriod++) { + if (myModelInitialSchedules.workPeriodsSchedulesOfFullTimeEmployees[employee][workPeriod].getValue() == 1) { + System.out.print("1"); + } else { + System.out.print("0"); + + } + if (workPeriod % 6 == 5 && workPeriod != 0) { + System.out.print("|"); + } + } + System.out.print(myModelInitialSchedules.workingPeriodsPerFullTimeEmployees[employee].getValue()); + System.out.println(""); + fullTimeemployeeNo++; + } + } + System.out.print("Working Employees "); + for (int workPeriod = 0; workPeriod < myScheduleParameters.workPeriodsPerSchedule; workPeriod++) { + System.out.print(myModelInitialSchedules.employeesPerWorkPeriods[workPeriod].getValue()); + if (workPeriod % 6 == 5 && workPeriod != 0) { + System.out.print("|"); + } + } + System.out.println(""); + System.out.print("Required Workforce "); + for (int workPeriod = 0; workPeriod < myScheduleParameters.workPeriodsPerSchedule; workPeriod++) { + System.out.print(myScheduleParameters.requiredWorkforce[workPeriod]); + if (workPeriod % 6 == 5 && workPeriod != 0) { + System.out.print("|"); + } + } + System.out.println(""); + + } + +} diff --git a/tp/code/TP/Travail_de_session/MainClass.java b/tp/code/TP/Travail_de_session/MainClass.java new file mode 100644 index 0000000..e87a43e --- /dev/null +++ b/tp/code/TP/Travail_de_session/MainClass.java @@ -0,0 +1,37 @@ + +import org.chocosolver.solver.Solver; + +public class MainClass { + + public static void main(String[] args) { + + // Le main ne devrait contenir que les 5 fonctions correspondantes aux etapes du pipeline + generateInitialSchedule(); + + // Creer les simulation avec une autre classe. Faire un nouveau package de fonctions. + // Algo de recouvrement d'absences. Faire un nouveau package de fonctions. + // Trouver meilleure solution et l'afficher. + } + + private static void generateInitialSchedule() { + + InitialSchedules.ParametersInitialSchedules myScheduleParameters + = new InitialSchedules.ParametersInitialSchedules(); + + InitialSchedules.ModelInitialSchedules myModelInitialSchedules + = new InitialSchedules.ModelInitialSchedules(myScheduleParameters); + + Solver solverInitialSchedules = myModelInitialSchedules.chocoModelInitialSchedules.getSolver(); + solverInitialSchedules.findSolution(); +// Solution bestInitialSchedules = solverInitialSchedules.findOptimalSolution +// (myModelInitialSchedules.scheduleProfit, Model.MINIMIZE); + + // fonction pour reduire le nombre d'horaire dans la banque d'horaire. +// InitialSchedules.UtilInitialSchedules.refineInitialSchedules(bestInitialSchedules); + // On pourrait creer un petit interface pour afficher les horaires optimales et les statistiques. + InitialSchedules.UtilInitialSchedules.printSolutionResults(myModelInitialSchedules, myScheduleParameters); + solverInitialSchedules.printStatistics(); + + //TODO Creer objet banque horaire + } +} diff --git a/tp/code/TP/Travail_de_session/choco-solver-4.0.6-with-dependencies.jar b/tp/code/TP/Travail_de_session/choco-solver-4.0.6-with-dependencies.jar new file mode 100644 index 0000000..0c8c6d9 Binary files /dev/null and b/tp/code/TP/Travail_de_session/choco-solver-4.0.6-with-dependencies.jar differ diff --git a/tp/code/Travail_de_session/InitialSchedules/ModelInitialSchedules.java b/tp/code/Travail_de_session/InitialSchedules/ModelInitialSchedules.java index e596bbd..ea9d829 100644 --- a/tp/code/Travail_de_session/InitialSchedules/ModelInitialSchedules.java +++ b/tp/code/Travail_de_session/InitialSchedules/ModelInitialSchedules.java @@ -20,10 +20,12 @@ public class ModelInitialSchedules { public int maxPartTimeEmployee; public int maxFullTimeEmployee; - public IntVar workPeriodsSchedulesOfPartTimeEmployees[][]; - private IntVar transposeWorkPeriodsSchedulesOfPartTimeEmployees[][]; - public IntVar workPeriodsSchedulesOfFullTimeEmployees[][]; - private IntVar transposeWorkPeriodsSchedulesOfFullTimeEmployees[][]; + public BoolVar workPeriodsSchedulesOfPartTimeEmployees[][]; + private BoolVar transposeWorkPeriodsSchedulesOfPartTimeEmployees[][]; + public BoolVar workPeriodsSchedulesOfFullTimeEmployees[][]; + private BoolVar transposeWorkPeriodsSchedulesOfFullTimeEmployees[][]; + + public BoolVar allWorkPeriods[]; public IntVar workingPeriodsPerPartTimeEmployees[]; public IntVar partTimeEmployeesPerWorkPeriods[]; @@ -61,22 +63,39 @@ public class ModelInitialSchedules { private void createScheduleVariables() { // Variable pour l'horaire des employes - this.workPeriodsSchedulesOfPartTimeEmployees = chocoModelInitialSchedules.intVarMatrix(this.maxPartTimeEmployee, this.myScheduleParameters.workPeriodsPerSchedule, 0, 1); - this.workPeriodsSchedulesOfFullTimeEmployees = chocoModelInitialSchedules.intVarMatrix(this.maxFullTimeEmployee, this.myScheduleParameters.workPeriodsPerSchedule, 0, 1); + this.workPeriodsSchedulesOfPartTimeEmployees = chocoModelInitialSchedules.boolVarMatrix(this.maxPartTimeEmployee, this.myScheduleParameters.workPeriodsPerSchedule); + this.workPeriodsSchedulesOfFullTimeEmployees = chocoModelInitialSchedules.boolVarMatrix(this.maxFullTimeEmployee, this.myScheduleParameters.workPeriodsPerSchedule); + + // Vecteur de toutes les variables + this.allWorkPeriods = chocoModelInitialSchedules.boolVarArray((this.maxPartTimeEmployee+this.maxFullTimeEmployee)*this.myScheduleParameters.workPeriodsPerSchedule); + + for (int employee = 0; employee < this.maxPartTimeEmployee; employee++) { + for(int workPeriod = 0; workPeriod < this.myScheduleParameters.workPeriodsPerSchedule; workPeriod++){ + this.allWorkPeriods[employee*this.myScheduleParameters.workPeriodsPerSchedule+workPeriod] = + this.workPeriodsSchedulesOfPartTimeEmployees[employee][workPeriod]; + } + } + for (int employee = 0; employee < this.maxFullTimeEmployee; employee++) { + for(int workPeriod = 0; workPeriod < this.myScheduleParameters.workPeriodsPerSchedule; workPeriod++){ + this.allWorkPeriods[this.maxPartTimeEmployee*this.myScheduleParameters.workPeriodsPerSchedule+ + employee*this.myScheduleParameters.workPeriodsPerSchedule+workPeriod] = + this.workPeriodsSchedulesOfFullTimeEmployees[employee][workPeriod]; + } + } // Variable pour faire le compte du nombre d'heures des employes this.workingPeriodsPerPartTimeEmployees = chocoModelInitialSchedules.intVarArray(this.maxPartTimeEmployee, 0, this.myScheduleParameters.workPeriodsPerSchedule, true); this.workingPeriodsPerFullTimeEmployees = chocoModelInitialSchedules.intVarArray(this.maxFullTimeEmployee, 0, this.myScheduleParameters.workPeriodsPerSchedule, true); // Creer la transpose des horaires pour compter les elements des colonnes - this.transposeWorkPeriodsSchedulesOfPartTimeEmployees = chocoModelInitialSchedules.intVarMatrix(this.myScheduleParameters.workPeriodsPerSchedule, this.maxPartTimeEmployee, 0, 1); + this.transposeWorkPeriodsSchedulesOfPartTimeEmployees = chocoModelInitialSchedules.boolVarMatrix(this.myScheduleParameters.workPeriodsPerSchedule, this.maxPartTimeEmployee); for (int workPeriod = 0; workPeriod < this.myScheduleParameters.workPeriodsPerSchedule; workPeriod++) { for (int employee = 0; employee < this.maxPartTimeEmployee; employee++) { this.transposeWorkPeriodsSchedulesOfPartTimeEmployees[workPeriod][employee] = this.workPeriodsSchedulesOfPartTimeEmployees[employee][workPeriod]; } } - this.transposeWorkPeriodsSchedulesOfFullTimeEmployees = chocoModelInitialSchedules.intVarMatrix(this.myScheduleParameters.workPeriodsPerSchedule, this.maxFullTimeEmployee, 0, 1); + this.transposeWorkPeriodsSchedulesOfFullTimeEmployees = chocoModelInitialSchedules.boolVarMatrix(this.myScheduleParameters.workPeriodsPerSchedule, this.maxFullTimeEmployee); for (int workPeriod = 0; workPeriod < this.myScheduleParameters.workPeriodsPerSchedule; workPeriod++) { for (int employee = 0; employee < this.maxFullTimeEmployee; employee++) { this.transposeWorkPeriodsSchedulesOfFullTimeEmployees[workPeriod][employee] @@ -141,6 +160,20 @@ public class ModelInitialSchedules { this.employeesPerWorkPeriods[workPeriod]).post(); } + + // Contrainte de bris de symétrie: + // chaque horaire d'employé est léxicographiquement inférieure à la suivante, par type d'employé + // Ne fonctionne pas avec l'heuristique par défaut + /*for (int employee = 0; employee < (this.maxPartTimeEmployee-1); employee++){ + chocoModelInitialSchedules.lexLessEq(this.workPeriodsSchedulesOfPartTimeEmployees[employee], + this.workPeriodsSchedulesOfPartTimeEmployees[employee+1]).post(); + }*/ + /*for (int employee = 0; employee < (this.maxFullTimeEmployee-1); employee++){ + chocoModelInitialSchedules.lexLessEq(this.workPeriodsSchedulesOfFullTimeEmployees[employee], + this.workPeriodsSchedulesOfFullTimeEmployees[employee+1]).post(); + }*/ + + } private void createModelObjectiveFunction() { diff --git a/tp/code/Travail_de_session/InitialSchedules/ParametersInitialSchedules.java b/tp/code/Travail_de_session/InitialSchedules/ParametersInitialSchedules.java index 07251a4..09a8ea7 100644 --- a/tp/code/Travail_de_session/InitialSchedules/ParametersInitialSchedules.java +++ b/tp/code/Travail_de_session/InitialSchedules/ParametersInitialSchedules.java @@ -79,17 +79,13 @@ public class ParametersInitialSchedules { this.requiredWorkforce = new int[this.daysPerSchedule * this.workPeriodsPerDay]; this.totalWorkedPeriodsInSchedule = 0; + int[] dailyRequiredWorkforce = new int[]{4,4,5,5,3,3}; for (int day = 0; day < this.daysPerSchedule; day++) { - // A ameliorer - this.requiredWorkforce[day * this.workPeriodsPerDay + 0] = 2; - this.requiredWorkforce[day * this.workPeriodsPerDay + 1] = 2; - this.requiredWorkforce[day * this.workPeriodsPerDay + 2] = 4; - this.requiredWorkforce[day * this.workPeriodsPerDay + 3] = 4; - this.requiredWorkforce[day * this.workPeriodsPerDay + 4] = 3; - this.requiredWorkforce[day * this.workPeriodsPerDay + 5] = 3; - this.totalWorkedPeriodsInSchedule += (2 * 2 + 2 * 4 + 2 * 3); + for(int shift = 0; shift < this.workPeriodsPerDay; shift++) { + this.requiredWorkforce[day * this.workPeriodsPerDay + shift] = dailyRequiredWorkforce[shift]; + this.totalWorkedPeriodsInSchedule += dailyRequiredWorkforce[shift]; + } } - } private void setWorkPeriodsSchedulesOfFullTimeEmployees() { diff --git a/tp/code/Travail_de_session/InitialSchedules/UtilInitialSchedules.java b/tp/code/Travail_de_session/InitialSchedules/UtilInitialSchedules.java index 4705b5c..9285298 100644 --- a/tp/code/Travail_de_session/InitialSchedules/UtilInitialSchedules.java +++ b/tp/code/Travail_de_session/InitialSchedules/UtilInitialSchedules.java @@ -26,7 +26,7 @@ public class UtilInitialSchedules { System.out.println("Part-Time Employees"); int partTimeemployeeNo = 1; for (int employee = 0; employee < myModelInitialSchedules.maxPartTimeEmployee; employee++) { - if (myModelInitialSchedules.workingPeriodsPerPartTimeEmployees[employee].getValue() != 0) { + if (myModelInitialSchedules.workingPeriodsPerPartTimeEmployees[employee].getValue() >= 0) { System.out.print("Employee "); System.out.print(partTimeemployeeNo); System.out.print(" "); @@ -40,7 +40,7 @@ public class UtilInitialSchedules { System.out.print("0"); } - if (workPeriod % 6 == 5 && workPeriod != 0) { + if (workPeriod % myScheduleParameters.workPeriodsPerDay == 5 && workPeriod != 0) { System.out.print("|"); } } @@ -52,7 +52,7 @@ public class UtilInitialSchedules { int fullTimeemployeeNo = 1; System.out.println("Full-Time Employees"); for (int employee = 0; employee < myModelInitialSchedules.maxFullTimeEmployee; employee++) { - if (myModelInitialSchedules.workingPeriodsPerFullTimeEmployees[employee].getValue() != 0) { + if (myModelInitialSchedules.workingPeriodsPerFullTimeEmployees[employee].getValue() >= 0) { System.out.print("Employee "); System.out.print(fullTimeemployeeNo); System.out.print(" "); diff --git a/tp/code/Travail_de_session/MainClass.java b/tp/code/Travail_de_session/MainClass.java index e87a43e..e3c20ef 100644 --- a/tp/code/Travail_de_session/MainClass.java +++ b/tp/code/Travail_de_session/MainClass.java @@ -1,5 +1,6 @@ import org.chocosolver.solver.Solver; +import org.chocosolver.solver.search.strategy.Search; public class MainClass { @@ -22,7 +23,9 @@ public class MainClass { = new InitialSchedules.ModelInitialSchedules(myScheduleParameters); Solver solverInitialSchedules = myModelInitialSchedules.chocoModelInitialSchedules.getSolver(); - solverInitialSchedules.findSolution(); + solverInitialSchedules.setSearch(Search.domOverWDegSearch(myModelInitialSchedules.allWorkPeriods)); + solverInitialSchedules.limitSolution(10); + solverInitialSchedules.findAllSolutions(); // Solution bestInitialSchedules = solverInitialSchedules.findOptimalSolution // (myModelInitialSchedules.scheduleProfit, Model.MINIMIZE);