25
Travail d'étude et de recherche VISUALISATION DE RESOLUTION DE PROBLEMES PAR SATISFACTION DE CONTRAINTES Alexandre KOWAL Master 1 Mathématiques  Informatique Faculté des sciences Jean Perrin de Lens Encadrant: Stéphane CARDON

Travail d'étude et de recherche VISUALISATION DE

  • Upload
    others

  • View
    3

  • Download
    0

Embed Size (px)

Citation preview

Page 1: Travail d'étude et de recherche VISUALISATION DE

Travail d'étude et de recherche

VISUALISATION DE RESOLUTION DE PROBLEMES PAR SATISFACTION DE CONTRAINTES

Alexandre KOWALMaster 1 Mathématiques  InformatiqueFaculté des sciences Jean Perrin de Lens

Encadrant:Stéphane CARDON

Page 2: Travail d'étude et de recherche VISUALISATION DE

Table des matières

1) Introduction

1.1: Description du sujet

1.2: Ce qui a déjà été fait

1.3:Utilisation de la librairie QT4

1.3.1: Les signaux

1.3.2: Compilation

2) Modélisation

2.1: Analyse du problème

2.1.1: Recueil des besoins

2.1.2: Diagramme des cas d'utilisation

2.1.3: Diagrammes de séquences

2.1.3.1: Chargement d'un problème

2.1.3.2: Résolution automatique

2.1.3.3: Résolution manuelle

2.2: Rappel

2.2.1: Filtrage

2.2.1.1: Revise (consistance d'arc)

2.2.1.2: AC­1

2.2.1.3: classe Filtre

2.2.2: Solveur

2.3: Diagramme principal

2.3.1: Explication des classes

2.3.1.1: Interface IParametres

2.3.1.2: Interface Probleme

2.3.1.3: Interface IFabrique

2.3.1.4: Classe Problemes

2.3.1.5: Boundary GProblèmes

2.3.1.6: Boundary GMain

2.4: Communication  entre le viewer et le solveur

2.4.1: Le Pattern Observer

2.4.2: Définition

Page 3: Travail d'étude et de recherche VISUALISATION DE

2.4.3: La classe IObserver

2.4.4: le solveur

2.5: La classe Viewer

2.5.1: L'historique pour la classe Viewer

2.6: Exemple concret d'implémentation de problèmes

2.6.1:  Le problème des N­Reines

2.6.2: Rappel

2.6.3: Création du CSP relatif au problème

2.6.3.1: Création de la classe Nreines

2.6.4: Création du viewer personnalisée

2.6.5: Enregistrement du problème dans la liste des problèmes

2.7: Séquence de lancement d'un problème

2.8: Représentation sous forme de graphe

3) Conclusion

3.1: Améliorations

3.2: Bug

Page 4: Travail d'étude et de recherche VISUALISATION DE

1) Introduction:

1.1: Description du sujet

Le but de ce sujet est de réaliser une interface graphique permettant de visualiser sous forme de graphe la solution d'un CSP (réseau de contraintes binaires) car une image est plus parlante que des données brutes. Ce graphe devait pouvoir être interactif de sorte que l'utilisateur puisse choisir les valeurs données à chaque variable.

Les  problèmes peuvent aussi  avoir  une représentation plus concrète encore que  le graphe avec, comme par exemple, le problème des N­Reines pouvant être soit affiché sous forme de graphe ou alors sous la forme d'un échiquier. 

1.2: Ce qui a déjà été fait

Pour ce sujet, une partie du travail à déjà été réalisée par un autre étudiant l'année dernière.

Cet étudiant avait réalisé les diagrammes de base concernant la représentation interne de CSP, ainsi qu'un loader de CSP non finalisé, un algorithme de filtrage et un modèle de solveur. 

Nous ferons un petit rappel de tout ceci dans un autre chapitre. Pour de plus amples informations se référer au rapport de stage de Sébastien RAMON  « réalisation objet d'un mini­solveur CSP »

1.3   : Utilisation de la librairie QT4   

Pour ce stage, deux librairies pouvaient être utilisées : GTK ou QT. 

L'avantage de QT par rapport à GTK fut qu'elle proposait des composants puissants pour l'affichage (QGraphicsView)   ainsi   qu'un   composant   XML   permettant   de   charger   les   fichiers   de   ce   type facilement et de plus un système de création de plugins très facile d'utilisation.

