/// <summary> /// /// </summary> /// <param name="owner"></param> private void setOwner(IDictionary <TNode, ExactBisimulationWorker <TNode, TLabel> > owner) { this.owner = owner; this.ownerInverted = Utils.Invert(owner); this.interestedIn = new Dictionary <ExactBisimulationWorker <TNode, TLabel>, HashSet <TNode> >(); // Initialize interested-in function foreach (var worker in ownerInverted.Keys) { interestedIn.Add(worker, new HashSet <TNode>()); } foreach (var target in ownerInverted[this]) { foreach (var ei in graph.In(target)) { var source = graph.Source(ei); if (!interestedIn[owner[source]].Contains(target)) { interestedIn[owner[source]].Add(target); } } } interestedIn.Remove(this); }
/// <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; } } }
/// <summary> /// /// </summary> /// <param name="D"></param> /// <param name="b"></param> /// <returns></returns> public static MultiDirectedGraph <int, int> GenerateNiceDAG(int D, int b) { // Create empty graph and label provider var graph = new MultiDirectedGraph <int, int>(); graph.Name = "Synthetic_DAG_" + D + "_" + b; // Define parent function Func <int, int> parent = node => { // Assume node > 0 (not the root node) return(graph.In(node).First()); }; // Define level function Func <int, int> level = Utils.Y <int, int>(fix => node => { if (node == 0) { // Root node return(0); } else { return(1 + fix(parent(node))); } }); // Create initial tree int counter = 0; graph.AddNode(counter, 0); counter += 1; while (graph.Nodes.Select(node => level(node)).Max() < D) { int max = graph.Nodes.Select(node => level(node)).Max(); var lowest = graph.Nodes.Where(node => level(node) == max).ToArray(); foreach (var node in lowest) { int k = StaticRandom.Next(b + 1); for (int i = 0; i < k; i++) { graph.AddNode(counter, 0); graph.AddEdge(node, counter, i); // graph.AddEdge(node, counter, 0); counter += 1; } } } // Transform tree to DAG with nicer partition block distribution var copy = graph.Clone(); var partitioner = new GraphPartitioner <int, int>(graph); var partition = partitioner.BoundedExactBisimulationReduction(D); var partitionInverted = Utils.Invert(partition); var blocks = partition.Values.Distinct(); var blockSizes = Utils.Distribution(partition.Values); int blockMax = blockSizes.Values.Max(); foreach (var block in blocks) { int size = blockSizes[block]; var nodes = new List <int>(partitionInverted[block]); for (int i = size; i < blockMax; i++) { // Replicate a random node in this partition block int k = StaticRandom.Next(size); var v = nodes[k]; // Replicate the node graph.AddNode(counter, graph.NodeLabel(v)); // Replicate its incoming edges foreach (var ei in copy.In(v)) { var u = graph.Source(ei); graph.AddEdge(u, counter, graph.EdgeLabel(ei)); } // Replicate its outgoing edges foreach (var eo in copy.Out(v)) { var w = graph.Target(eo); graph.AddEdge(counter, w, graph.EdgeLabel(eo)); } counter += 1; } } return(graph); }