menage
This commit is contained in:
parent
76c125998f
commit
2ab434fcbb
30 changed files with 0 additions and 2156 deletions
|
@ -1,116 +0,0 @@
|
|||
import org.chocosolver.solver.Model;
|
||||
import org.chocosolver.solver.Solver;
|
||||
import org.chocosolver.solver.search.limits.FailCounter;
|
||||
import org.chocosolver.solver.search.strategy.Search;
|
||||
import org.chocosolver.solver.search.strategy.selectors.variables.DomOverWDeg;
|
||||
import org.chocosolver.solver.search.strategy.selectors.variables.ImpactBased;
|
||||
import org.chocosolver.solver.variables.IntVar;
|
||||
|
||||
public class CarreMagique {
|
||||
public static final int HEURISTIQUE_DEFAUT = 0;
|
||||
public static final int HEURISTIQUE_DOMOVERWDEG = 1;
|
||||
public static final int HEURISTIQUE_IMPACT_BASED_SEARCH = 2;
|
||||
public static final int HEURISTIQUE_ACTIVITY = 3;
|
||||
public static final String COHERENCE_BORNES = "BC";
|
||||
public static final String COHERENCE_DOMAINES = "AC";
|
||||
|
||||
public static final int RESTART_AUCUN = 0;
|
||||
public static final int RESTART_LUBY = 1;
|
||||
public static final int RESTART_GEOMETRIQUE = 2;
|
||||
|
||||
public static void main(String[] args) {
|
||||
final int n = 12;
|
||||
|
||||
final int heuristique = HEURISTIQUE_ACTIVITY;
|
||||
final boolean bris_symetries = true;
|
||||
final int restart = RESTART_GEOMETRIQUE;
|
||||
final String coherence = COHERENCE_BORNES;
|
||||
|
||||
Model model = new Model("Carré magique");
|
||||
|
||||
// Creation d'une matrice de dimensions n x n de variables dont les domaines sont les entiers de 1 a n^2.
|
||||
IntVar[][] lignes = model.intVarMatrix("x", n, n, 1, n * n);
|
||||
|
||||
// Vecteur contenant toutes les variables de la matrice dans un seul vecteur
|
||||
IntVar[] toutesLesVariables = new IntVar[n * n];
|
||||
for (int i = 0; i < n * n; i++) {
|
||||
toutesLesVariables[i] = lignes[i / n][i % n];
|
||||
}
|
||||
|
||||
// Ajout d'une contrainte forcant toutes les variables a prendre des variables differentes
|
||||
model.allDifferent(toutesLesVariables, coherence).post();
|
||||
|
||||
// Creation de la tranpose de la matrice lignes.
|
||||
IntVar[][] colonnes = new IntVar[n][n];
|
||||
for (int i = 0; i < n; i++) {
|
||||
for (int j = 0; j < n; j++) {
|
||||
colonnes[i][j] = lignes[j][i];
|
||||
}
|
||||
}
|
||||
|
||||
final int sommeMagique = n * (n * n + 1) / 2;
|
||||
|
||||
// Creation d'une variable n'ayant qu'une seule valeur dans son domaine
|
||||
IntVar variableSommeMagique = model.intVar(sommeMagique);
|
||||
IntVar[] diagonale1 = new IntVar[n]; // Contient les variables sur la diagonale negative de la matrice
|
||||
IntVar[] diagonale2 = new IntVar[n]; // Contient les variables sur la diagonale positive de la matrice
|
||||
for (int i = 0; i < n; i++) {
|
||||
// Ajout de deux contraintes forcant les sommes des lignes et des colonnes a etre egales a la constante magique
|
||||
model.sum(lignes[i], "=", variableSommeMagique).post();
|
||||
model.sum(colonnes[i], "=", variableSommeMagique).post();
|
||||
diagonale1[i] = lignes[i][i];
|
||||
diagonale2[i] = lignes[n - i - 1][i];
|
||||
}
|
||||
model.sum(diagonale1, "=", variableSommeMagique).post();
|
||||
model.sum(diagonale2, "=", variableSommeMagique).post();
|
||||
|
||||
if (bris_symetries) {
|
||||
for (int i = 1; i < n / 2; i++)
|
||||
model.arithm(lignes[i - 1][i - 1], "<", lignes[i][i]).post();
|
||||
|
||||
model.arithm(lignes[0][0], "<", lignes[n - 1][0]).post();
|
||||
model.arithm(lignes[0][0], "<", lignes[0][n - 1]).post();
|
||||
model.arithm(lignes[0][0], "<", lignes[n - 1][n - 1]).post();
|
||||
// model.arithm(lignes[n - 1][0], "<", lignes[0][n - 1]).post();
|
||||
}
|
||||
|
||||
// Creation du solveur
|
||||
Solver solver = model.getSolver();
|
||||
|
||||
switch(heuristique) {
|
||||
case HEURISTIQUE_DOMOVERWDEG:
|
||||
solver.setSearch(Search.domOverWDegSearch(toutesLesVariables));
|
||||
break;
|
||||
case HEURISTIQUE_IMPACT_BASED_SEARCH:
|
||||
solver.setSearch(new ImpactBased(toutesLesVariables, true));
|
||||
break;
|
||||
case HEURISTIQUE_ACTIVITY:
|
||||
solver.setSearch(Search.activityBasedSearch(toutesLesVariables));
|
||||
break;
|
||||
}
|
||||
|
||||
switch(restart) {
|
||||
case RESTART_LUBY:
|
||||
solver.setLubyRestart(2, new FailCounter(model, 2), 25000);
|
||||
break;
|
||||
case RESTART_GEOMETRIQUE:
|
||||
solver.setGeometricalRestart(2, 2.1, new FailCounter(model, 2), 25000);
|
||||
break;
|
||||
}
|
||||
|
||||
solver.findSolution();
|
||||
|
||||
for (int i = 0; i < n; i++) {
|
||||
for (int j = 0; j < n; j++) {
|
||||
if (lignes[i][j].getValue() < 10)
|
||||
System.out.print(" ");
|
||||
if (lignes[i][j].getValue() < 100)
|
||||
System.out.print(" ");
|
||||
System.out.print(lignes[i][j].getValue());
|
||||
System.out.print(" ");
|
||||
}
|
||||
System.out.println("");
|
||||
}
|
||||
solver.printStatistics();
|
||||
}
|
||||
}
|
|
@ -1,10 +0,0 @@
|
|||
all: CarreMagique.class
|
||||
|
||||
%.class: %.java
|
||||
javac -cp .:choco-solver-4.0.6-with-dependencies.jar $<
|
||||
|
||||
run: CarreMagique.class
|
||||
java -cp .:choco-solver-4.0.6-with-dependencies.jar CarreMagique
|
||||
|
||||
clean:
|
||||
rm *.class
|
3
tp/.gitignore
vendored
3
tp/.gitignore
vendored
|
@ -1,3 +0,0 @@
|
|||
*.class
|
||||
*.aux
|
||||
|
Binary file not shown.
Before Width: | Height: | Size: 110 KiB |
|
@ -1,9 +0,0 @@
|
|||
@manual{chocoSolver,
|
||||
author = {Charles Prud'homme and Jean-Guillaume Fages and Xavier Lorca},
|
||||
title = {Choco Solver Documentation},
|
||||
year = {2016},
|
||||
organization = {TASC, INRIA Rennes, LINA CNRS UMR 6241, COSLING S.A.S.},
|
||||
timestamp = {Tue, 9 Feb 2016},
|
||||
url = {http://www.choco-solver.org},
|
||||
}
|
||||
|
|
@ -1,118 +0,0 @@
|
|||
import org.chocosolver.solver.Model;
|
||||
import org.chocosolver.solver.Solver;
|
||||
import org.chocosolver.solver.variables.IntVar;
|
||||
import org.chocosolver.solver.constraints.extension.Tuples;
|
||||
|
||||
public class Exercice1 {
|
||||
public static final int HEURISTIQUE_DEFAUT = 0;
|
||||
public static final int HEURISTIQUE_DOMOVERWDEG = 1;
|
||||
public static final int HEURISTIQUE_IMPACT_BASED_SEARCH = 2;
|
||||
public static final int HEURISTIQUE_ACTIVITY = 3;
|
||||
public static final String COHERENCE_BORNES = "BC";
|
||||
public static final String COHERENCE_DOMAINES = "AC";
|
||||
|
||||
public static final int RESTART_AUCUN = 0;
|
||||
public static final int RESTART_LUBY = 1;
|
||||
public static final int RESTART_GEOMETRIQUE = 2;
|
||||
|
||||
public static void main(String[] args) {
|
||||
|
||||
|
||||
final int N = 4;
|
||||
final int F = 4;
|
||||
final String coherence = COHERENCE_BORNES;
|
||||
|
||||
Model model = new Model("Quatre cubes");
|
||||
|
||||
// Énumération des combinaisons dans un tableau. 1: rouge, 2:vert, 3:bleu, 4:jaune
|
||||
int[][] tableauCubeUn = new int[][]{
|
||||
{3,4,1,2},{3,2,1,1},{3,2,1,4},{3,1,1,2},
|
||||
{2,3,4,1},{2,2,4,1},{2,1,4,3},{2,1,4,2},
|
||||
{1,2,3,4},{1,2,3,1},{1,4,3,2},{1,1,3,2},
|
||||
{4,2,2,1},{4,3,2,1},{4,1,2,2},{4,1,2,3},
|
||||
{2,4,1,2},{2,1,1,3},{2,2,1,4},{2,3,1,1},
|
||||
{1,4,2,2},{1,3,2,1},{1,2,2,4},{1,1,2,3},
|
||||
};
|
||||
|
||||
int[][] tableauCubeDeux = new int[][]{
|
||||
{4,2,3,2},{4,1,3,3},{4,2,3,2},{4,3,3,1},
|
||||
{2,1,2,3},{2,3,2,1},{2,3,2,4},{2,4,2,3},
|
||||
{3,1,4,3},{3,3,4,1},{3,2,4,2},{3,2,4,2},
|
||||
{2,1,2,3},{2,3,2,1},{2,4,2,3},{2,3,2,4},
|
||||
{1,3,3,4},{1,4,3,3},{1,2,3,2},{1,2,3,2},
|
||||
{3,4,1,3},{3,3,1,4},{3,2,1,2},{3,2,1,2},
|
||||
};
|
||||
int[][] tableauCubeTrois = new int[][]{
|
||||
{3,4,1,4},{3,4,1,4},{3,2,1,4},{3,4,1,2},
|
||||
{4,4,2,4},{4,4,2,4},{4,1,2,3},{4,3,2,1},
|
||||
{1,4,3,4},{1,4,3,4},{1,4,3,2},{1,2,3,4},
|
||||
{2,4,4,4},{2,4,4,4},{2,1,4,3},{2,3,4,1},
|
||||
{4,4,4,2},{4,2,4,4},{4,3,4,1},{4,1,4,3},
|
||||
{4,4,4,2},{4,2,4,4},{4,3,4,1},{4,1,4,3},
|
||||
};
|
||||
int[][] tableauCubeQuatre = new int[][]{
|
||||
{3,1,4,2},{3,2,4,1},{3,1,4,4},{3,4,4,1},
|
||||
{1,1,4,2},{1,2,4,1},{1,4,4,3},{1,3,4,4},
|
||||
{4,1,3,2},{4,2,3,1},{4,1,3,4},{4,4,3,1},
|
||||
{4,1,1,2},{4,2,1,1},{4,3,1,4},{4,4,1,3},
|
||||
{2,3,1,4},{2,4,1,3},{2,1,1,4},{2,4,1,1},
|
||||
{1,4,2,3},{1,3,2,4},{1,1,2,4},{1,4,2,1},
|
||||
};
|
||||
|
||||
// Création des tuples à partir des tableaux pour implémenter les contraintes table.
|
||||
Tuples tuplesCubeUn = new Tuples(tableauCubeUn, true);
|
||||
Tuples tuplesCubeDeux = new Tuples(tableauCubeDeux, true);
|
||||
Tuples tuplesCubeTrois = new Tuples(tableauCubeTrois, true);
|
||||
Tuples tuplesCubeQuatre = new Tuples(tableauCubeQuatre, true);
|
||||
|
||||
IntVar[][] facesCubes = model.intVarMatrix("x", N, F, 1, 4, false);
|
||||
|
||||
model.table(facesCubes[0], tuplesCubeUn).post();
|
||||
model.table(facesCubes[1], tuplesCubeDeux).post();
|
||||
model.table(facesCubes[2], tuplesCubeTrois).post();
|
||||
model.table(facesCubes[3], tuplesCubeQuatre).post();
|
||||
|
||||
// On créé la transpose de la matrice facesCubes pour pouvoir effectuer la contrainte ALLDIFFERENT.
|
||||
IntVar[][] faceRectangulaires = new IntVar[F][N];
|
||||
for (int noFace = 0; noFace < F; noFace++) {
|
||||
for (int noCube = 0; noCube < N; noCube++) {
|
||||
faceRectangulaires[noFace][noCube] = facesCubes[noCube][noFace];
|
||||
}
|
||||
model.allDifferent(faceRectangulaires[noFace], coherence).post();
|
||||
}
|
||||
|
||||
// Creation et lancement du solveur.
|
||||
Solver solver = model.getSolver();
|
||||
solver.findSolution();
|
||||
|
||||
// On affiche la solution.
|
||||
System.out.print(" ");
|
||||
for (int noCube = 0; noCube < N; noCube++) {
|
||||
System.out.print(" Cube ");
|
||||
System.out.print(noCube);
|
||||
System.out.print(" ");
|
||||
}
|
||||
System.out.println("");
|
||||
for (int noFace = 0; noFace < F; noFace++) {
|
||||
System.out.print(" Face ");
|
||||
System.out.print(noFace);
|
||||
System.out.print(" ");
|
||||
for (int noCube = 0; noCube < N; noCube++) {
|
||||
if (faceRectangulaires[noFace][noCube].getValue() == 1) {
|
||||
System.out.print(" R ");
|
||||
}else if (faceRectangulaires[noFace][noCube].getValue() == 2) {
|
||||
System.out.print(" V ");
|
||||
}else if (faceRectangulaires[noFace][noCube].getValue() == 3) {
|
||||
System.out.print(" B ");
|
||||
}else {
|
||||
System.out.print(" J ");
|
||||
}
|
||||
|
||||
System.out.print(" ");
|
||||
}
|
||||
System.out.println("");
|
||||
}
|
||||
solver.printStatistics();
|
||||
}
|
||||
}
|
||||
|
|
@ -1,198 +0,0 @@
|
|||
|
||||
import org.chocosolver.solver.Model;
|
||||
import org.chocosolver.solver.Solution;
|
||||
import org.chocosolver.solver.Solver;
|
||||
import org.chocosolver.solver.constraints.Constraint;
|
||||
import org.chocosolver.solver.exception.ContradictionException;
|
||||
import org.chocosolver.solver.search.limits.FailCounter;
|
||||
import org.chocosolver.solver.search.strategy.Search;
|
||||
import org.chocosolver.solver.search.strategy.selectors.variables.DomOverWDeg;
|
||||
import org.chocosolver.solver.search.strategy.selectors.variables.ImpactBased;
|
||||
import org.chocosolver.solver.variables.IntVar;
|
||||
import org.chocosolver.solver.variables.BoolVar;
|
||||
import java.io.*;
|
||||
import java.util.Arrays;
|
||||
|
||||
public class Exercice2FB {
|
||||
public static final int HEURISTIQUE_DEFAUT = 0;
|
||||
public static final int HEURISTIQUE_DOMOVERWDEG = 1;
|
||||
public static final int HEURISTIQUE_IMPACT_BASED_SEARCH = 2;
|
||||
public static final int HEURISTIQUE_ACTIVITY = 3;
|
||||
public static final String COHERENCE_BORNES = "BC";
|
||||
public static final String COHERENCE_DOMAINES = "AC";
|
||||
|
||||
public static final int RESTART_AUCUN = 0;
|
||||
public static final int RESTART_LUBY = 1;
|
||||
public static final int RESTART_GEOMETRIQUE = 2;
|
||||
|
||||
public static void main(String[] args) {
|
||||
|
||||
final int p = 16;
|
||||
String fileName = "instance.txt";
|
||||
String line = null;
|
||||
int[] PARAMETRES_HORAIRE = new int[4];
|
||||
int[] NBR_EMPLOYES_REQUIS = new int[p];
|
||||
int[] NBR_EMPLOYES_SOUHAITES = new int[p];
|
||||
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 + "'");
|
||||
}
|
||||
final int N = PARAMETRES_HORAIRE[0];
|
||||
final int MIN_H = PARAMETRES_HORAIRE[1];
|
||||
final int MAX_H = PARAMETRES_HORAIRE[2];
|
||||
final int MIN_PERIODE = PARAMETRES_HORAIRE[3];
|
||||
|
||||
Model model = new Model("Optimisation Employes");
|
||||
|
||||
IntVar heure_pause[] = model.intVarArray("HEURE_PAUSE", N, MIN_PERIODE, p-MIN_PERIODE-1, true);
|
||||
IntVar heure_debut[] = model.intVarArray("HEURE_DEBUT", N, 0, p-MIN_H, true);
|
||||
IntVar heure_fin[] = model.intVarArray("HEURE_FIN", N, p-MIN_H, p, true);
|
||||
|
||||
// Creation des contraintes
|
||||
for (int i = 0; i < N; i++) {
|
||||
model.arithm(heure_debut[i], "<=", heure_pause[i], "-", MIN_PERIODE).post();
|
||||
model.arithm(heure_fin[i], ">=", heure_pause[i], "+", (MIN_PERIODE + 1) ).post();
|
||||
}
|
||||
|
||||
IntVar[] heures_employe = model.intVarArray("C", N, MIN_H, MAX_H, true);
|
||||
for (int i = 0; i < N; i++) {
|
||||
model.arithm(heures_employe[i], "=", heure_fin[i], "-", heure_debut[i]).post();
|
||||
}
|
||||
|
||||
// Creation de la transpose de la matrice horaire.
|
||||
IntVar[][] horaire = model.intVarMatrix(p, N, 0, 1);
|
||||
IntVar[] nbr_employe = model.intVarArray("C", p, 0, N, true);
|
||||
for (int i = 0; i < p; i++) {
|
||||
for (int j = 0; j < N; j++) {
|
||||
BoolVar c1 = model.arithm(heure_pause[j], "!=", i).reify();
|
||||
BoolVar c2 = model.arithm(heure_debut[j], "<=", i).reify();
|
||||
BoolVar c3 = model.arithm(heure_fin[j], ">", i).reify();
|
||||
model.ifThenElse(model.and(c1, c2, c3), model.arithm(horaire[i][j], "=", 1), model.arithm(horaire[i][j], "=", 0));
|
||||
}
|
||||
model.count(model.intVar(1), horaire[i], nbr_employe[i]).post();
|
||||
model.arithm(nbr_employe[i], ">=", NBR_EMPLOYES_REQUIS[i]).post();
|
||||
}
|
||||
|
||||
IntVar[] diff_employe = model.intVarArray("DIFF_EMPLOYE", p, 0, N);
|
||||
IntVar[] diff_employe_abs = model.intVarArray("DIFF_EMPLOYE_ABS", p, 0, N);
|
||||
IntVar[] perte = model.intVarArray("COST", p, 0, 20 * N, true);
|
||||
for (int i = 0; i < p; i++) {
|
||||
model.arithm(diff_employe[i], "=", nbr_employe[i] , "-", NBR_EMPLOYES_SOUHAITES[i]).post();
|
||||
model.absolute(diff_employe_abs[i], diff_employe[i]).post();
|
||||
model.times(diff_employe_abs[i], model.intVar(20), perte[i]).post();
|
||||
|
||||
}
|
||||
|
||||
int[] coeffs = new int[p];
|
||||
Arrays.fill(coeffs, 0, p, 1);
|
||||
IntVar tot_perte = model.intVar("TOTAL_COST", 0, 20 * N * p, true);
|
||||
model.scalar(perte , coeffs , "=", tot_perte).post();
|
||||
|
||||
// Creation du solveur
|
||||
Solver solver = model.getSolver();
|
||||
Solution best = solver.findOptimalSolution(tot_perte, Model.MINIMIZE);
|
||||
for (int i = 0; i < N; i++) {
|
||||
System.out.print("Heure_debut : ");
|
||||
System.out.print(best.getIntVal(heure_debut[i]));
|
||||
System.out.print(" ");
|
||||
System.out.print("Heure_pause : ");
|
||||
System.out.print(best.getIntVal(heure_pause[i]));
|
||||
System.out.print(" ");
|
||||
System.out.print("Heure_fin : ");
|
||||
System.out.print(best.getIntVal(heure_fin[i]));
|
||||
System.out.println("");
|
||||
}
|
||||
System.out.print(9);
|
||||
System.out.print(" | ");
|
||||
System.out.print(" ");
|
||||
System.out.print(" | ");
|
||||
for (int j = 10; j < 17; j++) {
|
||||
System.out.print(j);
|
||||
System.out.print("| ");
|
||||
System.out.print(" ");
|
||||
System.out.print("| ");
|
||||
}
|
||||
System.out.print("Nbr_heures_travaillees_incluant_pause");
|
||||
System.out.println("");
|
||||
for (int i = 0; i < N; i++) {
|
||||
for (int j = 0; j < p; j++) {
|
||||
if (best.getIntVal(horaire[j][i]) == 1)
|
||||
System.out.print("1");
|
||||
else
|
||||
System.out.print(" ");
|
||||
System.out.print(" | ");
|
||||
}
|
||||
System.out.print(best.getIntVal(heures_employe[i]));
|
||||
System.out.println("");
|
||||
|
||||
}
|
||||
for (int i = 0; i < p; i++) {
|
||||
System.out.print(best.getIntVal(nbr_employe[i]));
|
||||
System.out.print(" | ");
|
||||
}
|
||||
System.out.print("Nbr_employes");
|
||||
System.out.println("");
|
||||
for (int i = 0; i < p; i++) {
|
||||
System.out.print(NBR_EMPLOYES_REQUIS[i]);
|
||||
System.out.print(" | ");
|
||||
}
|
||||
System.out.print("Nbr_employes_requis");
|
||||
System.out.println("");
|
||||
for (int i = 0; i < p; i++) {
|
||||
System.out.print(NBR_EMPLOYES_SOUHAITES[i]);
|
||||
System.out.print(" | ");
|
||||
}
|
||||
System.out.print("Nbr_employes_souhaites");
|
||||
System.out.println("");
|
||||
for (int i = 0; i < p; i++) {
|
||||
|
||||
System.out.print(best.getIntVal(perte[i]));
|
||||
if(best.getIntVal(perte[i])==0) {
|
||||
System.out.print(" | ");
|
||||
}else {
|
||||
System.out.print("| ");
|
||||
}
|
||||
}
|
||||
System.out.print("perte");
|
||||
System.out.println("");
|
||||
System.out.print("perte_totale : ");
|
||||
System.out.print(best.getIntVal(tot_perte));
|
||||
System.out.println("");
|
||||
solver.printStatistics();
|
||||
|
||||
}
|
||||
}
|
|
@ -1,220 +0,0 @@
|
|||
import java.nio.file.*;
|
||||
import java.io.IOException;
|
||||
import java.util.*;
|
||||
import org.chocosolver.solver.exception.ContradictionException;
|
||||
import org.chocosolver.solver.Model;
|
||||
import org.chocosolver.solver.variables.IntVar;
|
||||
import org.chocosolver.solver.variables.BoolVar;
|
||||
import org.chocosolver.solver.Solver;
|
||||
import org.chocosolver.solver.search.strategy.Search;
|
||||
import org.chocosolver.solver.search.limits.FailCounter;
|
||||
import org.chocosolver.solver.constraints.nary.automata.FA.FiniteAutomaton;
|
||||
import org.chocosolver.solver.search.strategy.selectors.variables.ImpactBased;
|
||||
import org.chocosolver.solver.Solution;
|
||||
|
||||
public class ProductionHoraire {
|
||||
public static final int N_PERIODE = 16;
|
||||
public static final int VALEUR_PERTE = 20;
|
||||
public static void main(String[] args) {
|
||||
|
||||
String instancePath = args[0];
|
||||
|
||||
// lecture des lignes du fichier d'instance
|
||||
String[] variablesInstance = null;
|
||||
String[] strLigne2 = null;
|
||||
String[] strLigne3 = null;
|
||||
try {
|
||||
List<String> lignesInstance = Files.readAllLines(Paths.get(instancePath));
|
||||
variablesInstance = lignesInstance.get(0).split("\\s+");
|
||||
strLigne2 = lignesInstance.get(1).split("\\s+");
|
||||
strLigne3 = lignesInstance.get(2).split("\\s+");
|
||||
}
|
||||
catch (IOException e){
|
||||
System.err.println("Caught IOException: " + e.getMessage());
|
||||
}
|
||||
catch (Exception e){
|
||||
System.err.println("Caught Exception: " + e.getMessage());
|
||||
}
|
||||
|
||||
// traitement de la 1re ligne
|
||||
Integer N = Integer.valueOf(variablesInstance[0]);
|
||||
Integer MIN_H = Integer.valueOf(variablesInstance[1]);
|
||||
Integer MAX_H = Integer.valueOf(variablesInstance[2]);
|
||||
Integer MIN_PERIODE = Integer.valueOf(variablesInstance[3]);
|
||||
|
||||
// traitement de la 2e ligne
|
||||
List<Integer> nbEmployesRequis = new ArrayList<>();
|
||||
for (String s: strLigne2) {
|
||||
Integer i = Integer.valueOf(s);
|
||||
nbEmployesRequis.add(i);
|
||||
}
|
||||
// traitement de la 3e ligne
|
||||
List<Integer> nbEmployesSouhaite = new ArrayList<>();
|
||||
for (String s: strLigne3) {
|
||||
Integer i = Integer.valueOf(s);
|
||||
nbEmployesSouhaite.add(i);
|
||||
}
|
||||
|
||||
// Vérification du fichier d'instance
|
||||
System.out.println("### Debut Validation Lecture Instance ###");
|
||||
System.out.println("N="+N.toString());
|
||||
System.out.println("MIN_H="+MIN_H.toString());
|
||||
System.out.println("MAX_H="+MAX_H.toString());
|
||||
System.out.println("MIN_PERIODE="+MIN_PERIODE.toString());
|
||||
System.out.println("nbEmployesRequis="+nbEmployesRequis.toString());
|
||||
System.out.println("nbEmployesSouhaite="+nbEmployesSouhaite.toString());
|
||||
System.out.println("### Fin Validation Lecture Instance ###");
|
||||
|
||||
Model model = new Model("Production Horaire");
|
||||
|
||||
// Création d'une matrice E de dimensions N x N_PERIODE de variables e(i,j) dont les domaines sont des variables binaires.
|
||||
// E(i,j)=0 signifie que l'employé i est au repos à la période j.
|
||||
// E(i,j)=1 signifie que l'employé i travaille à la période j.
|
||||
|
||||
BoolVar[][] LignesE = model.boolVarMatrix("E",N,N_PERIODE);
|
||||
|
||||
// Transposition de la matrice E
|
||||
BoolVar[][] ColonnesE = new BoolVar[N_PERIODE][N];
|
||||
for (Integer i = 0; i < N_PERIODE; i++) {
|
||||
for (Integer j = 0; j < N; j++) {
|
||||
ColonnesE[i][j] = LignesE[j][i];
|
||||
}
|
||||
}
|
||||
|
||||
// Vecteur contenant toutes les variables de la matrice dans un seul vecteur
|
||||
BoolVar[] toutesLesVariables = new BoolVar[N * N_PERIODE];
|
||||
for (Integer i = 0; i < N * N_PERIODE; i++) {
|
||||
toutesLesVariables[i] = LignesE[i / N_PERIODE][i % N];
|
||||
}
|
||||
|
||||
// Création de la contrainte du nombre requis d'employés
|
||||
|
||||
System.out.println("### Création: contrainte du nombre requis d'employés ###");
|
||||
|
||||
IntVar[] IVnbEmployesRequis = new IntVar[N_PERIODE];
|
||||
for (Integer i=0; i < N_PERIODE; i++) {
|
||||
IVnbEmployesRequis[i] = model.intVar(nbEmployesRequis.get(i));
|
||||
model.sum(ColonnesE[i], ">=", IVnbEmployesRequis[i]).post();
|
||||
}
|
||||
|
||||
// Création de l'automate fini pour la contrainte du motif d'horaire
|
||||
|
||||
System.out.println("### Création: contrainte du motif d'horaire ###");
|
||||
|
||||
Integer MAX_PERIODE = MAX_H-MIN_PERIODE-1;
|
||||
Integer MAX_PERIODE_REPOS = N_PERIODE-MIN_H-1;
|
||||
|
||||
String strAutomaton = "0{0,"+
|
||||
MAX_PERIODE_REPOS.toString()+
|
||||
"}1{"+
|
||||
MIN_PERIODE.toString()+
|
||||
","+
|
||||
MAX_PERIODE.toString()+
|
||||
"}01{"+
|
||||
MIN_PERIODE.toString()+
|
||||
","+
|
||||
MAX_PERIODE.toString()+
|
||||
"}0{0,"+
|
||||
MAX_PERIODE_REPOS.toString()+
|
||||
"}";
|
||||
|
||||
System.out.println("Expression régulière:"+strAutomaton);
|
||||
FiniteAutomaton FA = new FiniteAutomaton(strAutomaton);
|
||||
|
||||
// Constantes pour la contrainte du nombre minimum et maximum d'heures
|
||||
|
||||
IntVar MIN_H_TRAVAILLE = model.intVar(MIN_H-1);
|
||||
IntVar MAX_H_TRAVAILLE = model.intVar(MAX_H-1);
|
||||
|
||||
// Contrainte du motif d'horaire et du nombre minimum et maximum d'heures
|
||||
|
||||
for (Integer i=0; i<N; i++){
|
||||
model.regular(LignesE[i],FA).post();
|
||||
model.sum(LignesE[i], ">=", MIN_H_TRAVAILLE).post();
|
||||
model.sum(LignesE[i], "<=", MAX_H_TRAVAILLE).post();
|
||||
}
|
||||
|
||||
// Optimisation du nombre souhaité d'employés
|
||||
|
||||
System.out.println("### Création: Optimisation ###");
|
||||
|
||||
IntVar[] IVnbEmployesSouhaite = new IntVar[N_PERIODE];
|
||||
IntVar[] IVnbEmployesEffectif = new IntVar[N_PERIODE];
|
||||
IntVar[] IVnbEmployesDistance = new IntVar[N_PERIODE];
|
||||
|
||||
for (Integer i=0; i < N_PERIODE; i++) {
|
||||
IVnbEmployesEffectif[i] = model.intVar("nbEmployesEffectif",0,N);
|
||||
IVnbEmployesSouhaite[i] = model.intVar("nbEmployesSouhaite"+i.toString(),
|
||||
nbEmployesSouhaite.get(i));
|
||||
IVnbEmployesDistance[i] = model.intVar("nbEmployesDistance",0,N);
|
||||
model.sum(ColonnesE[i],"=",IVnbEmployesEffectif[i]).post();
|
||||
model.distance(IVnbEmployesEffectif[i],
|
||||
IVnbEmployesSouhaite[i],
|
||||
"=",
|
||||
IVnbEmployesDistance[i]).post();
|
||||
}
|
||||
|
||||
IntVar PERTE = model.intVar("perte",0,N*N_PERIODE);
|
||||
model.sum(IVnbEmployesDistance,"=",PERTE).post();
|
||||
|
||||
//model.setObjective(Model.MINIMIZE, PERTE);
|
||||
|
||||
// Creation du solveur
|
||||
|
||||
System.out.println("### Création: Solveur ###");
|
||||
|
||||
Solver solver = model.getSolver();
|
||||
|
||||
try {
|
||||
solver.propagate();
|
||||
}
|
||||
catch (ContradictionException e) {
|
||||
System.err.println("Caught ContradictionException: " + e.getMessage());
|
||||
solver.getEngine().flush();
|
||||
}
|
||||
catch (Exception e){
|
||||
System.err.println("Caught Exception: " + e.getMessage());
|
||||
}
|
||||
|
||||
// Résolution du modèle
|
||||
|
||||
System.out.println("### Résolution ###");
|
||||
|
||||
Solution maSolution = solver.findOptimalSolution(PERTE,Model.MINIMIZE);
|
||||
|
||||
// Affichage des résultats
|
||||
|
||||
System.out.println("### Meilleure Solution ###");
|
||||
|
||||
for (Integer i = 0; i < N; i++) {
|
||||
System.out.print("Employé "+i+": ");
|
||||
for (Integer j = 0; j < N_PERIODE; j++) {
|
||||
System.out.print(maSolution.getIntVal(LignesE[i][j]));
|
||||
System.out.print(" ");
|
||||
}
|
||||
System.out.println("");
|
||||
}
|
||||
|
||||
System.out.println("\nEmployés Totaux");
|
||||
System.out.print(" ");
|
||||
for (Integer j = 0; j < N_PERIODE; j++){
|
||||
System.out.print(maSolution.getIntVal(IVnbEmployesEffectif[j]));
|
||||
System.out.print(" ");
|
||||
}
|
||||
|
||||
System.out.println("\nEmployés Souhaités");
|
||||
System.out.print(" ");
|
||||
for (Integer j = 0; j < N_PERIODE; j++){
|
||||
System.out.print(maSolution.getIntVal(IVnbEmployesSouhaite[j]));
|
||||
System.out.print(" ");
|
||||
}
|
||||
System.out.println("");
|
||||
|
||||
Integer PERTE_OPT = solver.getBestSolutionValue().intValue()*VALEUR_PERTE;
|
||||
System.out.println("\nPerte optimale:"+PERTE_OPT.toString()+"$\n");
|
||||
|
||||
System.out.println("### Statistiques ###");
|
||||
|
||||
solver.printStatistics();
|
||||
}
|
||||
}
|
|
@ -1,152 +0,0 @@
|
|||
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();
|
||||
}
|
||||
|
||||
}
|
|
@ -1,211 +0,0 @@
|
|||
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 + "'");
|
||||
// }
|
||||
}
|
||||
|
||||
}
|
|
@ -1,97 +0,0 @@
|
|||
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("");
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -1,37 +0,0 @@
|
|||
|
||||
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
|
||||
}
|
||||
}
|
Binary file not shown.
Binary file not shown.
|
@ -1,3 +0,0 @@
|
|||
5 10 14 3
|
||||
1 1 1 1 1 1 1 1 1 1 1 1 1 1 2 2
|
||||
1 2 3 4 5 4 2 3 4 3 5 5 4 3 3 3
|
|
@ -1,12 +0,0 @@
|
|||
all: ProductionHoraire.class Exercice1.class Exercice2FB.class
|
||||
|
||||
%.class: %.java
|
||||
javac -cp .:choco-solver-4.0.6-with-dependencies.jar $<
|
||||
|
||||
run:
|
||||
java -cp .:choco-solver-4.0.6-with-dependencies.jar Exercice1
|
||||
java -cp .:choco-solver-4.0.6-with-dependencies.jar ProductionHoraire instance.txt
|
||||
java -cp .:choco-solver-4.0.6-with-dependencies.jar Exercice2FB instance.txt
|
||||
|
||||
clean:
|
||||
rm *.class
|
|
@ -1,185 +0,0 @@
|
|||
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 BoolVar workPeriodsSchedulesOfPartTimeEmployees[][];
|
||||
private BoolVar transposeWorkPeriodsSchedulesOfPartTimeEmployees[][];
|
||||
public BoolVar workPeriodsSchedulesOfFullTimeEmployees[][];
|
||||
private BoolVar transposeWorkPeriodsSchedulesOfFullTimeEmployees[][];
|
||||
|
||||
public BoolVar allWorkPeriods[];
|
||||
|
||||
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.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.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.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]
|
||||
= 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();
|
||||
}
|
||||
|
||||
|
||||
// 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() {
|
||||
|
||||
// this.scheduleProfit = chocoModelInitialSchedules.intVar("TOTAL_COST", 0, 20 * N * p, true);
|
||||
// chocoModelInitialSchedules.scalar(perte , coeffs , "=", this.scheduleProfit).post();
|
||||
}
|
||||
|
||||
}
|
|
@ -1,207 +0,0 @@
|
|||
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;
|
||||
int[] dailyRequiredWorkforce = new int[]{4,4,5,5,3,3};
|
||||
for (int day = 0; day < this.daysPerSchedule; day++) {
|
||||
for(int shift = 0; shift < this.workPeriodsPerDay; shift++) {
|
||||
this.requiredWorkforce[day * this.workPeriodsPerDay + shift] = dailyRequiredWorkforce[shift];
|
||||
this.totalWorkedPeriodsInSchedule += dailyRequiredWorkforce[shift];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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 + "'");
|
||||
// }
|
||||
}
|
||||
|
||||
}
|
|
@ -1,97 +0,0 @@
|
|||
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 % myScheduleParameters.workPeriodsPerDay == 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("");
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -1,40 +0,0 @@
|
|||
|
||||
import org.chocosolver.solver.Solver;
|
||||
import org.chocosolver.solver.search.strategy.Search;
|
||||
|
||||
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.setSearch(Search.domOverWDegSearch(myModelInitialSchedules.allWorkPeriods));
|
||||
solverInitialSchedules.limitSolution(10);
|
||||
solverInitialSchedules.findAllSolutions();
|
||||
// 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
|
||||
}
|
||||
}
|
Binary file not shown.
BIN
tp/logo.png
BIN
tp/logo.png
Binary file not shown.
Before Width: | Height: | Size: 104 KiB |
21
tp/makefile
21
tp/makefile
|
@ -1,21 +0,0 @@
|
|||
build: rapport.pdf
|
||||
|
||||
rapport.pdf: rapport.bbl
|
||||
pdflatex rapport.tex
|
||||
pdflatex rapport.tex
|
||||
|
||||
rapport.bbl: rapport.tex
|
||||
pdflatex rapport.tex
|
||||
bibtex rapport.aux
|
||||
|
||||
run: rapport.pdf
|
||||
-evince rapport.pdf &
|
||||
|
||||
clean:
|
||||
-rm *.aux
|
||||
-rm *.bbl
|
||||
-rm *.blg
|
||||
-rm *.lof
|
||||
-rm *.log
|
||||
-rm *.out
|
||||
-rm *.toc
|
|
@ -1,13 +0,0 @@
|
|||
\thispagestyle{empty} % Pour éviter d'avoir un en-tête et un pied de page sur la page couverture
|
||||
\includegraphics[width=5cm]{logo.png} % Pour inclure le logo (on précise la largeur de l'image)
|
||||
\vspace{4cm} % Espacement vertical
|
||||
\begin{center} % On centre le texte
|
||||
{\huge \bf \titre}\\ % \huge fait que le texte est gros, \bf fait que le texte est gras
|
||||
\vspace{4cm}
|
||||
\large Travail présenté à \destinataire \\ \cours\\
|
||||
\vspace{4cm}
|
||||
Réalisé par \\ \auteurs ;\\ \matricules
|
||||
\vfill % On va jusqu'au bas de la page avant de mettre le texte ci-dessous
|
||||
Dernière version produite le~\today~à~\currenttime
|
||||
\pagebreak
|
||||
\end{center}
|
121
tp/question1.tex
121
tp/question1.tex
|
@ -1,121 +0,0 @@
|
|||
\section{Problème 1}
|
||||
|
||||
Modélisation et résolution du problème des quatre cubes avec le solveur Choco 4 \cite{chocoSolver}.
|
||||
|
||||
\subsection{Constantes}
|
||||
\label{sec:q1constantes}
|
||||
|
||||
Deux constantes sont définies dans l'énoncé du problème. Il s'agit du nombre de cubes $N$ ainsi que du nombre de faces $F$ sur le prisme rectangulaire. Ces deux constantes sont fixées à 4.
|
||||
|
||||
Afin de faciliter la création des contraintes dans le solveur Choco, on définit une application: l'ensemble de nombres $\lbrace 1,2,3,4 \rbrace$ sert à représenter l'ensemble de quatre couleurs $\lbrace rouge, vert, bleu, jaune \rbrace$, dans cet ordre \eqref{eq:q1mapping}.
|
||||
|
||||
\begin{align}
|
||||
\label{eq:q1mapping}
|
||||
\left \{
|
||||
\begin{array}{lll}
|
||||
1 & \mapsto &\text{Rouge} \\
|
||||
2 & \mapsto &\text{Vert} \\
|
||||
3 & \mapsto &\text{Bleu} \\
|
||||
4 & \mapsto &\text{Jaune}
|
||||
\end{array}
|
||||
\right \}
|
||||
\end{align}
|
||||
|
||||
\subsection{Variables}
|
||||
\label{sec:q1variables}
|
||||
|
||||
On définit une matrice $FC$ de taille $N \times F$ où chaque variable $fc_{ij}$ correspond à la couleur que présente le cube $i$ sur la face $j$ du prisme rectangulaire.
|
||||
|
||||
\begin{align}
|
||||
\label{eq:q1v1}
|
||||
fc_{ij} &\in \lbrace 1,2,3,4 \rbrace & \forall 1 \leq i \leq N, 1 \leq j \leq F\\
|
||||
dom(fc_{ij}) &= \lbrace 1,2,3,4 \rbrace \in \theta(1) & \forall 1 \leq i \leq N, 1 \leq j \leq F\nonumber
|
||||
\end{align}
|
||||
|
||||
\subsubsection{Nombre total de variables et de valeurs}
|
||||
\label{sec:q1nbtotvar}
|
||||
|
||||
Le nombre total de variables pour la définition \eqref{eq:q1v1}:
|
||||
|
||||
\begin{align}
|
||||
\label{eq:q1vartot}
|
||||
NF \in \theta(NF)
|
||||
\end{align}
|
||||
|
||||
Le nombre total de valeurs possibles pour ces mêmes définitions est:
|
||||
\begin{align}
|
||||
\label{eq:q1valtot}
|
||||
NF \times 4 &= 4NF \in \theta(NF)
|
||||
\end{align}
|
||||
|
||||
\subsection{Contraintes}
|
||||
\label{sec:q1contraintes}
|
||||
|
||||
\subsubsection{Tableaux des couleurs}
|
||||
\label{sec:tableauCouleurs}
|
||||
|
||||
La contrainte du tableau des couleurs s'énonce comme suit: pour chaque cube $i$, un tableau doit être construit dans lequel seront énumérées toutes les séquences possibles des couleurs apparaissant sur les 4 faces du prisme. Pour chacun des 4 cubes, il y a 24 combinaisons (6 faces pointant dans une direction $\times$ 4 orientations par face) possibles. Si certaines combinaisons se répètent, ces doublons seront pris en charge par le solveur.
|
||||
|
||||
Il s'agit d'une contrainte de type \textsc{Tableau} qui s'écrit de la façon suivante :
|
||||
|
||||
\begin{align}
|
||||
\label{eq:q1c1}
|
||||
&\textsc{Tableau}(\lbrace fc_{i1},\dots,fc_{iF} \rbrace, T) & \forall 1 \leq i \leq N
|
||||
\end{align}
|
||||
|
||||
\subsubsection{Couleurs différentes sur les 4 faces}
|
||||
\label{sec:couleur4faces}
|
||||
|
||||
Le problème des 4 cubes consiste à trouver un agencement de ces cubes permettant d'obtenir chacune des 4 couleurs sur les 4 faces rectangulaires du prisme créé. Ce qui équivaut à ne pas avoir une paire de couleurs identiques sur une face latérale du prisme \eqref{eq:q1c2eq}.
|
||||
|
||||
\begin{align}
|
||||
\label{eq:q1c2eq}
|
||||
&fc_{ij_1} \neq fc_{ij_2} & \forall 1 \leq i \leq N, 1 \leq j_1 < j_2 \leq F\\
|
||||
\end{align}
|
||||
|
||||
Il s'agit d'une contrainte de type \textsc{AllDifferent} \eqref{eq:q1c2} pour chaque face latérale du prisme.
|
||||
|
||||
\begin{align}
|
||||
\label{eq:q1c2}
|
||||
\textsc{AllDifferent}(\lbrace fc_{i1},\ldots, fc_{iF} \rbrace ) & \forall 1 \leq i \leq N
|
||||
\end{align}
|
||||
|
||||
\subsubsection{Nombre total de contraintes}
|
||||
\label{sec:q1totcontr}
|
||||
|
||||
Le nombre total de contraintes pour les définitions \eqref{eq:q1c1} et \eqref{eq:q1c2} est:
|
||||
\begin{align}
|
||||
\label{eq:q1conttot}
|
||||
N \text{contraintes «tableau»} + \frac{4*N(N-1)}{2} \text{contraintes de différence} &= 2N^{2}-N \in \theta(N^{2})
|
||||
\end{align}
|
||||
\begin{center}
|
||||
De plus, chaque tableau contient au plus 24 $\in O(24)$ entrées.
|
||||
\end{center}
|
||||
|
||||
\subsection{Résultats}
|
||||
\label{sec:q1resultats}
|
||||
|
||||
Nous avons demandé au solveur Choco de trouver une solution au problème des 4 cubes à l'aide de la méthode \texttt{findSolution}. Nous avons utilisé les euristiques par défaut, car elles permettaient d'obtenir un résultat en moins d'une seconde. Le solveur trouve une seule solution en n'effectuant aucun retour arrière, et ce en 0,038s.
|
||||
|
||||
\subsubsection{Solution}
|
||||
La solution retournée par le solveur est représentée à la figure \ref{fig:q1sol}.
|
||||
|
||||
\begin{figure}[H]
|
||||
\centering
|
||||
\begin{verbatim}
|
||||
Cube 0 Cube 1 Cube 2 Cube 3
|
||||
Face 0 R B V J
|
||||
Face 1 V J B R
|
||||
Face 2 V R J B
|
||||
Face 3 J B R V
|
||||
\end{verbatim}
|
||||
\caption{Solution du problème 1}
|
||||
\label{fig:q1sol}
|
||||
\end{figure}
|
||||
|
||||
|
||||
|
||||
%%% Local Variables:
|
||||
%%% mode: latex
|
||||
%%% TeX-master: "rapport"
|
||||
%%% End:
|
213
tp/question2.tex
213
tp/question2.tex
|
@ -1,213 +0,0 @@
|
|||
|
||||
\section{Question 2}
|
||||
\label{sec:q2}
|
||||
|
||||
L'objectif de ce problème est de concevoir un horaire de travail avec minimisation de la perte de profit en utilisant le solveur Choco 4 \cite{chocoSolver}.
|
||||
|
||||
\subsection{Constantes}
|
||||
\label{sec:q2constantes}
|
||||
|
||||
Plusieurs constantes sont définies par l'énoncé du problème. On définit les périodes $t=1,\ldots,16$ de la journée comme étant des périodes de 30 minutes débutant à 9h00 et se terminant à 16h59.
|
||||
|
||||
\begin{itemize}
|
||||
\item $N$ = Nombre d'employés disponibles
|
||||
\item $MIN_H$ = Nombre minimal de périodes travaillées par l'employé, incluant la pause
|
||||
\item $MAX_H$ = Nombre maximal de périodes travaillées par l'employé, incluant la pause
|
||||
\item $MIN_{P}$ = Nombre minimal de périodes dans le bloc de travail précédant et suivant la pause
|
||||
\item $e_j^{req}$ = Nombre d'employés requis à la période $j \in \lbrace 1,16 \rbrace$.
|
||||
\item $e_j^{souh}$ = Nombre d'employés souhaités à la période $j \in \lbrace 1,16 \rbrace$.
|
||||
\item $P$ = Nombre de périodes dans l'horaire. Constante initialisée à 16.
|
||||
\item $V_{PERTE}$ = Valeur de la perte liée à un écart d'un employé par rapport au nombre souhaité. Constante initialisée à 20.
|
||||
\end{itemize}
|
||||
|
||||
On définit aussi ces constantes supplémentaires pour simplifier la création de contraintes, car Choco 4 ne permet pas d'effectuer d'opérations arithmétiques dans une contrainte autre que la contrainte arithmétique. Autrement il aurait fallu ajouter des contraintes redondantes à notre modèle.
|
||||
|
||||
\begin{itemize}
|
||||
\item $MAX_P = MAX_H-MIN_{P}-1$ = Nombre maximal de périodes dans le bloc de travail précédant et suivant la pause.
|
||||
\item $MAX_{PR} = MAX_P-MIN_H-1$ = Nombre maximal de périodes dans le bloc de repos débutant ou terminant la journée.
|
||||
\item $MIN_{HT} = MIN_H-1$ = Nombre minimal de périodes travaillées par l'employé, excluant la pause
|
||||
\item $MAX_{HT} = MAX_H-1$ = Nombre maximal de périodes travaillées par l'employé, excluant la pause
|
||||
\end{itemize}
|
||||
|
||||
\subsection{Variables}
|
||||
\label{sec:q2variables}
|
||||
|
||||
On définit une matrice de variables $E_{NP}$ où $e_{ij}$ correspondant à une valeur booléenne prenant la valeur $1$ si l'employé $i$ travaille à la période $j$ et $0$ sinon.
|
||||
|
||||
\begin{align}
|
||||
\label{eq:q2v1}
|
||||
&e_{ij} &= 1_{\text{Employé }i\text{ travaille à la période j}} \forall 1 \leq i \leq N, 1 \leq j \leq P\\
|
||||
dom(e_{ij}) &= \lbrace 0,1 \rbrace \in \theta(1) & \forall 1 \leq i \leq N, 1 \leq j \leq P\nonumber
|
||||
\end{align}
|
||||
|
||||
Afin de résoudre le problème d'optimisation, on doit définir des variables supplémentaires, car les composantes de la fonction d'optimisation sont aussi exprimées sous forme de contraintes.
|
||||
|
||||
$e_{j}^{eff}$, le nombre d'employés effectif à la période $j$, et $e_{j}^{dist}$ la différence absolue entre le nombre d'employés effectif et souhaité à la période $j$.
|
||||
|
||||
\begin{align}
|
||||
\label{eq:q2v2}
|
||||
e_{j}^{eff} &= \sum_{i=1}^{N} e_{ij} & \forall 1 \leq j \leq P\\
|
||||
dom(e_{j}^{eff}) &= \lbrace 0,N \rbrace \in \theta(N) & \forall 1 \leq j \leq P\nonumber\\
|
||||
\label{eq:q2v3}
|
||||
e_{j}^{dist} &= \lvert e_{j}^{eff} - e_j^{souh} \rvert & \forall 1 \leq j \leq P\\
|
||||
dom(e_{j}^{dist}) &= \lbrace 0,N \rbrace \in \theta(N) & \forall 1 \leq j \leq P\nonumber
|
||||
\end{align}
|
||||
|
||||
Enfin, nous créons une variable $N_{PERTE}$ représentant le total des unités de perte, équivalant
|
||||
à la somme des différences absolues. Le nombre total d'unités de perte prend une valeur entre $0$ et $NP$.
|
||||
|
||||
\begin{align}
|
||||
\label{eq:q2v4}
|
||||
&N_{PERTE} = \sum_{j=1}^{P} e_j^{dist}\\
|
||||
&dom(N_{PERTE}) = \lbrace 0, \ldots, NP \rbrace &\in \theta(NP)\nonumber
|
||||
\end{align}
|
||||
|
||||
\subsubsection{Nombre total de variables et de valeurs}
|
||||
\label{sec:q2nbtotvar}
|
||||
|
||||
Le nombre total de variables pour les définitions \eqref{eq:q2v1}, \eqref{eq:q2v2},
|
||||
\eqref{eq:q2v3} et \eqref{eq:q2v4}:
|
||||
|
||||
\begin{align}
|
||||
\label{eq:vartot}
|
||||
NP + P + P + 1 &= (N+2) \times N_p + 1 \in \theta(NP)
|
||||
\end{align}
|
||||
|
||||
Le nombre total de valeurs possibles pour ces mêmes définitions est:
|
||||
\begin{align}
|
||||
\label{eq:valtot}
|
||||
NP \times 2 + NP + NP + NP &= 5NP \in \theta(NP)
|
||||
\end{align}
|
||||
|
||||
\subsection{Contraintes}
|
||||
\label{sec:q2contraintes}
|
||||
|
||||
\subsubsection{Nombre d'employés requis}
|
||||
\label{sec:nbemployesreq}
|
||||
|
||||
La contrainte du nombre d'employés requis s'énonce comme suit: pour chaque période $i$, le nombre d'employés travaillant doit être supérieur ou égal au nombre d'employés minimum requis.
|
||||
|
||||
\begin{align}
|
||||
\label{eq:q2c1eq}
|
||||
&\sum_{i=1}^{N} e_{ij} \geq e_j^{req} & \forall 1 \leq j \leq P
|
||||
\end{align}
|
||||
|
||||
Il s'agit d'une contrainte de type \textsc{Sum}:
|
||||
|
||||
\begin{align}
|
||||
\label{eq:q2c1}
|
||||
&\textsc{Sum}(\lbrace e_{1j},\ldots,e_{Nj} \rbrace,\geq, e_j^{req}) & \forall 1 \leq j \leq P
|
||||
\end{align}
|
||||
|
||||
\subsubsection{Motif de la journée de travail}
|
||||
\label{sec:q2automatefini}
|
||||
|
||||
Afin de représenter le motif correspondant à une journée de travail alternant les périodes de travail et celles de repos, on utilisera une contrainte de type \textsc{Regular} qui est paramétrée par un automate fini, c'est-à-dire une chaine de caractère formant une expression régulière qui valide plusieurs contraintes définies par l'énoncé du problème.
|
||||
|
||||
Dans Choco 4, la contrainte \texttt{model.regular} prend en paramètre une séquence de variables entières à valider, et un automate fini défini par la classe \texttt{FiniteAutomaton}. Pour construire une instance de cette classe, on doit construire l'expression régulière en n'utilisant que des nombres comme valeurs. Comme nous avons choisi de représenter les différents états d'un employé par une variable boolienne, cette condition est satisfaite.
|
||||
|
||||
Voici comment nous avons construit l'expression:
|
||||
\begin{itemize}
|
||||
\item On débute par un bloc de repos d'au moins 0 et au plus $MAX_{PR}$ périodes.
|
||||
\item On a ensuite un bloc de travail d'au moins $MIN_{P}$ et au plus $MAX_P$ périodes.
|
||||
\item On a ensuite un bloc de repos d'une durée d'une période.
|
||||
\item On a ensuite un bloc de travail d'au moins $MIN_{P}$ et au plus $MAX_P$ périodes.
|
||||
\item On termine par un bloc de repos d'au moins 0 et au plus $MAX_{PR}$ périodes.
|
||||
\end{itemize}
|
||||
|
||||
On obtient ainsi un automate fini défini par l'expression régulière suivante:
|
||||
\begin{align}
|
||||
\label{eq:q2c2eq}
|
||||
{FA} = &0\lbrace 0,MAX_{PR} \rbrace\\
|
||||
&1 \lbrace MIN_{P},MAX_P \rbrace\nonumber\\
|
||||
&0\nonumber\\
|
||||
&1 \lbrace MIN_{P},MAX_P \rbrace\nonumber\\
|
||||
&0\lbrace 0,MAX_{PR} \rbrace\nonumber
|
||||
\end{align}
|
||||
|
||||
L'ensemble des contraintes pour le motif d'horaire peut donc s'écrire
|
||||
\begin{align}
|
||||
\label{eq:q2c2}
|
||||
&\textsc{Regular}(\lbrace e_{i1},\ldots,e_{ij} \rbrace, FA) &\forall 1 \leq i \leq N
|
||||
\end{align}
|
||||
|
||||
\subsubsection{Nombre de périodes travaillées par employé}
|
||||
\label{sec:q2minmax}
|
||||
|
||||
On définit l'inégalité suivante pour définir la contrainte du nombre minimum et maximum de périodes travaillées par employé.
|
||||
|
||||
\begin{align}
|
||||
\label{eq:q2c3eq}
|
||||
&MIN_{HT} \leq \sum_{j=1}^{P} e_{ij} \leq MAX_{HT} & \forall 1 \leq i \leq N
|
||||
\end{align}
|
||||
|
||||
On utilise deux contraintes \textsc{Sum} pour représenter dans Choco le nombre de périodes minimum et maximum devant être travaillées, pour chaque employé.
|
||||
|
||||
\begin{align}
|
||||
\label{eq:q2c3}
|
||||
&\textsc{Sum}(\lbrace e_{i1},\ldots,e_{iP} \rbrace,\geq,MIN_{HT}) & \forall 1 \leq i \leq N\\
|
||||
&\textsc{Sum}(\lbrace e_{i1},\ldots,e_{iP} \rbrace,\leq,MAX_{HT}) & \forall 1 \leq i \leq N\nonumber
|
||||
\end{align}
|
||||
|
||||
\subsubsection{Nombre total de contraintes}
|
||||
\label{sec:q2totcontr}
|
||||
|
||||
Le nombre total de contraintes pour les définitions \eqref{eq:q2c1}, \eqref{eq:q2c2} et \eqref{eq:q2c3} est:
|
||||
\begin{align}
|
||||
\label{eq:conttot}
|
||||
P + N + 2N &= P + 3N \in \theta(N)
|
||||
\end{align}
|
||||
|
||||
\subsection{Optimisation}
|
||||
\label{sec:q2optimisation}
|
||||
|
||||
Dans Choco, les contraintes d'optimisation sont créées de la même façon que les contraintes de satisfaction. Cependant, une des variables ne sera pas une constante, mais un intervalle dans lequel la fonction d'optimisation va effectuer sa recherche.
|
||||
|
||||
Nous implémenterons le nombre de travailleurs effectifs $e_j^{eff}$ à la période $j$ en utilisant une contrainte \textsc{Sum}:
|
||||
\begin{align}
|
||||
\label{q2opc1}
|
||||
&\textsc{Sum}(\lbrace e_{1j},\ldots,e_{Nj} \rbrace,=,e_j^{eff}) & \forall 1 \leq j \leq P
|
||||
\end{align}
|
||||
|
||||
Nous implémenterons ensuite la différence entre le nombre de travailleurs effectifs et souhaités $e_j^{dist}$ à la période $j$ en utilisant une contrainte \textsc{Distance}:
|
||||
\begin{align}
|
||||
\label{q2opc2}
|
||||
&\textsc{Distance}(e_j^{souh},e_j^{eff},=,e_j^{dist}) & \forall 1 \leq j \leq P
|
||||
\end{align}
|
||||
|
||||
Enfin, la variable $N_{PERTE}$ est implémentée par une contrainte \textsc{Sum}:
|
||||
\begin{align}
|
||||
\label{q2opc3}
|
||||
\textsc{Sum}(\lbrace e_1^{dist},\ldots,e_{P}^{dist} \rbrace,=,N_{PERTE})
|
||||
\end{align}
|
||||
|
||||
Nous n'incluons pas la valeur en dollars des unités de perte dans le modèle, car elle n'est pas pertinente dans l'élicitation des contraintes. Nous n'aurons qu'à multiplier le résultat obtenu par 20\$.
|
||||
|
||||
Nous avons donc ici $P+P+1 \in \theta(P)$ contraintes d'optimisation.
|
||||
|
||||
\subsection{Résultats}
|
||||
\label{sec:q2resultats}
|
||||
|
||||
Nous avons demandé au solveur Choco de minimiser la perte $N_{PERTE}$ à l'aide de la méthode \texttt{findOptimalSolution}. Nous avons utilisé les euristiques par défaut, car elles permettaient d'obtenir un résultat en moins d'une seconde. Le solveur trouve deux solutions optimales en effectuant 6397 retours arrière en 0,553s. La valeur optimale est de 4 unités de perte, pour une valeur de 80\$.
|
||||
|
||||
\subsubsection{Solution}
|
||||
La solution retournée par le solveur est représentée à la figure \ref{fig:q2sol}.
|
||||
|
||||
\begin{figure}[H]
|
||||
\centering
|
||||
\begin{verbatim}
|
||||
Employé 0: 0 0 0 1 1 1 1 1 0 1 1 1 1 1 1 1
|
||||
Employé 1: 0 1 1 1 1 1 0 1 1 1 1 1 1 0 0 0
|
||||
Employé 2: 1 1 1 1 1 0 1 1 1 1 1 1 0 0 0 0
|
||||
Employé 3: 0 0 0 0 1 1 1 0 1 1 1 1 1 1 1 1
|
||||
Employé 4: 0 0 1 1 1 1 0 1 1 1 1 1 1 1 1 1
|
||||
\end{verbatim}
|
||||
\caption{Solution du problème 2}
|
||||
\label{fig:q2sol}
|
||||
\end{figure}
|
||||
|
||||
|
||||
%%% Local Variables:
|
||||
%%% mode: latex
|
||||
%%% TeX-master: "rapport"
|
||||
%%% End:
|
BIN
tp/rapport.pdf
BIN
tp/rapport.pdf
Binary file not shown.
Binary file not shown.
|
@ -1,73 +0,0 @@
|
|||
\documentclass[12pt]{article} % Précise le type de document, et la taille de la police de caractère
|
||||
\usepackage[square,sort,numbers]{natbib}% Pour pouvoir utiliser une bibliographie externe
|
||||
\usepackage[french]{babel} % Pour préciser la langue du document
|
||||
\usepackage[utf8]{inputenc} % Précise comment le texte est saisi : cela permet de tapper directement les accents
|
||||
\usepackage[T1]{fontenc} % Précise la façon dont le document actuel est encodé
|
||||
\usepackage{setspace}
|
||||
\usepackage{datetime}
|
||||
\usepackage[margin=2.5cm]{geometry} % Précise les marges du document
|
||||
\title{IFT-7020 Optimisation combinatoire - Travail pratique\\Session d'hiver 2018}% N'affecte pas la page titre, mais défini le nom de votre projet
|
||||
\author{François Bérubé et François Pelletier} % N'affecte pas la page titre, mais défini le nom de l'auteur(e) du projet
|
||||
|
||||
%Bibliographie
|
||||
%----------------------------------------------------------------
|
||||
\bibliographystyle{plainnat} % Pour changer le style de bibliographie
|
||||
\addto{\captionsfrench}{\renewcommand{\refname}{Bibliographie}} % Comme le langage défini est le français, "Références" aurait été le titre par défaut pour la bibliographie
|
||||
\usepackage[nottoc]{tocbibind} % Ajoute la bibliographie dans la table des matières
|
||||
%----------------------------------------------------------------
|
||||
|
||||
%Sections
|
||||
%----------------------------------------------------------------
|
||||
%\usepackage{newclude} % Pour pouvoir utiliser l'étoile après \inculde pour éviter les sauts de page. Ce package a des problême de compatibilité avec la package natbib
|
||||
%\renewcommand\thesection{} % Pour éviter la numérotation des sections
|
||||
%----------------------------------------------------------------
|
||||
|
||||
%Informations destinées à la page de présentation
|
||||
%----------------------------------------------------------------
|
||||
\newcommand{\titre}{Travail pratique}
|
||||
\newcommand{\auteurs}{François Bérubé et François Pelletier}
|
||||
\newcommand{\matricules}{900226407, 908144032}
|
||||
\newcommand{\destinataire}{Claude-Guy Quimper}
|
||||
\newcommand{\cours}{IFT-7020 Optimisation combinatoire\\Session d'hiver 2018}
|
||||
%----------------------------------------------------------------
|
||||
|
||||
%Autres packages et commandes utiles
|
||||
%----------------------------------------------------------------
|
||||
\usepackage{amsmath,amsthm,amssymb,amsfonts,calc} % Pour pouvoir inclure certains symboles et environnements mathématiques
|
||||
\usepackage[
|
||||
left = \flqq,%
|
||||
right = \frqq,%
|
||||
leftsub = \flqq,%
|
||||
rightsub = \frqq%
|
||||
]{dirtytalk}
|
||||
\newtheorem{definition}{Définition}
|
||||
\usepackage{array}
|
||||
\usepackage{float}
|
||||
\usepackage{lscape}
|
||||
\usepackage{enumerate} % Pour mieux gérer la commande enumerate dans les sections
|
||||
\usepackage{graphicx} % Pour inclure des images
|
||||
\usepackage{color} % Pour inclure du texte en couleur
|
||||
\usepackage{units} % Pour pouvoir tapper les unités correctement
|
||||
\usepackage{pgf,tikz} % Utilisation du module tikz, qui permet de tracer des belles images
|
||||
\usetikzlibrary{shapes.geometric, arrows} % Quand on exporte une image GeoGebra, on a besoin de préciser cela
|
||||
\usepackage{hyperref} % Pour include des liens dans le document
|
||||
\newcommand{\N}{\mathbb{N}} % Commande personnelle, plus rapide pour tapper les ensembles
|
||||
\newcommand{\Z}{\mathbb{Z}} % Commande personnelle, plus rapide pour tapper les ensembles
|
||||
\newcommand{\R}{\mathbb{R}} % Commande personnelle, plus rapide pour tapper les ensembles
|
||||
\usepackage{cprotect} % Pour pouvoir personaliser la légende des figures
|
||||
%----------------------------------------------------------------
|
||||
|
||||
\begin{document}
|
||||
\input{pagetitre} % Inclut le code contenu dans un fichier comme s'il était entré ici
|
||||
\tableofcontents
|
||||
\listoffigures
|
||||
% Le package newclude mis en commentaire permet d'introduire une * pour éviter le saut de page entre les section
|
||||
\include{question1}
|
||||
\include{question2}
|
||||
\bibliography{bibliographie}
|
||||
\end{document}
|
||||
|
||||
%%% Local Variables:
|
||||
%%% mode: latex
|
||||
%%% TeX-master: t
|
||||
%%% End:
|
Loading…
Reference in a new issue