/// <summary> /// Checks whether two temporal network instances are the same (including the labeling of time steps and the labeling of nodes) /// </summary> /// <param name="obj"></param> /// <returns></returns> public override bool Equals(object obj) { if (obj.GetType() != this.GetType()) { return(false); } TemporalNetwork other = obj as TemporalNetwork; foreach (int t in this.Keys) { if (!other.ContainsKey(t)) { return(false); } else { foreach (var edge in this[t]) { if (!other[t].Contains(edge)) { return(false); } } } } return(true); }
/// <summary> /// Creates an instance of a random walk process /// </summary> /// <param name="network"></param> /// <param name="walkmode"></param> public RandomWalk(TemporalNetwork network, RandomWalkMode walkmode) { RandomWalkMode = walkmode; _network = network; rand = new Random(); _current_visitations = new Dictionary <string, int>(); _last_visits = new Dictionary <string, int>(); // Set visitations to 0 foreach (string v in network.AggregateNetwork.Vertices) { _current_visitations[v] = 0; } foreach (string v in network.AggregateNetwork.Vertices) { _last_visits[v] = -1000; } // Reduce first and second-order aggregate network to strongly connected component _network.AggregateNetwork.ReduceToLargestStronglyConnectedComponent(); _network.SecondOrderAggregateNetwork.ReduceToLargestStronglyConnectedComponent(); // Initialize random walk CurrentEdge = StringToTuple(_network.SecondOrderAggregateNetwork.RandomNode); CurrentNode = CurrentEdge.Item2; _current_visitations[CurrentNode] = 1; Time = 1; // Compute stationary distribution _stationary_dist = ComputeStationaryDist(); InitializeCumulatives(); }
/// <summary> /// Computes the baseline betweenness preference matrix of a node under the assumption /// that the temporal network does not contain a betweenness preference correlation. This corresponds to /// equation (5) in the paper. /// </summary> /// <param name="temp_net">The temporal network for which to compute the matrix</param> /// <param name="x">The node to compute the baseline betweenness preference for</param> /// <param name="ego_net">The weighted, aggregate ego network of node x</param> /// <param name="index_pred">Indices of predecessor nodes in the betweenness preference matrix</param> /// <param name="index_succ">Indices of successor nodes in the betweenness preference matric</param> /// <param name="normalize">Whether or not to normalize the betweenness preference matrix (i.e. whether B or P shall be returned)</param> /// <returns>Depending on the normalization, a betweenness preference matrix B or the normalized version P will be returned</returns> public static double[,] GetUncorrelatedBetweennessPrefMatrix(TemporalNetwork temp_net, string x, out Dictionary <string, int> index_pred, out Dictionary <string, int> index_succ) { // Use a mapping of indices to node labels index_pred = new Dictionary <string, int>(); index_succ = new Dictionary <string, int>(); // Compute the matrix from the weighted ego network return(GetUncorrelatedBetweennessPrefMatrix(temp_net.AggregateNetwork, x, out index_pred, out index_succ)); }
/// <summary> /// Creates a temporal network instance from an ordered sequence of edges /// </summary> /// <param name="sequence">An ordered sequence of edges</param> /// <returns>An instance of a temporal network</returns> public static TemporalNetwork FromEdgeSequence(List <Tuple <string, string> > sequence) { TemporalNetwork net = new TemporalNetwork(); int time = 0; foreach (Tuple <string, string> t in sequence) { net.AddTemporalEdge(time++, t.Item1, t.Item2); } return(net); }
/// <summary> /// Computes the (scalar) betwenness preference of a node /// </summary> /// <param name="temp_net">The temporal network for which to compute betweenness preference</param> /// <param name="x">The node for which to compute betweenness preference</param> /// <returns>The betweenness preference, defined as the mutual information of the source and target of two-paths</returns> public static double GetBetweennessPref(TemporalNetwork temp_net, string x) { // This will be used to store the index mappings in the betweenness preference matrix Dictionary <string, int> index_pred; Dictionary <string, int> index_succ; // Compute the normalized betweenness preference matrix of x according to equation (2) and (3) double[,] P = GetBetweennessPrefMatrix(temp_net, x, out index_pred, out index_succ); return(GetBetweennessPref(temp_net.AggregateNetwork, x, P)); }
/// <summary> /// Creates a random temporal network by shuffling the edges present in an original weighted network /// </summary> /// <param name="net">The weighted network to draw the microstate from</param> /// <param name="length">The length of the sequence in terms of the number of time-stamped interactions</param> /// <returns></returns> public static TemporalNetwork ShuffleEdges(TemporalNetwork 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 network length = length > 0 ? length : (int)net.AggregateNetwork.CumulativeWeight; int lcm = 1; foreach (var twopath in net.TwoPathWeights.Keys) { int whole, numerator, denominator; MathHelper.RoundToMixedFraction(net.TwoPathWeights[twopath], precision, out whole, out numerator, out denominator); lcm = MathHelper.LCM(lcm, denominator); } // Collect edges in two sampling sets for in and outgoing edges of two paths List <Tuple <string, string> > in_edges = new List <Tuple <string, string> >(); List <Tuple <string, string> > out_edges = new List <Tuple <string, string> >(); string[] split = null; foreach (var twopath in net.TwoPathWeights.Keys) { for (int k = 0; k < Math.Round(net.TwoPathWeights[twopath] * lcm); k++) { split = twopath.Split(','); in_edges.Add(new Tuple <string, string>(split[0], split[1])); out_edges.Add(new Tuple <string, string>(split[1], split[2])); } } TemporalNetwork output = new TemporalNetwork(); int l = 0; while (l < length) { // Draw edges uniformly at random and add them to temporal network var edge1 = in_edges.ElementAt(rand.Next(in_edges.Count)); Tuple <string, string> edge2 = null; while (edge2 == null) { edge2 = out_edges.ElementAt(rand.Next(out_edges.Count)); if (edge1.Item2 != edge2.Item1) { edge2 = null; } } // Add to the output network output.AddTemporalEdge(l++, edge1.Item1, edge1.Item2); output.AddTemporalEdge(l++, edge2.Item1, edge2.Item2); } return(output); }
/// <summary> /// Creates a weighted network representation of a temporal network by aggregating edge occurences /// (and thus discarding information on the temporal ordering of edges) /// </summary> /// <param name="temp_net">he temporal network that shall be aggregated</param> /// <returns>An instance of a weighted aggregate network</returns> public static WeightedNetwork FromTemporalNetwork(TemporalNetwork temp_net) { WeightedNetwork weighted_net = new WeightedNetwork(); foreach (var t in temp_net.Keys) { foreach (Tuple <string, string> edge in temp_net[t]) { weighted_net.AddEdge(edge.Item1, edge.Item2); } } return(weighted_net); }
/// <summary> /// Saves a temporal network to a file /// </summary> /// <param name="path">The path to which the file shall be saved. Any existing file will be overwritten silently.</param> /// <param name="net">The temporal network to save.</param> public static void SaveToFile(string path, TemporalNetwork net) { StringBuilder sb = new StringBuilder(); sb.AppendLine("time node1 node2"); foreach (int t in net.Keys) { foreach (var edge in net[t]) { sb.AppendLine(t + " " + edge.Item1 + " " + edge.Item2); } } System.IO.File.WriteAllText(path, sb.ToString()); }
/// <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); }
/// <summary> /// Computes the betweenness preference matrix of a node based on the set of two-paths of a node. /// By this we essentially implement equations (1) and (2). /// If additionally the normalization parameter is set, equation (3) will be computed. /// </summary> /// <param name="temp_net">The temporal network to compute betweeness preference for</param> /// <param name="x">The node for which to compute the betweenness preference matrix</param> /// <param name="ego_net">The weighted, aggregate ego network</param> /// <param name="index_pred">A mapping of nodes to columns in the betweenness preference matrix</param> /// <param name="index_succ">A mapping of nodes to rows in the betweenness preference matrix</param> /// <param name="normalize">Whether or not to normalize the matrix, i.e. whether B (eq. 2) or P (eq. 3) shall be returned</param> /// <returns>Depending on the normalization, a betweenness preference matrix B or the normalized version P will be returned</returns> public static double[,] GetBetweennessPrefMatrix(TemporalNetwork temp_net, string x, out Dictionary <string, int> index_pred, out Dictionary <string, int> index_succ, bool normalized = true) { // Use a mapping of indices to node labels index_pred = new Dictionary <string, int>(); index_succ = new Dictionary <string, int>(); // Create an empty matrix double[,] B = new double[temp_net.AggregateNetwork.GetIndeg(x), temp_net.AggregateNetwork.GetOutdeg(x)]; // Create the index-to-node mapping int i = 0; foreach (string u in temp_net.AggregateNetwork.GetPredecessors(x)) { index_pred[u] = i++; } i = 0; foreach (string w in temp_net.AggregateNetwork.GetSuccessors(x)) { index_succ[w] = i++; } // Here we implement equation (1) and (2), i.e. we normalize PER TIME STEP foreach (var t in temp_net.TwoPathsByNode[x].Keys) { foreach (var two_path in temp_net.TwoPathsByNode[x][t]) { B[index_pred[two_path.Item1], index_succ[two_path.Item2]] += 1d / (double)temp_net.TwoPathsByNode[x][t].Count; } } // This is equation 3, i.e. we normalize ACROSS THE MATRIX if (normalized) { return(NormalizeMatrix(x, temp_net.AggregateNetwork, B)); } else { return(B); } }
/// <summary> /// Reads a temporal network from a file containing lines with trigrams a,b,c /// </summary> /// <param name="path">The path to the data file</param> /// <returns>A temporal network instance</returns> public static TemporalNetwork FromTrigramsFile(string path) { TemporalNetwork temp_net = new TemporalNetwork(); string[] lines = System.IO.File.ReadAllLines(path); // if empty if (lines.Length == 0) { return(temp_net); } char[] split_chars = new char[] { ' ', '\t', ';', ',' }; char split_char = ' '; // detect split character string[] line = null; foreach (char c in split_chars) { line = lines[0].Split(c); if (line.Length == 3) { split_char = c; break; } } // Read trigrams and generate temporal network representation int time = 0; for (int i = 0; i < lines.Length; i++) { string[] components = lines[i].Split(split_char); temp_net.AddTemporalEdge(time, components[0], components[1]); temp_net.AddTemporalEdge(time + 1, components[1], components[2]); time = time + 3; } return(temp_net); }
/// <summary> /// Reads an edge sequence from a file containing ordered edges and creates a temporal network instance. The file is /// assumed to have one line per edge, each possibly consisting of several colums and separated by a special delimiter character. /// The caller can specify which (zero-based) column number indicate the source and the target of an interaction. If no parameters /// are specified apart from the path, each line in the file is assumed to contain two strings representing the source and target of an /// edge in the first two columns separated by a space. No header line is assumed by default. /// </summary> /// <param name="path">The path of the file containing the edge sequence.</param> /// <param name="source_col">The zero-based column number on the source node of an edge. 0 by default</param> /// <param name="target_col">The zero-based column number on the target node of an edge. 1 by default</param> /// <param name="header">Whether or not there is a header line that shall be ignored</param> /// <param name="split_char">The character used to separate columns in each line</param> /// <returns>An instance of a temporal network corresponding to the input sequence</returns> public static TemporalNetwork ReadFromFile(string path, bool undirected = false) { TemporalNetwork temp_net = new TemporalNetwork(); // Read all data from file string[] lines = System.IO.File.ReadAllLines(path); // If empty ... if (lines.Length == 0) { return(temp_net); } // Extract header char[] split_chars = new char[] { ' ', '\t', ';', ',' }; char split_char = ' '; // Detect the correct separator character in CSV format string[] header = null; foreach (char c in split_chars) { header = lines[0].Split(c); if (header.Length >= 2 && ((header.Contains("node1") && header.Contains("node2")) || (header.Contains("source") && header.Contains("target")))) { split_char = c; break; } } if (header.Length < 2) { return(temp_net); } // Extract indices of columns int time_ix = -1; int source_ix = -1; int target_ix = -1; for (int i = 0; i < header.Length; i++) { if (header[i] == "time") { time_ix = i; } else if (header[i] == "node1" || header[i] == "source") { source_ix = i; } else if (header[i] == "node2" || header[i] == "target") { target_ix = i; } } // If there is no source and target column if (source_ix < 0 || target_ix < 0) { return(temp_net); } for (int i = 1; i < lines.Length; i++) { string[] components = lines[i].Split(split_char); if (components[source_ix] != "" && components[target_ix] != "") { // If there is no explicit time, just consider each edge occuring at consecutive time steps int t = time_ix >= 0 ? int.Parse(components[time_ix]) : i; temp_net.AddTemporalEdge(t, components[source_ix], components[target_ix]); if (undirected) { temp_net.AddTemporalEdge(t, components[target_ix], components[source_ix]); } } } return(temp_net); }
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> /// Runs a simple SI spreading on a given temporal network and returns the dynamics of the infections /// </summary> /// <param name="temp_net">The temporal network to use</param> /// <param name="p">The infection probability (default is 1)</param> /// <returns>An enumerable of infection numbers, each entry giving the number of infected individuals at a certain time of the simulation</returns> public static string RunSpreading(TemporalNetwork temp_net, out string times, double p = 1d) { // Which nodes are already infected? Dictionary <string, bool> discovered = new Dictionary <string, bool>(); Dictionary <int, int> infections = new Dictionary <int, int>(temp_net.Count); // Initialize foreach (string s in temp_net.AggregateNetwork.Vertices) { discovered[s] = false; } // Build the initial matrix of fastestPathLengths Dictionary <string, int> indices = new Dictionary <string, int>(temp_net.AggregateNetwork.VertexCount); short[,] fastestPathLengths = new short[temp_net.AggregateNetwork.VertexCount, temp_net.AggregateNetwork.VertexCount]; short[,] fastestPath_mid_Lengths = new short[temp_net.AggregateNetwork.VertexCount, temp_net.AggregateNetwork.VertexCount]; uint[,] fastestPathDurations = new uint[temp_net.AggregateNetwork.VertexCount, temp_net.AggregateNetwork.VertexCount]; // Build the indices int i = 0; foreach (string s in temp_net.AggregateNetwork.Vertices) { indices[s] = i++; } // Initialize with maximum values ... foreach (string s in temp_net.AggregateNetwork.Vertices) { foreach (string d in temp_net.AggregateNetwork.Vertices) { fastestPathLengths[indices[s], indices[d]] = short.MaxValue; fastestPath_mid_Lengths[indices[s], indices[d]] = short.MaxValue; fastestPathDurations[indices[s], indices[d]] = uint.MaxValue; } } // Run a spreading process starting at each node in the network ... foreach (var start in temp_net.AggregateNetwork.Vertices) { // Reset the infected state for all foreach (string s in temp_net.AggregateNetwork.Vertices) { discovered[s] = false; } // Infect the start node int discovered_n = 1; discovered[start] = true; fastestPathLengths[indices[start], indices[start]] = 0; fastestPathDurations[indices[start], indices[start]] = 0; try { // Get the first time stamp where the start node was source of two path var start_time = temp_net.TwoPathsByStartTime.Keys.First(z => { foreach (string twopath in temp_net.TwoPathsByStartTime[z]) { if (twopath.StartsWith(start)) { return(true); } } return(false); }); uint t_ = (uint)start_time; // Create a list of ordered time stamps starting with the first activity of the start node var time_stamps = from x in temp_net.TwoPathsByStartTime.Keys where x >= start_time orderby x ascending select x; // Extract all paths consisting of "two path" building blocks foreach (int t in time_stamps) { // A path continues if the source node of a two-path has already been discovered foreach (var two_path in temp_net.TwoPathsByStartTime[t]) { // Get the three components of the two path string[] comps = two_path.Split(','); // Record the geodesic distance between the start and the middle node comps[1] fastestPath_mid_Lengths[indices[start], indices[comps[1]]] = (short)Math.Min(fastestPath_mid_Lengths[indices[start], indices[comps[1]]], fastestPathLengths[indices[start], indices[comps[0]]] + 1); // If the target node of a two path has not been discovered before, we just discovered a new fastest time-respecting path! if (discovered[comps[0]] && !discovered[comps[2]]) { // Add to nodes already discovered discovered_n++; discovered[comps[2]] = true; // Record geodesic distance of fastest time-respecting path fastestPathLengths[indices[start], indices[comps[2]]] = (short)(fastestPathLengths[indices[start], indices[comps[0]]] + 2); // Record temporal length of fastest time-respecting path fastestPathDurations[indices[start], indices[comps[2]]] = (uint)(t - start_time); } } // Stop as soon as all nodes have been discovered if (discovered_n == temp_net.AggregateNetwork.VertexCount) { break; } // Advance the time by two t_ += 2; } } catch (Exception) { // In this case, a start node is never the source of two-path, so we just ignore it ... } } // Aggregate the matrices foreach (string s in temp_net.AggregateNetwork.Vertices) { foreach (string d in temp_net.AggregateNetwork.Vertices) { fastestPathLengths[indices[s], indices[d]] = Math.Min(fastestPathLengths[indices[s], indices[d]], fastestPath_mid_Lengths[indices[s], indices[d]]); } } StringBuilder sb = new StringBuilder(); StringBuilder sb_t = new StringBuilder(); var nodes = from n in temp_net.AggregateNetwork.Vertices.AsParallel() orderby n ascending select n; foreach (string s in nodes) { foreach (string d in nodes) { sb.Append(fastestPathLengths[indices[s], indices[d]] + "\t"); sb_t.Append(fastestPathDurations[indices[s], indices[d]] + "\t"); } sb.Append("\n"); sb_t.Append("\n"); } times = sb_t.ToString(); return(sb.ToString()); }
/// <summary> /// Creates a TikZ representation of the temporal unfolding of the temporal network /// </summary> /// <param name="path">The path to which to write the tikz file</param> /// <param name="temp_net">The temporal network that shall be exported</param> public static void CreateTikzUnfolding(string path, string between_node, TemporalNetwork temp_net) { WeightedNetwork net = WeightedNetwork.FromTemporalNetwork(temp_net); StringBuilder strB = new StringBuilder(); strB.AppendLine("\\newcounter{a}"); strB.AppendLine("\\begin{tikzpicture}[->,>=stealth',auto,scale=0.5, every node/.style={scale=0.9}]"); strB.AppendLine("\\tikzstyle{node} = [fill=lightgray,text=black,circle]"); strB.AppendLine("\\tikzstyle{v} = [fill=black,text=white,circle]"); strB.AppendLine("\\tikzstyle{dst} = [fill=lightgray,text=black,circle]"); strB.AppendLine("\\tikzstyle{lbl} = [fill=white,text=black,circle]"); string last = ""; foreach (string v in net.Vertices.OrderBy(s => s)) { if (last == "") { strB.AppendLine("\\node[lbl] (" + v + "-0) {$" + v + "$};"); } else { strB.AppendLine("\\node[lbl,right=0.5cm of " + last + "-0] (" + v + "-0) {$" + v + "$};"); } last = v; } strB.AppendLine("\\setcounter{a}{0}"); strB.AppendLine("\\foreach \\number in {1,...," + (temp_net.Length + 1) + "}{"); strB.AppendLine("\\setcounter{a}{\\number}"); strB.AppendLine("\\addtocounter{a}{-1}"); strB.AppendLine("\\pgfmathparse{\\thea}"); foreach (string v in net.Vertices) { if (v != between_node) { strB.AppendLine("\\node[node,below=0.3cm of " + v + "-\\pgfmathresult] (" + v + "-\\number) {};"); } else { strB.AppendLine("\\node[v,below=0.3cm of " + v + "-\\pgfmathresult] (" + v + "-\\number) {};"); } } strB.AppendLine("\\node[lbl,left=0.5cm of " + net.Vertices.OrderBy(s => s).ElementAt(0) + "-\\number] (col-\\pgfmathresult) {$t=$\\number};"); strB.AppendLine("}"); strB.AppendLine("\\path[->,thick]"); int i = 1; foreach (var t in temp_net.Keys) { foreach (var edge in temp_net[t]) { strB.AppendLine("(" + edge.Item1 + "-" + (t + 1) + ") edge (" + edge.Item2 + "-" + (t + 2) + ")"); i++; } } strB.AppendLine(";"); strB.AppendLine("\\end{tikzpicture} "); System.IO.File.WriteAllText(path, strB.ToString()); }
/// <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); }