Ejemplo n.º 1
0
        /// <summary>
        /// Saves a graph to a file in the GraphML format.
        /// </summary>
        /// <typeparam name="TNode"></typeparam>
        /// <typeparam name="TLabel"></typeparam>
        /// <param name="graph"></param>
        /// <param name="labels"></param>
        public static void SaveToGraphML <TNode, TLabel>(MultiDirectedGraph <TNode, TLabel> graph, string path)
        {
            List <string> lines = new List <string>();

            lines.Add("<?xml version=\"1.0\" encoding=\"utf-8\" ?>");
            lines.Add("<graphml xmlns=\"http://graphml.graphdrawing.org/xmlns\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"http://graphml.graphdrawing.org/xmlns http://graphml.graphdrawing.org/xmlns/1.0/graphml.xsd\">");

            lines.Add("\t<key id=\"label\" for=\"all\" attr.name=\"label\" attr.type=\"string\">");
            lines.Add("\t\t<default>0</default>");
            lines.Add("\t</key>");

            lines.Add("\t<graph id=\"" + graph.Name + "\" edgedefault=\"" + (graph.IsDirected ? "directed" : "undirected") + "\">");

            foreach (var node in graph.Nodes)
            {
                lines.Add("\t\t<node id=\"" + node + "\">");
                lines.Add("\t\t\t<data key=\"label\">" + graph.NodeLabel(node) + "</data>");
                lines.Add("\t\t</node>");
            }

            foreach (var edge in graph.Edges)
            {
                var s = graph.Source(edge);
                var t = graph.Target(edge);
                lines.Add("\t\t<edge source=\"" + s + "\" target=\"" + t + "\">");
                lines.Add("\t\t\t<data key=\"label\">" + graph.EdgeLabel(edge) + "</data>");
                lines.Add("\t\t</edge>");
            }

            lines.Add("\t</graph>");
            lines.Add("</graphml>");

            File.WriteAllLines(path, lines);
        }
Ejemplo n.º 2
0
        /// <summary>
        /// Do a BFS sample with random seed nodes. Only use each edge label once for each outgoing edge of a node.
        /// </summary>
        /// <typeparam name="TNode"></typeparam>
        /// <param name="graph"></param>
        /// <param name="n">Upper bound on the number of nodes to sample.</param>
        /// <returns></returns>
        public static IEnumerable <TNode> DistinctLabelsSB <TNode, TLabel>(this MultiDirectedGraph <TNode, TLabel> graph, int n)
        {
            var Q     = new Queue <TNode>();
            var V     = new HashSet <TNode>();
            var nodes = graph.Nodes.ToArray();

            // Possible improvement: order seed nodes by degree
            Utils.Shuffle(nodes);
            int seedIndex = 0;

            // Breadth-first walk while we need to add nodes
            while (n > 0)
            {
                if (Q.Count <= 0)
                {
                    // Find next seed node, from an undiscovered connected component, and resume from there
                    while (V.Contains(nodes[seedIndex]))
                    {
                        seedIndex += 1;

                        // If we ran out of nodes early
                        if (seedIndex == nodes.Length)
                        {
                            return(V);
                        }
                    }
                    var seed = nodes[seedIndex];

                    // Add seed to queue and set of nodes
                    Q.Enqueue(seed);
                    V.Add(seed);
                    n -= 1;
                }

                // Select by edge label, and target node label
                var u = Q.Dequeue();
                var N = graph.Out(u).GroupBy(eo => Tuple.Create(graph.EdgeLabel(eo), graph.NodeLabel(graph.Target(eo)))).Select(group => graph.Target(group.First()));
                foreach (var v in N)
                {
                    if (!V.Contains(v) && n > 0)
                    {
                        Q.Enqueue(v);
                        V.Add(v);
                        n -= 1;
                    }
                }
            }

            return(V);
        }
        private void refine()
        {
            var newPartition = new Dictionary <TNode, int>();

            foreach (var u in graph.Nodes)
            {
                if (owner[u] == this)
                {
                    var H = new HashSet <int>();
                    H.Add(Hash(graph.NodeLabel(u)));

                    // Compute the hashes for pairs (label[u, v], pId_k-1(v))
                    foreach (var eo in graph.Out(u))
                    {
                        var v        = graph.Target(eo);
                        var edgeHash = Hash(graph.EdgeLabel(eo), partition[v]);
                        if (!H.Contains(edgeHash))
                        {
                            H.Add(edgeHash);
                        }
                    }

                    // Combine the hashes using some associative-commutative operator
                    int hash = 0;
                    foreach (var edgeHash in H)
                    {
                        hash += edgeHash;
                    }

                    // Assign partition block to node
                    newPartition.Add(u, hash);

                    // Determine if u has changed
                    changed[u] = partition[u] != hash;
                }
                else
                {
                    newPartition.Add(u, partition[u]);
                }
            }

            partition = newPartition;
        }
Ejemplo n.º 4
0
        /// <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);
        }
