Newer
Older
# Projet RI
Nous allons analyser un réseau de collaboration scientifique en informatique.
Le réseau est extrait de DBLP et disponible sur SNAP.
GraphStream permet de mesurer de nombreuses caractéristiques d'un réseau.
La plupart de ces mesures sont implantées comme des méthodes statiques dans la classe Toolkit.
Elles vous seront très utiles par la suite.
## 1- Tout d'abord :
j'ai commencé par télécharger les données et les lire avec GraphStream.
## 2- Quelques mesures de base :
J'ai calculé quelques mesures de base : comme le nombre de nœuds et d'arêtes, le degré moyen ainsi que le coefficient de clustring.
- Nombre de noeuds : N = 317080
```java
int nodeCount = graph.getNodeCount();
```
- Nombre de liens : E = 1049866
```java
int edgeCount = graph.getEdgeCount();
```
- Degré moyen : ⟨k⟩ = 6.62208890914917
```java
double averageDegree = Toolkit.averageDegree(graph);
```
- Coefficient de clustering (réel) : 0.6324308280637396
```java
double clusteringCoefficient = Toolkit.averageClusteringCoefficient(graph);
```
- Coefficient de clustering (aléatoire) : ⟨k⟩/N = 2.0884599814397534E-5
## 3- Autres mesures
Voyons maintenant si le graphe est connexe :
- Le réseau est-il connexe ? : Oui
```java
boolean isConnected = Toolkit.isConnected(graph);
```
- Degré moyen minimal pour qu'un graphe aléatoire soit connexe : 12.666909386951092
```java
double minAverageDegreeForConnectivity = Math.log(nodeCount);
```
## 4- Distribution des Degrés
Exportation des données : Les degrés des nœuds sont exportés dans le fichier degree_distribution.txt.
#### Analyse graphique :
- Échelle linéaire :
Tout d'abord,
nous pouvons tracer la distribution des degrés en
échelle linéaire. Cette courbe nous montrera comment
la probabilité p(k) varie avec le degré k.
Dans un graphique en échelle linéaire,
la relation entre k et p(k) peut ne pas être évidente
et pourrait ne pas révéler de structure particulière.

- Échelle log-log :
Lorsque nous traçons la même distribution en échelle
log-log, c'est-à-dire avec les axes
log(k) et log(p(k)), cela permet de mieux observer les tendances à grande échelle.
nous observons une ligne droite ce qui nous dit que la distribution suit une loi de puissance.

une ligne droite est observée, cela indique une loi de puissance.
- Comparaison avec la distribution de Poisson : Superposer la distribution de Poisson avec ⟨k⟩.
## 5- Distance moyenne et distribution des distances
Distance moyenne de notre réseau: 6.700611818856679
```java
double degreeAverage = Toolkit.averageDegree(graph);
double NetworkDistance = Math.log(graph.getNodeCount()) / Math.log(degreeAverage);
System.out.println("Distance moyenne dans notre réseau : " + NetworkDistance);
```
Oui, l'hypothèse des six degrés de séparation est confirmée : la distance moyenne entre les nœuds est proche de 6.
Le réseau montre des propriétés caractéristiques des réseaux "petit monde" : une distance moyenne faible et un clustering élevé.
- Quelle sera la distance moyenne dans un réseau aléatoire avec les mêmes caractéristiques ?
J'ai calculé la distance moyenne d'un réseau aléatoire de même taille et de même degré moyen que j'ai généré avec randomGenerator de graphstream et ça nous donne à peu prés la même chose
Distance moyenne du réseau Aléatoire : 6.70193902051403
```java
double degreeAverage = Toolkit.averageDegree(randomGraph);
double NetworkDistance = Math.log(randomGraph.getNodeCount()) / Math.log(degreeAverage);
System.out.println("Distance moyenne du réseau Aléatoire : " + NetworkDistance);
```
Tracer les distributions des distances :

