/// <summary> /// Parallely computes the betweenness preference distribution of all nodes in a temporal network /// </summary> /// <param name="temp_net">The temporal network to analyze</param> /// <returns>An IEnumerable containing betweenness preferences of all nodes</returns> public static IEnumerable <double> GetBetweennessPrefDist(TemporalNetwork temp_net) { List <double> dist = new List <double>(temp_net.AggregateNetwork.VertexCount); Parallel.ForEach <string>(temp_net.AggregateNetwork.Vertices, v => { double betweennessPref = BetweennessPref.GetBetweennessPref(temp_net, v); // Synchronized access to the list if (temp_net.AggregateNetwork.GetIndeg(v) > 0 && temp_net.AggregateNetwork.GetOutdeg(v) > 0) { lock (dist) dist.Add(betweennessPref); } }); return(dist); }
public static IDictionary <int, double> RunRW_BWP(TemporalNetwork temp_net, int max_steps = 100000, bool null_model = false) { Random r = new Random(); var cumulatives = new Dictionary <Tuple <string, string>, Dictionary <double, string> >(); var sums = new Dictionary <Tuple <string, string>, double>(); // Dictionary<string, Dictionary<double, string>> cumulatives = // Dictionary<string, double> sums = new Dictionary<string, double>(); Dictionary <string, Dictionary <string, int> > indices_pred = new Dictionary <string, Dictionary <string, int> >(); Dictionary <string, Dictionary <string, int> > indices_succ = new Dictionary <string, Dictionary <string, int> >(); Dictionary <string, double[, ]> matrices = new Dictionary <string, double[, ]>(); Dictionary <string, int> visitations = new Dictionary <string, int>(); Dictionary <string, double> stationary = new Dictionary <string, double>(); Dictionary <Tuple <string, string>, int> edge_visitations = new Dictionary <Tuple <string, string>, int>(); Dictionary <Tuple <string, string>, double> edge_stationary = new Dictionary <Tuple <string, string>, double>(); Dictionary <int, double> tvd = new Dictionary <int, double>(); // Aggregate network WeightedNetwork network = temp_net.AggregateNetwork; // Read analytical stationary distribution (i.e. flow-corrected edge weights) from disk string[] lines = System.IO.File.ReadAllLines("stationary_dist_RM.dat"); foreach (string x in lines) { string[] split = x.Split(' '); string[] nodes = split[0].Split('.'); var edge = new Tuple <string, string>(nodes[0], nodes[1]); // Extract stationary dist, set visitations to zero and adjust edge weights ... edge_stationary[edge] = double.Parse(split[1], System.Globalization.CultureInfo.GetCultureInfo("en-US").NumberFormat); edge_visitations[edge] = 0; network[edge] = edge_stationary[edge]; } // Compute stationary dist of vertices ... double total = 0d; foreach (string x in network.Vertices) { stationary[x] = 0d; foreach (string s in network.GetPredecessors(x)) { stationary[x] += edge_stationary[new Tuple <string, string>(s, x)]; } total += stationary[x]; } foreach (string x in network.Vertices) { stationary[x] = stationary[x] / total; } // Compute betweenness preference matrices if (!null_model) { Console.Write("Computing betweenness preference in temporal network ..."); } else { Console.Write("Calculating null model betweenness preference ..."); } foreach (string x in network.Vertices) { var ind_p = new Dictionary <string, int>(); var ind_s = new Dictionary <string, int>(); if (!null_model) { matrices[x] = BetweennessPref.GetBetweennessPrefMatrix(temp_net, x, out ind_p, out ind_s, false); } else { matrices[x] = BetweennessPref.GetUncorrelatedBetweennessPrefMatrix(temp_net, x, out ind_p, out ind_s); } indices_pred[x] = ind_p; indices_succ[x] = ind_s; } Console.WriteLine("done."); // Initialize visitations, stationary distribution and cumulatives ... foreach (string x in network.Vertices) { visitations[x] = 0; stationary[x] = 0d; foreach (string s in indices_pred[x].Keys) { Tuple <string, string> key = new Tuple <string, string>(s, x); stationary[x] += network.GetWeight(s, x); // Compute the transition probability for a edge (x,t) given that we are in (s,x) cumulatives[key] = new Dictionary <double, string>(); double sum = 0d; foreach (string t in indices_succ[x].Keys) { double transition_prob = 0d; string two_path = s + "," + x + "," + t; transition_prob = matrices[x][indices_pred[x][s], indices_succ[x][t]]; if (transition_prob > 0) { sum += transition_prob; cumulatives[key][sum] = t; } } sums[key] = sum; } } // Draw two initial nodes ... string pred = network.RandomNode; string current = network.GetRandomSuccessor(pred); visitations[pred] = 1; visitations[current] = 1; edge_visitations[new Tuple <string, string>(pred, current)] = 1; // Run the random walk (over edges) for (int t = 0; t < max_steps; t++) { // The edge via which we arrived at the current node Tuple <string, string> current_edge = new Tuple <string, string>(pred, current); // If this happens, we are stuck in a sink, i.e. there is no out edge System.Diagnostics.Debug.Assert(sums[current_edge] > 0, string.Format("Network not strongly connected! RW stuck after passing through edge {0}", current_edge)); // Draw a sample uniformly from [0,1] and multiply it with the cumulative sum for the current edge ... double sample = rand.NextDouble() * sums[current_edge]; // Determine the next transition ... string next_node = null; for (int i = 0; i < cumulatives[current_edge].Count; i++) { if (cumulatives[current_edge].Keys.ElementAt(i) > sample) { next_node = cumulatives[current_edge].Values.ElementAt(i); break; } } pred = current; current = next_node; visitations[current] = visitations[current] + 1; edge_visitations[new Tuple <string, string>(pred, current)] = edge_visitations[new Tuple <string, string>(pred, current)] + 1; tvd[t] = TVD(visitations, stationary); } return(tvd); }
/// <summary> /// This method creates a random sequence of two paths, where the betweenness preferences as well as edge weights match those of a given temporal network. /// The model implemented here can be viewd in two different ways: /// 1.) It can be seen as a reshuffling of two paths realized in a given temporal network, while destroying other correlations like bursty activity patterns /// 2.) Alternatively, it can be seen as a random sampling based on the betweenness preference matrices of nodes as computed from an empirical network /// </summary> /// <param name="temp_net">The temporal network based on which a randomized sequence of two paths will be created</param> /// <param name="length">The length of the sequence in terms of the number of time-stamped interactions</param> /// <param name="precision">The numerical precision that will be used when sampling from the distribution. This /// at the same time affects the memory requirements of the procedure, which is at most precision*two_paths in the input network</param> /// <returns>A temporal network that preserves betweenness preferences as well as the aggregated network of the input</returns> public static TemporalNetwork ShuffleTwoPaths(TemporalNetwork temp_net, int length = 0, int precision = 1000) { // If no length is specified (i.e. length has the default value of 0), use the length of the original sequence length = length > 0 ? length : temp_net.Length; // This will take the betweenness pref. matrices of all nodes ... Dictionary <string, double[, ]> betweenness_matrices = new Dictionary <string, double[, ]>(); Dictionary <string, Dictionary <string, int> > pred_indices = new Dictionary <string, Dictionary <string, int> >(); Dictionary <string, Dictionary <string, int> > succ_indices = new Dictionary <string, Dictionary <string, int> >(); int lcm = 1; // Compute unnormalized betweenness preference matrices of all nodes in the aggregate network foreach (string x in temp_net.AggregateNetwork.Vertices) { Dictionary <string, int> preds = new Dictionary <string, int>(); Dictionary <string, int> succs = new Dictionary <string, int>(); betweenness_matrices[x] = BetweennessPref.GetBetweennessPrefMatrix(temp_net, x, out preds, out succs, normalized: false); pred_indices[x] = preds; succ_indices[x] = succs; // Compute the least common multiple of the denominators of all entries ... // Eventually we will multiply ALL entries of the matrices of ALL nodes with the LCM in order to // ensure that all two paths are represented with the correct relative frequencies foreach (string s in temp_net.AggregateNetwork.GetPredecessors(x)) { foreach (string d in temp_net.AggregateNetwork.GetSuccessors(x)) { int whole, numerator, denominator; MathHelper.RoundToMixedFraction(betweenness_matrices[x][pred_indices[x][s], succ_indices[x][d]], precision, out whole, out numerator, out denominator); lcm = MathHelper.LCM(lcm, denominator); } } } List <string> sampling_set = new List <string>(); // Create a list of two_paths whose relative frequencies match the betweenness preference matrix... foreach (string v in betweenness_matrices.Keys) { // Add source and target of two paths to list according to their relative frequencies in the matrices foreach (string s in temp_net.AggregateNetwork.GetPredecessors(v)) { foreach (string d in temp_net.AggregateNetwork.GetSuccessors(v)) { for (int k = 0; k < Math.Round(betweenness_matrices[v][pred_indices[v][s], succ_indices[v][d]] * lcm); k++) { sampling_set.Add(s + "," + v + "," + d); } } } } // Create an empty temporal network TemporalNetwork microstate = new TemporalNetwork(); int time = 0; // Draw two-paths at random from the sampling set, this is equivalent to reshuffling existing two paths of the original sequence // However, it additionally correctly accounts for continued two paths (in which case an edge overlaps) and for multiple edges in // a single step (such two paths will be counted fractionally) for (int l = 0; l < length / 2; l++) { // Draw a random two path int r = rand.Next(sampling_set.Count); string tp = sampling_set[r]; string[] nodes = tp.Split(','); // Add two temporal edges microstate.AddTemporalEdge(time++, nodes[0], nodes[1]); microstate.AddTemporalEdge(time++, nodes[1], nodes[2]); } return(microstate); }