Ejemplo n.º 5
0
        private void refine()
        {
            var newPartition = new Dictionary <TNode, int>();

            partitionMap.Clear();
            int counter = 0;

            foreach (var u in graph.Nodes)
            {
                if (owner[u] == this)
                {
                    var S = new HashSet <Tuple <TLabel, int> >();
                    foreach (var eo in graph.Out(u))
                    {
                        var v = graph.Target(eo);
                        var t = Tuple.Create(graph.EdgeLabel(eo), partition[v]);
                        if (!S.Contains(t))
                        {
                            S.Add(t);
                        }
                    }

                    var signature = Tuple.Create(graph.NodeLabel(u), S);

                    if (!partitionMap.ContainsKey(signature))
                    {
                        partitionMap.Add(signature, counter++);
                    }

                    // Assign partition block to node
                    newPartition.Add(u, partitionMap[signature]);
                }
            }

            partition = newPartition;
        }
        /// <summary>
        /// Estimate the (unbounded) bisimulation partition of a graph.
        /// Uses a hash function to determine partition block signature equivalence.
        /// </summary>
        /// <returns></returns>
        public IDictionary <TNode, int> EstimateBisimulationReduction()
        {
            // List of partitions; the k+1-th entry in the list corresponds to the k-th bisimulation partition
            var partitions = new List <Dictionary <TNode, int> >();

            stopwatch.Reset();
            stopwatch.Start();
            {
                // Base (k = 0); add empty partition
                partitions.Add(new Dictionary <TNode, int>());

                // Assign block to each node; depending on the node's label
                foreach (var node in graph.Nodes)
                {
                    var label = graph.NodeLabel(node);
                    partitions[0].Add(node, Utils.Hash(label));
                }

                // Step (k > 0); repeat until the previous partition is no longer refined
                int k = 0;
                do
                {
                    // Add empty partition
                    k += 1;
                    partitions.Add(new Dictionary <TNode, int>());

                    foreach (var u in graph.Nodes)
                    {
                        var H = new HashSet <int>();
                        H.Add(Utils.Hash(graph.NodeLabel(u)));

                        // Compute the hashes for pairs (label[u, v], pId_k-1(v))
                        foreach (var eo in graph.Out(u))
                        {
                            var v        = graph.Target(eo);
                            var edgeHash = Utils.Hash(graph.EdgeLabel(eo), partitions[k - 1][v]);
                            if (!H.Contains(edgeHash))
                            {
                                H.Add(edgeHash);
                            }
                        }

                        // Combine the hashes using some associative-commutative operator
                        int hash = 0;
                        foreach (var edgeHash in H)
                        {
                            hash += edgeHash;
                        }

                        // Assign partition block to node
                        partitions[k].Add(u, hash);
                    }
                } while (partitions[k].Values.Distinct().Count() > partitions[k - 1].Values.Distinct().Count());

                // Remove last partition because it is equivalent to the second last partition
                partitions.RemoveAt(partitions.Count - 1);
            }
            stopwatch.Stop();

            return(partitions[partitions.Count - 1]);
        }
        /// <summary>
        /// Measures the weighted k-bisimulation partition equivalence between two graphs.
        /// </summary>
        /// <typeparam name="TNode"></typeparam>
        /// <typeparam name="TLabel"></typeparam>
        /// <param name="G1"></param>
        /// <param name="G2"></param>
        /// <param name="L1"></param>
        /// <param name="L2"></param>
        /// <param name="k">A tuple indicating how many nodes of G1 and G2 are in partition blocks that are shared between G1 and G2.</param>
        /// <returns></returns>
        public static Tuple <int, int> WeightedBisimulationEquivalence <TNode, TLabel>(MultiDirectedGraph <TNode, TLabel> G1, MultiDirectedGraph <TNode, TLabel> G2, int k)
        {
            // Create new empty graph and label provider
            var G = new MultiDirectedGraph <Tuple <int, TNode>, TLabel>();

            // Add nodes of G1
            foreach (var node in G1.Nodes.Select(node => Tuple.Create(1, node)))
            {
                G.AddNode(node, G1.NodeLabel(node.Item2));
            }

            // Add nodes of G2
            foreach (var node in G2.Nodes.Select(node => Tuple.Create(2, node)))
            {
                G.AddNode(node, G2.NodeLabel(node.Item2));
            }

            // Add edges of G1
            foreach (var edge in G1.Edges)
            {
                var s = Tuple.Create(1, G1.Source(edge));
                var t = Tuple.Create(1, G1.Target(edge));
                G.AddEdge(s, t, G1.EdgeLabel(edge));
            }

            // Add edges of G2
            foreach (var edge in G2.Edges)
            {
                var s = Tuple.Create(2, G2.Source(edge));
                var t = Tuple.Create(2, G2.Target(edge));
                G.AddEdge(s, t, G2.EdgeLabel(edge));
            }

            // Perform bisimulation reduction
            var partitioner = new GraphPartitioner <Tuple <int, TNode>, TLabel>(G);
            var partition   = partitioner.BoundedExactBisimulationReduction(k);

            // Partition blocks of G1 and G2
            HashSet <int> P1 = new HashSet <int>();
            HashSet <int> P2 = new HashSet <int>();

            foreach (var node in G.Nodes)
            {
                int block = partition[node];

                switch (node.Item1)
                {
                case 1:
                    if (!P1.Contains(block))
                    {
                        P1.Add(block);
                    }
                    break;

                case 2:
                    if (!P2.Contains(block))
                    {
                        P2.Add(block);
                    }
                    break;
                }
            }

            int s1 = 0;
            int s2 = 0;

            foreach (var node in G.Nodes)
            {
                if (P1.Contains(partition[node]) && P2.Contains(partition[node]))
                {
                    switch (node.Item1)
                    {
                    case 1:
                        s1 += 1;
                        break;

                    case 2:
                        s2 += 1;
                        break;
                    }
                }
            }

            return(Tuple.Create(s1, s2));
        }
Ejemplo n.º 8
0
        /// <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);
        }