public void NegativeModularity() { var N = NetworkHelper.InitBarabasi(); var A = N.Actors; var C = A.Select(a => new Community(a)).ToList(); var M = Modularity.Compute(N, C); Assert.Equal(-0.12, Math.Round(M, 2)); }
public void SingleCommunity() { var N = NetworkHelper.InitBarabasi(); var A = N.Actors; var C = new List <Community> { new Community(A), }; var M = Modularity.Compute(N, C); Assert.Equal(0.0, M); }
public void SuboptimalParition() { var N = NetworkHelper.InitBarabasi(); var A = N.Actors; var C = new List <Community> { new Community(A[0], A[1], A[2]), new Community(A[3], A[4], A[5], A[6], A[7], A[8]) }; var M = Modularity.Compute(N, C); Assert.Equal(0.22, Math.Round(M, 2)); }
public void Zero() { for (var i = 0; i < 10; i++) { var network = new MNCD.Generators.CompleteGraphGenerator().Generate(2 + i); var communities = new List <Community> { new Community(network.Actors) }; var modularity = Modularity.Compute(network, communities); Assert.Equal(0.0, modularity); } }
/// <summary> /// Computes communities hierarchy. /// </summary> /// <param name="inputNetwork">Input network.</param> /// <returns>Hierarchy of communities and it's modularities.</returns> public List <(double modularity, List <Community> communities)> GetHierarchy(Network inputNetwork) { if (inputNetwork.LayerCount > 1) { throw new ArgumentException("Louvain works only on single layered networks."); } var network = inputNetwork; List <Community> communities; Dictionary <Actor, Community> actorToCommunity; Dictionary <Actor, List <Actor> > actorToActors = null; var hierarchy = new List <(double modularity, List <Community> communities)>(); while (true) { (communities, actorToCommunity) = PhaseOne(network); var com = communities; if (actorToActors != null) { var original = new List <Community>(); foreach (var c in communities) { var actors = c.Actors.SelectMany(a => actorToActors[a]); original.Add(new Community(actors)); } com = original; } com = com.Where(c => c.Size > 0).ToList(); hierarchy.Add((Modularity.Compute(inputNetwork, com), com)); (network, actorToActors) = PhaseTwo(network, communities, actorToCommunity); var edges = network.FirstLayer.Edges; if (network.ActorCount == 1 || edges.Count == 0 || (edges.Count == 1 && edges.Any(e => e.From == e.To))) { break; } } return(hierarchy); }
/// <summary> /// Phase one of louvain. /// </summary> /// <param name="network">Network.</param> /// <returns>list of communities and mapping of actor to community.</returns> internal (List <Community>, Dictionary <Actor, Community>) PhaseOne(Network network) { var actorToCommunity = network.Actors .ToDictionary(a => a, a => new Community(a)); var communities = actorToCommunity.Values.ToList(); var actorToNeighbours = network.FirstLayer.GetNeighboursDict(); // First Phase - Local Optimum var change = true; var iterations = 0; while (change && iterations < 1000) { iterations++; change = false; foreach (var actor in network.Actors) { if (!actorToNeighbours.ContainsKey(actor)) { continue; } var ac = actorToCommunity[actor]; var mc = Modularity.Compute(network, communities); var maxModularity = mc; var com = ac; foreach (var neighbour in actorToNeighbours[actor]) { var nc = actorToCommunity[neighbour]; if (ac == nc) { continue; } ac.Actors.Remove(actor); nc.Actors.Add(actor); var comms = communities.Where(c => c.Size > 0).ToList(); var nm = Modularity.Compute(network, comms); if (nm > maxModularity) { maxModularity = nm; com = nc; } ac.Actors.Add(actor); nc.Actors.Remove(actor); } if (maxModularity > mc) { change = true; ac.Actors.Remove(actor); com.Actors.Add(actor); actorToCommunity[actor] = com; } } } return(communities, actorToCommunity); }