package fr.univ.dblp.generators;
import fr.univ.dblp.analysis.*;
import fr.univ.dblp.export.ResultsPrinter;
import org.graphstream.graph.Graph;
import org.graphstream.graph.implementations.SingleGraph;
import org.graphstream.algorithm.generator.BarabasiAlbertGenerator;
import org.graphstream.algorithm.generator.RandomGenerator;
/**
* Génère des réseaux synthétiques pour comparaison (Question 6).
*
* Cette classe permet de générer des réseaux aléatoires (modèle d'Erdős-Rényi)
* et des réseaux à attachement préférentiel (modèle de Barabási-Albert) pour
* les comparer avec le réseau DBLP réel.
*
* @author Hamadou BA
* @see <a href="https://www-apps.univ-lehavre.fr/forge/bh243413/tp2-ri-mesures-de-reseaux-interaction.git">Dépôt Git</a>
*/
public class NetworkGenerator {
/**
* Génère un réseau aléatoire avec le modèle d'Erdős-Rényi.
*
* Dans ce modèle, chaque paire de nœuds est connectée avec une probabilité
* uniforme, produisant une distribution de degrés de type Poisson.
*
* @param n Nombre de nœuds
* @param avgDegree Degré moyen souhaité
* @return Le graphe aléatoire généré
*/
public static Graph generateRandomGraph(int n, double avgDegree) {
ResultsPrinter.printInfo(
String.format("Génération d'un réseau aléatoire: N=%,d, <k>=%.2f", n, avgDegree));
Graph g = new SingleGraph("Random");
g.setStrict(false);
g.setAutoCreate(true);
// Calcul du nombre d'arêtes cible
int targetEdges = (int) Math.round((n * avgDegree) / 2.0);
RandomGenerator gen = new RandomGenerator(avgDegree);
gen.addSink(g);
gen.begin();
// Génération des nœuds
for (int i = 0; i < n && g.getEdgeCount() < targetEdges; i++) {
gen.nextEvents();
}
gen.end();
ResultsPrinter.printSuccess(
String.format("Réseau aléatoire généré: %,d nœuds, %,d arêtes",
g.getNodeCount(), g.getEdgeCount()));
return g;
}
/**
* Génère un réseau Barabási-Albert (attachement préférentiel).
*
* Dans ce modèle, les nouveaux nœuds se connectent préférentiellement
* aux nœuds déjà bien connectés ("rich get richer"), produisant une
* distribution de degrés en loi de puissance.
*
* @param n Nombre de nœuds
* @param edgesPerNode Nombre d'arêtes créées par nouveau nœud
* @return Le graphe Barabási-Albert généré
*/
public static Graph generateBarabasiAlbert(int n, int edgesPerNode) {
ResultsPrinter.printInfo(
String.format("Génération d'un réseau Barabási-Albert: N=%,d, m=%d", n, edgesPerNode));
Graph g = new SingleGraph("Barabasi-Albert");
g.setStrict(false);
g.setAutoCreate(true);
BarabasiAlbertGenerator gen = new BarabasiAlbertGenerator(edgesPerNode);
gen.addSink(g);
gen.begin();
for (int i = 0; i < n; i++) {
gen.nextEvents();
if ((i + 1) % 10000 == 0) {
ResultsPrinter.printInfo(
String.format(" Progression: %,d/%,d nœuds générés", i + 1, n));
}
}
gen.end();
ResultsPrinter.printSuccess(
String.format("Réseau Barabási-Albert généré: %,d nœuds, %,d arêtes",
g.getNodeCount(), g.getEdgeCount()));
return g;
}
/**
* Exécute toutes les analyses sur un réseau généré.
*
* Cette méthode privée applique l'ensemble des analyses (métriques de base,
* connexité, distribution des degrés, distances) sur un réseau synthétique.
*
* @param g Le graphe à analyser
* @param networkName Nom du réseau
* @param baseFilename Nom de base pour les fichiers d'export
*/
private static void runAllAnalyses(Graph g, String networkName, String baseFilename) {
ResultsPrinter.printHeader("ANALYSE COMPLÈTE: " + networkName);
// Question 2: Métriques de base
BasicMetrics.analyze(g, networkName);
// Question 3: Connexité
ConnectivityAnalyzer.analyzeConnectivity(g, networkName);
// Question 4: Distribution des degrés
DegreeAnalyzer.analyze(g, networkName, baseFilename);
// Question 5: Distance moyenne (avec échantillon réduit pour les réseaux générés)
if (g.getNodeCount() > 100000) {
ResultsPrinter.printWarning(
"Réseau trop grand, analyse de distance ignorée pour gain de temps");
} else {
DistanceAnalyzer.analyze(g, networkName, baseFilename);
}
}
/**
* Effectue l'analyse complète de la Question 6.
*
* Cette méthode génère un réseau aléatoire et un réseau Barabási-Albert,
* effectue toutes les analyses sur ces réseaux, et les compare avec DBLP
* dans un tableau récapitulatif.
*
* @param dblpGraph Le graphe DBLP de référence
*/
public static void analyze(Graph dblpGraph) {
long startTime = System.currentTimeMillis();
ResultsPrinter.printHeader("QUESTION 6: Comparaison avec générateurs");
int n = dblpGraph.getNodeCount();
double avgDegree = BasicMetrics.getAverageDegree(dblpGraph);
// Utilisation d'une taille réduite pour les performances
int generatedSize = Math.min(n, 50000);
int edgesPerNode = (int) Math.round(avgDegree / 2.0);
ResultsPrinter.printInfo(
String.format("Paramètres DBLP: N=%,d, <k>=%.2f", n, avgDegree));
ResultsPrinter.printInfo(
String.format("Taille des réseaux générés: N=%,d (réduit pour performance)", generatedSize));
// Génération du réseau aléatoire
ResultsPrinter.printSubHeader("Génération réseau aléatoire");
Graph randomGraph = generateRandomGraph(generatedSize, avgDegree);
// Génération du réseau Barabási-Albert
ResultsPrinter.printSubHeader("Génération réseau Barabási-Albert");
Graph baGraph = generateBarabasiAlbert(generatedSize, Math.max(1, edgesPerNode));
// Exécution des analyses
runAllAnalyses(randomGraph, "Aléatoire", "random");
runAllAnalyses(baGraph, "Barabási-Albert", "ba");
// Affichage du tableau comparatif
printComparisonTable(dblpGraph, randomGraph, baGraph);
ResultsPrinter.printElapsedTime(startTime);
}
/**
* Affiche un tableau comparatif des trois réseaux.
*
* Cette méthode privée crée un tableau récapitulatif comparant les propriétés
* principales (nombre de nœuds, arêtes, degré moyen, clustering) des trois
* réseaux: DBLP, aléatoire et Barabási-Albert.
*
* @param dblp Graphe DBLP
* @param random Graphe aléatoire
* @param ba Graphe Barabási-Albert
*/
private static void printComparisonTable(Graph dblp, Graph random, Graph ba) {
ResultsPrinter.printHeader("TABLEAU COMPARATIF");
ResultsPrinter.printComparisonHeader("DBLP", "Aléatoire", "Barabási-Albert");
ResultsPrinter.printComparisonRow("Nœuds",
dblp.getNodeCount(),
random.getNodeCount(),
ba.getNodeCount());
ResultsPrinter.printComparisonRow("Arêtes",
dblp.getEdgeCount(),
random.getEdgeCount(),
ba.getEdgeCount());
ResultsPrinter.printComparisonRow("Degré moyen",
BasicMetrics.getAverageDegree(dblp),
BasicMetrics.getAverageDegree(random),
BasicMetrics.getAverageDegree(ba));
ResultsPrinter.printComparisonRow("Clustering",
BasicMetrics.getClusteringCoefficient(dblp),
BasicMetrics.getClusteringCoefficient(random),
BasicMetrics.getClusteringCoefficient(ba));
ResultsPrinter.printSeparator();
ResultsPrinter.printInfo("CONCLUSIONS:");
ResultsPrinter.printInfo(" - Aléatoire: clustering très faible, pas de structure");
ResultsPrinter.printInfo(" - Barabási-Albert: loi de puissance mais clustering faible");
ResultsPrinter.printInfo(" - DBLP: loi de puissance ET clustering élevé (propriété unique!)");
}
}
package fr.univ.dblp.loader;
import org.graphstream.graph.Graph;
import org.graphstream.graph.implementations.SingleGraph;
import org.graphstream.stream.file.FileSourceEdge;
import java.io.IOException;
/**
* Classe utilitaire pour charger des graphes depuis des fichiers.
*
* Cette classe gère le chargement du réseau de collaboration DBLP
* depuis un fichier au format liste d'arêtes.
*
* @author Hamadou BA
* @see <a href="https://www-apps.univ-lehavre.fr/forge/bh243413/tp2-ri-mesures-de-reseaux-interaction.git">Dépôt Git</a>
*/
public class GraphLoader {
/**
* Charge le réseau de collaboration DBLP depuis un fichier.
*
* Utilise FileSourceEdge de GraphStream pour lire le fichier au format
* liste d'arêtes (chaque ligne contient deux identifiants de nœuds).
*
* @param filePath Chemin vers le fichier de données DBLP
* @return Le graphe chargé, ou null si le chargement a échoué
*/
public static Graph loadDBLP(String filePath) {
System.out.println("\n[CHARGEMENT] Lecture du graphe DBLP depuis: " + filePath);
Graph graph = new SingleGraph("DBLP");
configureGraph(graph);
FileSourceEdge fs = new FileSourceEdge();
fs.addSink(graph);
try {
long startTime = System.currentTimeMillis();
fs.readAll(filePath);
long elapsed = System.currentTimeMillis() - startTime;
System.out.printf(" Graphe chargé avec succès en %.2f secondes%n", elapsed / 1000.0);
displayGraphInfo(graph);
return graph;
} catch (IOException e) {
System.err.println(" [ERREUR] Impossible de charger le graphe: " + e.getMessage());
e.printStackTrace();
return null;
} finally {
fs.removeSink(graph);
}
}
/**
* Configure les propriétés du graphe.
*
* Active la création automatique de nœuds lors de la lecture des arêtes
* et configure le mode non-strict pour gérer les multi-arêtes.
*
* @param graph Le graphe à configurer
*/
private static void configureGraph(Graph graph) {
// Ne pas créer d'arêtes multiples entre les mêmes nœuds
graph.setStrict(false);
// Création automatique des nœuds quand les arêtes les référencent
graph.setAutoCreate(true);
}
/**
* Affiche les informations de base sur le graphe chargé.
*
* Affiche le nombre de nœuds, d'arêtes et le type de graphe
* (dirigé ou non dirigé).
*
* @param graph Le graphe dont on affiche les informations
*/
public static void displayGraphInfo(Graph graph) {
System.out.println("\n[INFORMATION DU GRAPHE]");
System.out.printf(" Nombre de nœuds : %,d%n", graph.getNodeCount());
System.out.printf(" Nombre d'arêtes : %,d%n", graph.getEdgeCount());
// Note: SingleGraph est toujours non dirigé
System.out.printf(" Graphe dirigé : %s%n", "Non");
}
}
package fr.univ.dblp.utils;
import org.graphstream.algorithm.Toolkit;
import org.graphstream.graph.Graph;
import org.graphstream.graph.Node;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
/**
* Utilitaire pour l'échantillonnage aléatoire de nœuds.
*
* Cette classe permet de sélectionner aléatoirement des nœuds d'un graphe,
* utile pour les analyses sur de grands réseaux où il n'est pas possible
* de traiter tous les nœuds.
*
* @author Hamadou BA
* @see <a href="https://www-apps.univ-lehavre.fr/forge/bh243413/tp2-ri-mesures-de-reseaux-interaction.git">Dépôt Git</a>
*/
public class RandomSampler {
/**
* Échantillonne aléatoirement un nombre spécifié de nœuds du graphe.
*
* Cette méthode garantit que chaque nœud n'est sélectionné qu'une seule fois
* (échantillonnage sans remise).
*
* @param g Le graphe dont on extrait les nœuds
* @param sampleSize Nombre de nœuds à échantillonner
* @return Liste des nœuds échantillonnés aléatoirement
* @throws IllegalArgumentException si sampleSize dépasse le nombre de nœuds
*/
public static List<Node> sampleNodes(Graph g, int sampleSize) {
if (sampleSize > g.getNodeCount()) {
throw new IllegalArgumentException(
"Sample size cannot exceed number of nodes");
}
Set<String> sampledIds = new HashSet<>();
List<Node> sampledNodes = new ArrayList<>();
while (sampledNodes.size() < sampleSize) {
Node node = Toolkit.randomNode(g);
if (node != null && !sampledIds.contains(node.getId())) {
sampledIds.add(node.getId());
sampledNodes.add(node);
}
}
return sampledNodes;
}
/**
* Retourne un nœud aléatoire du graphe.
*
* @param g Le graphe
* @return Un nœud choisi aléatoirement
*/
public static Node getRandomNode(Graph g) {
return Toolkit.randomNode(g);
}
}
package fr.univ.dblp.utils;
import java.util.List;
/**
* Fonctions utilitaires pour les calculs statistiques.
*
* Cette classe fournit des méthodes pour calculer des statistiques de base
* comme la moyenne, l'écart-type et la normalisation de distributions.
*
* @author Hamadou BA
* @see <a href="https://www-apps.univ-lehavre.fr/forge/bh243413/tp2-ri-mesures-de-reseaux-interaction.git">Dépôt Git</a>
*/
public class Statistics {
/**
* Calcule la moyenne d'une liste de valeurs.
*
* @param values Liste de valeurs numériques
* @return La moyenne des valeurs
*/
public static double mean(List<Double> values) {
if (values.isEmpty()) return 0.0;
double sum = 0.0;
for (double v : values) {
sum += v;
}
return sum / values.size();
}
/**
* Calcule l'écart-type d'une liste de valeurs.
*
* L'écart-type mesure la dispersion des valeurs autour de la moyenne.
*
* @param values Liste de valeurs numériques
* @return L'écart-type des valeurs
*/
public static double standardDeviation(List<Double> values) {
if (values.isEmpty()) return 0.0;
double mean = mean(values);
double sumSquaredDiff = 0.0;
for (double v : values) {
double diff = v - mean;
sumSquaredDiff += diff * diff;
}
return Math.sqrt(sumSquaredDiff / values.size());
}
/**
* Normalise un tableau de valeurs en probabilités.
*
* Chaque valeur est divisée par le total pour obtenir une distribution
* de probabilités sommant à 1.
*
* @param values Tableau de valeurs entières
* @param total Total des valeurs (pour la normalisation)
* @return Tableau de probabilités normalisées
*/
public static double[] normalize(int[] values, int total) {
double[] normalized = new double[values.length];
for (int i = 0; i < values.length; i++) {
normalized[i] = (double) values[i] / total;
}
return normalized;
}
}
Ce source diff n'a pas pu être affiché car il est trop volumineux. Vous pouvez voir le blob à la place.