-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathLabelPropagation.cs
137 lines (116 loc) · 4.16 KB
/
LabelPropagation.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
using MNCD.Core;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace MNCD.CommunityDetection.SingleLayer
{
/// <summary>
/// Implements Label Propagation Algorithm (LPA) based on the
/// synchronous model.
///
/// Community Detection via Semi–Synchronous Label Propagation Algorithms
/// Gennaro Cordasco and Luisa Gargano
/// https://arxiv.org/pdf/1103.4550.pdf
/// </summary>
public class LabelPropagation
{
private static readonly Random RANDOM = new Random();
/// <summary>
/// Computes communities in network based on Label Propagation algorithm.
/// </summary>
/// <param name="network">Network in which to compute communities.</param>
/// <param name="maxIterations">Maximum number of iterations.</param>
/// <returns>List of communities.</returns>
public List<Community> GetCommunities(Network network, int maxIterations = 10_000)
{
network = network ?? throw new ArgumentNullException(nameof(network));
if (maxIterations < 1)
{
throw new ArgumentException("MaxIterations must be greater than 0.");
}
if (network.LayerCount > 1)
{
throw new ArgumentException("A single-layer network is required.");
}
var labels = InitLabels(network);
var neighbours = network.FirstLayer.GetNeighboursDict();
for (int i = 0; i < maxIterations; i++)
{
var newLabels = new Dictionary<Actor, int>();
var hasChanged = false;
foreach (var a in network.Actors)
{
if (neighbours.ContainsKey(a))
{
newLabels[a] = MostCommonLabel(a, neighbours[a], labels);
}
else
{
// Assign previous label
newLabels[a] = labels[a];
}
if (newLabels[a] != labels[a])
{
hasChanged = true;
}
}
if (!hasChanged)
{
break;
}
labels = newLabels;
}
return LabelsToCommunities(labels);
}
private int MostCommonLabel(Actor actor, List<Actor> neighbours, Dictionary<Actor, int> labels)
{
var neighbourLabels = new Dictionary<int, int>();
var maxCount = 0;
foreach (var n in neighbours)
{
var label = labels[n];
if (neighbourLabels.ContainsKey(label))
{
neighbourLabels[label]++;
}
else
{
neighbourLabels[label] = 1;
}
if (neighbourLabels[label] > maxCount)
{
maxCount = neighbourLabels[label];
}
}
var maximal = neighbourLabels.Where(nl => nl.Value == maxCount).ToList();
if (maximal.Count > 1)
{
var original = labels[actor];
// If original label is present in maximal, keep it.
if (maximal.Any(m => m.Key == original))
{
return original;
}
// If there are multiple labels with same count, take one randomly
return maximal[RANDOM.Next(maximal.Count)].Key;
}
else
{
return maximal.First().Key;
}
}
private List<Community> LabelsToCommunities(Dictionary<Actor, int> labels)
{
return labels
.GroupBy(l => l.Value)
.Select(l => new Community(l.Select(a => a.Key)))
.ToList();
}
private Dictionary<Actor, int> InitLabels(Network network)
{
var i = 0;
return network.Actors.ToDictionary(n => n, n => i++);
}
}
}