1.3.1: Les signaux

La communication entre objets dans QT se fait par un mécanisme de « signals and slots ». Cela ressemble au pattern observer.

Un signal est connecté à un slot par la méthode connect.

On peut connecter autant de slots que l'on souhaite à un même signal. Lorsqu'un signal est émis par un objet, tous les slots lui étant connectés sont appelés.

La méthode connect permet de faire la liaison entre les signaux et les slots.

Ci­dessous un schéma explicatif du fonctionnement de ce mécanisme.

Page 5: Travail d'étude et de recherche VISUALISATION DE

1.3.2: Compilation

La compilation d'un programme QT s'effectue en 3 étapes:

qmake ­projet //crée un fichier  *.pro utilisé par qmake

qmake //permet de créer un makefile à partir du *.pro

make //effectue la compilation et la création de l'exécutable

Illustration : signaux et slots en QT4.3

Page 6: Travail d'étude et de recherche VISUALISATION DE

2) Modélisation

2.1: Analyse du problème

2.1.1: Recueil des besoins

Le but de l'application est de charger des problèmes au formats XML ou ceux intégrés directement dans le programme, pour ensuite les résoudre.

Il fallait donc trouver de quelle façon les représenter. Après réflexion, il a été décidé que chaque problème pourrait avoir deux modes de vue différentes.

● Mode standard:  représentant le problème sous forme de graphe.

● Mode personnalisé: représentant le problème sous une autre forme qu'un graphe.

Pour cela va être créée une classe Viewer pour représenter cette idée. 

Une autre demande avait été faite, il fallait aussi ajouter de l'interactivité lors de la résolution des problèmes, là aussi deux modes devaient être intégré.

● Mode automatique: la résolution se fait en temps réelle devant nos yeux.

● Mode manuel: l'utilisateur affecte lui même les variables du problème.

On comprend ici que pour le mode automatique, le solveur du problème doit communiquer avec le Viewer pour que l'affichage puisse changer en temps réel. De même, en poussant la réflexion plus loin, en mode manuel, l'utilisateur doit communiquer également avec le solveur.

 

Ici nous voyons donc que le Viewer devra communiquer avec le solveur. Pour cela on intégrera le concept de design pattern observer qui répondra parfaitement à nos besoins.

Concernant le mode manuel, il se pourrait que l'utilisateur de l'application s'aperçoive qu'il a choisi une mauvaise valeur pour des variables du problème et donc qu'il souhaiterai revenir en arrière pour corriger son erreur. Pour cela un historique des actions sera réalisé et la classe viewer devra donc l'implémenter.

En ce qui concerne les problèmes, il ne sera pas possible de choisir le solveur désiré lors de la sélection du problème à résoudre. De ce fait le solveur à utiliser sera stocké dans chaque dérivation de la classe Problème.  

Chaque  problème pouvant  être  paramétré   si  besoin  est,  une  classe   s'occupant  de   recueillir   ces informations sera introduite.

Toutes   les   interfaces   et   classes   citées  précédemment   seront   en   fait   codées   en   tant  que  classes 

Page 7: Travail d'étude et de recherche VISUALISATION DE

abstraites dans lesquelles une majorité  de méthodes auront une implémentation de base afin de simplifier la programmation lors de l'ajout de problèmes.

2.1.2: Diagramme des cas d'utilisation

Diagramme des cas d'utilisation

Page 8: Travail d'étude et de recherche VISUALISATION DE

2.1.3: Diagrammes de séquences

2.1.3.1: Chargement d'un problème

Ce diagramme explique les principales étapes réalisées lors du chargement d'un problème.

Diagramme de séquence de chargement d'un problème

Page 9: Travail d'étude et de recherche VISUALISATION DE

2.1.3.2: Résolution automatique

Lorsque l'utilisateur clique sur le bouton de résolution automatique, le viewer appelle la méthode solve du solveur et  celui­ci  envoie des messages de mise à   jour du viewer pour qu'il  puisse se rafraîchir.

Diagramme de séquence de résolution automatique d'un CSP

2.1.3.3: Résolution manuelle

L'utilisateur  demande  au viewer de modifier la variable souhaitée (par l'intermédiaire du solveur).

Diagramme de séquence de résolution manuelle d'un CSP

Page 10: Travail d'étude et de recherche VISUALISATION DE

2.2: Rappel

