TD Exercice 1
Placer
sur un échiquier de taille n, n reines telles quaucune
dentre elles ne soit en prise.
Modéliser
le problème et trouver la solution au problème
en utilisant le solveur Choco 2.0.
Solution
Modèle 1
Comment
modéliser le problème avec les contraintes
déjà évoquées ?
On
associe à chaque ligne une variable précisant
la position de la reine dans le ligne
- Une
variable énumérée par ligne : X1=[[1,n]]
- Une
reine par ligne (cest évident)
- Une
reine par colonne :
- Une
reine par diagonale :
- allDifferent(X1+1,
X2+2,
Xn+n)
- allDifferent(X1-1,
X2-2,
Xn-n)
Modèle
plus classique en PPC : moins de variables et moins
de contraintes
Voici
le code java en Choco
2.0 de ce premier modèle :
import
choco.kernel.model.Model;
import choco.kernel.model.variables.integer.IntegerVariable;
import choco.kernel.solver.Solver;
import choco.cp.model.CPModel;
import choco.cp.solver.CPSolver;
import choco.Choco;
public
class NReinesModel1 {
public
static final int NB_REINES = 10;
public
static void main(String[] args) {
//
0. Création du problème
Model
m = new CPModel();
//
1. Création des variables
IntegerVariable[]
vars = createVariables(m);
//
2. Création des contraintes
postConstraints
( m, vars );
//
3. Choix solver et heuristique
Solver
s = new CPSolver ();
s.read(m);
setHeuristic(s);
//
4. Résolution du problème
s.solve();
//
5. Récupérer la solution
displayResult(s,
vars);
}
//
1. Création des variables
private
static IntegerVariable[] createVariables(Model m) {
IntegerVariable[]
vars = new IntegerVariable[NB_REINES];
for
(int i = 0; i < NB_REINES; i++) {
vars[i]
= Choco.makeIntVar("x" + i, 0, NB_REINES - 1);
}
return
vars;
}
//
2. Création des contraintes
private
static void postConstraints(Model m, IntegerVariable[] vars)
{
postConstraints1(m,
vars);
postConstraints2(m,
vars);
}
//
2.1. Une reine par colonne
private
static void postConstraints1(Model m, IntegerVariable[]
vars) {
for(int
i = 0; i < NB_REINES; i++) {
for(int
j = i+1; j < NB_REINES; j++) {
m.addConstraint(
Choco.neq(vars[i], vars[j]) );
}
}
}
//
2.2. Une reine par diagonale
private
static void postConstraints2(Model m, IntegerVariable[]
vars) {
for
(int i = 0; i < NB_REINES; i++) {
for
(int j = i + 1; j < NB_REINES; j++) {
int
k = j - i;
m.addConstraint(Choco.neq(vars[i],
Choco.plus(vars[j], k)));
m.addConstraint(Choco.neq(vars[i],
Choco.minus(vars[j], k)));
}
}
}
//
3. Réglage de l'heuristique de choix de valeurs
private
static void setHeuristic(Solver s) {
s.setValIntIterator(new
DecreasingDomain());
}
//
5. Affichage des résultats
private
static void displayResult(Solver s, IntegerVariable[] vars)
{
if
(s.getNbSolutions() > 0) {
System.out.println("Solution
trouve : ");
for
(int i = 0; i < NB_REINES; i++) {
int
val = s.getVar(vars[i]).getVal();
for
(int j = 0; j < NB_REINES; j++) {
System.out.print(val
== j ? "R " : ". ");
}
System.out.println("");
}
}
else {
System.out.println("Pas
de solution trouve !!");
}
}
Solution
Modèle 2
On
associe à chaque case un booléen (reine présente
ou non)
Xij
= { 0,1 } avec 0 pas reine, 1 une reine
Une
reine par ligne :
De
même pour les colonnes et les diagonales (partielles
ou non).
Modèle
classique à la Programmation Linéaire.
Voici
le code java en Choco
2.0 de ce second modèle :
import
choco.kernel.model.Model;
import choco.kernel.model.variables.integer.IntegerVariable;
import choco.kernel.solver.Solver;
import choco.cp.model.CPModel;
import choco.cp.solver.CPSolver;
import choco.cp.solver.search.integer.valiterator.DecreasingDomain;
import choco.Choco;
import
java.util.List;
import java.util.ArrayList;
public
class NReineModele2 {
public
static final int NB_REINES = 10;
public
static void main(String[] args) {
long
time = System.currentTimeMillis();
System.out.println("NReine
mod?le 1");
//
0. Création du problème
Model
m = new CPModel();
//
1. Création des variables
IntegerVariable[]
vars =
createVariables(m);
//
2. Création des contraintes
postConstraints(m,
vars);
//
3. Choix solver et heuristique
Solver
s = new CPSolver();
s.read(m);
setHeuristic(s);
//
4. Résolution du problème
s.solve();
//
5. Récupération de la solution
displayResult(s,
vars);
System.out.println("Time
ellapsed: " + (System.currentTimeMillis() - time) +
"ms.");
}
//
1. Création des
variables
private
static IntegerVariable[] createVariables(Model m) {
IntegerVariable[]
vars = new IntegerVariable[NB_REINES * NB_REINES];
for
(int i = 0; i < NB_REINES; i++) {
for
(int j = 0; j < NB_REINES; j++) {
vars[index(i,
j)] = Choco.makeIntVar("x" + i + "_"
+ j, 0, 1);
}
}
return
vars;
}
//
2. Création des
contraintes
private
static void postConstraints(Model m, IntegerVariable[] vars)
{
postConstraints1(m,
vars);
postConstraints2(m,
vars);
}
//
2.1. Une occurence par ligne et par colonne
private
static void postConstraints1(Model m, IntegerVariable[]
vars) {
IntegerVariable
one = Choco.makeConstantVar("one", 1);
for
(int i = 0; i < NB_REINES; i++) {
IntegerVariable[]
col = new IntegerVariable[NB_REINES];
IntegerVariable[]
line = new IntegerVariable[NB_REINES];
for
(int j = 0; j < NB_REINES; j++) {
col[j]
= vars[index(i, j)];
line[j]
= vars[index(j, i)];
}
m.addConstraint(Choco.occurrence(1,
one, col));
m.addConstraint(Choco.occurrence(1,
one, line));
}
}
//
2.2 Une
occurence par diagonale
private
static void postConstraints2(Model m, IntegerVariable[]
vars) {
IntegerVariable
one = Choco.makeConstantVar("one", 1);
for
(int diag = 0; diag < 2 * NB_REINES - 1; diag++) {
List<IntegerVariable>
diag1 = new ArrayList<IntegerVariable>();
List<IntegerVariable>
diag2 = new ArrayList<IntegerVariable>();
for
(int i = 0; i < NB_REINES; i++) {
int
index1 = index(i, i + diag - NB_REINES + 1);
int
index2 = index(NB_REINES - i - 1, i + diag - NB_REINES +
1);
if
(index1 >= 0 && index1 < NB_REINES * NB_REINES)
{
diag1.add(vars[index1]);
}
if
(index2 >= 0 && index2 < NB_REINES * NB_REINES)
{
diag2.add(vars[index2]);
}
}
m.addConstraint(Choco.occurrenceMax(1,
one, diag1.toArray(new IntegerVariable[]{})));
m.addConstraint(Choco.occurrenceMax(1,
one, diag2.toArray(new IntegerVariable[]{})));
}
}
//
3. Réglage de l'heuristique
private
static void setHeuristic(Solver s) {
s.setValIntIterator(new
DecreasingDomain());
}
//
5. Affichage des résultats
private
static int index(int i, int j) {
if
(i < 0 || i >= NB_REINES) return -1;
if
(j < 0 || j >= NB_REINES) return -1;
return
i * NB_REINES + j;
}
//
5. Affichage des résultats
private
static void displayResult(Solver s, IntegerVariable[] vars)
{
if
(s.getNbSolutions() > 0) {
System.out.println("Solution
trouvée : ");
for
(int i = 0; i < NB_REINES; i++) {
for
(int j = 0; j < NB_REINES; j++) {
System.out.print(s.getVar(vars[index(i,
j)]).getVal() == 1 ? "R " : ". ");
}
System.out.println("");
}
}
else
{
System.out.println("Pas
de solution trouvée !!");
}
}
}
Voici
le plan de cette présentation sur la programmation par contraintes
- Les
notions de base
:
- Quelques
notions avancées :
- Quelques
exemples pour utiliser la P.P.C. :
Cette page
a été co-réalisée avec Guillaume
Rochart, docteur en mathématiques dans mon équipe de
recherche au Bouygues
e-lab.10/03/2009.