This commit is contained in:
François Pelletier 2018-03-24 01:12:44 -04:00
parent 76c125998f
commit 2ab434fcbb
30 changed files with 0 additions and 2156 deletions

View file

@ -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();
}
}

View file

@ -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
View file

@ -1,3 +0,0 @@
*.class
*.aux

Binary file not shown.

Before

Width:  |  Height:  |  Size: 110 KiB

View file

@ -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},
}

View file

@ -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();
}
}

View file

@ -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();
}
}

View file

@ -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();
}
}

View file

@ -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();
}
}

View file

@ -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 + "'");
// }
}
}

View file

@ -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("");
}
}

View file

@ -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
}
}

View file

@ -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

View file

@ -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

View file

@ -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();
}
}

View file

@ -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 + "'");
// }
}
}

View file

@ -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("");
}
}

View file

@ -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.

Before

Width:  |  Height:  |  Size: 104 KiB

View file

@ -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

View file

@ -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}

View file

@ -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:

View file

@ -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}$$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:

Binary file not shown.

Binary file not shown.

View file

@ -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: