TD1 Réétiquetages de graphes dynamiques 1

publicité
Algorithmique distribuée
Réétiquetages de graphes
dynamiques
1
TD1
Installation de JBotSim
JBotSim est une bibliothèque java pour développer rapidement des algorithmes distribués et les
tester de manière interactive. Commençons par télécharger la dernière version sur jbotsim.sf.net.
Il s’agit d’un fichier .jar. Il est fortement recommandé d’utiliser un IDE comme IntelliJ ou Eclipse
pour ce TP, avec une préférence pour IntelliJ. Dans l’IDE, créez un nouveau projet et ajoutez le jar
aux dépendances comme suit :
— IntelliJ : Project structure > Modules (select your module) > Dependencies > "+" > fichier
— Eclipse : Project properties > Java Build Path > Librairies > external JAR > fichier
Puis créez une classe HelloWorld avec le contenu suivant executez-là pour vérifier que tout fonctionne. Vous devriez voir apparaître une surface grise sur laquelle vous pouvez cliquer pour ajouter
des sommets. Si ça ne fonctionne pas appelez-moi.
public static void main(String args[]){
Topology tp = new Topology();
new JViewer(tp);
}
2
Notions de bases
Un exemple d’algorithme de réétiquetage très simple est donné par l’Algorithme 1. Ici les sommets sont initialement non-informés (étiquette N ), à l’exception d’un sommet qui est déjà informé
(étiquette I). La règle de réétiquetage se lit comme :
Lorsqu’un sommet informé interagit avec un sommet non-informé, il l’informe.
Le nouveau sommet informé pourra à son tour informer d’autres sommets par cette même règle.
Algorithm 1 Diffusion d’une information dans le réseau
Etats initiaux : I pour le sommet sélectionné ; N pour tous les autres.
Règle de réétiquetage : I
N
I
I
Le premier objectif de ce TD est de créer un ordonnanceur pour ce type d’interaction. Son rôle
est de choisir (en l’occurrence, aléatoirement) les arêtes sur lesquelles l’algorithme tente d’appliquer
une règle. Ainsi, dans ce modèle, l’algorithme ne contrôle pas l’ordre des interactions. Il fait ce qu’il
peut avec les choix de l’ordonnanceur. Durant cette séance, nous allons :
1. Créer un ordonnanceur aléatoire.
2.
3.
4.
5.
3
Implémenter l’algorithme de diffusion présenté à l’Algorithme 1
Implémenter un algorithme de comptage centralisé
Implémenter deux algorithmes de comptage décentralisé
Implémenter un algorithme de maintien d’arbres couvrants
Création de l’ordonnanceur
Même si les réétiquetages de graphes représentent des algorithmes distribués, notre implémentation sera, elle, centralisée : l’ordonnanceur choisit une arête au hasard et la passe à l’algorithme pour
y exécuter une interaction. Puis il recommence sur une autre arête.
Pour commencer nous allons compléter le squelette d’ordonnanceur disponible sur la page du
site (Scheduler.java). Il vous sera utile de savoir qu’il existe une méthode getLinks(). Si vous
voyez les arêtes clignoter une à la fois, vous pouvez passer à l’exercice suivant.
4
Une classe abstraite pour les algorithmes
Récupérez la classe abstraite Algorithm sur la page du cours. Chaque algorithme que vous implémenterez héritera de cette classe. En particulier, elle a trois méthodes abstraites que vous devrez
surcharger. Dans la première (setDefaultState()), vous affecterez au sommet donné l’état initial de l’algorithme (par exemple, N ). Observez que cette méthode est appelée à chaque fois qu’un
sommet est ajouté à la topologie (onNodeAdded()), ainsi que lorsque vous redémarrez l’exécution
(onStart()). Dans la seconde méthode (setDistinguishedState()), vous affecterez au sommet donné l’état distingué de l’algorithme (s’il y en a un, par exemple I). Observez que cette méthode
est appelée lorsqu’un sommet est sélectionné par l’utilisateur (onSelection()). Prenez le temps de
bien comprendre tous ces enchaînements.
5
Interactions entre ordonnanceur et algorithme
1. Modifiez le constructeur de l’ordonnanceur de sorte à prendre un objet de type Algorithm
en second paramètre. L’ordonnanceur devra appeler la troisième méthode abstraite
applyRule() de cet algorithme lorsqu’une arête est sélectionnée.
2. Implémentez maintenant l’Algorithme 1 dans une classe Diffusion, en surchargeant les trois
méthodes de façon appropriée. Concernant le constructeur, il suffira d’appeler super() avec
la topologie en paramètre. Il est recommandé d’utiliser des couleurs à la place des états I et
N pour visualiser le résultat plus facilement. Vous pouvez récupérer les sommets extremités
d’une arête en utilisant link.endpoint(0) et link.endpoint(1). Attention, une règle
peut être applicable dans un sens ou dans l’autre (endpoint 0 à gauche ou endpoint 1 à gauche),
il faudra donc tester les deux possibilités si pertinent.
3. Testez votre algorithme en jouant avec la souris et en sélectionnant un sommet distingué (clic
du milieu).
6
Algorithmes de comptage
On s’intéresse maintenant au problème du comptage, où l’un des sommets doit apprendre combien de participants se trouvent dans le réseau. On considère d’abord un algorithme très limité où
Page 2
le sommet compteur est désigné initialement (état distingué (C, 1)). Le compteur ne compte que les
sommets avec lesquels il interagit directement (c.f. Algorithme 2).
Algorithm 2 Comptage du nombre de sommets (avec compteur sélectionné)
Etats initiaux : C,1 pour le sommet compteur (sélectionné à la souris) ; N pour tous les autres.
Règle de réétiquetage :
C, i
N
C, i + 1 F
→ Implémentez cet algorithme. Astuce : utilisez trois couleur : une pour le compteur (C), une pour
les sommets non-comptés (N ), une pour les sommets déjà comptés (F ). Vous pouvez aussi bricoler
avec setID() et getID() sur le sommet compteur pour encoder l’entier i dans son identifiant (de
sorte à ce qu’il s’affiche quand la souris passe dessus).
→ Quelle propriété doit avoir la topologie pour que l’Algorithme 2 finisse par compter tout le
monde ? Vous répondrez pour les deux cas où 1) on peut choisir le compteur et 2) c’est un ennemi qui
choisit le compteur (pire cas).
On s’intéresse maintenant à un second algorithme où tous les sommets démarrent dans le même
état (initialisation uniforme).
Algorithm 3 Comptage du nombre de sommets (version uniforme avec compteurs fusionnants)
Etats initiaux : 1 pour tous les sommets.
Règle de réétiquetage :
i 6= 0 j 6= 0
i+j
0
→ Quelle propriété doit avoir la topologie pour que l’Algorithme 3 finisse par compter tout le
monde ? Vous répondrez pour les deux cas où 1) le compteur qui survit après chaque interaction est
celui qui nous arrange et 2) c’est un adversaire qui choisit le compteur qui survit.
Algorithm 4 Comptage du nombre de sommets (avec compteurs fusionnants et circulants)
Etats initiaux : 1 pour tous les sommets.
Règle de fusion :
i 6= 0 j 6= 0
Règle de circulation :
i 6= 0
i+j
0
0
0
i
→ Quelle propriété doit avoir la topologie pour que l’Algorithme 4 parvienne à compter tout le
monde ?
7
Forêt couvrante pour réseaux dynamiques
Nous considérons maintenant l’exemple d’un algorithme capable de « réagir » à la disparition
des arêtes. L’algorithme consiste à maintenir une forêt d’arbres couvrants. L’objectif est de rester
cohérent (i.e. pas de cycle et une seule racine par arbre) quitte à mettre plus longtemps à converger
vers un état optimal (un arbre par composante connexe). Cet algorithme est constitué de trois règles
de réétiquetage. Les deux premières sont classiques :
1. une règle de fusion : si deux racines d’arbres différents se retrouvent en vis à vis, l’une des
deux est supprimée et les deux arbres sont fusionnés en mettant en gras l’arête correspondante
(désactiver le setWidth() de l’ordonnanceur pour ne pas confondre). De plus, le sommet
“perdant” mémorise l’autre comme parent (représenté ci-dessous par une orientation).
Page 3
2. une règle de circulation, consistant à faire circuler une racine au sein de son propre arbre, en
inversant la relation parent/enfant locale à chaque mouvement.
La troisième règle est différente. Elle donne le traitement à effectuer immédiatement après qu’une
arête a disparu. Le traitement consiste à régénérer une racine si l’arête menait vers son parent.
Algorithm 5 Maintien d’une forêt d’arbres couvrants
Etats initiaux : R pour tous les sommets.
Règle de fusion : R
R
Règle de circulation : R
Règle de réparation :
N
R
N
×
N
N
R
R
La détection des cassures se fera en utilisant l’interface ConnectivityListener. Concrètement, l’algorithme demandera à être notifié lorsque des arêtes apparaissent ou disparaissent en invoquant addConnectivityListener dans setTopology() (à surcharger, donc). Cela vous permettra d’avoir une méthode onLinkRemoved() dans laquelle vous ferez le traitement nécessaire. Ce
traitement consistera à tester si l’arête perdue est une arête de l’arbre (p.ex. est-elle épaisse ?) et si
oui, régénérer une racine sur celui des deux qui a perdu son parent. Une vidéo du résultat à obtenir
est disponible sur YouTube (chaîne JBotSim).
Page 4
Téléchargement