Université de Versailles – St-Quentin en Yvelines
Licence Informatique
ARHAB Fatima
BLAIZE Julien
BOISSIER Antoine
FROMENT Anne-Claire
KOBAR
Birame
NOTT Thomas
OUAREZKI Malik
PAIG Chong-Woo
PIERRE Adrien
Monsieur F.-X. JOSSET
Jeudi 11 mai 2000
Table des
matières
II. Fonctionnement du logiciel
1. La forme et la taille du treillis
2. Le nombre et la nature des états
IV. Description du nouvel automate
2. Spécifications de la grammaire
1. Sauvegarde de traces commandé
par le moteur et/ou l'interface
2. Sauvegarde de fichier de
description passé par l'interface
3. Ouverture / sauvegarde d'un
automate et préparation du moteur demandés par l'interface
4. Ouverture d'un état précédent
demandé par l'interface
Dans le cadre du module projet de licence d'informatique, notre groupe a choisi le sujet intitulé Simulation d'Automates Cellulaires.
Il s'agit de faire un logiciel permettant de simuler des automates
cellulaires.
Un automate cellulaire est un ensemble de cellules qui évoluent
dans un ensemble d'états finis, au cours d'un temps discret. Les automates
cellulaires se différencient par la forme de la cellule, les états que peut
prendre chaque cellule, les règles d'évolution et les cellules voisines à
prendre en compte pour l'évolution.
Le plus célèbre d'entre eux est le jeu de la vie de John Conway.
Ce jeu de simulation cherche à modéliser l'évolution d'organismes vivants
(Figure 1).
Figure 1.
On peut aussi modéliser de nombreux phénomènes tels que
l'évolution d'une faune (Figure 2) ou la propagation de signaux électriques
(Figure 3).
Figure2.
Figure 3.
L'objectif de ce projet de génie logiciel est de produire un
programme capable de modéliser un grand nombre d'automates cellulaires.
Pour lancer l'application, l'utilisateur entre la ligne de commandes :
java ProSAC
L'interface présente une barre de menu dans sa partie supérieure
(Figure 4). Le premier menu est "Fichier". Nous y trouvons la
commande "Nouveau", qui nous permet de définir un nouvel automate. Il
obtient alors une première fenêtre (Figure 5).
Figure 4.
Figure 5.
Un automate cellulaire est un réseau de cellules dont l'état à
l'instant t+1 est calculé en fonction de son état et de celui de ses
cellules avoisinantes au temps t.
Pour décrire un nouvel automate, l'utilisateur doit donc
configurer ses 4 caractéristiques: le treillis, les états, le voisinage et les
règles d'évolution.
Cette première fenêtre lui permet de choisir la forme de la
cellule dans une liste de cinq possibilités prédéfinies. Il sélectionne ensuite
le nombre de lignes et de colonnes qu'il veut visualiser. Ce nombre est compris
entre 2 et 80 afin de ne pas obtenir des cellules trop petites.
Cette fenêtre dispose également de 2 boutons: "Aide" et
"Etats >". Un clic sur celui intitulé "Aide" fait
apparaître un texte d'explications détaillées sur cette fenêtre. Un clic sur le
bouton "Etats >" le fait passer à la deuxième fenêtre. (Figure 6)
Figure 6.
Cette deuxième fenêtre est consacrée aux états des cellules.
L'utilisateur doit choisir comment les symboliser, le nombre d'états et les
états eux-mêmes.
Il commence par choisir des couleurs ou des symboles. Le choix est
exclusif. En fonction de ce choix, il peut prendre entre 2 et 10 états pour les
couleurs ou entre 2 et 60 pour les symboles (cf. 3. Interface graphique).
Si l'utilisateur a choisi de mettre des couleurs, il doit cliquer
sur les cases de couleur qu'il désire. S'il a choisi d'avoir n états, il ne
pourra prendre que n-1 couleurs car il doit également choisir une
couleur pour l'état par défaut dans la liste déroulante.
Si l'utilisateur a choisi de mettre des symboles, il lui faut
entrer le symbole par défaut et les autres n-1 symboles. Cette fenêtre
dispose également de 3 boutons: "Aide", "< Treillis" et
"Voisinage >".
Un clic sur "Aide" fait apparaître un texte d'explications
détaillées. Un clic sur "< Treillis" renvoie l'utilisateur à la
saisie du treillis. Un clic sur "Voisinage >" l'envoie sur la
troisième fenêtre (Figure 7).
Figure 7.
Cette troisième fenêtre est dédiée à la saisie du voisinage.
L'utilisateur a le choix d'entrer graphiquement le voisinage ou d'utiliser
directement des formules.
Pour la saisie graphique, on affiche un treillis dont la cellule
centrale est noire. L'utilisateur doit alors cliquer sur les cellules à
considérer pour l'évolution de la cellule noire.
Le choix d'entrer des formules fait apparaître un texte pour la
saisie ainsi qu'un bouton "Grammaire" où celle-ci sera explicitée
pour les utilisateurs qui ne la connaissent pas.
En bas de la fenêtre, il y a 3 boutons. Le premier,
"Aide", a la même fonction que les boutons "Aide"
précédents. Un clic sur "< Etats" renvoie l'utilisateur à la
saisie des états et un clic sur "Règles > le fait passer à la saisie
des règles d'évolution (Figure 8).
La quatrième fenêtre propose à l'utilisateur de réaliser une
saisie guidée ou de saisir des formules pour les règles d'évolution (Figure 9).
Dans le cas d'une saisie guidée, l'utilisateur doit entrer l'état de la cellule
au temps initial t et son état au temps suivant. Il doit ensuite choisir l'état
de ses voisins pour que l'évolution ait lieu. Pour chaque symbole, il doit dire
le nombre de voisins dans cet état et si le nombre est minimal, maximal ou à
respecter exactement. Après la saisie de cette règle, il peut en entrer une
autre en cliquant sur le bouton "Encore" ou ne plus en mettre et le
valider en cliquant sur "Terminé".
Figure 8.
Figure 9.
En bas de la fenêtre se trouvent les boutons "Aide",
"< Voisinage" et "Terminer". Un clic sur
"Aide" affiche une aide, un clic sur "< Voisinage" renvoie
l'utilisateur à la page précédente et un clic sur "Terminer" le fait
sortir de la description.
Le programme lance alors le compilateur (dont la fenêtre est
cachée), et invite l'utilisateur à patienter pendant l'opération.
La saisie de l'automate de départ s'effectue sur le treillis
précédemment défini sur l'interface générale (Figure 10). L'utilisateur
cliquera sur les cases pour en changer l'état.
Figure 10.
Ensuite, une boîte de dialogue laisse à l'utilisateur le choix de
démarrer l'automate suivant les paramètres par défaut ou de modifier ceux-ci.
Si l'utilisateur choisit de modifier les paramètres, l'écran de
dialogue "Paramètres" s'affiche (Figure 11). Cette fenêtre est aussi
accessible par le menu "Options / Paramètres". On peut y définir l'intervalle
de sauvegarde des états dans le fichier de traces (un état sur 10 par défaut),
l'intervalle d'affichage (tous les états par défaut), le nombre maximal d'états
à calculer (infini par défaut).
Une fois ces données confirmées, on est prêt à partir ! Un clic
sur le bouton "lecture" ou sur "Exécution / Normal" du menu
(Figure 12) lance l'animation de l'automate.
L'utilisateur peut contrôler l'évolution de l'automate par les
boutons "lecture","arrêt", "ralenti" et
"avance rapide" (aussi par le menu "Exécution") (Figure 4).
L'usage des boutons "lecture" et "arrêt" est évident. Les
boutons "ralenti" et "avance rapide" diminuent et
augmentent respectivement l'intervalle d'affichage de 10 états. Le bouton
"ralenti" n'a aucun effet si l'intervalle d'affichage vaut un
(afficher tous les états).
Figure 11.
Figure 12.
Il est aussi possible de sauvegarder un état en particulier ou
d'enregistrer les fichiers compilés de description de l'automate à un
emplacement donné via la commande "Enregistrer" du menu
"Fichier". "Enregistrer" propose un sous-menu en cascade
(Figure 13), composé de "Etat" et de "Description". Un clic
sur "Etat" ouvre une fenêtre d'enregistrement standard (Figure 14),
et l'utilisateur pourra enregistrer l'état en cours dans un fichier (non
zippé). "Description" ouvre une fenêtre similaire et saisit un chemin
et un nom qui serviront de base aux noms des classes Java correspondant à
l'automate en cours.
Il est aussi possible de revenir à un état précédent. La commande
"Exécution / traces" ouvre une fenêtre listant les états sauvegardés
dans la trace, avec un numéro correspondant au numéro d'étape de calcul (Figure
15). L'utilisateur peut de même ouvrir un état particulier sauvegardé par "Enregistrer / Etat". Il passera
alors par la commande "Ouvrir / Etat" du menu "Fichier"
(Figure 16). La commande affiche une fenêtre d'ouverture standard et le
programme lit l'état sélectionné.
Figure 13.
Figure 14.
L'ouverture d'un automate préalablement sauvegardé se fait par la
commande "Ouvrir / Description" (Figure 16). Elle fait appel à une
fenêtre d'ouverture standard. Les fichiers sélectionnés seront recopiés dans le
répertoire du moteur. Si un automate est déjà chargé, le programme demandera si
l'utilisateur souhaite enregistrer l'automate en cours. Si oui, la
commande "Enregistrer /
Description" sera exécutée avant l'ouverture, et le fichier de traces
correspondant sera sauvegardé au même emplacement.
L'utilisateur pourra quitter le programme par la commande
"Quitter" du menu "Fichier" (Figure 17). Il sera demandé à
l'utilisateur de confirmer son choix, puis s'il souhaite enregistrer
l'automate, ainsi que son fichier de traces. Les opérations de sauvegarde
seront exécutées le cas échéant.
Figure 15.
Figure 16.
Figure 17.
L'interface graphique est le centre de contrôle général du
programme. C'est à partir de là que se font les saisies et sont fixés les
paramètres.
Elle comporte des menus "Office compatible",
réalisés à l'aide des composants Swing (JMenu entre
autres), des boutons scope (JButton). Dans la suite, les captures
d'écran sont des éléments Win32, car les sources de l'interface sont en
réédition (Visual Café génère du code avec des objets de la bibliothèque
com.symantec.*).
L'interface intègre la partie "Description de
l'automate". La saisie, décomposée en quatre fenêtres, a pour but de
recueillir les différents paramètres de l'automate à modéliser :
· la forme et la taille du treillis,
· le nombre et la nature des états,
· le voisinage,
· les règles.
La taille du treillis est comprise entre 2 lignes x 2colonnes et 80 lignes x 80 colonnes. La forme du treillis est à choisir dans un panel prédéfini : carré, rectangle, triangle, pavage carré, pavage rectangle. Nous avons estimé que cet ensemble était suffisant pour représenter des automates à deux dimensions.
Dans ce cas, chaque cellule est représentable par des coordonnées cartésiennes (ligne, colonne), même si les "lignes" et les "colonnes" ne se coupent pas en angle droit (cas du pavage).
Le nombre d'états sera limité à 10 valeurs pour les couleurs. Il ne s'agit pas en pratique d'une limitation technique, mais plutôt d'une limitation pratique : au-delà de 10 couleurs, il devient difficile de trouver une teinte qui ne se confonde pas aisément avec une couleur déjà choisie. L'utilisateur pourra opter pour une représentation par symboles s'il souhaite un plus grand nombre d'états. Ce nombre est fixé à 60.
Un JRadioButton se charge de la permutation du
choix de représentation Couleurs / Symboles. Les couleurs seront choisies dans
un panel, par des JCheckBox, avec un JComboBox qui permettra de choisir un "état par défaut" parmi une
liste. Les symboles seront saisis par des JTextField.
Le voisinage peut être saisi sur un treillis ou par une formule.
Le choix est toujours assuré par des JRadioButton.
La saisie graphique affichera une image du treillis précédemment défini, et
l'utilisateur devra indiquer les cases à prendre en compte pour une case
donnée, indiquée en noir. La saisie par formule se fait dans un JTextPane. Si l'utilisateur ignore la syntaxe à utiliser, il pourra faire
appel à une aide affichée par le bouton "Grammaire".
Les règles d'évolution seront définis soit par formule, soit pas à
pas. En mode formule, on saisira les règles dans un JTextPane. La syntaxe sera proche de la syntaxe à employer pour les
fichiers d'entrée du compilateur. Le mode guidé demande l'état de la cellule au
temps t, au temps t+1 et les conditions sur ses voisins pour
cette évolution, au moyen de quantificateurs "Au moins", "Au
plus", "Exactement" associés à un état.
Les informations de treillis et d'états sont sauvegardées par le
biais des traces dans un fichier (cf. VII. Trace). Les informations de
voisinage et de règles sont également enregistrées par les traces. L'interface
fournira une chaîne ou un vecteur de chaînes aux traces qui le sauvegardera
dans un fichier. L'interface lancera ensuite le compilateur, puis le
compilateur Java, afin de créer des classes utilisables par le moteur. A
noter ici que l'interface lance des applications externes. En effet, le
compilateur (cf. V. Compilateur) est un programme C, fourni par Lex/Yacc,
et qui n'est donc pas directement
implémentable dans le reste du programme, écrit en Java. Les traces
seront chargées par l'interface de placer les classes compilées à disposition
du moteur (enregistrer les données temporaires dans un répertoire à part permet
d'éviter de polluer les répertoires du programme lors d'éventuels plantages).
L'interface utilise les informations concernant le treillis et les états pour afficher l'écran de "Saisie de l'automate initial". Il s'agit en fait de l'interface principale, et l'automate est saisi sur le treillis qui sera utilisé pour l'animation. Le mécanisme de saisie suivant est celui utilisé dans l'affichage des états.
On initialise un tableau d'entiers de la dimension du treillis. Un
objet Canevas implémentant un MouseListener est créé. Le treillis est tracé à
l'aide de drawLine. Quand l'utilisateur clique sur
une case, le programme détermine les coordonnées de la case choisie à partir
des coordonnées indiquées par la
souris. Le programme remplit alors cette case par la couleur ou le symbole de
l'état suivant (les valeurs des états sont dans un vecteur).
Une fois l'automate de départ saisi, l'interface envoie le tableau
au module de traces, qui le stockera dans le fichier d'historique.
Lors des rafraîchissements d'affichages, l'interface comparera le
tableau d'entiers fourni par le moteur à son tableau actuel, et ne mettra à
jour que les cases modifiées. Cependant, il faudra peut-être rafraîchir
l'affichage entier de temps en temps, en cas de corruption graphique due à une
éventuelle désynchronisation.
L'interface saisit aussi les paramètres de traces et d'affichage
fournis par la suite au moteur lors de son lancement. Elle agit aussi sur le
moteur en interrompant ou en stoppant le déroulement du thread, par les
commandes d'exécution et les boutons scope.
L'interface permet de saisir les noms des fichiers et les chemins
correspondant lors des opérations d'ouverture et de sauvegarde. En pratique, le
module de traces ne peut pas s'exécuter seul, il est intégré au programme.
L'interface doit gérer les éventuels messages d'erreur des divers
autres modules, qui ne disposent pas d'affichage graphique propre, et donc
d'aucun moyen de communication directe avec l'utilisateur (à l'exception du
compilateur et de javac, qui devront probablement ouvrir une fenêtre de
terminal).
Le cheminement pas à pas dans la description du nouvel automate étant réalisée dans le paragraphe "Fonctionnement du logiciel", nous allons ici parler de cette partie d'un point de vue plus technique, fenêtre par fenêtre.
La forme de cellule par défaut est "carré" mais l'utilisateur peut choisir une autre forme. Pour choisir le nombre de lignes et de colonnes, l'utilisateur peut cliquer sur les flèches, ce qui nous assure que son choix est autorisé, ou bien entrer textuellement une valeur. Cette valeur subira systématiquement un test pour vérifier qu'elle est bien comprise entre 2 et 80. Par défaut il y aura 2 lignes sur 2 colonnes. La valeur est limitée à 80 pour que l'image ne soit pas trop petite et que l'utilisateur puisse voir correctement les états de ses cellules.
Le bouton "Aide" fait apparaître une fenêtre contenant des schémas pour montrer le résultat du choix de chaque forme de treillis proposée et indiquant ce qui est fait par défaut.
Le bouton "Etats >" provoque l'enregistrement des
données saisies dans le fichier "treillis" et présente la deuxième
fenêtre à l'utilisateur. Pour l'exemple illustré dans la fenêtre de la Figure
5, le fichier ressemblerait à :
r;5;7 |
Dans tous les cas, il ne contiendra que trois informations
séparées par un ";". Les nombres de lignes et de colonnes seront mis
tel quel et la forme de la cellule sera c (carré), r (rectangulaire), t
(triangle), pc (pavage carré) ou pr (pavage rectangle).
Le choix de la symbolisation est exclusif. Il semble évident que l'utilisateur ne puisse mélanger les couleurs et les symboles. Le choix du nombre d'états peut se faire textuellement ou en cliquant sur les flèches. Il y a au minimum 2 états. Le nombre maximum est de 10 dans le cas des couleurs et de 60 dans le cas des symboles. Un test est effectué avant l'enregistrement des données. Par défaut, il y aura 2 états.
Pour ce qui est des couleurs, l'état par défaut est à choisir dans
la liste déroulante. Elle contient les mêmes couleurs que celles indiquées en
dessous pour les autres états. Ceux-ci doivent être cliqués pour être pris. A
chaque clic, on vérifie que cette couleur n'est pas celle de l'état par défaut
et si le nombre de couleurs total est égal au nombre d'états, on bloque le
choix en grisant les couleurs non choisies. Si l'utilisateur clique ensuite sur
une couleur déjà sélectionnée, on débloque les couleurs grisées pour qu'il
puisse faire un nouveau choix.
Dans le cas des symboles, l'utilisateur doit les entrer
textuellement. De même que pour les couleurs, on vérifie que le symbole entré
n'est pas déjà choisi.
Le bouton "Aide" présente à l'utilisateur la même
explication qu'il ait choisi de mettre des couleurs ou des symboles. Cette aide
explique que le choix est exclusif, que le nombre d'états est limité en
fonction de ce choix ainsi que la saisie des états.
Le bouton "< Treillis" déclenche la sauvegarde des
données dans un fichier "etats" et présente à nouveau la première
fenêtre à l'utilisateur.
Le bouton "Voisinage >" déclenche la sauvegarde comme
le bouton "< Treillis" et fait passer l'utilisateur à la fenêtre
de définition du voisinage.
Pour l'exemple illustré dans la fenêtre de la Figure 6 de gauche,
le fichier ressemblerait à :
c;4;blanc;bleu;rouge;noir |
Pour l'exemple illustré dans la fenêtre de la Figure 6 de droite, le fichier ressemblerait à :
s;4; ;#;X;* |
Les informations sont séparées par des ";". La première indique la symbolisation : c (couleurs) ou s (symboles); la deuxième indique le nombre d'états. Les informations suivantes sont les états, le premier étant l'état par défaut.
Le choix de mode de saisie est exclusif. L'utilisateur peut choisir entre graphique et formule.
Pour la saisie graphique, on affiche un treillis correspondant aux
données précédentes de l'utilisateur et on grise la cellule centrale.
L'utilisateur doit alors cliquer sur la cellules à prendre en compte. On sauve
les coordonnées des cellules cliquées.
Pour la saisie avec des formules, l'utilisateur doit entrer sa
formule dans une zone de saisie. Il dispose aussi d'un bouton
"Grammaire" pour lui expliquer sous quelle forme il doit la mettre.
Le bouton "Aide" présente à l'utilisateur la même
explication qu'il ait choisi de faire une saisie graphique ou avec des
formules. L'utilisateur pourra voir que le choix est exclusif et la grammaire
pour les formules.
Le bouton "< Etats" renvoie l'utilisateur à la fenêtre
précédente et sauve les données de celle-ci dans une chaîne
"voisinage"qui sera transmise au compilateur.
Le bouton "Règles >" sauve les données dans une
chaîne "voisinage" et présente à l'utilisateur la quatrième fenêtre.
La chaîne "voisinage" ressemblera à :
dv(i-1,j-1)(i-2,j+3)(i+2,j-1)(i+1,j+2)fv |
L'utilisateur a le choix exclusif entre une saisie guidée ou une saisie de formules.
Pour la saisie guidée, l'utilisateur peut mettre chaque règle
l'une après l'autre. Il passe à la règle suivante avec le bouton
"Encore" et valide ses règles avec le bouton "Terminé".
Pour saisir la règle, l'utilisateur peut mettre ce qu'il veut du moment qu'il
n'a pas déjà entré une règle strictement identique.
Dans le cas des formules, l'utilisateur dispose d'un bouton
"Grammaire" s'il ne la connaît pas.
Le bouton "Aide" présente toutes les explications
nécessaires à l'utilisateur. Le bouton "< Voisinage" renvoie
l'utilisateur à la page précédente et sauve les données de cette fenêtre dans
une chaîne "regles" qui sera transmise au compilateur. Le bouton
"Terminer" entraîne la transmission des chaînes au compilateur et des
fichiers aux traces.
La chaîne "regles" ressemblera à :
DR dr * # m1Espace e0# p1X e2* fr
dr Espace X e2Espace m1# p1X e0* fr FR |
Si l'utilisateur retourne sur une page qu'il a déjà visitée, le
fichier enregistré est écrasé à la nouvelle sauvegarde. Avant de réaliser cette
nouvelle sauvegarde, on vérifie que tout coïncide, c'est-à-dire que par exemple
l'utilisateur n'ait pas défini son voisinage sur un treillis carré alors qu'il
veut à présent des cellules triangulaires. Dans ce type de cas, on affiche un
message d'erreur. Si tout va bien quand on clique sur "Terminer", la
saisie se termine effectivement, sinon, on demande à l'utilisateur s'il veut
vraiment enregistrer cet automate et il doit alors réaliser des modifications
sinon, on annule ce qu'il a entré.
Le compilateur reçoit deux chaînes de la part de l'interface graphique, plus précisément du module d'entrée de l'automate de départ. Ces chaînes sont le "voisinage" et les "regles". Celles-ci respectent une syntaxe définie à l'avance, qu'elles aient été entrées par saisie de formules ou par saisie guidée. Nous verrons plus tard sur l'exemple cette syntaxe.
Avant de connaître les "regles" et le "voisinage", une partie du code java est déjà implementée, le compilateur se chargera de vérifier la syntaxe et de compléter le code.
La classe automate définit toutes les caractéristiques de base de tout automate cellulaire. Les règles et le voisinage variant, on utilise une deuxième classe qui hérite des caractéristiques de la classe automate, et implémente les outils manquants pour le calcul du voisinage et des règles.
Le moteur devant manipuler ces objets, des fonctions seront
ajoutées en fonction des nécessités.
class automate
{
int matrice1[][] ; /* Définition du
treillis a l’étape t */
int matrice2[][] ; /* Définition du
treillis a l’étape t+1 */
int nb_lignes ; /* Définition de la taille du treillis */
int nb_colonnes ;
/* Définition de la forme des cellules du
treillis */
String forme ;
/*
Liste des états possibles de notre automate */
Vector etats ;
/* Constucteur d’automate */
public automate (
int num1 , int num2 , String chaine )
{
nb_lignes = num1 ;
nb_colonnes = num2 ;
forme = chaine ;
}
}
class regle extends automate
{
/* Liste du voisinage d’une cellule (i,j)
*/
/* Liste remplie par le compilateur */
Vector voisinage ;
/*
Liste des états possibles et nombre de cases */ /* à cet état dans le voisinage d’une
cellule */
Vector voisins ;
/* Méthode qui sera implémentée par le
compilateur à */
/* partir des données saisies dans
l’interface. Elle */
/* prend en entrée une cellule. */
public void regle ( cellule test )
{
int etat1;
int etat2;
}
}
Le compilateur reçoit ses données de l'interface graphique sous forme de chaînes de caractères ayant certaines spécificités. Nous allons voir sur des exemples le travail du compilateur et une partie de son code.
Soit la chaine "dv (i-1,j-1)(i-2,j+3)(i+2,j-1)(i+1,j+2)
fv". Clairement, cette chaîne est conforme à la syntaxe souhaitée. Sans
entrer dans les détails, le fichier Lex reconnaîtra chaque mot (mot = suite de caractères non séparés par
un espace) et fournira une suite de symboles terminaux du genre :
DEBUTV COORDONNEE COORDONNEE
COORDONNEE COORDONNEE FINV .
Le fichier Yacc lancera les actions associées à chaque
symbole terminal :
DEBUTV |
Initialisation du vecteur voisinage de la classe regle, dans le
but de l’incrémenter. |
COORDONNEE |
Ajout de l’élément dans le vecteur. |
FINV |
Aucune action associée. |
Donc, une expression régulière pour décrire le voisinage peut être
défini ainsi :
le symbole DEBUTV |
au moins une coordonnée |
le symbole FINV |
Soit la déclaration des règles suivantes :
DR dr * # m1Espace e0# p1X e2* fr dr Espace X e2Espace m1# p1X
e0* fr FR |
Les mots "DR" et "FR" balisent le début et la
fin de la déclaration des règles. Les mots "dr" et "fr"
balisent le début et la fin d'une règle. Clairement, notre automate a deux
règles d'évolution. Une expression régulière est de la forme :
balise "dr" / état initial / état final / état du
voisinage / balise "fr".
Reprenons la première formule : dr * # m1Espace e0# p1X e2*
fr.
Elle signifie : si une cellule est à l'état *, pour qu'elle
passe à l'état #, il faut que dans son voisinage elle ait : au moins 1 cellule
à l'état Espace, exactement 0 cellule à l'état #, au plus 1 cellule à l'état X
et exactement 2 cellules à l'état *.
Pour définir le voisinage d'une cellule on utilise donc des
triplets de la forme : [m/p/e][chiffre][état].
Actions engendrées :
-
à la
lecture de la balise "DR", on se place dans la méthode à incrémenter
-
à la
lecture de état initial, on initialise la variable etat1
-
à la
lecture de état final, on initialise la variable etat2
-
à
chaque début de règle ( balise "fr" ) on crée une boucle
"if" du genre :
if ( cellule.etat == etat1
)
if
( conditions )
{
cellule.etat
= etat2 ;
}
Les conditions sont données par le ou les triplets, par
exemple :
"m1Espace" -> si Espace est
l’état 0,
voisins[0].nombre >= 1
"e0#" -> si # est l’état 1,
voisins[1].nombre == 0
"p1X" -> si X est l’état 2,
voisins[2].nombre <= 1
"e2*" -> si * est l’état 3,
voisins[3].nombre == 2
notre boucle devient :
if ( cellule.etat == etat1 )
if (voisins[0].nombre >=1)
if ( voisins[1].nombre == 0 )
if ( voisins[2].nombre <= 1 )
if ( voisins[3].nombre == 2 )
{
cellule.etat = etat2 ;
}
-
à la
lecture de la balise "fr", aucune action.
-
à la
lecture de la balise "FR", aucune action.
Le moteur calcule les différents états de l'évolution d'un
automate. Il est lancé dans un thread différent de celui de l'interface,
pour pouvoir être suspendu, stoppé ou relancé facilement. Il faudra penser aux
problèmes de désynchronisation possibles.
Les classes de calcul (règles, voisinage) sont fournies par le
compilateur, et produites par javac. Les classes et les méthodes auront
toujours le même nom, quelle que soit la nature de l'automate : cela
permet de ne pas tout recompiler à chaque changement de règles. Ainsi, le
moteur en lui-même est totalement inconscient de son polymorphisme.
Le moteur manipulera deux tableaux, un contenant l'état actuel et
l'autre l'état suivant. Il calculera l'état de chaque case de l'état suivant à
partir de l'état actuel en se servant des règles et de la définition du
voisinage.
Le voisinage sera recalculé pour chaque case, et sera stocké dans
un vecteur d'entiers, et les règles s'appuieront sur ce Vecteur pour déterminer
le nouvel état.
Le moteur dispose en outre d'un compteur interne qui lui permet de
connaître le numéro d'itération. C'est à partir de ce nombre que sera prise la
décision d'envoyer ou non l'état calculé aux traces ou à l'affichage.
Le moteur reçoit à son lancement par l'interface trois
paramètres : l'intervalle de sauvegarde des traces (10 par défaut),
l'intervalle d'affichage (un par défaut) et le nombre d'états maximal à
calculer (infini par défaut).
Le module d'entrées – sorties, ou traces, est le composant du logiciel chargé de toutes les opérations disque. Cela évite d'avoir du code redondant d'ouverture / sauvegarde de fichier dans l'interface.
Les traces doivent gérer quatre types d'appels différents :
·
sauvegarde
de traces commandé par le moteur et/ou l’interface,
·
sauvegarde
de fichier de description passé par l’interface,
·
ouverture
/ sauvegarde d’un automate et préparation du moteur demandés par l’interface,
·
ouverture
d’un état précédent demandé par l’interface.
Il s'agit de sauvegarder des états de l'automate en évolution à intervalles réguliers (toutes les 10 itérations par défaut), pour avoir un historique d'évolution. Dans ce cas, le moteur fournira aux traces un tableau d'entiers correspondant à l'état à sauvegarder. Ce tableau est mis dans un fichier contenu dans une archive au format Zip. Les fichiers d'état porteront un nom du type EtatXXXX.sta, où XXXX est le numéro d'itération. La taille de l'archive devrait être réduite, les tableaux d'entiers se rapprochant dans leur structure des images bitmap.
L'utilisateur peut choisir d'enregistrer un état en particulier. Dans ce cas, le tableau correspondant à l'état désiré sera sauvé dans le fichier de traces.
A la fin de la saisie de la description de l'automate, l'interface envoie les données aux traces. Le premier appel porte sur la forme et la taille du treillis et le nombre et la valeur des états. Les traces vont écrire ces valeurs dans un fichier à part, non zippé, avec un nom temporaire comme "desc.rul". Un nom définitif lui sera donné si l'utilisateur décide de sauvegarder son automate.
Le deuxième appel porte sur le voisinage et les règles. Ceux-ci arrivent formatés pour être traités par le compilateur. Les traces enregistreront ces données dans un fichier dans un répertoire donné. Une fois cette opération réalisée, l'interface pourra lancer le compilateur.
Une fois la compilation terminée, il nous faut placer les fichiers ".class" avec le moteur. Les traces copient ces fichiers vers l'endroit où le moteur est supposé trouver ses routines de calcul.
De même, lorsque l'utilisateur souhaite ouvrir un automate précédemment enregistré ou sauvegarder son automate (description et états), les traces déplacent les fichiers ".class", le fichier ".rul" et l'archive d'historique vers le répertoire du moteur, ou le répertoire de sauvegarde désigné via l'interface.
L'utilisateur peut demander à reprendre l'évolution à partir d'un point précédemment calculé. L'interface appelle alors les traces, qui lui rendent la liste des fichiers contenus dans l'archive d'historique. L'utilisateur choisit un état parmi ceux-ci, et les traces extraient le fichier correspondant, lisent le tableau d'entiers, et le transmettent vers le moteur et l'interface, qui mettront à jour leurs tableaux d'état.
A ce jour, le cheminement de l'utilisateur à travers le logiciel ProSAC
est déterminé de façon précise. Sont également fixés ce qui entre et ce qui sort de chaque module.
Chacun a pu ainsi établir clairement ce qui s'y passe et commencer à
implémenter le code. A présent, il ne nous reste donc plus qu'à coder
entièrement le logiciel.