- La courbe montre un pic central autour de 6. Cela suggère que la distance moyenne entre
les paires de nœuds est proche de cette valeur. Cela soutient l'hypothèse des six degrés de séparation, car la majorité des distances sont à 6 ou moins.
- Décroissance rapide : Les distances très petites et très grandes sont rares, tandis que les distances proches de la moyenne sont les plus fréquentes.
On conclut donc que la forme de la distribution est proche d'une loi normale, ce qui est souvent observé dans les réseaux petits mondes.
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
1 - le graphe aléatoire:
Cette méthode génère un graphe aléatoire basé sur les propriétés d'un graphe d'entrée initialGraph, à l'aide d'un générateur de graphes aléatoires de GraphStream.
Le graphe généré a un nombre total de nœuds fixé (N = 317080) et un degré moyen similaire à celui de initialGraph.
```java
public static Graph createRandomGraph(Graph initialGraph) {
double averageDegree = Toolkit.averageDegree(initialGraph);
Generator generator = new RandomGenerator(averageDegree, false);
Graph graphAlea = new SingleGraph("graphe aléatoire");
int N = 317080;
// graphe aléatoire générer de taille N
generator.addSink(graphAlea);
generator.begin();
while (graphAlea.getNodeCount() < N) {
generator.nextEvents();
}
generator.end();
if (graphAlea.getNodeCount() == N) {
System.out.println("Graph aléatoire générer !");
}
return graphAlea;
}
```
Réseau aléatoire :
- Nombre de nœuds : 317080
- Nombre de liens : 1049473
- Degré moyen : 6.61961030960083
- Coefficient de clustering : 4.364833098823207E-5
j'ai aussi calculé les degrés de distribution à l'échelle linéaire et à l'échelle log-log
- Linéaire :

- Log-log :
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
2 - Le graphe Barabàsi-Albert:
Cette méthode génère un graphe Barabási-Albert en utilisant le graphe d'entrée initialGraph comme référence.
Le modèle Barabási-Albert est un modèle de croissance qui suit le principe de l'attachement préférentiel :
les nouveaux nœuds ont une probabilité plus élevée de se connecter aux nœuds déjà fortement connectés (hubs).
Ce modèle permet de générer des graphes sans échelle,
où la distribution des degrés suit une loi de puissance.
```java
public static Graph generateBarabasiAlbertGraph(Graph initialGraph) {
int nodeCount = initialGraph.getNodeCount();
double averageDegree = Toolkit.averageDegree(initialGraph);
Graph barabasiGraph = new SingleGraph("Barabasi-Albert Network");
BarabasiAlbertGenerator generator = new BarabasiAlbertGenerator((int) averageDegree);
generator.addSink(barabasiGraph);
generator.begin();
while (barabasiGraph.getNodeCount() < nodeCount) {
generator.nextEvents();
}
generator.end();
return barabasiGraph;
}
```
Les caractéristiques de ce graphe sont :
Nombre de nœuds : 317080
Nombre de liens : 1108680
Degré moyen : 6.993061542510986
j'ai aussi calculé les degrés de distribution à l'échelle linéaire et à l'échelle log-log
- Linéaire :