Pour   pouvoir   visualiser  l'effet   d'une   affectation   effectuée   par   un   utilisateur   (l'affectation   d'une variable implique la modification du domaines des autres variables), il nous faut un filtre.

Cette partie va fournir les rappels pour expliquer le fonctionnement de l'affectation et ses effets sur le problème. 

Un problème de satisfaction de contraintes peut être représenté par  un triplet {X,D,C} où:

– X = { v1 , v2 ,..., vn } est un ensemble de n variables;

– D = { d 1 , d 2 ,..., d n } est un ensemble des n domaines finis associés aux variables; chaque  d i  est de cardinalité finie.

– C = { c1 , c2 ,..., ce } est l'ensemble des e contraintes, chaque contrainte  c i  est définie par un couple ( v i , r i ):

– v i  est une séquence de variables  x i1 ,... , xit ∈X  sur lesquelles porte la contrainte c i . 

– r i  est une relation définie par un sous­ensemble du produit cartésien   d i1 x ... x  d it  des domaines associés aux variables de  v i . Il représente les n­uplets de valeurs autorisées pour ces variables.

 

2.2.1: Filtrage

Le filtrage consiste en l'élimination d'éléments dont on est assuré qu'ils ne peuvent figurer dans une quelconque   solution   (valeurs   ou   n­uplets   de   relation).   Il   tend   donc   vers   la   simplification   du problème par réduction de l'espace de recherche.

Méthode de filtrage:

Nous allons voir ici la méthode de filtrage qui a été implémentée pour cette application.

