ajout de documentation et optimisation de l'automate fini

This commit is contained in:
François Pelletier 2018-02-04 00:46:26 -05:00
parent 1f06504908
commit 789bc73cd4
2 changed files with 127 additions and 13 deletions

View file

@ -1,12 +1,15 @@
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 {
@ -64,12 +67,13 @@ public class ProductionHoraire {
Model model = new Model("Production Horaire");
// Création d'une matrice de dimensions N x N_PERIODE de variables E(i,j) dont les domaines sont des variables binaires.
// 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++) {
@ -77,6 +81,12 @@ public class ProductionHoraire {
}
}
// 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 ###");
@ -91,18 +101,26 @@ public class ProductionHoraire {
System.out.println("### Création: contrainte du motif d'horaire ###");
Integer MAX_PERIODE = MAX_H-1-MIN_PERIODE;
FiniteAutomaton FA = new FiniteAutomaton("0*1{"+
MIN_PERIODE.toString()+
","+
MAX_PERIODE.toString()+
"}01{"+
MIN_PERIODE.toString()+
","+
MAX_PERIODE.toString()+
"}0*");
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 IVMIN_H = model.intVar(MIN_H-1);
@ -147,12 +165,29 @@ public class ProductionHoraire {
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());
}
// Améliore un peu la performance
solver.setRestartOnSolutions();
// 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++) {

View file

@ -2,4 +2,83 @@
\section{Question 2}
\label{sec:q2}
Conception d'un horaire de travail avec minimisation de la perte de profit en utilisant le solveur \cite{chocoSolver}.
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 de 30 minutes travaillées par l'employés, incluant la pause
\item $MAX_H$ = Nombre maximal de périodes de 30 minutes travaillées par l'employés, incluant la pause
\item $MIN_{PERIODE}$ = Nombre minimal de période dans le bloc de travail précédant et suivant la pause
\item $N_{REQUIS}(t)$ = Nombre d'employés requis à la période $t \in \lbrace 1,16 \rbrace$.
\item $N_{SOUHAITE}(t)$ = Nombre d'employés souhaités à la période $t \in \lbrace 1,16 \rbrace$.
\item $N_{PERIODE}$ = Nombre de périodes dans l'horaire. Constante initialisée à 16.
\item $V_{PERTE}$ = Valeur de la perte lié à un écart d'un employé par rapport au nombre souhaité. Constante initialisée à 20.
\end{itemize}
On définit aussi ces constantes pour simplifier les calculs.
\begin{itemize}
\item $MAX_{PERIODE} = MAX_H-MIN_{PERIODE}-1$ = Nombre minimal de période dans le bloc de travail précédant et suivant la pause
\item $MAX_{PERIODE_REPOS} = MAX_{PERIODE}-MIN_H-1$ = Nombre minimal de période dans le bloc de repos débutant ou terminant la journée
\end{itemize}
\subsection{Variables}
\label{sec:q2variables}
On définit une matrice de variables $E_{N \times N_{PERIODE}}$$e_{i,j}$ correspondant à une valeur booléenne prenant la valeur $1$ si l'employé $i$ travaille à la période $j$ et $0$ sinon.
\begin{align*}
&e_{i,j} & \forall 1 \leq i \leq N, 1 \leq j \leq N_{PERIODE}\\
&dom(e_{i,j}) = \lbrace 0,1 \rbrace & \forall 1 \leq i \leq N, 1 \leq j \leq N_{PERIODE}
\end{align*}
Nombre total de variables:
\begin{align*}
&N \times N_{PERIODE}
\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. Il s'agit d'une contrainte de type \texttt{SUM}.
\begin{align*}
&\sum_{i=1}^{N} e_{i,j} \geq N_{REQUIS}(j) & \forall 1 \leq j \leq N_{PERIODE}
\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 \texttt{REGULAR} qui est paramétrée par un automate fini, c'est à dire une chaîne 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 boolenne, cette condition est satisfaite.
Voici comment nous avons construit l'expression:
\begin{itemize}
\item On débute par 0 ou plusieurs périodes de repos, allant jusqu'à $MAX_{PERIODE_REPOS}$
\item On a ensuite une période de travail d'au moins $MIN_{PERIODE}$ et au plus $MAX_{PERIODE}$
\item On a ensuite une pause
\item On a ensuite une période de travail d'au moins $MIN_{PERIODE}$ et au plus $MAX_{PERIODE}$
\item On termine par 0 ou plusieurs périodes de repos, allant jusqu'à $MAX_{PERIODE_REPOS}$
\end{itemize}
\subsection{Paramètres}
\label{sec:q2parametres}
\subsection{Resultats}
\label{sec:q2resultats}
%%% Local Variables:
%%% mode: latex
%%% TeX-master: "rapport"
%%% End: