// Do for each layer random walk for every pair of nodes on the layer. // Average the value over all possible starting layers for the actor. /// <summary> /// Returns dictionary, where actors are keys and random walk betweenness centrality is their value. /// </summary> /// <param name="mnet">Multilayer network.</param> /// <param name="jump">Jump probability for random walker, default value is 0.2.</param> /// <param name="transitions">Matrix of transition probabilities between layers. Default is uniform for each pair of layers.</param> /// <returns>Dictionary, where actors are keys and random walk betweenness centrality is their value.</returns> public ConcurrentDictionary <Actor, int> RandomWalkBetweenness(MultilayerNetwork mnet, double jump = 0.2, double[][] transitions = null) { // If not set transitions, use uniform probability for every layer. transitions = new double[mnet.Layers.Count][]; for (int i = 0; i < mnet.Layers.Count; i++) { transitions[i] = new double[mnet.Layers.Count]; for (int j = 0; j < transitions[i].Length; j++) { transitions[i][j] = 1.0 / transitions[i].Length; } } var rw = new Walker(mnet, jump, transitions); // Number of random walks passing through given actor. var actorRandomWalkCount = new ConcurrentDictionary <Actor, int>(); //foreach (var a in mnet.GetActors()) Parallel.ForEach(mnet.GetActors(), (a) => { actorRandomWalkCount.TryAdd(a, 0); }); // Do random walk between every pair of nodes. // Average it over the layers. var nodes = mnet.GetNodes().ToArray(); for (int i = 0; i < nodes.Length - 1; i++) { //for (int j = i + 1; j < nodes.Length; j++) Parallel.For(i + 1, nodes.Length, j => { RandomWalkActors(rw, nodes[i], nodes[j], ref actorRandomWalkCount); }); } var temp = new ConcurrentDictionary <Actor, int>(actorRandomWalkCount); // Average it - divide by number of nodes with the corresponding actor. //foreach (var a in temp.Keys) Parallel.ForEach(temp.Keys, (a) => { if (mnet.NodesByActor.ContainsKey(a.Id)) { var nodesCount = mnet.NodesByActor[a.Id].Count; actorRandomWalkCount[a] = temp[a] / nodesCount; } }); return(actorRandomWalkCount); }
/// <summary> /// Utility method, for creating new layer in the multilayer network. /// </summary> /// <param name="mnet">Multilayer network.</param> /// <param name="newLayerName">Name of the new layer.</param> /// <param name="layers">Layers of the network.</param> /// <param name="forceDirected">True if new edges should be directed, false if not.</param> /// <param name="forceActors">True if all actors should be on the new layer, false if not.</param> /// <returns>Newly created layer.</returns> private Layer createLayer(MultilayerNetwork mnet, string newLayerName, HashSet <Layer> layers, bool forceDirected, bool forceActors) { var directed = forceDirected; // Check if there are any directed layers, if YES, then new layer will be directed as well. if (!directed) { foreach (var layer1 in layers) { foreach (var layer2 in layers) { if (mnet.IsDirected(layer1, layer2)) { directed = true; break; } } if (directed) { break; } } } var dir = directed ? EdgeDirectionality.Directed : EdgeDirectionality.Undirected; var newLayer = mnet.AddLayer(newLayerName, dir); if (newLayer == null) { throw new ArgumentException("Layer " + newLayerName + " already exists."); } if (forceActors) { foreach (var actor in mnet.GetActors()) { mnet.AddNode(actor, newLayer); } } else { foreach (var layer in layers) { foreach (var node in mnet.GetNodes(layer)) { mnet.AddNode(node.Actor, newLayer); } } } return(newLayer); }
/// <summary> /// Returns dictionary, where actors are keys and their random walk closeness centrality is value. /// </summary> /// <param name="mnet">Multilayer network.</param> /// <param name="jump">Jump probability, default value is 0.2.</param> /// <param name="transitions">Matrix of transition probabilities between layers. Default is uniform for each pair of layers.</param> /// <returns>Dictionary, where actors are keys and their random walk closeness centrality is value.</returns> public ConcurrentDictionary <Actor, double> RandomWalkCloseness(MultilayerNetwork mnet, double jump = 0.2, double[][] transitions = null) { // If not set transitions, use uniform probability for every layer. transitions = new double[mnet.Layers.Count][]; for (int i = 0; i < mnet.Layers.Count; i++) { transitions[i] = new double[mnet.Layers.Count]; for (int j = 0; j < transitions[i].Length; j++) { transitions[i][j] = 1.0 / transitions[i].Length; } } var rw = new Walker(mnet, jump, transitions); // Create adjacency matrix for actors. // Every actor has its Id. // First Id starts at 0. // Last Id is actors count - 1. var adjActors = new int[mnet.GetActors().Count][]; for (int i = 0; i < mnet.Actors.Count; i++) { adjActors[i] = new int[mnet.Actors.Count]; } // Traverse the matrix for every pair of nodes. var nodes = mnet.GetNodes().ToArray(); for (int i = 0; i < nodes.Length - 1; i++) { //for (int j = i + 1; j < nodes.Length; j++) Parallel.For(i + 1, nodes.Length, (j) => { //Console.WriteLine(i + ":" + j); // Do random walk from i to j. // And save only the first walk length. var walkLen = RandomWalkSteps(rw, nodes[i], nodes[j]); // Use only first walk. if (adjActors[nodes[i].Actor.Id][nodes[j].Actor.Id] == 0) { adjActors[nodes[i].Actor.Id][nodes[j].Actor.Id] = walkLen; adjActors[nodes[j].Actor.Id][nodes[i].Actor.Id] = walkLen; } }); } var actorById = new ConcurrentDictionary <int, Actor>(); //foreach (var actor in mnet.GetActors()) Parallel.ForEach(mnet.GetActors(), (a) => { actorById.TryAdd(a.Id, a); }); // Actual Clonesess centrality. // Harmonic mean distance. var closenessByActor = new ConcurrentDictionary <Actor, double>(); for (int i = 0; i < adjActors[0].Length; i++) { double sum = 0; //for (int j = 0; j < adjActors[0].Length; j++) Parallel.For(0, adjActors[0].Length, (j) => { if (i == j) { adjActors[i][j] = 0; } else { if (adjActors[i][j] != 0) { sum += 1.0 / adjActors[i][j]; } } }); double closeness = (1.0 / (adjActors[0].Length - 1)) * sum; closenessByActor[actorById[i]] = closeness; } return(closenessByActor); }