2.2.1.1: Revise (consistance d'arc)

La procédure Revise C ij , d i , d j  retire du domaine de  x i  toutes les valeurs sans support pour la contrainte  C ij  et retourne un booleen indiquant si le domaine de  x i  a été modifié.

Page 11: Travail d'étude et de recherche VISUALISATION DE

2.2.1.2: AC­1

Le filtrage par consistance d'arc AC­1 consiste à appliquer la consistance d'arc Revise(Cij,di,dj) sur toutes   les   contraintes   (propagation   de   contraintes)   jusqu'à   ce   que   plus   aucune   réduction   ne s'effectue. De cette manière on palie au problème de la simple application de Revise sur tous les couples de variables.

2.2.1.3: classe Filtre

Ceci  est l'interface à implémenter pour créer de nouveau filtre.

Pour cela, il suffit juste de redéfinir la méthode filtrer dans une classe fille.

2.2.2: Solveur

Son rôle est de résoudre un problème.

Lors de la phase de résolution, à chaque changement de valeur pour une variable, un algorithme de filtrage est lancé.

Pour créer un nouveau solveur  il suffit juste de redéfinir la méthode solve dans une classe fille.

Page 12: Travail d'étude et de recherche VISUALISATION DE

2.3: Diagramme principal

Page 13: Travail d'étude et de recherche VISUALISATION DE

2.3.1: Explication des classes

2.3.1.1: Interface IParametres

Cette interface est utilisée pour ajouter des paramètres à un problème. Une fonction permet de créer le QWidget qui représentera cette classe dans l'interface graphique.

2.3.1.2: Interface Probleme

Classe abstraite dont tous problèmes doivent dériver.

Utilisation:

Deux méthodes sont à redéfinir pour créer un problème:

  //c'est ici que l'on crée le réseau CSP relatif à notre problème, à noter que les paramètre sont  //stoqués dans la variable  _parametre  virtual void creer(); 

et

   //retourne le viewer du problème   virtual Viewer* getViewerPersonnalise();

2.3.1.3: Interface  IFabrique

Permet de centraliser la création d'objets de même type dans un même endroit pour avoir un code plus commode à utiliser.

Redéfinir:

    //indique si l'objet donc on entre le nom possède des paramètres.    //sera utile pour savoir quelle méthode d'instanciation utiliser    virtual bool possedeParametres(const QString & name) = 0;

    //retourne un void* correspondant à l'objet dont on a donné son nom à la fonction.    //Les noms des objets instanciables sont fournis par la méthode getListe

    virtual void* instancie(const QString & name) = 0;

Page 14: Travail d'étude et de recherche VISUALISATION DE

2.3.1.4: Classe Problemes

C'est à l'intérieur de cette classe que les problèmes nouvellement créés sont ajoutés.

=> Cette classe ne contient que la liste des problèmes nouvellement créés. A chaque nouveau problème, une ligne est ajoutée dans la méthode instancie(const QString & name) afin que le problème soit accessible à l'utilisateur.

2.3.1.5: Boundary GProblemes

Cette classe affiche  la boite de dialogue de sélection et création d'un problème.

2.3.1.6: Boundary Gmain

C'est la fenêtre principale de l'application, elle permet  le chargement  de la liste des problèmes, et l'affichage des viewers se fait dedans.

Dans la barre des menus, le menu édit permet d'accéder à la fonction rollback utilisée pour des retours arrières lors de manipulation de problèmes. 

2.3: Communication entre le viewer et le solveur

Le solveur occupe une place importante dans les interactions avec l'utilisateur.

Chaque fois que l'on voudra modifier la valeur d'une variable, une « autorisation » devra être demandée au solveur pour qu'il vérifie si l'affectation est correcte. 

Deux cas sont possibles:

– soit l'affectation n'est pas possible et donc rien ne se passe

– soit l'affectation est possible et le solveur enregistre cela dans son historique, puis émet un signal pour prévenir le viewer que l'affectation s'est passée et que l'affichage peut être modifié en conséquence.

Lors d'une annulation d'une action, un message sera envoyé au solveur qui se remettra dans son état précédent et émettra un signal pour prévenir le viewer que le rollback a bien eu lieu.

Pour  réaliser tout cela le design pattern Observer a été utilisé

Page 15: Travail d'étude et de recherche VISUALISATION DE

2.4.1: Le Pattern Observer

2.4.2: Définition

Le design pattern   observateur/observable  est utilisé pour envoyer un signal à des modules qui jouent   le   rôle  d'observateur.  En  cas  de  notification,   les  observateurs  effectuent   alors   l'action adéquate en  fonction  des   informations  qui  parviennent  depuis   les  modules  qu'ils  observent   (les "observables").

Pour cette application le Subject  sera le solveur et l'Observer sera le viewer.

2.4.3: La classe IObserver

Elle est implémentée par la classe Viewer.

class IObserver: {

public:virtual void update(int id_variable, int valeur,  ISolveur::State state) = 0;

};

Cette fonction est appelée par le Solveur à  chaque fois qu'il change d'état.

Nous reviendrons sur cette classe plus tard.

Page 16: Travail d'étude et de recherche VISUALISATION DE

2.4.4: le solveur

class ISolveur : public QObject, public Historique {

public:

    enum State{

      State_Solving,      State_Solved,      State_Unsolved,      State_Rollback,      State_Commit   };

   ISolveur(Reseau *reseau);

    virtual ~Isolveur();

    virtual void solve() = 0;

    void attach(IObserver *obs);

    Reseau* getReseau();

    virtual void setVariable(int id_variable, int valeur) = 0;

    virtual void valueChanged(int id_variable, int valeur, State state);

};

les méthodes:

virtual void solve() = 0;

réalise la résolution du problème 

void attach(IObserver *obs);

permet d'attacher les observer (notre viewer) à avertir en cas de modification du solveur.

Reseau* getReseau();

retourne le réseau(CSP) sur lequel porte la résolution

virtual void setVariable(int id_variable, int valeur) = 0;

permet de changer la variable d'indice id_variable en lui mettant valeur comme nouvelle affectation

Cette méthode  appelle valueChanged  pour avertir les observateurs (le viewer) du changement effectué

Page 17: Travail d'étude et de recherche VISUALISATION DE

virtual void valueChanged(int id_variable, int valeur, State state);

C'est la méthode qui va se charger d'avertir chaque observer que le Solveur vient d'effectuer une certaine action de type State.

Les actions du solveurs sont :

      ­State_Solving: le solveur est en cours de calcul      ­State_Solved: la solution vient d'être trouvée      ­State_Unsolved: pas de solution trouvée      ­State_Rollback: un rollback viens d'être effectué      ­State_Commit: un commit viens d'être effectué   

ces états seront utilisées par les viewers personnalisés pour rafraîchir le visuel du problème correctement et pour d'autres choses que nous verrons plus tard.

2.5: La classe Viewer

Classe de base pour visualiser un CSP sous une forme plus conviviale et possédant les mécanismes pour communiquer avec le solveur

class Viewer : public QWidget, public Historique,  public IObserver {protected:

Viewer(ISolveur *solveur);

public:void desireNewAffectation(int id_variable, int valeur);

virtual update(int id_variable, int valeur, ISolveur::State state) = 0;

virtual void paintEvent( QPaintEvent * event) = 0;

};

La classe Viewer est commune à toute représentation de problèmes que se soit sous forme de graphe ou autre.Elle entretient une relation étroite avec le solveur car toutes les communications passent par elle.

Deux méthodes principales permettent cette communication:

Envoie requête d'affectation de variable:

Lorsque l'on souhaite modifier la valeur d'une variable, il suffit d'appeler la méthode:

 void desireNewAffectation(int id_variable, int valeur)

en paramètres:

Page 18: Travail d'étude et de recherche VISUALISATION DE

id_variable: l'indice de la variable sur laquelle va porter la modification

valeur: la nouvelle valeur que l'on souhaite lui donner 

Lorsque  l'on envoie  une   requête  de  modification  d'une variable   il   faut   savoir  que parfois  cette affectation n'est pas possible (violation de contrainte). C'est ici que la seconde méthode vient jouer un rôle.

Réception de la validation de l'affectation:

Comme expliqué ci­dessus une modification de variable n'est pas toujours possible. Si une affectation est correcte la méthode qui suit est appelée:

void update(int id_variable, int valeur, ISolveur::State state) ;

en paramètres:

 id_variable: l'indice de la variable sur laquelle va porter la modification

valeur: la nouvelle valeur que l'on souhaite lui donner

state: l'état dans lequel est le solveur

Cette méthode est virtuelle pour qu'on puisse la redéfinir pour gérer correctement la mise à jour du Qwidget.

2.5.1: L'historique pour la classe Viewer

Le viewer réalisant l'interface Historique, à chaque fois qu'une modification de variable est faite cela est immédiatement enregistré pour pouvoir faire des retours arrières.

Page 19: Travail d'étude et de recherche VISUALISATION DE

2.6: Exemple concret d'implémentation de problème

2.6.1:  Le problème des N­Reines

2.6.2: Rappel

Il s'agit de placer n reines sur un échiquier (n x n) sans qu'elles se menacent. Deux reines ne doivent pas se trouver sur la même ligne, sur la même colonne ou sur la même diagonale.

Illustration : solution possible avec 8 reines

2.6.3: Création du CSP relatif au problème

2.6.3.1: Création de la classe NReines

On dériver  la classe problème pour y redéfinir la méthode creer et getViewerPersonnalise :

class NReines : public Probleme {public:

NReines();

virtual void creer();

virtual  Viewer* getViewerPersonnalise();

};

dans cette méthode on peut voir un exemple utilisant un objet de type IPrametres vu dans le point 2.1.1.1.

NReines::NReines() {//Création des données qui figureront dans la boîte de paramétrage du problème lors de sa sélection

//création d'un domaineQList<QString> domaineParametre;  //valeurs possiblesdomaineParametre << "4" << "7" << "8";   //ajout à la liste des paramètres (_parametres est de type Iparametres, se trouve dans la classe

Page 20: Travail d'étude et de recherche VISUALISATION DE

//probleme_parametres.ajouterParametre("nb reines:",COMBO_BOX, domaineParametre);

}

void NReines::creer() {//création d'un csp videBFabrique *reseauFactory = Bfabrique::get_instance();_reseau = reseauFactory­>creer();

//récupération du nombre de reines désiréint nbReines = parametres.getValeurParametre("nb reines:").toInt(); 

//CREATION DES VARIABLES,  DES  CONTRAINTES ICI

}

Viewer* Nreines::getViewerPersonnalise() {

//retourne le viewer personnaliséreturn new NReinesViewer(reseau);

 }

2.6.4: Création du viewer personnalisée

On dérive  notre viewerNReines de la classe Viwer et réimplémente les méthodes paintevent et update.

Une méthode pour détecter les clics sur la souris sera aussi nécessaire

class ViewerNReines : public Viewer {

public:

ViewerNReines(ISolveur *solveur): Viewer(solveur) {}

protected:virtual void update(int id_variable, int valeur, ISolveur::State state);virtual void paintEvent( QPaintEvent * event);

void mousePressEvent ( QMouseEvent * event );

};

void ViewerNReines::paintEvent(QPaintEvent * event){

drawEchiquier();//dessine l'échiquier

drawCaseAutorisees();//illumine les cases autorisées pour la reine courante

drawReines();//dessine les reines présentes sur l'échiquier

}

//gère les clics sur les cases

Page 21: Travail d'étude et de recherche VISUALISATION DE

void ViewerNReines::mousePressEvent( QMouseEvent * event ){

valeur = valeurDeLaCase();//retourne le numéro de la case cliquée. ­1 en cas d'erreur

if(valeur != ­1) 

desireNewAffectationl(id_courante_reine, valeur);

}

//appelée par le solveur après avoir effectué une action

void ViewerNReines::update(int id_variable, int valeur, ISolveur::State state){

switch(state) {

case ISolveur::State_Solving:

  //le solveur vient de valider une modification du graphe 

  id_courante_reine++;//on passe à la reine suivante

  break;

case ISolveur::State_Solved:

QMessageBox::warning(NULL, "N­Reines","Une solution a été trouvée",

QMessageBox::Ok); 

  break;

case ISolveur::State_Solved:QMessageBox::warning(NULL, "N­Reines","problème inconsistant",

QMessageBox::Ok); 

  break;

case ISolveur::State_Rollback:

//un retour arrière a été fait on retourne vers la reine précédente

  id_courante_reine­­;

  break;

default:;

}repaint();

}

2.6.5: Enregistrement du problème dans la liste des problèmes

Une classe Problème existant déjà il suffit de la modifier pour prendre en compte le nouveau problème

Problemes::Problemes(){

//ajout du prblème des NReines dans la liste des problèmes 

     _lesNomsProblemes << "ColoGraph";

Page 22: Travail d'étude et de recherche VISUALISATION DE

    _lesNomsProblemes << "NReines";

  }

//retourne le problème dont le nom est passé en paramètre

 void* Problemes::instancie(const QString & name){

    if(name == "ColoGraph") return new ColoGraph;

    if(name == "NReines") return new NReines;

    return NULL;

  }

2.7: Séquence de lancement d'un problème

­Lors du clic sur Fichier­>liste CSP...  la fenêtre ci­dessous s'affiche.

Dans le 1er encadré liste problèmes :

­Choix du problème: liste tous les problèmes disponibles (N­Reines,ColoGraph...).

­Visualisation: au maximum 2 types de visualisation sont disponibles :

­Standard: affiche le problème sous forme de graphe.

­Personnalisée: affiche le problème sous une forme plus élégante (ex: pour les N­Reines l'affichage serait un échiquier sur lequel des images de pions de reines s'afficheraient)

Page 23: Travail d'étude et de recherche VISUALISATION DE

Lors du clic sur valider, la liste des paramètres du problème s'affiche nous permettant de choisir les valeurs désirées.

Lors du clic sur générer, le viewer  est généré et passé à la fenêtre principale.

Représentation personnalisée du problème des N­Reines

Page 24: Travail d'étude et de recherche VISUALISATION DE

2.8: Représentation sous forme de graphe

Cette partie montre l'affichage standard de tous problèmes, c'est à dire sous forme de graphe.Celui­ci utilise l'algorithme des graphes élastiques basé sur les forces d'attraction et de répulsion exercées sur des nœuds.

Utilisation:

La partie gauche de l'image ci­dessous montre les variables du graphe, il suffit de choisir une valeur pour chaque et d'appuyer sur le commit correspondant pour valider l'action. 

Le graphique réagira automatiquement en illuminant le nœud assigné.

Lorsqu'une solution est trouvée une boite de dialogue apparaît pour vous prévenir.

Représentation sous forme de graphe d'un problème

Page 25: Travail d'étude et de recherche VISUALISATION DE

3)Conclusion

3.1: Améliorations

Le processus de création de problèmes dans ce modèle est assez lourd. En effet pour en ajouter un nouveau il faut modifier la classe Problemes pour qu'il se retrouve dans la liste de sélection. Mais le désavantage majeur est la recompilation obligatoire de toute l'application pour que le problème soit réellement intégré dans l'application ce qui est très lourd.

Une solution serait de créer un système de plugin pour éviter tout cela. Chaque problème serait donc un plugin et il suffirait de ne compiler que ce problème et de le placer dans un dossier « plugins » pour que le programme puisse le charger automatiquement.

3.2: Bug

Un bug n'a pas pu être corrigé à temps, celui­ci concerne les listeurs des domaines des variables. De ce fait des erreurs lors des rolback peuvent survenir. Cela a empêché d'implémenter la méthode solve du solveur utilisé.