- Log-log :
Comparaison des réseaux générés
En théorie, les deux modèles de réseaux, aléatoire
(Erdős-Rényi) et Barabási-Albert, se distinguent
par leur structure et leur comportement.
Les liens sont créés de manière totalement aléatoire entre les nœuds.
Le degré moyen suit une distribution de Poisson :
la plupart des nœuds ont un degré proche de
la moyenne, et il y a très peu de nœuds avec un
degré beaucoup plus élevé ou plus faible.
Le coefficient de clustering est très faible car les
triangles (groupes de trois nœuds connectés entre
eux) sont rares dans ce type de réseau.
Ce modèle suit une loi de puissance : quelques
nœuds, appelés hubs, ont un très grand nombre de
connexions, tandis que la majorité des nœuds sont
faiblement connectés.
Le coefficient de clustering est plus élevé que
dans un réseau aléatoire, car les hubs favorisent
la connexion entre plusieurs nœuds, augmentant la
probabilité de former des triangles.
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
Les résultats expérimentaux correspondent à ces prédictions théoriques comme le démontre le tableau ci-dessous :
| Propriété | Réseau Aléatoire | Réseau Barabási-Albert |
|---------------------------|-----------------------------|-------------------|
| **Nombre de nœuds** | 317 080 | 317 080 |
| **Nombre de liens** | 1 049 907 | 1 108 082 |
| **Degré moyen** | 6,6223 | 6,9893 |
| **Clustering** | 3.57 × 10⁻⁵ | 3.82 × 10⁻⁴ |
Le faible clustering du réseau random et le clustering un peu plus élevé du réseau BA sont conformes à ce qu'on attend.
En résumé, ces expériences confirment que le modèle Barabási-Albert est plus adapté pour modéliser des réseaux où les hubs
jouent un rôle important.
## 7- La méthode Copie :
La méthode de copie modifiée sert à générer un réseau en imitant des caractéristiques des réseaux réels, comme la formation
de triangles et un haut coefficient de clustering.
Comment ça fonctionne ?
- On commence par choisir un nœud au hasard.
À chaque étape :
- Un nouveau nœud est ajouté au réseau.
- Ce nouveau nœud choisit au hasard un nœud existant dans le réseau, qu’on appelle nœud cible.
- Il parcourt les voisins du nœud cible. Pour chaque voisin, il a une probabilité p (par exemple, p=0,5) de se connecter à ce voisin.
- À la fin, il se connecte obligatoirement au nœud cible.
Pourquoi c'est intéressant ?
La probabilité p permet de créer des connexions locales, ce qui augmente le coefficient de clustering.
ATTENTION : Le nouveau nœud ne se connecte pas à tous les voisins du nœud cible, mais seulement à certains d’entre eux,
en fonction de la probabilité p.
Cette méthode garde le réseau connexe grâce à la connexion obligatoire au nœud cible.
Voici comment je m'y suis prise :
```java
public static Graph genererGrapheCopie(int nombreNoeuds, double probabilitéCopie) {
Graph grapheCopie = new SingleGraph("GrapheCopie");
Random aleatoire = new Random();
// Ajouter un premier nœud pour démarrer le réseau
grapheCopie.addNode("0");
for (int i = 1; i < nombreNoeuds; i++) {
Node nouveauNoeud = grapheCopie.addNode(String.valueOf(i));
// Choisir un nœud aléatoire existant
Node noeudCible = grapheCopie.getNode(aleatoire.nextInt(grapheCopie.getNodeCount()));
// Parcourir les voisins de noeudCible
noeudCible.edges().forEach(edge -> {
if (edge != null) { // Vérifier que l'arête n'est pas null
Node voisin = edge.getOpposite(noeudCible);
// Connecter au voisin avec probabilité p
String edgeIdVoisin = nouveauNoeud.getId() + "-" + voisin.getId();
if (aleatoire.nextDouble() < probabilitéCopie && grapheCopie.getEdge(edgeIdVoisin) == null) {
grapheCopie.addEdge(edgeIdVoisin, nouveauNoeud, voisin);
}
}
});
// Connecter le nouveau nœud au nœud cible
String edgeIdCible = nouveauNoeud.getId() + "-" + noeudCible.getId();
if (grapheCopie.getEdge(edgeIdCible) == null) {
grapheCopie.addEdge(edgeIdCible, nouveauNoeud, noeudCible);
}
}
return grapheCopie;
}
```
Voici les résultats après éxecution du code :
- Nombre de nœuds : 317080
- Nombre de liens : 3392116
- Degré moyen : 21.395963668823242
- Coefficient de clustering : 0.44452828185775123
On remarque bien que le degré moyen est très élevé, mais aussi le coeff de clustring.
# TP 2 :
## 1 - Taux de propagation et seuil épidémique du réseau ainsi que le seuil théorique d'un réseau aléatoire du même degré moyen :
Avant de commencer, il faut savoir que ce modèle est un SIS (Susceptible-Infected-Susceptible)
##### Dans un modèle SIS:
chaque individu de la population peut être dans l’un des deux états suivants :
- Susceptible (S) :
L'individu est en bonne santé mais peut être infecté.
- Infecté (I) :
L'individu est malade et peut transmettre l'infection.
##### Dynamique des transitions
- Un individu susceptible (S) peut devenir infecté (I) après un contact avec une personne infectée, avec une probabilité appelée taux d'infection (β).
- Un individu infecté (I) peut se rétablir et redevenir susceptible (S) avec une probabilité appelée taux de récupération (μ).
La principale caractéristique du modèle SIS est que les individus infectés ne développent pas d'immunité après récupération, ce qui signifie qu'ils peuvent être réinfectés.
- Taux de propagation :
###### τ = β/μ
avec β = 1 (une personne est infécté a partir du moment où elle reçoit un mail)
et μ = 0.5 ( il mettent à jour leurs anti-virus 2 fois par mois donc 2 semaines sur 4)
ce qui nous donne un taux de propagation (τ) : 2.0 que j'ai calculé comme suit :
```java
double infectionProbability = 1.0; // β = 1
double recoveryProbability = 0.5; // μ = 0.5
double tau = infectionRate / recoveryRate; // Taux de propagation
```
- Seuil épidémique :
###### c = < k > / <k^2>
avec <k> : degré moyen (le nombre moyen de connexions par nœud)
et <k^2>: moyenne des carrés des degrés des nœuds.
ce qui nous donne un seuil épidémique réel (c_réel) de 0.04598472436222584 que j'ai calculé comme suit :
```java
double cReal = avgDegree / avgDegreeSquared;
```
```java
private static double calculateSquaredAverageDegree(Graph graph) {
double totalDegreeSquared = 0;
for (Node node : graph) {
totalDegreeSquared += Math.pow(node.getDegree(), 2); // Somme des carrés des degrés
}
return totalDegreeSquared / graph.getNodeCount(); // Moyenne des carrés des degrés
}
```
enfin, le seuil théorique :
```java
double cTheoretical = 1.0 / (avgDegree + 1); // Seuil théorique pour un réseau aléatoire avec normalisation
```
ce qui nous donne un seuil théorique de 0.13119762993051035.
on constate que la maladie persiste La maladie persiste dans le réseau réel (τ > c_réel) et que le réseau réel est plus vulnérable que le réseau aléatoire (c_réel < c_théorique).
## 2 - Simulation des 3 scénario :
Voici les paramètres de ma méthode de simulation : il y'en a 6 :
- Graph graph : Le graphe
- double infectionRate : La probabilité qu'un nœud infecté transmette la maladie à un voisin susceptible.
- double recoveryRate : La probabilité qu'un nœud infecté se rétablisse et redevienne susceptible.
- int days : Le nombre total de jours pendant lesquels la simulation est exécutée.
- double immunizationFraction : La fraction de nœuds ou voisins à immuniser avant le début de la simulation.
- boolean randomImmunization : Détermine la stratégie d'immunisation :
true : Immunisation aléatoire.
false : Immunisation sélective (immuniser un voisin d'un nœud sélectionné).
Cette partie là concerne les deux scénario où il y'a des gens à immuniser (scénario 2 et 3)
ceci est assuré grâce au premier if, et le deuxième if nous permet de savoir si c'est une random immunisation donc le scénario 2 (on convint 50% des gens à mettre à jour leurs anti-virus) où la condition nous retournera true car c'est un boolean
ou non et on passera au else donc le scénario 3 (on convint 50% des gens à convaincre un de leurs voisins).
```java
// Immunization
if (immunizationFraction > 0) {
int immunizedCount = (int) (immunizationFraction * graph.getNodeCount());
if (randomImmunization) {
// Récupérer tous les nœuds dans une liste
List<Node> allNodes = new ArrayList<>(graph.nodes().toList());
// Mélanger la liste pour une sélection aléatoire unique
Collections.shuffle(allNodes, random);
// Immuniser les premiers `immunizedCount` nœuds
Node node = allNodes.get(i);
if (node != null) {
node.setAttribute("immune", true);
}
}
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
} else {
// Immunisation sélective : immuniser un voisin pour 50% des nœuds existants
List<Node> nodes = new ArrayList<>( graph.nodes().toList());
// Calculer le nombre de nœuds à immuniser (50% des nœuds existants)
int nodesToImmunize = (int) (immunizationFraction * nodes.size());
// Mélanger les nœuds pour garantir une sélection aléatoire
Collections.shuffle(nodes, random);
// Sélectionner les premiers `nodesToImmunize` nœuds et immuniser un voisin pour chacun
for (int i = 0; i < nodesToImmunize; i++) {
Node node = nodes.get(i);
// Vérifier que le nœud a des voisins
if (node.getDegree() > 0) {
// Prendre un voisin aléatoire
List<Node> neighbors = node.neighborNodes().toList();
Node neighbor = neighbors.get(random.nextInt(neighbors.size()));
// Immuniser ce voisin
neighbor.setAttribute("immune", true);
}
}
}
}
```
viens maintenant la simulation (c'est un peu là ou tout se déroule y compris le scénario 1)
On commence par infecter un patient qu'on appellera patient 0.
- infectedCount : Nombre de nœuds infectés au cours de la journée actuelle.
- totalNonImmune : Nombre total de nœuds non immunisés dans le graphe
(c'est-à-dire les nœuds susceptibles ou infectés).
- Exclusion des nœuds immunisés : Les nœuds avec l'attribut immune ne participent pas à la propagation.
###### Propagation (S→I) :
- Les nœuds infectés propagent l'infection à leurs voisins susceptibles avec une probabilité définie par infectionRate.
- Les nœuds susceptibles infectés reçoivent un état futur "infected" stocké dans nextState.
###### Récupération (I→S) :
- Les nœuds infectés peuvent récupérer avec une probabilité définie par recoveryRate et sont marqués comme "susceptible" dans nextState.
On fait ensuite une mise à jour des états des nœuds, Les changements d’état sont appliqués après chaque jour.
Résultats : La fraction de nœuds infectés est calculée chaque jour et retournée à la fin.
```java
// Infect patient zero
Node patientZero = graph.getNode(new Random().nextInt(graph.getNodeCount()));
patientZero.setAttribute("state", "infected");
// Simulation
for (int day = 0; day < days; day++) {
int infectedCount = 0;
int totalNonImmune = 0;
for (Node node : graph) {
if (!node.hasAttribute("immune")) {
totalNonImmune++;
if (node.getAttribute("state").equals("infected")) {
infectedCount++;
for (Node neighbor : node.neighborNodes().toList()) {
if (!neighbor.hasAttribute("immune") && neighbor.getAttribute("state").equals("susceptible") && random.nextDouble() < infectionRate) {
neighbor.setAttribute("nextState", "infected");
}
}
if (random.nextDouble() < recoveryRate) {
node.setAttribute("nextState", "susceptible");
}
}
}
}
// mise à jour de l'état des noeuds
for (Node node : graph) {
if (node.hasAttribute("nextState")) {
node.setAttribute("state", node.getAttribute("nextState"));
node.removeAttribute("nextState");
}
}
infectedFractions[day] = (double) infectedCount / totalNonImmune;
}
return infectedFractions;
}
```
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
#### Attention : La réalisation d'un scénario autour des valeurs critiques est sensible aux conditions initiales.
c'est pour ça que j'ai simulé plusieurs fois chaque scénario en **itérant sur 10** et en faire la moyenne après.
```java
// --- Scénarios avec itérations ---
for (int scenario = 0; scenario < 3; scenario++) {
double[] averageFractions = new double[daysToSimulate];
Arrays.fill(averageFractions, 0); // Initialiser à zéro pour chaque scénario
for (int iteration = 0; iteration < iterations; iteration++) {
// Cloner le graphe pour garantir une nouvelle simulation à chaque itération
Graph graphClone = cloneGraph(graph);
// Définir les paramètres spécifiques au scénario
double immunizationFraction = 0;
boolean randomImmunization = false;
if (scenario == 1) { // Immunisation aléatoire
immunizationFraction = 0.5;
randomImmunization = true;
} else if (scenario == 2) { // Immunisation sélective
immunizationFraction = 0.5;
randomImmunization = false;
}
// Exécuter la simulation et capturer les résultats
double[] fractions = simulateAndCaptureResults(graphClone, infectionProbability, recoveryProbability, daysToSimulate, immunizationFraction, randomImmunization);
// Ajouter les résultats de cette itération à la moyenne
for (int day = 0; day < daysToSimulate; day++) {
averageFractions[day] += fractions[day];
}
}
// Diviser par le nombre d'itérations pour obtenir la moyenne
for (int day = 0; day < daysToSimulate; day++) {
averageFractions[day] /= iterations;
}
// Stocker les résultats du scénario
results[scenario] = averageFractions;
// Enregistrer les résultats dans un fichier
writeResultsToFile(fileNames[scenario], averageFractions);
}
```
#### on obtient ces courbes qui montrent bien l'efficacité de l'immunisation séléctive.

- on voit bien à quel point l'immunisation séléctive est efficace.
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
## 3 - Le degré moyen des groupes 0 et 1 :
Il faut savoir que le groupe 0 sont les nœuds choisis aléatoirement et le groupe un de leurs voisins.
Resumé :
- Groupe 0 => 50% des nœuds [non immunisé]
- Groupe 1 => 1 voisin de ces nœuds [immunisés]
voici comment j'ai procédé :
```java
// Appliquer une immunisation aléatoire (immuniser 50 % des nœuds)
Set<Node> immune = new HashSet<>();
Random random = new Random();
int immuneCount = (int) (0.5 * graph.getNodeCount()); // Immuniser 50 % des nœuds
List<Node> nodes = new ArrayList<>(graph.nodes().toList());
Collections.shuffle(nodes, random);
for (int i = 0; i < immuneCount; i++) {
Node node = nodes.get(i);
node.setAttribute("immune", true); // Marquer comme immunisé
immune.add(node);
}
// Groupes
Set<Node> group0 = new HashSet<>(); // Groupe 0 : 50 % des nœuds non immunisés
Set<Node> group1 = new HashSet<>(); // Groupe 1 : Un voisin immunisé de chaque nœud du Groupe 0
// Sélectionner 50 % des nœuds non immunisés pour le Groupe 0
List<Node> nonImmuneNodes = new ArrayList<>();
for (Node node : graph) {
if (!immune.contains(node)) { // Nœuds non immunisés
nonImmuneNodes.add(node);
}
}
Collections.shuffle(nonImmuneNodes, random); // Mélanger les nœuds non immunisés
int targetCount = (int) (0.5 * nonImmuneNodes.size()); // 50 % des nœuds non immunisés
for (int i = 0; i < targetCount; i++) {
group0.add(nonImmuneNodes.get(i)); // Ajouter au groupe 0
}
// Pour chaque nœud du Groupe 0, ajouter un voisin immunisé au Groupe 1
for (Node node : group0) {
List<Node> neighbors = node.neighborNodes().toList();
for (Node neighbor : neighbors) {
if (immune.contains(neighbor)) { // Vérifier si le voisin est immunisé
group1.add(neighbor); // Ajouter un seul voisin immunisé au groupe 1
break; // Sortir de la boucle après avoir trouvé un voisin immunisé
}
}
}
// Calcul du degré moyen pour le Groupe 0 (non immunisé)
double totalDegreeGroup0 = 0;
for (Node node : group0) {
totalDegreeGroup0 += node.getDegree();
}
double averageDegreeGroup0 = group0.isEmpty() ? 0 : totalDegreeGroup0 / group0.size();
System.out.printf("Degré moyen (Groupe 0 - Non immunisé) : %.9f%n", averageDegreeGroup0);
// Calcul du degré moyen pour le Groupe 1 (voisins immunisés)
double totalDegreeGroup1 = 0;
for (Node node : group1) {
totalDegreeGroup1 += node.getDegree();
}
double averageDegreeGroup1 = group1.isEmpty() ? 0 : totalDegreeGroup1 / group1.size();
System.out.printf("Degré moyen (Groupe 1 - Voisins immunisés) : %.9f%n", averageDegreeGroup1);
```
Immunisation aléatoire :
50 % des nœuds du graphe sont sélectionnés de manière aléatoire pour être immunisés.
Ces nœuds sont marqués avec l'attribut "immune" et ajoutés à un ensemble immune.
###### Groupe 0 (non immunisé) :
les nœuds non immunisés forment le groupe 0.
Ces nœuds représentent une population aléatoire non immunisée dans le graphe.
###### Groupe 1 (voisins immunisés) :
Pour chaque nœud du Groupe 0, on cherche un voisin immunisé (parmi ceux marqués "immune").
Ce voisin immunisé est ajouté au Groupe 1.
Chaque nœud du Groupe 0 est associé à un seul voisin immunisé.
Voici les résultats :
- Degré moyen (Groupe 0 - Non immunisé) : 6,601652580
- Degré moyen (Groupe 1 - Voisins immunisés) : 14,067850086
La différence entre les degrés moyens reflète l’efficacité de l’immunisation sélective :
###### Immunisation aléatoire :
Le degré moyen est similaire au degré moyen global du graphe.
###### Immunisation sélective :
Le degré moyen est nettement plus élevé, car les voisins des hubs
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
(nœuds critiques) sont ciblés, ce qui fragmente davantage le réseau.
## 4 - suppression des noeuds si ils sont immunisés :
on utilise une méthode pour chaque immunisation :
- immunisation random :
Cette méthode applique une immunisation aléatoire en supprimant un pourcentage donné (fraction) de nœuds sélectionnés
au hasard dans le graphe.
```java
private static void applyRandomImmunization(Graph graph, double fraction) {
Random random = new Random();
int immunizedCount = (int) (fraction * graph.getNodeCount());
for (int i = 0; i < immunizedCount; i++) {
Node node = graph.getNode(random.nextInt(graph.getNodeCount()));
if (node != null) {
graph.removeNode(node);
}
}
}
```
Cette méthode applique une immunisation sélective en parcourant les nœuds du graphe et,
pour chaque nœud sélectionné avec une probabilité donnée (fraction), elle supprime tous ses voisins.
```java
private static void applySelectiveImmunization(Graph graph, double fraction) {
Random random = new Random();
// Créer une liste des nœuds
var nodes = graph.nodes().toList();
for (Node node : nodes) {
if (node != null && random.nextDouble() < fraction) {
// Parcourir les voisins et les supprimer
var neighbors = node.neighborNodes().toList();
for (Node neighbor : neighbors) {
if (graph.getNode(neighbor.getId()) != null) { // Vérifier que le voisin existe toujours
graph.removeNode(neighbor.getId());
}
}
}
}
}
```
Voici les résultats :
- Analyse après immunisation aléatoire :
- Taux de propagation (τ) : 2.0
- Seuil épidémique réel (c_réel) : 0.08716647329769069
- Seuil épidémique théorique (c_théorique) : 0.23112472214969867
- Analyse après immunisation sélective :
- Taux de propagation (τ) : 2.0
- Seuil épidémique réel (c_réel) : 0.5494896486700256
- Seuil épidémique théorique (c_théorique) : 0.8383065431501645
on constate que ça correspond parfaitement aux résultats théoriques :
| **Stratégie d’immunisation** | **Impact sur ⟨k⟩** | **Impact sur ⟨k²⟩** | **Seuil épidémique c** |
|-------------------------------|-------------------------------|------------------------------|-------------------------------|
| Aucune immunisation | Aucun changement | Aucun changement | Bas |
| Immunisation aléatoire | Réduction proportionnelle | Faible réduction | Modérément augmenté |
| Immunisation sélective | Réduction modérée | Forte réduction | Significativement augmenté |
## 5 - Simulez l'épidémie avec un réseau aléatoire et un réseau BA:
J'ai utilisé les graphes que j'ai généré dans le TP1.
```java
private static void runSimulations(Graph graph) {
int daysToSimulate = 90; // 3 mois
double infectionProbability = 1.0; // β = 1
double recoveryProbability = 0.5; // μ = 0.5
// Scénario 1 : Aucune immunisation
System.out.println("Scénario 1 : Aucune immunisation");
simulateAndCaptureResults(graph, infectionProbability, recoveryProbability, daysToSimulate, 0, false);
// Scénario 2 : Immunisation aléatoire
System.out.println("Scénario 2 : Immunisation aléatoire");
applyRandomImmunization(graph, 0.5); // Immunisation aléatoire de 50 %
simulateAndCaptureResults(graph, infectionProbability, recoveryProbability, daysToSimulate, 0, true);
// Scénario 3 : Immunisation sélective
System.out.println("Scénario 3 : Immunisation sélective");
applySelectiveImmunization(graph, 0.5); // Immunisation sélective de 50 %
simulateAndCaptureResults(graph, infectionProbability, recoveryProbability, daysToSimulate, 0, false);
}
```