diff --git a/tp/.gitignore b/tp/.gitignore new file mode 100644 index 0000000..f33ccf7 --- /dev/null +++ b/tp/.gitignore @@ -0,0 +1,3 @@ +*.class +*.aux + diff --git a/tp/Sans titre.png b/tp/Sans titre.png new file mode 100644 index 0000000..16f3b32 Binary files /dev/null and b/tp/Sans titre.png differ diff --git a/tp/code/Exercice1.java b/tp/code/Exercice1.java new file mode 100644 index 0000000..b4c014c --- /dev/null +++ b/tp/code/Exercice1.java @@ -0,0 +1,104 @@ +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 String coherence = COHERENCE_BORNES; + + Model model = new Model("Quatre cubes"); + + // Ajout des tuples. 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}, + }; + + 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", 4, 4, 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(); + + IntVar[][] faceRectangulaires = new IntVar[4][4]; + + for (int noFace = 0; noFace < 4; noFace++) { + for (int noCube = 0; noCube < 4; noCube++) { + faceRectangulaires[noFace][noCube] = facesCubes[noCube][noFace]; + } + model.allDifferent(faceRectangulaires[noFace], coherence).post(); + } + + // Creation du solveur + Solver solver = model.getSolver(); + + solver.findSolution(); + + for (int noFace = 0; noFace < 4; noFace++) { + for (int noCube = 0; noCube < 4; 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(); + } +} + diff --git a/tp/code/Exercice2FB.java b/tp/code/Exercice2FB.java new file mode 100644 index 0000000..98c10e8 --- /dev/null +++ b/tp/code/Exercice2FB.java @@ -0,0 +1,198 @@ + +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(); + + } +} diff --git a/tp/code/ProductionHoraire.java b/tp/code/ProductionHoraire.java index bc640a6..f81a781 100644 --- a/tp/code/ProductionHoraire.java +++ b/tp/code/ProductionHoraire.java @@ -176,10 +176,6 @@ public class ProductionHoraire { System.err.println("Caught Exception: " + e.getMessage()); } - // Améliore un peu la performance - - solver.setRestartOnSolutions(); - // Résolution du modèle System.out.println("### Résolution ###"); diff --git a/tp/code/choco-solver-4.0.6-with-dependencies.jar b/tp/code/choco-solver-4.0.6-with-dependencies.jar new file mode 100644 index 0000000..0c8c6d9 Binary files /dev/null and b/tp/code/choco-solver-4.0.6-with-dependencies.jar differ diff --git a/tp/code/execution-20180204.txt b/tp/code/execution-20180204.txt deleted file mode 100644 index 9861e2a..0000000 --- a/tp/code/execution-20180204.txt +++ /dev/null @@ -1,54 +0,0 @@ --*- mode: compilation; default-directory: "~/git/tpIFT7020/tp/code/" -*- -Compilation started at Mon Feb 5 00:07:51 - -make run -javac -cp .:choco-solver-4.0.6-with-dependencies.jar ProductionHoraire.java -java -cp .:choco-solver-4.0.6-with-dependencies.jar ProductionHoraire instance.txt -### Debut Validation Lecture Instance ### -N=5 -MIN_H=10 -MAX_H=14 -MIN_PERIODE=3 -nbEmployesRequis=[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2] -nbEmployesSouhaite=[1, 2, 3, 4, 5, 4, 2, 3, 4, 3, 5, 5, 4, 3, 3, 3] -### Fin Validation Lecture Instance ### -### Création: contrainte du nombre requis d'employés ### -### Création: contrainte du motif d'horaire ### -Expression régulière:0{0,5}1{3,10}01{3,10}0{0,5} -### Création: Optimisation ### -### Création: Solveur ### -### Résolution ### -### Meilleure Solution ### -Employé 0: 0 1 1 1 1 1 0 1 1 1 1 1 0 0 0 0 -Employé 1: 0 0 1 1 1 1 0 1 1 1 1 1 1 1 1 1 -Employé 2: 0 0 0 0 1 1 1 1 0 1 1 1 1 1 1 1 -Employé 3: 0 0 0 1 1 1 0 1 1 1 1 1 1 1 1 1 -Employé 4: 1 1 1 1 1 0 1 1 1 1 1 1 1 0 0 0 - -Employés Totaux - 1 2 3 4 5 4 2 5 4 5 5 5 4 3 3 3 -Employés Souhaités - 1 2 3 4 5 4 2 3 4 3 5 5 4 3 3 3 - -Perte optimale:80$ - -### Statistiques ### -** Choco 4.0.6 (2017-11) : Constraint Programming Solver, Copyleft (c) 2010-2017 -- Model[Production Horaire] features: - Variables : 133 - Constraints : 64 - Building time : 0,790s - User-defined search strategy : yes - Complementary search strategy : no -- Complete search - 2 solution(s) found. - Model[Production Horaire] - Solutions: 2 - MINIMIZE perte = 4, - Building time : 0,790s - Resolution time : 0,567s - Nodes: 3 052 (5 380,5 n/s) - Backtracks: 6 052 - Fails: 3 000 - Restarts: 2 - -Compilation finished at Mon Feb 5 00:07:53 diff --git a/tp/code/makefile b/tp/code/makefile index ac3b856..2c72d7a 100644 --- a/tp/code/makefile +++ b/tp/code/makefile @@ -1,10 +1,12 @@ -all: ProductionHoraire.class +all: ProductionHoraire.class Exercice1.class Exercice2FB.class %.class: %.java javac -cp .:choco-solver-4.0.6-with-dependencies.jar $< -run: ProductionHoraire.class +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 diff --git a/tp/question1.tex b/tp/question1.tex index 851ef6e..a0508c6 100644 --- a/tp/question1.tex +++ b/tp/question1.tex @@ -1,4 +1,99 @@ -\section{Problème 1} - -Modélisation et résolution du problème des quatre cubes avec le solveur Choco \cite{chocoSolver}. - +\section{Problème 1} + +Modélisation et résolution du problème des quatre cubes avec le solveur Choco \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 rectangualaire. Ces deux constantes sont fixées à 4. + +\subsection{Variables} +\label{sec:q1variables} + +On définit une matrice de variables $facesCubes_{NF}$ où $facesCubes_{ij}$ correspondant aux couleurs que prennent chacun des 4 cubes sur les 4 faces du prisme rectangulaire. Les valeurs 1 à 4 servent respectivement à identifier le rouge, le vert, le bleu et le jaune. + +\begin{align} + \label{eq:q1v1} + &facesCubes_{ij} &= 1_{\text{Cube }i\text{ - face rectangulaire j = rouge}} \forall 1 \leq i \leq N, 1 \leq j \leq F\\ + dom(facesCubes_{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:vartot} + NF \in \theta(NF) +\end{align} + +Le nombre total de valeurs possibles pour ces mêmes définitions est: +\begin{align} + \label{eq:valtot} + 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 x 4 orientations par face) possibles. Si certaines combinaisons se répètent, ces doublons seront pris en charge par le solveur. + +\bigskip + +Il s'agit d'une contrainte de type \textsc{tableau} qui s'écrit de la façon suivante : + +\begin{align} +\label{eq:q1c1} +&Tableau(facesCubes_{i1} , ... , facesCubes_{iF} , T) & \text{pour i = 1 .. 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éé. + +\bigskip + +Il s'agit d'une contrainte de type \textsc{AllDifferent} qui s'écrit de la façon suivante: + +\begin{align} +\label{eq:q1c2} +&facesCubes_{i1} \neq ... \neq facesCubes_{iF} & \text{pour i = 1 .. 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:conttot} +N \text{contraintes «tableau»} + N \text{contraintes «AllDifferent»} &= 2N \in \theta(N) \\ +\text{De plus, chaque tableau contient 24} \in \theta(1) & \text{ entrées} +\end{align} + + +\subsection{Resultats} +\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 heuristiques par défaut car elles permettaient d'obtenir un résultat en moins d'une seconde. Le solveur trouve une seule solution en effectuant 0 retours arrières et ce, en 0,038s. + +\bigskip +La solution retournée par le solveur est la suivante : + +\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} + + +%%% Local Variables: +%%% mode: latex +%%% TeX-master: "rapport" +%%% End: \ No newline at end of file diff --git a/tp/rapport.pdf b/tp/rapport.pdf new file mode 100644 index 0000000..74c6a42 Binary files /dev/null and b/tp/rapport.pdf differ