Skip to content
GitLab
Projets
Groupes
Sujets
Extraits de code
/
Aide
Aide
Support
Forum de la communauté
Raccourcis clavier
?
Proposer une rétroaction
Contribuer à GitLab
Connexion
Activer/désactiver la navigation
Menu
Hamadou Ba
TP RI Mesures de réseaux interaction
Comparer les révisions
34f551af547228b83fc0aba3e9dec8c0c435c52e...e8ffba295201011987b1b96accdb1b7507634ac3
Masquer les modifications d'espaces
En ligne
Côte à côte
output/data/random_degree_comparison.dat
0 → 100644
Voir le fichier @
e8ffba29
# k p_k poisson_pk
0 0.0013598096 0.0013338133
1 0.0093386926 0.0088294616
2 0.0298558202 0.0292242521
3 0.0635910972 0.0644853901
4 0.1072249885 0.1067186988
5 0.1394604755 0.1412894381
6 0.1567580539 0.1558825956
7 0.1489791429 0.1474140132
8 0.1193432919 0.1219798131
9 0.0908072870 0.0897190435
10 0.0590517328 0.0593914346
11 0.0365548823 0.0357412973
12 0.0191373208 0.0197164284
13 0.0091987122 0.0100397772
14 0.0057191993 0.0047471748
15 0.0022596836 0.0020949957
16 0.0007998880 0.0008667669
17 0.0004799328 0.0003375146
18 0.0000399944 0.0001241250
19 0.0000199972 0.0000432459
20 0.0000199972 0.0000143138
output/data/random_degree_distribution.dat
0 → 100644
Voir le fichier @
e8ffba29
# k p_k
0 0.0013598096
1 0.0093386926
2 0.0298558202
3 0.0635910972
4 0.1072249885
5 0.1394604755
6 0.1567580539
7 0.1489791429
8 0.1193432919
9 0.0908072870
10 0.0590517328
11 0.0365548823
12 0.0191373208
13 0.0091987122
14 0.0057191993
15 0.0022596836
16 0.0007998880
17 0.0004799328
18 0.0000399944
19 0.0000199972
20 0.0000199972
output/data/random_distances.dat
0 → 100644
Voir le fichier @
e8ffba29
# distance frequency
1 6614
2 43997
3 290147
4 1866389
5 10226906
6 26207333
7 10700774
8 440999
9 5007
10 20
output/images/clustering_comparison.png
0 → 100644
Voir le fichier @
e8ffba29
22 ko
output/images/clustering_comparison_log.png
0 → 100644
Voir le fichier @
e8ffba29
24,4 ko
output/images/comparison_all_networks.png
0 → 100644
Voir le fichier @
e8ffba29
35 ko
output/images/dd_comparison.png
0 → 100644
Voir le fichier @
e8ffba29
36,3 ko
output/images/dd_dblp_linear.png
0 → 100644
Voir le fichier @
e8ffba29
28,4 ko
output/images/dd_dblp_loglog.png
0 → 100644
Voir le fichier @
e8ffba29
26,6 ko
output/images/dd_powerlaw_fit.png
0 → 100644
Voir le fichier @
e8ffba29
39,5 ko
output/images/distances_dblp.png
0 → 100644
Voir le fichier @
e8ffba29
32 ko
pom.xml
0 → 100644
Voir le fichier @
e8ffba29
<?xml version="1.0" encoding="UTF-8"?>
<project
xmlns=
"http://maven.apache.org/POM/4.0.0"
xmlns:xsi=
"http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation=
"http://maven.apache.org/POM/4.0.0
http://maven.apache.org/xsd/maven-4.0.0.xsd"
>
<modelVersion>
4.0.0
</modelVersion>
<groupId>
fr.univ
</groupId>
<artifactId>
dblp-network-analysis
</artifactId>
<version>
1.0-SNAPSHOT
</version>
<packaging>
jar
</packaging>
<name>
DBLP Network Analysis
</name>
<description>
TP analyse réseau de collaboration DBLP avec GraphStream
</description>
<properties>
<project.build.sourceEncoding>
UTF-8
</project.build.sourceEncoding>
<maven.compiler.source>
11
</maven.compiler.source>
<maven.compiler.target>
11
</maven.compiler.target>
<graphstream.version>
2.0
</graphstream.version>
</properties>
<dependencies>
<!-- GraphStream Core -->
<dependency>
<groupId>
org.graphstream
</groupId>
<artifactId>
gs-core
</artifactId>
<version>
${graphstream.version}
</version>
</dependency>
<!-- GraphStream Algorithms -->
<dependency>
<groupId>
org.graphstream
</groupId>
<artifactId>
gs-algo
</artifactId>
<version>
${graphstream.version}
</version>
</dependency>
<!-- GraphStream UI Swing pour visualisation -->
<dependency>
<groupId>
org.graphstream
</groupId>
<artifactId>
gs-ui-swing
</artifactId>
<version>
${graphstream.version}
</version>
</dependency>
</dependencies>
<build>
<plugins>
<!-- Compiler Plugin -->
<plugin>
<groupId>
org.apache.maven.plugins
</groupId>
<artifactId>
maven-compiler-plugin
</artifactId>
<version>
3.11.0
</version>
<configuration>
<source>
11
</source>
<target>
11
</target>
</configuration>
</plugin>
<!-- Exec Plugin pour exécuter Main -->
<plugin>
<groupId>
org.codehaus.mojo
</groupId>
<artifactId>
exec-maven-plugin
</artifactId>
<version>
3.1.0
</version>
<configuration>
<mainClass>
fr.univ.dblp.Main
</mainClass>
</configuration>
</plugin>
<!-- Assembly Plugin pour créer JAR exécutable -->
<plugin>
<groupId>
org.apache.maven.plugins
</groupId>
<artifactId>
maven-assembly-plugin
</artifactId>
<version>
3.6.0
</version>
<configuration>
<archive>
<manifest>
<mainClass>
fr.univ.dblp.Main
</mainClass>
</manifest>
</archive>
<descriptorRefs>
<descriptorRef>
jar-with-dependencies
</descriptorRef>
</descriptorRefs>
</configuration>
<executions>
<execution>
<id>
make-assembly
</id>
<phase>
package
</phase>
<goals>
<goal>
single
</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
src/main/java/fr/univ/dblp/Main.java
0 → 100644
Voir le fichier @
e8ffba29
package
fr.univ.dblp
;
import
fr.univ.dblp.analysis.*
;
import
fr.univ.dblp.export.ResultsPrinter
;
import
fr.univ.dblp.generators.CopyGenerator
;
import
fr.univ.dblp.generators.NetworkGenerator
;
import
fr.univ.dblp.loader.GraphLoader
;
import
org.graphstream.graph.Graph
;
import
java.util.Scanner
;
/**
* Point d'entrée principal pour l'analyse du réseau DBLP.
*
* Cette classe gère le menu interactif et orchestre l'exécution
* des différentes analyses du réseau de collaboration scientifique DBLP.
*
* @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
Main
{
private
static
final
String
DBLP_FILE_PATH
=
"src/main/resources/snap/com-dblp.ungraph.txt"
;
private
static
Graph
dblpGraph
=
null
;
private
static
Graph
baGraph
=
null
;
public
static
void
main
(
String
[]
args
)
{
ResultsPrinter
.
printHeader
(
"TP: ANALYSE DU RÉSEAU DBLP"
);
ResultsPrinter
.
printInfo
(
"Mesures de réseaux d'interaction - Collaboration scientifique"
);
ResultsPrinter
.
printInfo
(
"Données: DBLP (Digital Bibliography & Library Project)"
);
System
.
out
.
println
();
// Chargement initial du graphe DBLP
runQuestion1
();
if
(
dblpGraph
==
null
)
{
ResultsPrinter
.
printError
(
"Impossible de charger le graphe DBLP!"
);
ResultsPrinter
.
printError
(
"Vérifiez que le fichier existe: "
+
DBLP_FILE_PATH
);
return
;
}
// Affichage du menu interactif
Scanner
scanner
=
new
Scanner
(
System
.
in
);
boolean
continueRunning
=
true
;
while
(
continueRunning
)
{
displayMenu
();
System
.
out
.
print
(
"\nVotre choix: "
);
String
choice
=
scanner
.
nextLine
().
trim
();
switch
(
choice
)
{
case
"1"
:
runQuestion1
();
break
;
case
"2"
:
runQuestion2
();
break
;
case
"3"
:
runQuestion3
();
break
;
case
"4"
:
runQuestion4
();
break
;
case
"5"
:
runQuestion5
();
break
;
case
"6"
:
runQuestion6
();
break
;
case
"7"
:
runQuestion7
();
break
;
case
"8"
:
runAllQuestions
();
break
;
case
"0"
:
continueRunning
=
false
;
ResultsPrinter
.
printInfo
(
"Au revoir!"
);
break
;
default
:
ResultsPrinter
.
printWarning
(
"Choix invalide! Essayez encore."
);
}
if
(
continueRunning
&&
!
choice
.
equals
(
"8"
))
{
System
.
out
.
println
(
"\nAppuyez sur Entrée pour continuer..."
);
scanner
.
nextLine
();
}
}
scanner
.
close
();
}
/**
* Affiche le menu interactif principal.
*
* Ce menu permet à l'utilisateur de choisir quelle analyse exécuter
* parmi les 7 questions du TP ou d'exécuter toutes les analyses en séquence.
*/
private
static
void
displayMenu
()
{
System
.
out
.
println
(
"\n"
+
"="
.
repeat
(
80
));
System
.
out
.
println
(
"MENU PRINCIPAL"
);
System
.
out
.
println
(
"="
.
repeat
(
80
));
System
.
out
.
println
(
" 1. Question 1 - Chargement des données"
);
System
.
out
.
println
(
" 2. Question 2 - Mesures de base"
);
System
.
out
.
println
(
" 3. Question 3 - Analyse de connexité"
);
System
.
out
.
println
(
" 4. Question 4 - Distribution des degrés"
);
System
.
out
.
println
(
" 5. Question 5 - Distance moyenne"
);
System
.
out
.
println
(
" 6. Question 6 - Comparaison avec générateurs"
);
System
.
out
.
println
(
" 7. Question 7 - Générateur par copie (BONUS)"
);
System
.
out
.
println
(
" 8. TOUT EXÉCUTER (Questions 1-7)"
);
System
.
out
.
println
(
" 0. Quitter"
);
System
.
out
.
println
(
"="
.
repeat
(
80
));
}
/**
* Question 1: Charge les données du réseau DBLP.
*
* Cette méthode charge le graphe de collaboration DBLP depuis le fichier
* de données et affiche les informations de base sur le graphe chargé.
*/
private
static
void
runQuestion1
()
{
ResultsPrinter
.
printHeader
(
"QUESTION 1: Chargement des données"
);
dblpGraph
=
GraphLoader
.
loadDBLP
(
DBLP_FILE_PATH
);
if
(
dblpGraph
!=
null
)
{
ResultsPrinter
.
printSuccess
(
"Graphe DBLP chargé avec succès!"
);
GraphLoader
.
displayGraphInfo
(
dblpGraph
);
ResultsPrinter
.
printInfo
(
"\nNote: La visualisation n'est pas recommandée pour ce graphe"
);
ResultsPrinter
.
printInfo
(
" (trop de nœuds: visualisation très lente et peu informative)"
);
}
}
/**
* Question 2: Calcule et affiche les mesures de base du réseau.
*
* Cette méthode calcule le nombre de nœuds, d'arêtes, le degré moyen
* et le coefficient de clustering du réseau DBLP.
*/
private
static
void
runQuestion2
()
{
if
(
dblpGraph
==
null
)
{
ResultsPrinter
.
printError
(
"Chargez d'abord le graphe (Question 1)!"
);
return
;
}
BasicMetrics
.
analyze
(
dblpGraph
,
"DBLP"
);
}
/**
* Question 3: Analyse la connexité du réseau.
*
* Cette méthode vérifie si le réseau est connexe, compte le nombre de
* composantes connexes et détermine le degré critique pour la connexité.
*/
private
static
void
runQuestion3
()
{
if
(
dblpGraph
==
null
)
{
ResultsPrinter
.
printError
(
"Chargez d'abord le graphe (Question 1)!"
);
return
;
}
ConnectivityAnalyzer
.
analyze
(
dblpGraph
);
}
/**
* Question 4: Analyse la distribution des degrés du réseau.
*
* Cette méthode calcule la distribution des degrés, l'exporte pour
* visualisation avec gnuplot et vérifie si elle suit une loi de puissance.
*/
private
static
void
runQuestion4
()
{
if
(
dblpGraph
==
null
)
{
ResultsPrinter
.
printError
(
"Chargez d'abord le graphe (Question 1)!"
);
return
;
}
DegreeAnalyzer
.
analyze
(
dblpGraph
,
"DBLP"
,
"dblp"
);
ResultsPrinter
.
printInfo
(
"\nPour générer les graphiques avec gnuplot:"
);
ResultsPrinter
.
printInfo
(
" cd gnuplot"
);
ResultsPrinter
.
printInfo
(
" gnuplot plot_dd_linear.gnu"
);
ResultsPrinter
.
printInfo
(
" gnuplot plot_dd_loglog.gnu"
);
ResultsPrinter
.
printInfo
(
" gnuplot plot_dd_powerlaw.gnu"
);
}
/**
* Question 5: Calcule la distance moyenne du réseau.
*
* Cette méthode effectue un échantillonnage de 1000 nœuds et calcule
* la distance moyenne par parcours BFS. Attention: opération longue (15-25 min).
*/
private
static
void
runQuestion5
()
{
if
(
dblpGraph
==
null
)
{
ResultsPrinter
.
printError
(
"Chargez d'abord le graphe (Question 1)!"
);
return
;
}
ResultsPrinter
.
printWarning
(
"ATTENTION: Cette analyse peut prendre 15-25 minutes!"
);
ResultsPrinter
.
printInfo
(
"(1000 parcours BFS sur un graphe de 317k nœuds)"
);
System
.
out
.
print
(
"\nContinuer? (o/n): "
);
Scanner
scanner
=
new
Scanner
(
System
.
in
);
String
response
=
scanner
.
nextLine
().
trim
().
toLowerCase
();
if
(
response
.
equals
(
"o"
)
||
response
.
equals
(
"oui"
)
||
response
.
equals
(
"y"
)
||
response
.
equals
(
"yes"
))
{
DistanceAnalyzer
.
analyze
(
dblpGraph
,
"DBLP"
,
"dblp"
);
ResultsPrinter
.
printInfo
(
"\nPour générer le graphique avec gnuplot:"
);
ResultsPrinter
.
printInfo
(
" cd gnuplot && gnuplot plot_distances.gnu"
);
}
else
{
ResultsPrinter
.
printInfo
(
"Analyse annulée."
);
}
}
/**
* Question 6: Compare le réseau DBLP avec des générateurs de réseaux.
*
* Cette méthode génère un réseau aléatoire (Erdős-Rényi) et un réseau
* Barabási-Albert, puis compare leurs propriétés avec DBLP. Durée: 30-40 min.
*/
private
static
void
runQuestion6
()
{
if
(
dblpGraph
==
null
)
{
ResultsPrinter
.
printError
(
"Chargez d'abord le graphe (Question 1)!"
);
return
;
}
ResultsPrinter
.
printWarning
(
"ATTENTION: Cette analyse peut prendre 30-40 minutes!"
);
ResultsPrinter
.
printInfo
(
"(Génération et analyse de 2 grands réseaux)"
);
System
.
out
.
print
(
"\nContinuer? (o/n): "
);
Scanner
scanner
=
new
Scanner
(
System
.
in
);
String
response
=
scanner
.
nextLine
().
trim
().
toLowerCase
();
if
(
response
.
equals
(
"o"
)
||
response
.
equals
(
"oui"
)
||
response
.
equals
(
"y"
)
||
response
.
equals
(
"yes"
))
{
NetworkGenerator
.
analyze
(
dblpGraph
);
ResultsPrinter
.
printInfo
(
"\nPour générer le graphique comparatif:"
);
ResultsPrinter
.
printInfo
(
" cd gnuplot && gnuplot plot_comparison_networks.gnu"
);
}
else
{
ResultsPrinter
.
printInfo
(
"Analyse annulée."
);
}
}
/**
* Question 7 (BONUS): Teste le générateur par copie.
*
* Cette méthode génère un réseau avec le mécanisme de copie et compare
* son clustering avec DBLP et Barabási-Albert. Durée: 15-20 min.
*/
private
static
void
runQuestion7
()
{
if
(
dblpGraph
==
null
)
{
ResultsPrinter
.
printError
(
"Chargez d'abord le graphe (Question 1)!"
);
return
;
}
// Génération du graphe BA si nécessaire pour la comparaison
if
(
baGraph
==
null
)
{
ResultsPrinter
.
printInfo
(
"Génération du graphe Barabási-Albert pour comparaison..."
);
int
n
=
Math
.
min
(
dblpGraph
.
getNodeCount
(),
50000
);
double
avgDegree
=
BasicMetrics
.
getAverageDegree
(
dblpGraph
);
int
edgesPerNode
=
(
int
)
Math
.
round
(
avgDegree
/
2.0
);
baGraph
=
NetworkGenerator
.
generateBarabasiAlbert
(
n
,
Math
.
max
(
1
,
edgesPerNode
));
}
ResultsPrinter
.
printWarning
(
"ATTENTION: Cette analyse peut prendre 15-20 minutes!"
);
System
.
out
.
print
(
"\nContinuer? (o/n): "
);
Scanner
scanner
=
new
Scanner
(
System
.
in
);
String
response
=
scanner
.
nextLine
().
trim
().
toLowerCase
();
if
(
response
.
equals
(
"o"
)
||
response
.
equals
(
"oui"
)
||
response
.
equals
(
"y"
)
||
response
.
equals
(
"yes"
))
{
CopyGenerator
.
analyze
(
dblpGraph
,
baGraph
);
}
else
{
ResultsPrinter
.
printInfo
(
"Analyse annulée."
);
}
}
/**
* Exécute toutes les questions en séquence.
*
* Cette méthode lance l'exécution automatique de toutes les analyses
* (Questions 1 à 7) sans interruption. Durée totale: environ 1h30.
*/
private
static
void
runAllQuestions
()
{
ResultsPrinter
.
printHeader
(
"EXÉCUTION COMPLÈTE - TOUTES LES QUESTIONS"
);
ResultsPrinter
.
printWarning
(
"ATTENTION: L'exécution complète peut prendre 1h30 à 2h!"
);
ResultsPrinter
.
printInfo
(
"Les questions longues (Q5, Q6, Q7) seront exécutées automatiquement."
);
System
.
out
.
print
(
"\nVoulez-vous vraiment tout exécuter? (o/n): "
);
Scanner
scanner
=
new
Scanner
(
System
.
in
);
String
response
=
scanner
.
nextLine
().
trim
().
toLowerCase
();
if
(!
response
.
equals
(
"o"
)
&&
!
response
.
equals
(
"oui"
)
&&
!
response
.
equals
(
"y"
)
&&
!
response
.
equals
(
"yes"
))
{
ResultsPrinter
.
printInfo
(
"Exécution annulée."
);
return
;
}
long
globalStart
=
System
.
currentTimeMillis
();
// Question 1: Chargement
if
(
dblpGraph
==
null
)
{
runQuestion1
();
}
// Question 2: Mesures de base
if
(
dblpGraph
!=
null
)
{
runQuestion2
();
}
// Question 3: Connexité
if
(
dblpGraph
!=
null
)
{
runQuestion3
();
}
// Question 4: Distribution des degrés
if
(
dblpGraph
!=
null
)
{
runQuestion4
();
}
// Question 5: Distance moyenne
if
(
dblpGraph
!=
null
)
{
ResultsPrinter
.
printInfo
(
"\n>>> Démarrage Question 5 (Distance moyenne)..."
);
DistanceAnalyzer
.
analyze
(
dblpGraph
,
"DBLP"
,
"dblp"
);
}
// Question 6: Comparaison avec générateurs
if
(
dblpGraph
!=
null
)
{
ResultsPrinter
.
printInfo
(
"\n>>> Démarrage Question 6 (Générateurs)..."
);
NetworkGenerator
.
analyze
(
dblpGraph
);
}
// Question 7: Générateur par copie (BONUS)
if
(
dblpGraph
!=
null
)
{
ResultsPrinter
.
printInfo
(
"\n>>> Démarrage Question 7 (Générateur copie - BONUS)..."
);
// Génération du graphe BA si nécessaire
if
(
baGraph
==
null
)
{
int
n
=
Math
.
min
(
dblpGraph
.
getNodeCount
(),
50000
);
double
avgDegree
=
BasicMetrics
.
getAverageDegree
(
dblpGraph
);
int
edgesPerNode
=
(
int
)
Math
.
round
(
avgDegree
/
2.0
);
baGraph
=
NetworkGenerator
.
generateBarabasiAlbert
(
n
,
Math
.
max
(
1
,
edgesPerNode
));
}
CopyGenerator
.
analyze
(
dblpGraph
,
baGraph
);
}
ResultsPrinter
.
printHeader
(
"TOUTES LES ANALYSES TERMINÉES!"
);
ResultsPrinter
.
printElapsedTime
(
globalStart
);
ResultsPrinter
.
printInfo
(
"\nPROCHAINES ÉTAPES:"
);
ResultsPrinter
.
printInfo
(
" 1. Générez les graphiques avec gnuplot (voir gnuplot/*.gnu)"
);
ResultsPrinter
.
printInfo
(
" 2. Consultez les fichiers de données dans output/data/"
);
ResultsPrinter
.
printInfo
(
" 3. Rédigez le rapport README.md avec les résultats et graphiques"
);
}
}
src/main/java/fr/univ/dblp/analysis/BasicMetrics.java
0 → 100644
Voir le fichier @
e8ffba29
package
fr.univ.dblp.analysis
;
import
fr.univ.dblp.export.ResultsPrinter
;
import
org.graphstream.algorithm.Toolkit
;
import
org.graphstream.graph.Graph
;
/**
* Calcule les métriques de base d'un réseau (Question 2).
*
* Cette classe permet de calculer et d'afficher les mesures fondamentales
* d'un réseau: nombre de nœuds, nombre d'arêtes, degré moyen et coefficient
* de clustering. Elle compare également ces métriques avec un réseau aléatoire
* théorique de même taille.
*
* @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
BasicMetrics
{
/**
* Retourne le nombre de nœuds du graphe.
*
* @param g Le graphe à analyser
* @return Le nombre de nœuds
*/
public
static
int
getNodeCount
(
Graph
g
)
{
return
g
.
getNodeCount
();
}
/**
* Retourne le nombre d'arêtes du graphe.
*
* @param g Le graphe à analyser
* @return Le nombre d'arêtes
*/
public
static
int
getEdgeCount
(
Graph
g
)
{
return
g
.
getEdgeCount
();
}
/**
* Calcule le degré moyen du graphe.
*
* @param g Le graphe à analyser
* @return Le degré moyen
*/
public
static
double
getAverageDegree
(
Graph
g
)
{
return
Toolkit
.
averageDegree
(
g
);
}
/**
* Calcule le coefficient de clustering du graphe.
*
* Le coefficient de clustering mesure la probabilité que deux voisins
* d'un nœud soient également voisins entre eux (formation de triangles).
*
* @param g Le graphe à analyser
* @return Le coefficient de clustering moyen
*/
public
static
double
getClusteringCoefficient
(
Graph
g
)
{
return
Toolkit
.
averageClusteringCoefficient
(
g
);
}
/**
* Calcule le coefficient de clustering théorique d'un réseau aléatoire.
*
* Pour un réseau aléatoire de même taille et même degré moyen,
* le coefficient de clustering théorique est: C = <k> / N
*
* @param n Nombre de nœuds du réseau
* @param avgDegree Degré moyen du réseau
* @return Coefficient de clustering théorique
*/
public
static
double
theoreticalRandomClusteringCoeff
(
int
n
,
double
avgDegree
)
{
return
avgDegree
/
n
;
}
/**
* Affiche toutes les métriques de base d'un réseau.
*
* Cette méthode calcule et affiche le nombre de nœuds, d'arêtes,
* le degré moyen et le coefficient de clustering. Elle compare
* également le clustering avec un réseau aléatoire théorique.
*
* @param g Le graphe à analyser
* @param networkName Le nom du réseau (pour l'affichage)
*/
public
static
void
printMetrics
(
Graph
g
,
String
networkName
)
{
ResultsPrinter
.
printHeader
(
"QUESTION 2: Mesures de base - "
+
networkName
);
int
nodes
=
getNodeCount
(
g
);
int
edges
=
getEdgeCount
(
g
);
double
avgDegree
=
getAverageDegree
(
g
);
double
clustering
=
getClusteringCoefficient
(
g
);
ResultsPrinter
.
printMetric
(
"Nombre de nœuds"
,
nodes
);
ResultsPrinter
.
printMetric
(
"Nombre d'arêtes"
,
edges
);
ResultsPrinter
.
printMetric
(
"Degré moyen"
,
avgDegree
);
ResultsPrinter
.
printMetric
(
"Coefficient de clustering"
,
clustering
);
// Comparaison avec un réseau aléatoire théorique
double
theoreticalClustering
=
theoreticalRandomClusteringCoeff
(
nodes
,
avgDegree
);
ResultsPrinter
.
printSeparator
();
ResultsPrinter
.
printInfo
(
"Comparaison avec un réseau aléatoire de même taille:"
);
ResultsPrinter
.
printMetric
(
"Clustering théorique (aléatoire)"
,
theoreticalClustering
);
double
ratio
=
clustering
/
theoreticalClustering
;
ResultsPrinter
.
printMetric
(
"Ratio (DBLP / aléatoire)"
,
ratio
);
if
(
ratio
>
1000
)
{
ResultsPrinter
.
printInfo
(
String
.
format
(
"Le clustering du réseau DBLP est %.0fx plus élevé qu'un réseau aléatoire!"
,
ratio
));
}
}
/**
* Analyse et affiche les métriques de base d'un graphe.
*
* Cette méthode orchestre l'analyse complète en appelant printMetrics()
* et en affichant le temps d'exécution total.
*
* @param g Le graphe à analyser
* @param networkName Le nom du réseau (pour l'affichage)
*/
public
static
void
analyze
(
Graph
g
,
String
networkName
)
{
long
startTime
=
System
.
currentTimeMillis
();
printMetrics
(
g
,
networkName
);
ResultsPrinter
.
printElapsedTime
(
startTime
);
}
}
src/main/java/fr/univ/dblp/analysis/ConnectivityAnalyzer.java
0 → 100644
Voir le fichier @
e8ffba29
package
fr.univ.dblp.analysis
;
import
fr.univ.dblp.export.ResultsPrinter
;
import
org.graphstream.algorithm.ConnectedComponents
;
import
org.graphstream.graph.Graph
;
import
org.graphstream.graph.implementations.SingleGraph
;
import
org.graphstream.algorithm.generator.RandomGenerator
;
/**
* Analyse la connexité d'un réseau (Question 3).
*
* Cette classe permet de vérifier si un réseau est connexe, de compter
* le nombre de composantes connexes et de déterminer le degré critique
* pour la connexité d'un réseau aléatoire.
*
* @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
ConnectivityAnalyzer
{
/**
* Vérifie si le graphe est connexe.
*
* Un graphe est connexe s'il existe un chemin entre toute paire de nœuds,
* c'est-à-dire s'il ne contient qu'une seule composante connexe.
*
* @param g Le graphe à analyser
* @return true si le graphe est connexe, false sinon
*/
public
static
boolean
isConnected
(
Graph
g
)
{
ConnectedComponents
cc
=
new
ConnectedComponents
();
cc
.
init
(
g
);
cc
.
compute
();
return
cc
.
getConnectedComponentsCount
()
==
1
;
}
/**
* Compte le nombre de composantes connexes du graphe.
*
* Une composante connexe est un sous-ensemble maximal de nœuds
* tel qu'il existe un chemin entre toute paire de nœuds de ce sous-ensemble.
*
* @param g Le graphe à analyser
* @return Le nombre de composantes connexes
*/
public
static
int
countConnectedComponents
(
Graph
g
)
{
ConnectedComponents
cc
=
new
ConnectedComponents
();
cc
.
init
(
g
);
cc
.
compute
();
return
cc
.
getConnectedComponentsCount
();
}
/**
* Génère un réseau aléatoire avec une taille et un degré moyen donnés.
*
* Utilise le modèle d'Erdős-Rényi pour créer un graphe aléatoire
* où les arêtes sont créées aléatoirement.
*
* @param n Nombre de nœuds du réseau
* @param avgDegree Degré moyen souhaité
* @return Le graphe aléatoire généré
*/
public
static
Graph
generateRandomGraph
(
int
n
,
double
avgDegree
)
{
Graph
g
=
new
SingleGraph
(
"Random"
);
g
.
setStrict
(
false
);
g
.
setAutoCreate
(
true
);
// Nombre d'arêtes nécessaires: E = (N × degré_moyen) / 2
int
targetEdges
=
(
int
)
Math
.
round
((
n
*
avgDegree
)
/
2.0
);
// Utilisation du générateur aléatoire de GraphStream
RandomGenerator
gen
=
new
RandomGenerator
(
avgDegree
);
gen
.
addSink
(
g
);
gen
.
begin
();
// Génération des nœuds et arêtes
for
(
int
i
=
0
;
i
<
n
&&
g
.
getEdgeCount
()
<
targetEdges
;
i
++)
{
gen
.
nextEvents
();
}
gen
.
end
();
return
g
;
}
/**
* Trouve le degré critique pour la connexité d'un réseau aléatoire.
*
* Utilise une recherche binaire pour déterminer le degré moyen minimum
* au-dessus duquel un réseau aléatoire devient connexe. La théorie prédit
* que ce degré critique est approximativement ln(N).
*
* @param nodeCount Nombre de nœuds du réseau
* @return Le degré critique expérimental
*/
public
static
double
findCriticalAverageDegree
(
int
nodeCount
)
{
ResultsPrinter
.
printInfo
(
"Recherche du degré critique pour la connexité..."
);
ResultsPrinter
.
printInfo
(
"(Cela peut prendre quelques minutes)"
);
double
theoreticalCritical
=
Math
.
log
(
nodeCount
);
ResultsPrinter
.
printInfo
(
String
.
format
(
"Degré critique théorique: %.2f (ln(%,d))"
,
theoreticalCritical
,
nodeCount
));
// Utilisation d'une taille réduite pour accélérer le calcul
int
sampleSize
=
Math
.
min
(
nodeCount
,
10000
);
double
low
=
1.0
;
double
high
=
theoreticalCritical
*
2
;
double
epsilon
=
0.1
;
while
(
high
-
low
>
epsilon
)
{
double
mid
=
(
low
+
high
)
/
2.0
;
ResultsPrinter
.
printInfo
(
String
.
format
(
" Test degré moyen = %.2f"
,
mid
));
// Tests multiples pour plus de fiabilité statistique
int
connectedCount
=
0
;
int
trials
=
5
;
for
(
int
trial
=
0
;
trial
<
trials
;
trial
++)
{
Graph
testGraph
=
generateRandomGraph
(
sampleSize
,
mid
);
if
(
isConnected
(
testGraph
))
{
connectedCount
++;
}
}
// Si la majorité sont connexes, on teste avec un degré plus faible
if
(
connectedCount
>=
trials
/
2
)
{
high
=
mid
;
}
else
{
low
=
mid
;
}
}
double
critical
=
(
low
+
high
)
/
2.0
;
ResultsPrinter
.
printSuccess
(
String
.
format
(
"Degré critique trouvé: %.2f"
,
critical
));
return
critical
;
}
/**
* Analyse la connexité d'un graphe et affiche les résultats.
*
* @param g Le graphe à analyser
* @param networkName Le nom du réseau (pour l'affichage)
*/
public
static
void
analyzeConnectivity
(
Graph
g
,
String
networkName
)
{
ResultsPrinter
.
printSubHeader
(
"Analyse de connexité - "
+
networkName
);
boolean
connected
=
isConnected
(
g
);
int
componentCount
=
countConnectedComponents
(
g
);
ResultsPrinter
.
printMetric
(
"Graphe connexe"
,
connected
?
"Oui"
:
"Non"
);
ResultsPrinter
.
printMetric
(
"Nombre de composantes connexes"
,
componentCount
);
if
(!
connected
)
{
ResultsPrinter
.
printWarning
(
"Le graphe n'est pas connexe!"
);
}
}
/**
* Effectue l'analyse complète de la Question 3.
*
* Cette méthode analyse la connexité du réseau DBLP, génère et teste
* un réseau aléatoire équivalent, et détermine le degré critique
* pour la connexité.
*
* @param dblpGraph Le graphe DBLP à analyser
*/
public
static
void
analyze
(
Graph
dblpGraph
)
{
long
startTime
=
System
.
currentTimeMillis
();
ResultsPrinter
.
printHeader
(
"QUESTION 3: Analyse de connexité"
);
// 1. Vérification de la connexité de DBLP
analyzeConnectivity
(
dblpGraph
,
"DBLP"
);
// 2. Génération et test d'un réseau aléatoire avec les mêmes paramètres
ResultsPrinter
.
printSubHeader
(
"Réseau aléatoire (même taille et degré moyen)"
);
int
n
=
dblpGraph
.
getNodeCount
();
double
avgDegree
=
BasicMetrics
.
getAverageDegree
(
dblpGraph
);
ResultsPrinter
.
printInfo
(
String
.
format
(
"Génération d'un réseau aléatoire: N=%,d, <k>=%.2f"
,
n
,
avgDegree
));
// Utilisation d'une taille réduite pour accélérer le calcul
int
randomSize
=
Math
.
min
(
n
,
50000
);
ResultsPrinter
.
printInfo
(
String
.
format
(
"(Utilisation d'une taille réduite pour le calcul: N=%,d)"
,
randomSize
));
Graph
randomGraph
=
generateRandomGraph
(
randomSize
,
avgDegree
);
analyzeConnectivity
(
randomGraph
,
"Aléatoire"
);
// 3. Recherche du degré critique
ResultsPrinter
.
printSubHeader
(
"Degré critique pour connexité"
);
double
critical
=
findCriticalAverageDegree
(
randomSize
);
double
theoreticalCritical
=
Math
.
log
(
randomSize
);
ResultsPrinter
.
printSeparator
();
ResultsPrinter
.
printMetric
(
"Degré critique (expérimental)"
,
critical
);
ResultsPrinter
.
printMetric
(
"Degré critique (théorique ln(N))"
,
theoreticalCritical
);
ResultsPrinter
.
printMetric
(
"Différence"
,
Math
.
abs
(
critical
-
theoreticalCritical
));
ResultsPrinter
.
printElapsedTime
(
startTime
);
}
}
src/main/java/fr/univ/dblp/analysis/DegreeAnalyzer.java
0 → 100644
Voir le fichier @
e8ffba29
package
fr.univ.dblp.analysis
;
import
fr.univ.dblp.export.DataExporter
;
import
fr.univ.dblp.export.ResultsPrinter
;
import
org.graphstream.algorithm.Toolkit
;
import
org.graphstream.graph.Graph
;
/**
* Analyse la distribution des degrés d'un réseau (Question 4).
*
* Cette classe calcule la distribution des degrés, l'exporte pour
* visualisation avec gnuplot et la compare avec une distribution de Poisson
* théorique pour identifier si le réseau suit une loi de puissance.
*
* @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
DegreeAnalyzer
{
/**
* Calcule la distribution des degrés du graphe.
*
* Retourne un tableau où l'indice représente le degré et la valeur
* représente le nombre de nœuds ayant ce degré.
*
* @param g Le graphe à analyser
* @return Tableau de la distribution des degrés
*/
public
static
int
[]
getDegreeDistribution
(
Graph
g
)
{
return
Toolkit
.
degreeDistribution
(
g
);
}
/**
* Normalise la distribution pour obtenir des probabilités.
*
* Chaque valeur est divisée par le nombre total de nœuds pour obtenir
* la probabilité qu'un nœud ait un degré donné.
*
* @param dd Distribution des degrés (nombre de nœuds par degré)
* @param nodeCount Nombre total de nœuds
* @return Distribution normalisée (probabilités)
*/
public
static
double
[]
normalizeDistribution
(
int
[]
dd
,
int
nodeCount
)
{
double
[]
normalized
=
new
double
[
dd
.
length
];
for
(
int
i
=
0
;
i
<
dd
.
length
;
i
++)
{
normalized
[
i
]
=
(
double
)
dd
[
i
]
/
nodeCount
;
}
return
normalized
;
}
/**
* Exporte la distribution des degrés pour visualisation avec gnuplot.
*
* @param g Le graphe à analyser
* @param outputFile Chemin du fichier de sortie
*/
public
static
void
exportForGnuplot
(
Graph
g
,
String
outputFile
)
{
int
[]
dd
=
getDegreeDistribution
(
g
);
int
nodeCount
=
g
.
getNodeCount
();
DataExporter
.
exportDegreeDistribution
(
dd
,
nodeCount
,
outputFile
);
}
/**
* Exporte la distribution avec comparaison à une distribution de Poisson.
*
* Permet de comparer la distribution réelle avec celle d'un réseau
* aléatoire théorique (distribution de Poisson).
*
* @param g Le graphe à analyser
* @param outputFile Chemin du fichier de sortie
*/
public
static
void
exportWithPoisson
(
Graph
g
,
String
outputFile
)
{
int
[]
dd
=
getDegreeDistribution
(
g
);
int
nodeCount
=
g
.
getNodeCount
();
double
avgDegree
=
BasicMetrics
.
getAverageDegree
(
g
);
DataExporter
.
exportDegreeDistributionWithPoisson
(
dd
,
nodeCount
,
avgDegree
,
outputFile
);
}
/**
* Analyse la distribution des degrés et affiche les statistiques.
*
* @param g Le graphe à analyser
* @param networkName Nom du réseau (pour l'affichage)
*/
public
static
void
analyzeDistribution
(
Graph
g
,
String
networkName
)
{
ResultsPrinter
.
printSubHeader
(
"Distribution des degrés - "
+
networkName
);
int
[]
dd
=
getDegreeDistribution
(
g
);
int
nodeCount
=
g
.
getNodeCount
();
// Recherche du degré maximum
int
maxDegree
=
dd
.
length
-
1
;
ResultsPrinter
.
printMetric
(
"Degré maximum"
,
maxDegree
);
// Comptage des nœuds avec degrés spécifiques
int
degreeZero
=
dd
.
length
>
0
?
dd
[
0
]
:
0
;
ResultsPrinter
.
printMetric
(
"Nœuds de degré 0"
,
degreeZero
);
if
(
degreeZero
>
0
)
{
ResultsPrinter
.
printWarning
(
String
.
format
(
"%d nœuds isolés détectés!"
,
degreeZero
));
}
}
/**
* Effectue l'analyse complète de la Question 4.
*
* Cette méthode analyse la distribution des degrés, exporte les données
* pour gnuplot et fournit des indications pour l'interprétation.
*
* @param g Le graphe à analyser
* @param networkName Nom du réseau (pour l'affichage)
* @param baseFilename Nom de base pour les fichiers de sortie
*/
public
static
void
analyze
(
Graph
g
,
String
networkName
,
String
baseFilename
)
{
long
startTime
=
System
.
currentTimeMillis
();
ResultsPrinter
.
printHeader
(
"QUESTION 4: Distribution des degrés - "
+
networkName
);
analyzeDistribution
(
g
,
networkName
);
// Export pour gnuplot
ResultsPrinter
.
printInfo
(
"Export des données pour gnuplot..."
);
String
degreeFile
=
"output/data/"
+
baseFilename
+
"_degree_distribution.dat"
;
String
comparisonFile
=
"output/data/"
+
baseFilename
+
"_degree_comparison.dat"
;
exportForGnuplot
(
g
,
degreeFile
);
exportWithPoisson
(
g
,
comparisonFile
);
ResultsPrinter
.
printInfo
(
"Observations attendues en échelle log-log:"
);
ResultsPrinter
.
printInfo
(
" - Ligne droite = loi de puissance p_k = C * k^(-γ)"
);
ResultsPrinter
.
printInfo
(
" - Utilisez gnuplot pour tracer et ajuster la loi"
);
ResultsPrinter
.
printElapsedTime
(
startTime
);
}
}
src/main/java/fr/univ/dblp/analysis/DistanceAnalyzer.java
0 → 100644
Voir le fichier @
e8ffba29
package
fr.univ.dblp.analysis
;
import
fr.univ.dblp.export.DataExporter
;
import
fr.univ.dblp.export.ResultsPrinter
;
import
fr.univ.dblp.utils.RandomSampler
;
import
org.graphstream.graph.Edge
;
import
org.graphstream.graph.Graph
;
import
org.graphstream.graph.Node
;
import
java.util.*
;
/**
* Analyse les distances moyennes dans un réseau (Question 5).
*
* Cette classe calcule la distance moyenne entre les nœuds du réseau
* par échantillonnage et parcours en largeur (BFS). Elle permet également
* de vérifier l'hypothèse des "six degrés de séparation" et de comparer
* avec un réseau aléatoire théorique.
*
* @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
DistanceAnalyzer
{
private
static
final
int
SAMPLE_SIZE
=
1000
;
/**
* Calcule la distance moyenne par échantillonnage et parcours BFS.
*
* Pour éviter de calculer toutes les paires de nœuds (O(N²)), cette méthode
* échantillonne aléatoirement SAMPLE_SIZE nœuds et effectue un BFS depuis
* chacun pour estimer la distance moyenne.
*
* @param g Le graphe à analyser
* @return La distance moyenne estimée
*/
public
static
double
computeAverageDistance
(
Graph
g
)
{
ResultsPrinter
.
printInfo
(
String
.
format
(
"Échantillonnage de %d nœuds pour estimer la distance moyenne..."
,
SAMPLE_SIZE
));
List
<
Node
>
sampledNodes
=
RandomSampler
.
sampleNodes
(
g
,
SAMPLE_SIZE
);
// Utilisation de somme et compteur au lieu de stocker toutes les distances
double
sum
=
0.0
;
long
count
=
0
;
int
progress
=
0
;
for
(
Node
source
:
sampledNodes
)
{
Map
<
String
,
Integer
>
distancesFromSource
=
bfsDistances
(
g
,
source
.
getId
());
for
(
int
dist
:
distancesFromSource
.
values
())
{
if
(
dist
>
0
)
{
// Exclure la distance à soi-même
sum
+=
dist
;
count
++;
}
}
progress
++;
if
(
progress
%
100
==
0
)
{
ResultsPrinter
.
printInfo
(
String
.
format
(
" Progression: %d/%d nœuds traités"
,
progress
,
SAMPLE_SIZE
));
}
}
if
(
count
==
0
)
{
return
0.0
;
}
return
sum
/
count
;
}
/**
* Calcule la distribution des distances à partir de nœuds échantillonnés.
*
* Cette méthode retourne une map associant chaque distance au nombre
* de paires de nœuds séparées par cette distance.
*
* @param g Le graphe à analyser
* @return Map distance -> fréquence
*/
public
static
Map
<
Integer
,
Integer
>
computeDistanceDistribution
(
Graph
g
)
{
ResultsPrinter
.
printInfo
(
"Calcul de la distribution des distances..."
);
List
<
Node
>
sampledNodes
=
RandomSampler
.
sampleNodes
(
g
,
SAMPLE_SIZE
);
Map
<
Integer
,
Integer
>
distribution
=
new
HashMap
<>();
for
(
Node
source
:
sampledNodes
)
{
Map
<
String
,
Integer
>
distancesFromSource
=
bfsDistances
(
g
,
source
.
getId
());
for
(
int
dist
:
distancesFromSource
.
values
())
{
if
(
dist
>
0
)
{
distribution
.
put
(
dist
,
distribution
.
getOrDefault
(
dist
,
0
)
+
1
);
}
}
}
return
distribution
;
}
/**
* Effectue un parcours en largeur (BFS) depuis un nœud source.
*
* Cette méthode privée calcule les distances depuis un nœud source
* vers tous les nœuds atteignables du graphe.
*
* @param g Le graphe
* @param sourceId Identifiant du nœud source
* @return Map associant chaque nœud atteignable à sa distance depuis la source
*/
private
static
Map
<
String
,
Integer
>
bfsDistances
(
Graph
g
,
String
sourceId
)
{
Map
<
String
,
Integer
>
distances
=
new
HashMap
<>();
Queue
<
String
>
queue
=
new
LinkedList
<>();
queue
.
add
(
sourceId
);
distances
.
put
(
sourceId
,
0
);
while
(!
queue
.
isEmpty
())
{
String
currentId
=
queue
.
poll
();
int
currentDist
=
distances
.
get
(
currentId
);
Node
currentNode
=
g
.
getNode
(
currentId
);
if
(
currentNode
==
null
)
continue
;
for
(
Edge
edge
:
currentNode
.
edges
().
toArray
(
Edge
[]::
new
))
{
Node
neighbor
=
edge
.
getOpposite
(
currentNode
);
String
neighborId
=
neighbor
.
getId
();
if
(!
distances
.
containsKey
(
neighborId
))
{
distances
.
put
(
neighborId
,
currentDist
+
1
);
queue
.
add
(
neighborId
);
}
}
}
return
distances
;
}
/**
* Calcule la distance moyenne théorique pour un réseau aléatoire.
*
* Pour un réseau aléatoire, la distance moyenne théorique est:
* l ≈ ln(N) / ln(<k>)
*
* @param n Nombre de nœuds
* @param avgDegree Degré moyen
* @return Distance moyenne théorique
*/
public
static
double
theoreticalRandomDistance
(
int
n
,
double
avgDegree
)
{
if
(
avgDegree
<=
1
)
{
return
Double
.
POSITIVE_INFINITY
;
}
return
Math
.
log
(
n
)
/
Math
.
log
(
avgDegree
);
}
/**
* Exporte la distribution des distances pour visualisation avec gnuplot.
*
* @param dist Distribution des distances (distance -> fréquence)
* @param filePath Chemin du fichier de sortie
*/
public
static
void
exportDistanceDistribution
(
Map
<
Integer
,
Integer
>
dist
,
String
filePath
)
{
DataExporter
.
exportDistanceDistribution
(
dist
,
filePath
);
}
/**
* Effectue l'analyse complète de la Question 5.
*
* Cette méthode calcule la distance moyenne, la compare avec un réseau
* aléatoire théorique, vérifie l'hypothèse des "six degrés de séparation"
* et exporte la distribution des distances.
*
* @param g Le graphe à analyser
* @param networkName Nom du réseau (pour l'affichage)
* @param baseFilename Nom de base pour les fichiers de sortie
*/
public
static
void
analyze
(
Graph
g
,
String
networkName
,
String
baseFilename
)
{
long
startTime
=
System
.
currentTimeMillis
();
ResultsPrinter
.
printHeader
(
"QUESTION 5: Distance moyenne - "
+
networkName
);
// Calcul de la distance moyenne
double
avgDistance
=
computeAverageDistance
(
g
);
ResultsPrinter
.
printMetric
(
"Distance moyenne (expérimentale)"
,
avgDistance
);
// Comparaison avec un réseau aléatoire théorique
int
n
=
g
.
getNodeCount
();
double
avgDegree
=
BasicMetrics
.
getAverageDegree
(
g
);
double
theoreticalDist
=
theoreticalRandomDistance
(
n
,
avgDegree
);
ResultsPrinter
.
printSeparator
();
ResultsPrinter
.
printInfo
(
"Comparaison avec réseau aléatoire théorique:"
);
ResultsPrinter
.
printMetric
(
"Distance théorique (aléatoire)"
,
theoreticalDist
);
ResultsPrinter
.
printMetric
(
"Différence"
,
Math
.
abs
(
avgDistance
-
theoreticalDist
));
// Vérification de l'hypothèse des "six degrés de séparation"
ResultsPrinter
.
printSeparator
();
if
(
avgDistance
<=
7.0
)
{
ResultsPrinter
.
printSuccess
(
"Hypothèse des 'six degrés de séparation' CONFIRMÉE! (distance ≈ "
+
String
.
format
(
"%.1f"
,
avgDistance
)
+
")"
);
}
else
{
ResultsPrinter
.
printInfo
(
"Distance moyenne: "
+
String
.
format
(
"%.1f"
,
avgDistance
)
+
" (légèrement supérieure à 6)"
);
}
// Calcul et export de la distribution
ResultsPrinter
.
printSeparator
();
Map
<
Integer
,
Integer
>
distribution
=
computeDistanceDistribution
(
g
);
String
distFile
=
"output/data/"
+
baseFilename
+
"_distances.dat"
;
exportDistanceDistribution
(
distribution
,
distFile
);
// Recherche de la distance maximale
int
maxDistance
=
distribution
.
keySet
().
stream
().
max
(
Integer:
:
compareTo
).
orElse
(
0
);
ResultsPrinter
.
printMetric
(
"Distance maximale observée"
,
maxDistance
);
ResultsPrinter
.
printInfo
(
"C'est un réseau 'petit monde' (small world)!"
);
ResultsPrinter
.
printElapsedTime
(
startTime
);
}
}
src/main/java/fr/univ/dblp/export/DataExporter.java
0 → 100644
Voir le fichier @
e8ffba29
package
fr.univ.dblp.export
;
import
java.io.File
;
import
java.io.FileWriter
;
import
java.io.IOException
;
import
java.io.PrintWriter
;
import
java.util.Locale
;
import
java.util.Map
;
/**
* Classe utilitaire pour l'export de données vers des fichiers (pour gnuplot).
*
* Cette classe fournit des méthodes pour exporter différents types de données
* (distributions de degrés, distributions de distances, etc.) dans des formats
* compatibles avec gnuplot pour la visualisation.
*
* @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
DataExporter
{
/**
* Exporte des données à deux colonnes vers un fichier.
*
* Cette méthode générique permet d'exporter n'importe quelle paire de données
* (x, y) dans un format lisible par gnuplot.
*
* @param x Valeurs de la première colonne
* @param y Valeurs de la deuxième colonne
* @param filePath Chemin du fichier de sortie
* @param header En-tête optionnel (commentaire)
*/
public
static
void
exportTwoColumns
(
double
[]
x
,
double
[]
y
,
String
filePath
,
String
header
)
{
try
{
createDirectoryIfNeeded
(
filePath
);
try
(
PrintWriter
writer
=
new
PrintWriter
(
new
FileWriter
(
filePath
)))
{
if
(
header
!=
null
&&
!
header
.
isEmpty
())
{
writer
.
println
(
"# "
+
header
);
}
for
(
int
i
=
0
;
i
<
Math
.
min
(
x
.
length
,
y
.
length
);
i
++)
{
writer
.
printf
(
Locale
.
US
,
"%.10f %.10f%n"
,
x
[
i
],
y
[
i
]);
}
}
ResultsPrinter
.
printSuccess
(
"Données exportées vers: "
+
filePath
);
}
catch
(
IOException
e
)
{
ResultsPrinter
.
printError
(
"Erreur lors de l'export vers "
+
filePath
+
": "
+
e
.
getMessage
());
}
}
/**
* Exporte la distribution des degrés vers un fichier pour gnuplot.
*
* Le fichier contient deux colonnes: le degré k et la probabilité p_k
* qu'un nœud ait ce degré.
*
* @param degreeDistribution Tableau où l'indice = degré, valeur = nombre de nœuds
* @param nodeCount Nombre total de nœuds
* @param filePath Chemin du fichier de sortie
*/
public
static
void
exportDegreeDistribution
(
int
[]
degreeDistribution
,
int
nodeCount
,
String
filePath
)
{
try
{
createDirectoryIfNeeded
(
filePath
);
try
(
PrintWriter
writer
=
new
PrintWriter
(
new
FileWriter
(
filePath
)))
{
writer
.
println
(
"# k p_k"
);
for
(
int
k
=
0
;
k
<
degreeDistribution
.
length
;
k
++)
{
if
(
degreeDistribution
[
k
]
>
0
)
{
double
pk
=
(
double
)
degreeDistribution
[
k
]
/
nodeCount
;
writer
.
printf
(
Locale
.
US
,
"%d %.10f%n"
,
k
,
pk
);
}
}
}
ResultsPrinter
.
printSuccess
(
"Distribution des degrés exportée vers: "
+
filePath
);
}
catch
(
IOException
e
)
{
ResultsPrinter
.
printError
(
"Erreur lors de l'export: "
+
e
.
getMessage
());
}
}
/**
* Exporte la distribution des degrés avec comparaison à une distribution de Poisson.
*
* Le fichier contient trois colonnes: le degré k, la probabilité observée p_k
* et la probabilité théorique selon une distribution de Poisson.
*
* @param degreeDistribution Tableau où l'indice = degré, valeur = nombre de nœuds
* @param nodeCount Nombre total de nœuds
* @param avgDegree Degré moyen (paramètre lambda pour Poisson)
* @param filePath Chemin du fichier de sortie
*/
public
static
void
exportDegreeDistributionWithPoisson
(
int
[]
degreeDistribution
,
int
nodeCount
,
double
avgDegree
,
String
filePath
)
{
try
{
createDirectoryIfNeeded
(
filePath
);
try
(
PrintWriter
writer
=
new
PrintWriter
(
new
FileWriter
(
filePath
)))
{
writer
.
println
(
"# k p_k poisson_pk"
);
for
(
int
k
=
0
;
k
<
degreeDistribution
.
length
;
k
++)
{
if
(
degreeDistribution
[
k
]
>
0
)
{
double
pk
=
(
double
)
degreeDistribution
[
k
]
/
nodeCount
;
double
poissonPk
=
poissonProbability
(
k
,
avgDegree
);
writer
.
printf
(
Locale
.
US
,
"%d %.10f %.10f%n"
,
k
,
pk
,
poissonPk
);
}
}
}
ResultsPrinter
.
printSuccess
(
"Distribution avec Poisson exportée vers: "
+
filePath
);
}
catch
(
IOException
e
)
{
ResultsPrinter
.
printError
(
"Erreur lors de l'export: "
+
e
.
getMessage
());
}
}
/**
* Exporte la distribution des distances vers un fichier.
*
* Le fichier contient deux colonnes: la distance et la fréquence
* (nombre de paires de nœuds à cette distance).
*
* @param distanceDistribution Map associant distance -> fréquence
* @param filePath Chemin du fichier de sortie
*/
public
static
void
exportDistanceDistribution
(
Map
<
Integer
,
Integer
>
distanceDistribution
,
String
filePath
)
{
try
{
createDirectoryIfNeeded
(
filePath
);
try
(
PrintWriter
writer
=
new
PrintWriter
(
new
FileWriter
(
filePath
)))
{
writer
.
println
(
"# distance frequency"
);
distanceDistribution
.
entrySet
().
stream
()
.
sorted
(
Map
.
Entry
.
comparingByKey
())
.
forEach
(
entry
->
{
writer
.
printf
(
Locale
.
US
,
"%d %d%n"
,
entry
.
getKey
(),
entry
.
getValue
());
});
}
ResultsPrinter
.
printSuccess
(
"Distribution des distances exportée vers: "
+
filePath
);
}
catch
(
IOException
e
)
{
ResultsPrinter
.
printError
(
"Erreur lors de l'export: "
+
e
.
getMessage
());
}
}
/**
* Calcule la probabilité selon une distribution de Poisson.
*
* Formule: P(k) = (lambda^k * e^(-lambda)) / k!
* Utilise les logarithmes pour éviter les débordements numériques.
*
* @param k Valeur pour laquelle calculer la probabilité
* @param lambda Paramètre de la distribution (moyenne)
* @return Probabilité P(k)
*/
private
static
double
poissonProbability
(
int
k
,
double
lambda
)
{
// Utilisation des logarithmes pour éviter les débordements
double
logProb
=
k
*
Math
.
log
(
lambda
)
-
lambda
-
logFactorial
(
k
);
return
Math
.
exp
(
logProb
);
}
/**
* Calcule le logarithme de la factorielle.
*
* Méthode utilisée pour éviter les débordements lors du calcul
* de la probabilité de Poisson pour de grandes valeurs de k.
*
* @param n Nombre dont on calcule log(n!)
* @return log(n!)
*/
private
static
double
logFactorial
(
int
n
)
{
if
(
n
<=
1
)
return
0.0
;
double
result
=
0.0
;
for
(
int
i
=
2
;
i
<=
n
;
i
++)
{
result
+=
Math
.
log
(
i
);
}
return
result
;
}
/**
* Crée le répertoire parent si nécessaire.
*
* Cette méthode garantit que le répertoire de destination existe
* avant d'écrire un fichier.
*
* @param filePath Chemin du fichier (le répertoire parent sera créé)
*/
private
static
void
createDirectoryIfNeeded
(
String
filePath
)
{
File
file
=
new
File
(
filePath
);
File
parentDir
=
file
.
getParentFile
();
if
(
parentDir
!=
null
&&
!
parentDir
.
exists
())
{
parentDir
.
mkdirs
();
}
}
}
src/main/java/fr/univ/dblp/export/ResultsPrinter.java
0 → 100644
Voir le fichier @
e8ffba29
package
fr.univ.dblp.export
;
import
java.util.Locale
;
/**
* Classe utilitaire pour l'affichage formaté des résultats dans la console.
*
* Cette classe fournit des méthodes pour afficher de manière cohérente
* les en-têtes, métriques, messages et tableaux comparatifs dans la console.
*
* @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
ResultsPrinter
{
private
static
final
String
SEPARATOR
=
"="
.
repeat
(
80
);
private
static
final
String
LINE
=
"-"
.
repeat
(
80
);
/**
* Affiche un en-tête de section principale.
*
* @param title Titre de la section
*/
public
static
void
printHeader
(
String
title
)
{
System
.
out
.
println
(
"\n"
+
SEPARATOR
);
System
.
out
.
println
(
" "
+
title
);
System
.
out
.
println
(
SEPARATOR
);
}
/**
* Affiche un en-tête de sous-section.
*
* @param subtitle Titre de la sous-section
*/
public
static
void
printSubHeader
(
String
subtitle
)
{
System
.
out
.
println
(
"\n"
+
LINE
);
System
.
out
.
println
(
" "
+
subtitle
);
System
.
out
.
println
(
LINE
);
}
/**
* Affiche une métrique avec son nom et sa valeur.
*
* La méthode formate automatiquement la valeur selon son type
* (Double, Integer, Long ou autre).
*
* @param name Nom de la métrique
* @param value Valeur de la métrique
*/
public
static
void
printMetric
(
String
name
,
Object
value
)
{
if
(
value
instanceof
Double
)
{
System
.
out
.
printf
(
Locale
.
US
,
" %-40s: %.6f%n"
,
name
,
(
Double
)
value
);
}
else
if
(
value
instanceof
Integer
)
{
System
.
out
.
printf
(
Locale
.
US
,
" %-40s: %,d%n"
,
name
,
(
Integer
)
value
);
}
else
if
(
value
instanceof
Long
)
{
System
.
out
.
printf
(
Locale
.
US
,
" %-40s: %,d%n"
,
name
,
(
Long
)
value
);
}
else
{
System
.
out
.
printf
(
Locale
.
US
,
" %-40s: %s%n"
,
name
,
value
);
}
}
/**
* Affiche une ligne de séparation.
*/
public
static
void
printSeparator
()
{
System
.
out
.
println
(
LINE
);
}
/**
* Affiche l'en-tête d'un tableau comparatif.
*
* @param networkNames Noms des réseaux à comparer (colonnes du tableau)
*/
public
static
void
printComparisonHeader
(
String
...
networkNames
)
{
System
.
out
.
printf
(
Locale
.
US
,
"\n%-30s"
,
"Metric"
);
for
(
String
name
:
networkNames
)
{
System
.
out
.
printf
(
Locale
.
US
,
" | %-20s"
,
name
);
}
System
.
out
.
println
();
System
.
out
.
println
(
SEPARATOR
);
}
/**
* Affiche une ligne de données dans un tableau comparatif.
*
* @param metricName Nom de la métrique (première colonne)
* @param values Valeurs pour chaque réseau
*/
public
static
void
printComparisonRow
(
String
metricName
,
Object
...
values
)
{
System
.
out
.
printf
(
Locale
.
US
,
"%-30s"
,
metricName
);
for
(
Object
value
:
values
)
{
if
(
value
instanceof
Double
)
{
System
.
out
.
printf
(
Locale
.
US
,
" | %-20.6f"
,
(
Double
)
value
);
}
else
if
(
value
instanceof
Integer
)
{
String
formatted
=
String
.
format
(
Locale
.
US
,
"%,d"
,
(
Integer
)
value
);
System
.
out
.
printf
(
Locale
.
US
,
" | %-20s"
,
formatted
);
}
else
{
System
.
out
.
printf
(
Locale
.
US
,
" | %-20s"
,
value
);
}
}
System
.
out
.
println
();
}
/**
* Affiche un message d'information.
*
* @param message Le message à afficher
*/
public
static
void
printInfo
(
String
message
)
{
System
.
out
.
println
(
" [INFO] "
+
message
);
}
/**
* Affiche un message de succès.
*
* @param message Le message à afficher
*/
public
static
void
printSuccess
(
String
message
)
{
System
.
out
.
println
(
" [SUCCESS] "
+
message
);
}
/**
* Affiche un message d'avertissement.
*
* @param message Le message à afficher
*/
public
static
void
printWarning
(
String
message
)
{
System
.
out
.
println
(
" [WARNING] "
+
message
);
}
/**
* Affiche un message d'erreur.
*
* @param message Le message à afficher
*/
public
static
void
printError
(
String
message
)
{
System
.
err
.
println
(
" [ERROR] "
+
message
);
}
/**
* Affiche le temps écoulé depuis un instant de départ.
*
* Le temps est affiché en secondes (si < 60s) ou en minutes et secondes.
*
* @param startTime Instant de départ (en millisecondes, obtenu via System.currentTimeMillis())
*/
public
static
void
printElapsedTime
(
long
startTime
)
{
long
elapsed
=
System
.
currentTimeMillis
()
-
startTime
;
double
seconds
=
elapsed
/
1000.0
;
if
(
seconds
<
60
)
{
System
.
out
.
printf
(
Locale
.
US
,
" Temps écoulé: %.2f secondes%n"
,
seconds
);
}
else
{
int
minutes
=
(
int
)
(
seconds
/
60
);
double
remainingSeconds
=
seconds
-
(
minutes
*
60
);
System
.
out
.
printf
(
Locale
.
US
,
" Temps écoulé: %d minutes %.2f secondes%n"
,
minutes
,
remainingSeconds
);
}
}
}
src/main/java/fr/univ/dblp/generators/CopyGenerator.java
0 → 100644
Voir le fichier @
e8ffba29
package
fr.univ.dblp.generators
;
import
fr.univ.dblp.analysis.BasicMetrics
;
import
fr.univ.dblp.analysis.DegreeAnalyzer
;
import
fr.univ.dblp.export.ResultsPrinter
;
import
org.graphstream.graph.Edge
;
import
org.graphstream.graph.Graph
;
import
org.graphstream.graph.Node
;
import
org.graphstream.graph.implementations.SingleGraph
;
import
java.util.ArrayList
;
import
java.util.List
;
import
java.util.Random
;
/**
* Générateur de réseau par mécanisme de copie (Question 7 - Bonus).
*
* Algorithme:
* 1. Un nouveau nœud choisit un nœud aléatoire v
* 2. Il se connecte à chaque voisin de v avec une probabilité p
* 3. Il se connecte toujours à v lui-même
*
* Ce mécanisme crée naturellement des triangles (clustering élevé) car
* si le nouveau nœud se connecte à deux voisins de v qui sont eux-mêmes
* connectés, un triangle est formé.
*
* @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
CopyGenerator
{
private
double
connectionProbability
;
private
Random
random
;
public
CopyGenerator
(
double
p
)
{
this
.
connectionProbability
=
p
;
this
.
random
=
new
Random
();
}
/**
* Génère un graphe en utilisant le mécanisme de copie.
*
* Cette méthode implémente l'algorithme de copie qui favorise la formation
* de triangles et donc un coefficient de clustering élevé.
*
* @param targetNodes Nombre de nœuds cible
* @param p Probabilité de connexion aux voisins
* @return Le graphe généré
*/
public
static
Graph
generateGraph
(
int
targetNodes
,
double
p
)
{
ResultsPrinter
.
printInfo
(
String
.
format
(
"Génération réseau par copie: N=%,d, p=%.2f"
,
targetNodes
,
p
));
Graph
g
=
new
SingleGraph
(
"Copy-Model"
);
g
.
setStrict
(
false
);
g
.
setAutoCreate
(
true
);
// Initialisation avec quelques nœuds connectés (réseau de départ)
int
seedSize
=
Math
.
min
(
10
,
targetNodes
);
for
(
int
i
=
0
;
i
<
seedSize
;
i
++)
{
g
.
addNode
(
"n"
+
i
);
}
// Création des connexions initiales (petite clique)
for
(
int
i
=
0
;
i
<
seedSize
;
i
++)
{
for
(
int
j
=
i
+
1
;
j
<
Math
.
min
(
i
+
3
,
seedSize
);
j
++)
{
g
.
addEdge
(
"e_init_"
+
i
+
"_"
+
j
,
"n"
+
i
,
"n"
+
j
);
}
}
Random
rand
=
new
Random
();
int
currentNodeCount
=
seedSize
;
// Génération des nœuds restants avec le mécanisme de copie
while
(
currentNodeCount
<
targetNodes
)
{
// Choix d'un nœud aléatoire v PARMI LES NŒUDS EXISTANTS
// (avant d'ajouter le nouveau nœud, pour éviter l'explosion)
int
randomIndex
=
rand
.
nextInt
(
currentNodeCount
);
Node
v
=
g
.
getNode
(
"n"
+
randomIndex
);
if
(
v
==
null
)
{
v
=
g
.
getNode
(
"n0"
);
// Solution de repli
}
String
newNodeId
=
"n"
+
currentNodeCount
;
g
.
addNode
(
newNodeId
);
Node
newNode
=
g
.
getNode
(
newNodeId
);
// Connexion aux voisins de v avec probabilité p
List
<
Node
>
neighborsOfV
=
new
ArrayList
<>();
for
(
Edge
e
:
v
.
edges
().
toArray
(
Edge
[]::
new
))
{
Node
neighbor
=
e
.
getOpposite
(
v
);
if
(
neighbor
!=
null
&&
!
neighbor
.
getId
().
equals
(
newNodeId
))
{
neighborsOfV
.
add
(
neighbor
);
}
}
for
(
Node
neighbor
:
neighborsOfV
)
{
if
(
rand
.
nextDouble
()
<
p
)
{
String
edgeId
=
"e_"
+
currentNodeCount
+
"_"
+
neighbor
.
getId
();
if
(!
g
.
getNode
(
newNodeId
).
hasEdgeBetween
(
neighbor
.
getId
()))
{
g
.
addEdge
(
edgeId
,
newNodeId
,
neighbor
.
getId
());
}
}
}
// Connexion systématique à v
String
edgeToV
=
"e_"
+
currentNodeCount
+
"_to_"
+
v
.
getId
();
if
(!
g
.
getNode
(
newNodeId
).
hasEdgeBetween
(
v
.
getId
()))
{
g
.
addEdge
(
edgeToV
,
newNodeId
,
v
.
getId
());
}
currentNodeCount
++;
if
(
currentNodeCount
%
10000
==
0
)
{
ResultsPrinter
.
printInfo
(
String
.
format
(
" Progression: %,d/%,d nœuds générés"
,
currentNodeCount
,
targetNodes
));
}
}
ResultsPrinter
.
printSuccess
(
String
.
format
(
"Réseau par copie généré: %,d nœuds, %,d arêtes"
,
g
.
getNodeCount
(),
g
.
getEdgeCount
()));
return
g
;
}
/**
* Effectue l'analyse complète de la Question 7 (Bonus).
*
* Cette méthode teste différentes valeurs du paramètre p, génère les
* réseaux correspondants, et compare leur clustering avec DBLP et
* Barabási-Albert pour démontrer l'amélioration apportée par le
* mécanisme de copie.
*
* @param dblpGraph Le graphe DBLP de référence
* @param baGraph Le graphe Barabási-Albert pour comparaison
*/
public
static
void
analyze
(
Graph
dblpGraph
,
Graph
baGraph
)
{
long
startTime
=
System
.
currentTimeMillis
();
ResultsPrinter
.
printHeader
(
"QUESTION 7 (BONUS): Générateur par copie"
);
ResultsPrinter
.
printInfo
(
"Objectif: Améliorer le coefficient de clustering par rapport à Barabási-Albert"
);
// Test de différentes valeurs de p
double
[]
pValues
=
{
0.3
,
0.5
,
0.7
};
int
generatedSize
=
Math
.
min
(
dblpGraph
.
getNodeCount
(),
50000
);
ResultsPrinter
.
printSubHeader
(
"Tests avec différentes valeurs de p"
);
Graph
bestGraph
=
null
;
double
bestP
=
0.0
;
double
bestClustering
=
0.0
;
for
(
double
p
:
pValues
)
{
ResultsPrinter
.
printInfo
(
String
.
format
(
"\n=== Test avec p = %.1f ==="
,
p
));
Graph
copyGraph
=
generateGraph
(
generatedSize
,
p
);
double
clustering
=
BasicMetrics
.
getClusteringCoefficient
(
copyGraph
);
double
avgDegree
=
BasicMetrics
.
getAverageDegree
(
copyGraph
);
ResultsPrinter
.
printMetric
(
"Degré moyen"
,
avgDegree
);
ResultsPrinter
.
printMetric
(
"Coefficient de clustering"
,
clustering
);
if
(
clustering
>
bestClustering
)
{
bestClustering
=
clustering
;
bestP
=
p
;
bestGraph
=
copyGraph
;
}
}
// Analyse détaillée de la meilleure configuration
ResultsPrinter
.
printSubHeader
(
"Meilleure configuration: p = "
+
bestP
);
BasicMetrics
.
analyze
(
bestGraph
,
"Copie (p="
+
bestP
+
")"
);
DegreeAnalyzer
.
analyze
(
bestGraph
,
"Copie"
,
"copy"
);
// Tableau de comparaison
ResultsPrinter
.
printHeader
(
"COMPARAISON CLUSTERING"
);
double
dblpClustering
=
BasicMetrics
.
getClusteringCoefficient
(
dblpGraph
);
double
baClustering
=
BasicMetrics
.
getClusteringCoefficient
(
baGraph
);
ResultsPrinter
.
printComparisonHeader
(
"DBLP"
,
"Barabási-Albert"
,
"Copie (p="
+
bestP
+
")"
);
ResultsPrinter
.
printComparisonRow
(
"Clustering"
,
dblpClustering
,
baClustering
,
bestClustering
);
ResultsPrinter
.
printSeparator
();
double
improvementVsBA
=
bestClustering
/
baClustering
;
ResultsPrinter
.
printMetric
(
"Amélioration vs BA"
,
improvementVsBA
+
"x"
);
if
(
bestClustering
>
baClustering
*
10
)
{
ResultsPrinter
.
printSuccess
(
"Le générateur par copie reproduit BEAUCOUP MIEUX le clustering!"
);
}
else
if
(
bestClustering
>
baClustering
)
{
ResultsPrinter
.
printSuccess
(
"Le générateur par copie améliore le clustering!"
);
}
ResultsPrinter
.
printInfo
(
"\nCONCLUSIONS:"
);
ResultsPrinter
.
printInfo
(
" - La méthode de copie crée naturellement des triangles (clustering)"
);
ResultsPrinter
.
printInfo
(
" - Compromis à trouver avec la valeur de p"
);
ResultsPrinter
.
printInfo
(
" - Meilleure modélisation que BA pour les réseaux sociaux!"
);
ResultsPrinter
.
printElapsedTime
(
startTime
);
}
}
Précédent
1
2
3
Suivant