On nous a demandé récemment dans le cadre d'un cours sur l'informatique répartie d'implémenter et simuler un algorithme avec ViSiDiA. Malheureusement, bien que bien documenté, le manque d'exemple d'implémentation nous a rendu la tâche un peu plus difficile. Du coût, voici un petit tuto pour ceux expliquant ViSiDiA en surface.

# Algorithme

Évidemment, pour simuler un algorithme, il faut... un algorithme ! Essayons donc d'implémenter un algoritme simple.
Imaginons que nous disposons de multiples noeuds qui s'envoient des nombres, disons entre 1 et 15. Si un des noeuds envoie à son voisin le nombre , celui-ci devra répondre par : "Trouvé !".

# Implémentation Java

Comment utiliser l'API ViSiDiA ? 

ViSiDiA nous fourni une API qui nous permet d'implémenter un algorithme. Il suffit donc d'ajouter le .jar en tant qu'External Library ( File > Project Structure > Module > Add (Alt + Inser) sur IntelliJ) ou de tout simplement utiliser un éditeur de text classique et de générer votre fichier .class en utilisant :

javac -classpath [chemin vers le .jar] VotreClass.java

Que représente notre fichier .class ?

Le fichier .class représente le fonctionnement d'un noeud. Lequel ? Et bien tous ! On doit donc dans notre fichier .class gérer non seulement l'envoi de message mais aussi la récéption de la réponse et ce indépendemment de la position du noeud. 

Envoi d'un nombre entre 1 et 15

Commençons par le commencement. Conformément à la documentation, nous devons créer une class qui hérite de la classe abstraite Algorithm. Celle-ci nous impose d'implémenter les méthodes clone() et init(). La méthode clone() permet de créer des instances de votre class et la méthode init() contient le comportement du noeud. Nous nous retrouvons du coup avec quelque chose qui ressemble à ceci :

import visidia.simulation.process.algorithm.Algorithm;

public class MonAlgo extends Algorithm{
    @Override
    public Object clone() {
        return new MonAlgo();
    }

    @Override
    public void init() {

    }
}

Essayons de demander à nos noeuds d'envoyer un nombre aléatoire entre 1 et 15 et de les envoyer à tous les voisins. Pour cela, nous auront besoin de 3 méthodes :

  • void sendAll(Message m) : Envoi m à tous ses voisins.
  • int getArity() : Renvoi le nombre de noeuds présents.
  • boolean sendTo(int door, Message m) : Envoi m via la porte door.

Chaque noeuds possède une à plusieures portes qui mène à son / ses voisins. Si vous désirez que tous vos noeuds envoient un message à leur premier voisin il suffit d'utiliser sendTo(1,Message m) si vous voulez que les noeuds envoient un message à tous les voisins un sendAll(Message m) est préférable.

@Override
public void init() {
    Random nb = new Random();
    int nodes = getArity(); //On récupère le nombre de noeuds présents lors de la simulation
 
    while(true){
        int nbAlea = nb.nextInt(15 - 1)+1; //On génère un nombre entre 1 et 15
        sendAll(new IntegerMessage(nbAlea)); // On envoie ce nombre à tous les voisins
        for (int i = 0; i < nodes; i++) { 
            /* On utilise une boucle pour demander à notre noeud d'attendre un message
             * provenant de ses voisins. On sait que ces messages sont des entiers on
             * les stocke donc dans une variable de type IntegerMessage via un cast.
             */
            IntegerMessage msg = (IntegerMessage)receiveFrom(i);
        }
    }
}

Si on lance la simulation (avec le nombre de noeuds et la dispositions que vous voulez) on obtient qulque chose comme ceci :

Traitement du message reçu

Pour l'instant nous avons nos voisins qui nous envoient des messages à intervalles réguiliers, il faut maintenant traiter ces messages. 

/* Taitement du message recu */
if(msg.value()==7){
    /* Si le message reçu est 7, on met en évidence la porte (le chemin) qui
     * mène vers le voisin qui ce voisin, et on lui envoi le message : "Trouvé!"
     */
    setDoorState(new MarkedState(true),i); // Mise en évidence de la porte menant vers i
    sendTo(i,new StringMessage("Trouvé !")); // On envoi "Trouvé !" au voisin i.
    receiveFrom(i); // On attends que le voisin réponde.
    setDoorState(new MarkedState(false),i); //On reset la forme de la porte
}

Et voici ce qu'on obtient :

Une fois que qu'un noeud reçois 7 il réponds par "Trouve".

Code complet

import visidia.simulation.process.algorithm.Algorithm;
import visidia.simulation.process.edgestate.MarkedState;
import visidia.simulation.process.messages.IntegerMessage;
import visidia.simulation.process.messages.Message;
import visidia.simulation.process.messages.StringMessage;

import java.util.Random;

public class MonAlgo extends Algorithm{
    @Override
    public Object clone() {
        return new MonAlgo();
    }

    @Override
    public void init() {
        Random nb = new Random();
        int nodes = getArity(); //On récupère le nombre de noeuds présents lors de la simulation

        while(true){
            int nbAlea = nb.nextInt(15 - 1)+1; //On génère un nombre entre 1 et 15
            sendAll(new IntegerMessage(nbAlea)); // On envoie ce nombre à tous les voisins

            for (int i = 0; i < nodes; i++) {
                /* On utilise une boucle pour demander à notre noeud d'attendre un message
                 * provenant de ses voisins. On sait que ces messages sont des entiers on
                 * les stocke donc dans une variable de type IntegerMessage via un cast.
                 */
                IntegerMessage msg = (IntegerMessage) receiveFrom(i);
                /* Taitement du message recu */
                if(msg.value()==7){
                   /* Si le message reçu est 7, on met en évidence la porte (le chemin) qui
                    * mène vers le voisin qui ce voisin, et on lui envoi le message : "Trouvé!"
                    */
                    setDoorState(new MarkedState(true),i); // Mise en évidence de la porte vers i
                    sendTo(i,new StringMessage("Trouve!")); // On envoi "Trouvé !" au voisin i.
                    receiveFrom(i); // On attends que le voisin réponde.
                    setDoorState(new MarkedState(false),i); //On reset la forme de la porte
                }
            }
        }
    }
}

 

Partager