/// <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 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> /// 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); }
/// <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); }