public static void Bar() { // Stanford graphs conversion var inPath = Program.Input("In path?", string.Copy); var outPath = Program.Input("Out path?", string.Copy); var graph = new MultiDirectedGraph <int, int>(); var lines = File.ReadAllLines(inPath); foreach (var line in lines) { var tokens = line.Split(new char[] { ' ', '\t' }, StringSplitOptions.RemoveEmptyEntries); if (tokens[0] != "#") { int source = int.Parse(tokens[0]); int target = int.Parse(tokens[1]); if (!graph.HasNode(source)) { graph.AddNode(source); } if (!graph.HasNode(target)) { graph.AddNode(target); } if (!graph.HasEdge(source, target) && !graph.HasEdge(target, source)) { graph.AddEdge(source, target); } } } GraphConverter.SaveToGraphML(graph, outPath); }
public static void Bar() { // Stanford graphs conversion var inPath = Program.Input("In path?", string.Copy); var outPath = Program.Input("Out path?", string.Copy); var graph = new MultiDirectedGraph<int, int>(); var lines = File.ReadAllLines(inPath); foreach (var line in lines) { var tokens = line.Split(new char[] { ' ', '\t' }, StringSplitOptions.RemoveEmptyEntries); if (tokens[0] != "#") { int source = int.Parse(tokens[0]); int target = int.Parse(tokens[1]); if (!graph.HasNode(source)) { graph.AddNode(source); } if (!graph.HasNode(target)) { graph.AddNode(target); } if (!graph.HasEdge(source, target) && !graph.HasEdge(target, source)) { graph.AddEdge(source, target); } } } GraphConverter.SaveToGraphML(graph, outPath); }
/// <summary> /// Computes a reduced graph under some bisimulation equivalence relation. /// The input graph must be partitioned by the partitioner modulo said equivalence relation. /// </summary> /// <typeparam name="TNode">Node type.</typeparam> /// <typeparam name="TLabel">Label type.</typeparam> /// <param name="graph">Input graph.</param> /// <param name="labels">Labels of graph.</param> /// <param name="partitioner">Function which partitions the graph modulo some bisimulation equivalence relation.</param> /// <returns>A reduced graph where each partition block is a node and edges are reconstructued such that bisimulation equivalence is maintained.</returns> public static MultiDirectedGraph <int, TLabel> ReducedGraph <TNode, TLabel>(MultiDirectedGraph <TNode, TLabel> graph, Func <IDictionary <TNode, int> > partitioner) { var reduced = new MultiDirectedGraph <int, TLabel>(); var partition = partitioner(); var inverted = Utils.Invert(partition); // Add a node for each partition block foreach (var kvp in inverted) { var block = kvp.Key; var nodes = kvp.Value.ToArray(); // var someNode = Utils.Shuffled(nodes).First(); var someNode = nodes.First(); reduced.AddNode(block, graph.NodeLabel(someNode)); } // Add the edge going from each partition block to another foreach (var kvp in inverted) { var block = kvp.Key; var nodes = kvp.Value.ToArray(); // var someSource = Utils.Shuffled(nodes).First(); var someSource = nodes.First(); foreach (var eo in graph.Out(someSource)) { var someTarget = graph.Target(eo); var label = graph.EdgeLabel(eo); if (!reduced.HasEdge(block, partition[someTarget], label)) { reduced.AddEdge(block, partition[someTarget], label); } } } return(reduced); }
/// <summary> /// KerninghanLin algorithm which refines a partition. /// Equalizes block sizes and swaps nodes between partition blocks to minimize the edge cut. /// </summary> /// <typeparam name="TNode">Type of node.</typeparam> /// <typeparam name="TLabel">Type of label.</typeparam> /// <param name="graph">The graph of the partition.</param> /// <param name="partition">The partition to refine.</param> /// <param name="K">Maximum number of iterations.</param> public static void KernighanLin <TNode, TLabel>(MultiDirectedGraph <TNode, TLabel> graph, Dictionary <TNode, int> partition, int K) { // Compute ED and ID of each node var ED = new Dictionary <TNode, int>(); var ID = new Dictionary <TNode, int>(); Func <TNode, int> D = node => ED[node] - ID[node]; foreach (var node in graph.Nodes) { ED.Add(node, 0); ID.Add(node, 0); } foreach (var edge in graph.Edges) { var s = graph.Source(edge); var t = graph.Target(edge); if (partition[s] == partition[t]) { ID[s] += 1; ID[t] += 1; } else { ED[s] += 1; ED[t] += 1; } } // Stick nodes into sets of their partition block var inverted = Utils.Invert(partition); var AI = inverted.Keys.First(); var BI = inverted.Keys.Last(); // Swaps a node from its original partition block to the other Action <TNode> swap = node => { foreach (var edge in graph.Out(node).Concat(graph.In(node))) { var neighbor = graph.Target(edge); if (node.Equals(neighbor)) { continue; } if (partition[node] == partition[neighbor]) { // Will be in other block now ID[neighbor] -= 1; ID[node] -= 1; ED[neighbor] += 1; ED[node] += 1; } else { // Will be in same block now ID[neighbor] += 1; ID[node] += 1; ED[neighbor] -= 1; ED[node] -= 1; } } if (partition[node] == AI) { partition[node] = BI; inverted[AI].Remove(node); inverted[BI].Add(node); } else { partition[node] = AI; inverted[AI].Add(node); inverted[BI].Remove(node); } }; // Equalize block sizes while (Math.Abs(inverted[AI].Count - inverted[BI].Count) > 1) { if (inverted[AI].Count > inverted[BI].Count) { // Move from A to B var a = inverted[AI].MaxBy(node => D(node)); swap(a); } else { // Move from B to A var b = inverted[BI].MaxBy(node => D(node)); swap(b); } } // Keep performing positive swaps int n = Math.Min(inverted[AI].Count, inverted[BI].Count); for (int i = 0; i < K; i++) { bool hasGained = false; var AA = new HashSet <TNode>(inverted[AI]); var BB = new HashSet <TNode>(inverted[BI]); for (int j = 0; j < n; j++) { var a = AA.MaxBy(node => D(node)); var b = BB.MaxBy(node => D(node)); int gain = D(a) + D(b); if (graph.HasEdge(a, b)) { gain -= 2; } if (graph.HasEdge(b, a)) { gain -= 2; } if (gain > 0) { hasGained = true; swap(a); swap(b); } AA.Remove(a); BB.Remove(b); } if (!hasGained) { break; } } }