Algorithmique de la mobilité
L'objectif de cette séance est de tester automatiquement certaines propriétés sur les graphes dynamiques. Dans une première partie, nous rappellons certaines définitions et familles de graphes vues en cours. Nous proposons ensuite une classe java qui permet d'enregistrer les apparitions et disparitions de liens de communication dans JBotSim, afin d'obtenir quelques traces réseaux sur lesquelles travailler. Le coeur de la séance s'intéresse à tester des propriétés temporelles sur ces traces réseaux, permettant de déterminer à quelle famille de graphe dynamique elles appartiennent.
Si vous le l'avez pas encore fait, suivez le mini tutoriel Enregistrement des liens.
Une trajet (ou chemin temporel) est un chemin qui se réalise à travers le temps, comme illustré ci-dessous. Lorsque le temps est discret (c'est le cas ici), on distingue deux types de trajets : les trajets stricts et les trajets non-stricts. Un trajet non-strict autorise plusieurs sauts consécutifs à la même date (par exemple, aller de $a$ à $d$ dans le premier graphe). À l'inverse, un trajet strict impose au plus un saut consécutif par graphe (p.ex. le trajet représenté en rouge ci-dessous).
Un graphe dynamique est temporellement connexe s'il existe un trajet de tout sommet vers tout sommet (famille C2 ci-dessous).
Il existe un grand nombre de familles de graphes dynamiques. Nous nous intéressons ici à quelques familles basiques vues en cours, correspondant aux propriétés temporelles suivantes.
Q1. À quelle(s) famille(s) le graphe de la figure 1 appartient-il ?
Pour chaque classe de graphe dynamique présentée plus haut (C1
à C7
), nous allons écrire des méthodes pour tester automatiquement si les propriétés correspondantes sont vérifiées. Les propriétés des classes C5
et C6
sont les plus faciles à tester. Nous commencerons donc par elles. Si votre format d'enregistrement des liens est une List<Contact>
(ou capable d'importer une telle liste), alors vous pouvez utilisez les jeux de données disponibles en bas de page pour tester vos algorithmes.
Q2 (facile). Écrire une méthode qui prend en entrée votre structure de donnée et renvoie vrai
si le graphe dynamique correspondant appartient à la famille C5
. Idem pour C6
.
Q3 (moins facile). Écrire une méthode qui prend en entrée votre structure de donnée ainsi qu'un noeud et renvoie vrai
si ce noeud est capable de joindre tous les autres par un trajet strict. Utiliser cette méthode pour tester C3
et C4
.
Q4 (plus difficile, bonus). Écrire une méthode qui prend en entrée votre structure de donnée ainsi qu'un noeud et renvoie vrai
si ce noeud est capable de joindre tous les autres par un trajet non-strict. Utiliser cette méthode pour tester C1
et C2
(voire C7
).
Remarque. Il est possible de construire, puis utiliser des structures intermédiaires telles l'empreinte (pour C5
et C6
), la fermeture transitive des trajets stricts (pour C3
et C4
) et la fermeture transitive des trajets non-stricts (pour C1
, C2
et C7
). Mais ce n'est pas obligatoire.
Voici quelques jeux de données (graphes sous forme de List<Contact>
) préparés par Jason. N'hésitez pas à les utiliser pour tester vos algorithmes au fur et à mesure.
public static List<Contact> contactsFigure1(){
String g = "1-3,2-3,2-4,3-4\n" +
"1-2,2-3,3-4\n" +
"1-2,3-4,3-5,4-5\n" +
"3-5,4-5";
return parse(g);
}
public static List<Contact> contactsNone(){
String g = "0-1,2-3\n" +
"1-2,3-4";
return parse(g);
}
public static List<Contact> contactsC1(){
String g = "3-4,4-5\n" +
"1-2,2-3";
return parse(g);
}
public static List<Contact> contactsC2(){
String g = "1-2,2-3\n" +
"3-4,4-5\n" +
"1-2,2-3";
return parse(g);
}
public static List<Contact> contactsC3(){
String g = "4-5\n" +
"1-2,3-4\n" +
"2-3\n" +
"1-2";
return parse(g);
}
public static List<Contact> contactsC4(){
String g = "2-3\n" +
"2-4\n" +
"0-2\n" +
"0-1\n" +
"0-2\n" +
"2-3\n" +
"2-4";
return parse(g);
}
public static List<Contact> contactsC5(){
String g = "0-1\n" +
"1-2\n" +
"2-3\n" +
"3-4\n" +
"0-4\n" +
"1-4\n" +
"2-4";
return parse(g);
}
public static List<Contact> contactsC6(){
String g = "0-1,0-2,0-3,0-4,1-2,1-3,1-4,2-3,2-4,3-4";
return parse(g);
}
public static List<Contact> contactsC7(){
String g = "0-1,1-2,3-4\n" +
"2-3";
return parse(g);
}
public static List<Contact> parse(String g){
List<Contact> contacts = new LinkedList<>();
int time = 0;
String[] snapshots = g.split("\n");
for (String snapshot : snapshots){
String[] timeEdges = snapshot.split(",");
for (String timeEdge : timeEdges){
String[] nodes = timeEdge.split("-");
int node0 = Integer.parseInt(nodes[0]);
int node1 = Integer.parseInt(nodes[1]);
Contact c = new Contact(node0, node1, time);
contacts.add(c);
}
time++;
}
return contacts;
}