コード例 #1
0
        /// <summary>
        /// Sample using a random walk with teleport technique.
        /// </summary>
        /// <typeparam name="TNode"></typeparam>
        /// <typeparam name="TLabel"></typeparam>
        /// <param name="graph"></param>
        /// <param name="n">Upper bound on the number of nodes to sample.</param>
        /// <param name="p">Probability to teleport to a random node after visiting a node.</param>
        /// <returns></returns>
        public static HashSet <TNode> RandomWalkTeleport <TNode, TLabel>(this MultiDirectedGraph <TNode, TLabel> graph, int n, double p)
        {
            var V     = new HashSet <TNode>();
            var nodes = graph.Nodes.ToArray();

            n = Math.Min(n, graph.NumNodes);

            // Initial teleport
            var v = nodes[StaticRandom.Next(nodes.Length)];

            while (n > 0)
            {
                if (!V.Contains(v))
                {
                    V.Add(v);
                    n -= 1;
                }

                double t            = StaticRandom.NextDouble();
                var    outNeighbors = graph.Out(v).Select(eo => graph.Target(eo)).ToArray();

                if (t < p || outNeighbors.Length <= 0)
                {
                    // Teleport
                    v = nodes[StaticRandom.Next(nodes.Length)];
                }
                else
                {
                    v = outNeighbors[StaticRandom.Next(outNeighbors.Length)];
                }
            }

            return(V);
        }
コード例 #2
0
        /// <summary>
        /// Compute distances to all target nodes from a single source node.
        /// </summary>
        /// <typeparam name="TNode"></typeparam>
        /// <param name="graph"></param>
        /// <param name="source"></param>
        /// <returns></returns>
        public static Dictionary <TNode, int> SingleSourceDistances <TNode, TLabel>(MultiDirectedGraph <TNode, TLabel> graph, TNode source)
        {
            var distance = new Dictionary <TNode, int>();

            foreach (var v in graph.Nodes)
            {
                distance.Add(v, int.MaxValue);
            }

            var Q = new Queue <TNode>();
            var V = new HashSet <TNode>();

            Q.Enqueue(source);
            V.Add(source);
            distance[source] = 0;

            // Breadth-first walk
            while (Q.Count > 0)
            {
                var s = Q.Dequeue();

                foreach (var eo in graph.Out(s))
                {
                    var t = graph.Target(eo);
                    if (!V.Contains(t))
                    {
                        Q.Enqueue(t);
                        V.Add(t);
                        distance[t] = distance[s] + 1;
                    }
                }
            }

            return(distance);
        }
コード例 #3
0
        /// <summary>
        ///
        /// </summary>
        /// <param name="n"></param>
        /// <param name="p"></param>
        /// <returns></returns>
        public static MultiDirectedGraph <int, int> ErdosRenyi(int n, double p)
        {
            // Create empty graph and label provider
            var graph = new MultiDirectedGraph <int, int>();

            graph.Name = "Synthetic_ErdosRenyi_" + n + "_" + p;

            // Add n nodes
            for (int i = 0; i < n; i++)
            {
                graph.AddNode(i, 0);
            }

            // Add edges with probability p
            for (int i = 0; i < n; i++)
            {
                for (int j = 0; j < n; j++)
                {
                    if (StaticRandom.NextDouble() <= p)
                    {
                        graph.AddEdge(i, j, 0);
                    }
                }
            }

            return(graph);
        }
コード例 #4
0
        /// <summary>
        /// Perform random matching partitioning.
        /// Input graph must be weighted on nodes.
        /// Nodes are only matched if they share an edge.
        /// </summary>
        /// <param name="graph">Graph with weighted nodes.</param>
        /// <param name="maxWeight">Maximum weight a matched pair is allowed to have.</param>
        /// <returns>A random matching of the nodes of the graph.</returns>
        public static Dictionary <int, int> RandomMatching(MultiDirectedGraph <int, int> graph, int maxWeight)
        {
            int counter = 0;
            var matches = new Dictionary <int, int>();

            // Visit nodes randomly
            var nodes = graph.Nodes.ToArray();

            nodes.Shuffle();
            foreach (var u in nodes)
            {
                if (!matches.ContainsKey(u))
                {
                    // Node u in unmatched, match it with one of the unmatched neighbors
                    var unmatchedNeighbors = graph.Neighbors(u).Where(v => !u.Equals(v) && !matches.ContainsKey(v) && graph.NodeLabel(u) + graph.NodeLabel(v) <= maxWeight).ToArray();

                    // Only match if such a neighbor exists
                    if (unmatchedNeighbors.Length > 0)
                    {
                        var v = Utils.Shuffled(unmatchedNeighbors).First();
                        matches.Add(u, counter);
                        matches.Add(v, counter);
                    }
                    else
                    {
                        matches.Add(u, counter);
                    }

                    counter += 1;
                }
            }

            return(matches);
        }
コード例 #5
0
        /// <summary>
        /// Generates a graph with chains of nodes as close to the desired properties as possible.
        /// Under k-bisimulation it is guaranteed that there are p / (k + 1) * (k + 1) partition blocks.
        /// It is also guaranteed that the number of nodes is at least n.
        /// Hint: choose p as multiple of k + 1, and choose n as multiple of p.
        /// </summary>
        /// <param name="n">Desired number of nodes.</param>
        /// <param name="p">Desired number of partition blocks.</param>
        /// <param name="k">Depth parameter for bisimulation.</param>
        /// <returns></returns>
        public static MultiDirectedGraph <int, int> GenerateChains(int n, int p, int k)
        {
            // Create empty graph and label provider
            var graph = new MultiDirectedGraph <int, int>();

            graph.Name = "Synthetic_Chains_" + k + "_" + p + "_" + n;

            // Node counter for uniqueness
            int node = 0;
            // Number of chains of length k + 1 to satisfy p partition requirement
            int c = p / (k + 1);

            // Keep adding chains while we lack nodes
            while (graph.NumNodes < n)
            {
                // Add c chains
                for (int i = 0; i < c; i++)
                {
                    // Add initial node
                    graph.AddNode(node, i);
                    node += 1;

                    // Add subsequent nodes with edges
                    for (int j = 1; j <= k; j++)
                    {
                        graph.AddNode(node, i);
                        graph.AddEdge(node - 1, node, i);
                        node += 1;
                    }
                }
            }

            return(graph);
        }
コード例 #6
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);
        }
        /// <summary>
        /// Weighted coverage and correctness vs sample fraction.
        /// </summary>
        /// <param name="graph"></param>
        /// <param name="labels"></param>
        /// <param name="samplerName"></param>
        /// <param name="sampler"></param>
        /// <param name="k"></param>
        /// <returns></returns>
        public static Experiment WeightedBisimulationMetrics <TNode, TLabel>(MultiDirectedGraph <TNode, TLabel> graph, string samplerName, Func <double, MultiDirectedGraph <TNode, TLabel> > sampler, int k)
        {
            double[] percentages = new double[]
            {
                1.0, 2.0, 4.0, 8.0, 16.0, 32.0, 64.0
            };

            var experiment = new Experiment(3)
            {
                Labels = new string[] { "Sample fraction", "Weighted coverage", "Weighted correctness" },
                Meta   = new string[] { "Weighted", graph.Name, samplerName, k + "-bisimulation" },
                F      = i =>
                {
                    double p      = percentages[Convert.ToInt32(i)] / 100.0;
                    var    sample = sampler(p);
                    var    counts = GraphMetrics.WeightedBisimulationEquivalence(graph, sample, k);

                    // Weighted coverage
                    double wr = (double)counts.Item1 / (double)graph.NumNodes;
                    // Weighted correctness
                    double wp = (double)counts.Item2 / (double)sample.NumNodes;

                    return(new double[] { p, wr, wp });
                },
            };

            experiment.Run(0, percentages.Length - 1, 1, 10);
            return(experiment);
        }
        /// <summary>
        /// Coverage and correctness vs sample fraction.
        /// </summary>
        /// <param name="graph"></param>
        /// <param name="labels"></param>
        /// <param name="samplerName"></param>
        /// <param name="sampler"></param>
        /// <param name="k"></param>
        /// <returns></returns>
        public static Experiment StandardBisimulationMetrics <TNode, TLabel>(MultiDirectedGraph <TNode, TLabel> graph, string samplerName, Func <double, MultiDirectedGraph <TNode, TLabel> > sampler, int k)
        {
            double[] percentages = new double[]
            {
                1.0, 2.0, 4.0, 8.0, 16.0, 32.0, 64.0
            };

            var experiment = new Experiment(3)
            {
                Labels = new string[] { "Sample fraction", "Coverage", "Correctness" },
                Meta   = new string[] { "Standard", graph.Name, samplerName, k + "-bisimulation" },
                F      = i =>
                {
                    double p      = percentages[Convert.ToInt32(i)] / 100.0;
                    var    sample = sampler(p);
                    var    counts = GraphMetrics.BisimulationEquivalence(graph, sample, k);

                    // Graph block count
                    double N1 = counts.Item1;
                    // Sample block count
                    double N2 = counts.Item2;
                    // Shared block count
                    double NS = N1 + N2 - (double)counts.Item3;

                    double coverage    = NS / N1;
                    double correctness = NS / N2;

                    return(new double[] { p, coverage, correctness });
                },
            };

            experiment.Run(0, percentages.Length - 1, 1, 10);
            return(experiment);
        }
コード例 #9
0
        /// <summary>
        /// Generates a graph with stars of nodes as close to the desired properties as possible.
        /// Under k-bisimulation it is guaranteed that there are p / (s + 1) * (s + 1) partition blocks.
        /// It is also guaranteed that the number of nodes is at least n.
        /// Hint: choose p as multiple of s + 1, and choose n as multiple of p.
        /// </summary>
        /// <param name="n">Desired number of nodes.</param>
        /// <param name="p">Desired number of partition blocks.</param>
        /// <param name="s">Degree of each star.</param>
        /// <returns></returns>
        public static MultiDirectedGraph <int, int> GenerateStars(int n, int p, int s)
        {
            // Create empty graph and label provider
            var graph = new MultiDirectedGraph <int, int>();

            graph.Name = "Synthetic_" + s + "_Stars_" + p + "_" + n;

            // Node counter for uniqueness
            int node = 0;
            // Number of stars of size s + 1 to satisfy p partition requirement
            int c = p / (s + 1);

            // Keep adding stars while we lack nodes
            while (graph.NumNodes < n)
            {
                // Add c stars
                for (int i = 0; i < c; i++)
                {
                    // Add center node
                    graph.AddNode(node, 0);
                    node += 1;

                    // Add child nodes
                    for (int j = 1; j <= s; j++)
                    {
                        graph.AddNode(node, i * (s + 1) + j);
                        graph.AddEdge(node - j, node, 0);
                        node += 1;
                    }
                }
            }

            return(graph);
        }
コード例 #10
0
        /// <summary>
        /// Compute the partition block size distribution.
        /// </summary>
        /// <param name="graph"></param>
        /// <param name="labels"></param>
        /// <param name="k"></param>
        /// <returns></returns>
        public static Experiment PartitionBlockDistribution <TNode, TLabel>(MultiDirectedGraph <TNode, TLabel> graph)
        {
            var partitioner = new GraphPartitioner <TNode, TLabel>(graph);
            var partitions  = partitioner.MultilevelExactBisimulationReduction();
            int k_max       = partitions.Count - 1;

            var sizes = Utils.Distribution(partitions[k_max].Values).Values.ToArray();

            Array.Sort(sizes);
            Array.Reverse(sizes);

            var experiment = new Experiment(2)
            {
                Labels = new string[] { "Partition block", "Number of nodes" },
                Meta   = new string[] { "Blocks", graph.Name, },
                F      = i =>
                {
                    int index = Convert.ToInt32(i);
                    int size  = sizes[index];

                    return(new double[] { index + 1, size });
                },
            };

            experiment.Run(0, sizes.Length - 1, 1, 1);
            return(experiment);
        }
コード例 #11
0
        /// <summary>
        /// Takes the first n nodes, ordered ascendingly by degree.
        /// </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> LowDegreeFirst <TNode, TLabel>(this MultiDirectedGraph <TNode, TLabel> graph, int n)
        {
            // Sort nodes by their degree in ascending order
            TNode[] nodes = Utils.Shuffled(graph.Nodes.ToArray()).ToArray();
            Array.Sort(nodes, (n1, n2) => graph.Degree(n1).CompareTo(graph.Degree(n2)));

            // Take lowest degree nodes first
            return(nodes.Take(Math.Min(n, graph.NumNodes)));
        }
コード例 #12
0
        /// <summary>
        /// Splits the nodes of a graph into P blocks by exploring.
        /// </summary>
        /// <typeparam name="TNode">Type of node.</typeparam>
        /// <typeparam name="TLabel">Type of label.</typeparam>
        /// <param name="graph">Graph to partition the nodes of.</param>
        /// <param name="P">Number of partition blocks.</param>
        public static Dictionary <TNode, int> ExploreSplit <TNode, TLabel>(MultiDirectedGraph <TNode, TLabel> graph, int P)
        {
            int n = graph.NumNodes;
            // Bucket size
            int B     = (n + P - 1) / P;
            var V     = new HashSet <TNode>();
            var Q     = new AiroQueue <TNode>();
            var nodes = graph.Nodes.ToArray();

            Utils.Shuffle(nodes);
            int seedIndex = 0;
            var partition = new Dictionary <TNode, int>();

            Action <TNode> bucketize = node =>
            {
                partition.Add(node, (n - 1) / B);
            };

            // 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;
                    }
                    var seed = nodes[seedIndex];

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

                var u = Q.Take();
                var N = graph.Neighbors(u);
                foreach (var v in N)
                {
                    if (!V.Contains(v) && n > 0)
                    {
                        Q.Put(v);
                        V.Add(v);
                        bucketize(v);
                        n -= 1;
                    }
                }
            }

            return(partition);
        }
コード例 #13
0
        public static void Foo()
        {
            // Process log generator petrinet dot conversion

            var inPath  = Program.Input("In path?", string.Copy);
            var outPath = Program.Input("Out path?", string.Copy);
            var graph   = new MultiDirectedGraph <int, int>();

            var nodeMap = new Dictionary <string, int>();
            int counter = 0;

            var lines = File.ReadAllLines(inPath);

            foreach (var line in lines)
            {
                var tokens = line.Split(new char[] { ' ', '\t', '[', ']' }, StringSplitOptions.RemoveEmptyEntries);

                if (tokens.Length <= 1)
                {
                    continue;
                }

                if (tokens[0][0] == 't')
                {
                    if (!nodeMap.ContainsKey(tokens[0]))
                    {
                        nodeMap.Add(tokens[0], counter++);
                        graph.AddNode(nodeMap[tokens[0]], 0);
                    }
                }

                if (tokens[0][0] == 'p')
                {
                    if (!nodeMap.ContainsKey(tokens[0]))
                    {
                        nodeMap.Add(tokens[0], counter++);
                        graph.AddNode(nodeMap[tokens[0]], 1);
                    }
                }

                if (tokens[1] == "->")
                {
                    var u = nodeMap[tokens[0]];
                    var v = nodeMap[tokens[2]];

                    graph.AddEdge(u, v);
                }
            }

            GraphConverter.SaveToGraphML(graph, outPath);
        }
コード例 #14
0
        public static void Bla()
        {
            // Merge graphs in a folder with a single source node and sink node

            string path    = Program.Input("Please enter the path to folder with graph files", string.Copy);
            var    outPath = Program.Input("Out path?", string.Copy);

            string[] filePaths    = Directory.GetFiles(path, "*.xml");
            var      finalGraph   = new MultiDirectedGraph <int, int>();
            var      finalSources = new List <int>();
            var      finalSinks   = new List <int>();
            int      count        = 0;

            foreach (var filePath in filePaths)
            {
                var graph = GraphLoader.LoadGraphML(filePath, int.Parse, int.Parse);

                foreach (var node in graph.Nodes)
                {
                    finalGraph.AddNode(node + count, graph.NodeLabel(node));
                }

                foreach (var edge in graph.Edges)
                {
                    var s = graph.Source(edge);
                    var t = graph.Target(edge);
                    var l = graph.EdgeLabel(edge);

                    finalGraph.AddEdge(s + count, t + count, l);
                }

                var sources = graph.Nodes.Where(u => graph.In(u).Count() == 0);
                var sinks   = graph.Nodes.Where(u => graph.Out(u).Count() == 0);

                if (sources.Count() != 1 || sinks.Count() != 1)
                {
                    throw new Exception();
                }

                finalSources.Add(sources.First() + count);
                finalSinks.Add(sinks.First() + count);

                count += graph.NumNodes;
            }

            finalGraph.MergeNodes(finalSources);
            finalGraph.MergeNodes(finalSinks);

            GraphConverter.SaveToGraphML(finalGraph, outPath);
        }
コード例 #15
0
        public static void Bla()
        {
            // Merge graphs in a folder with a single source node and sink node

            string path = Program.Input("Please enter the path to folder with graph files", string.Copy);
            var outPath = Program.Input("Out path?", string.Copy);

            string[] filePaths = Directory.GetFiles(path, "*.xml");
            var finalGraph = new MultiDirectedGraph<int, int>();
            var finalSources = new List<int>();
            var finalSinks = new List<int>();
            int count = 0;

            foreach (var filePath in filePaths)
            {
                var graph = GraphLoader.LoadGraphML(filePath, int.Parse, int.Parse);

                foreach (var node in graph.Nodes)
                {
                    finalGraph.AddNode(node + count, graph.NodeLabel(node));
                }

                foreach (var edge in graph.Edges)
                {
                    var s = graph.Source(edge);
                    var t = graph.Target(edge);
                    var l = graph.EdgeLabel(edge);

                    finalGraph.AddEdge(s + count, t + count, l);
                }

                var sources = graph.Nodes.Where(u => graph.In(u).Count() == 0);
                var sinks = graph.Nodes.Where(u => graph.Out(u).Count() == 0);

                if (sources.Count() != 1 || sinks.Count() != 1)
                {
                    throw new Exception();
                }

                finalSources.Add(sources.First() + count);
                finalSinks.Add(sinks.First() + count);

                count += graph.NumNodes;
            }

            finalGraph.MergeNodes(finalSources);
            finalGraph.MergeNodes(finalSinks);

            GraphConverter.SaveToGraphML(finalGraph, outPath);
        }
コード例 #16
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);
        }
コード例 #17
0
        /// <summary>
        ///
        /// </summary>
        /// <param name="n"></param>
        /// <param name="p"></param>
        /// <param name="k"></param>
        /// <returns></returns>
        public static MultiDirectedGraph <int, int> GenerateTrees(int n, int p, int k)
        {
            // Create empty graph and label provider
            var graph = new MultiDirectedGraph <int, int>();

            graph.Name = "Synthetic_Trees_" + k + "_" + p + "_" + n;

            // Find the degree necessary for a k-depth tree to achieve at least p number of nodes
            int degree = 1;

            while ((int)Math.Pow(degree, k + 1) - 1 < p)
            {
                degree += 1;
            }
            int branchSize = (int)Math.Pow(degree, k + 1) - 1;

            // Keep adding trees while we lack nodes
            for (int treeOffset = 0; treeOffset < n; treeOffset += branchSize)
            {
                int partitionSize = k + 1;

                // Add nodes
                for (int i = 0; i < branchSize; i++)
                {
                    graph.AddNode(treeOffset + i);

                    if (partitionSize < p && Math.Log(i + 1, degree) % 1 != 0)
                    {
                        graph.SetNodeLabel(treeOffset + i, i);
                        partitionSize += 1;
                    }
                    else
                    {
                        graph.SetNodeLabel(treeOffset + i, branchSize);
                    }
                }

                // Add edges
                for (int i = 0; i < branchSize / degree; i++)
                {
                    for (int j = 1; j <= degree; j++)
                    {
                        graph.AddEdge(treeOffset + i, treeOffset + degree * i + j, 0);
                    }
                }
            }

            return(graph);
        }
コード例 #18
0
        /// <summary>
        /// Sample nodes by walking the graph. The walk is done using a generic queue.
        /// </summary>
        /// <typeparam name="TNode"></typeparam>
        /// <typeparam name="TLabel"></typeparam>
        /// <typeparam name="TQueue"></typeparam>
        /// <param name="graph"></param>
        /// <param name="n"></param>
        /// <returns></returns>
        public static HashSet <TNode> QueuedSampler <TNode, TLabel, TQueue>(this MultiDirectedGraph <TNode, TLabel> graph, int n) where TQueue : GenericQueue <TNode>, new()
        {
            var V     = new HashSet <TNode>();
            var Q     = new TQueue();
            var nodes = graph.Nodes.ToArray();

            Utils.Shuffle(nodes);
            int seedIndex = 0;

            // 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.Put(seed);
                    V.Add(seed);
                    n -= 1;
                }

                var u = Q.Take();
                var N = graph.Out(u).Select(eo => graph.Target(eo));
                foreach (var v in N)
                {
                    if (!V.Contains(v) && n > 0)
                    {
                        Q.Put(v);
                        V.Add(v);
                        n -= 1;
                    }
                }
            }

            return(V);
        }
コード例 #19
0
        /// <summary>
        /// Splits the nodes of a graph into P blocks using a multilevel approach.
        /// </summary>
        /// <typeparam name="TNode">Type of node.</typeparam>
        /// <typeparam name="TLabel">Type of label.</typeparam>
        /// <param name="graph"></param>
        /// <param name="P">Number of partition blocks.</param>
        /// <param name="e">Coarsening stop condition.</param>
        /// <param name="M">Coarsening stop condition.</param>
        /// <param name="K">KernighanLin number of iterations.</param>
        public static Dictionary <TNode, int> MetisSplit <TNode, TLabel>(MultiDirectedGraph <TNode, TLabel> graph, int P, double e, int M, int K)
        {
            // Collapse the graph
            int counter     = 0;
            var mapNodes    = new Dictionary <TNode, int>();
            var transformed = Collapse(graph).Clone(node =>
            {
                if (!mapNodes.ContainsKey(node))
                {
                    mapNodes.Add(node, counter);
                    counter += 1;
                }

                return(mapNodes[node]);
            });

            // Coarsen the graph
            int n           = graph.NumNodes;
            var coarsened   = Coarsen(transformed, e, M, n / 2);
            var coarseGraph = coarsened.Item1;
            var projections = coarsened.Item2;

            // Partition the coarse graph
            var partition = Balance(coarseGraph.Nodes, node => coarseGraph.NodeLabel(node), 8);

            // Unproject the partition of the coarse graph
            projections.Add(partition);
            var finePartition = new Dictionary <TNode, int>();

            foreach (var node in graph.Nodes)
            {
                int p = mapNodes[node];

                foreach (var projection in projections)
                {
                    p = projection[p];
                }

                finePartition.Add(node, p);
            }

            // Refine the partition
            KernighanLin(graph, finePartition, K);

            return(finePartition);
        }
コード例 #20
0
        /// <summary>
        /// Measures the cut of a partition of a graph.
        /// </summary>
        /// <typeparam name="TNode"></typeparam>
        /// <typeparam name="TLabel"></typeparam>
        /// <param name="graph"></param>
        /// <param name="partition"></param>
        /// <returns></returns>
        public static int Cut <TNode, TLabel>(MultiDirectedGraph <TNode, TLabel> graph, IDictionary <TNode, int> partition)
        {
            int cut = 0;

            foreach (var edge in graph.Edges)
            {
                var s = graph.Source(edge);
                var t = graph.Target(edge);

                if (partition[s] != partition[t])
                {
                    cut += 1;
                }
            }

            return(cut);
        }
コード例 #21
0
        /// <summary>
        /// Randomly splits the nodes of a graph into P blocks.
        /// </summary>
        /// <typeparam name="TNode">Type of node.</typeparam>
        /// <typeparam name="TLabel">Type of label.</typeparam>
        /// <param name="graph">Graph to partition the nodes of.</param>
        /// <param name="P">Number of partition blocks.</param>
        public static Dictionary <TNode, int> RandomSplit <TNode, TLabel>(MultiDirectedGraph <TNode, TLabel> graph, int P)
        {
            var partition = new Dictionary <TNode, int>();
            var nodes     = graph.Nodes.ToArray();

            nodes.Shuffle();

            int p = 0;

            for (int i = 0; i < nodes.Length; i++)
            {
                partition.Add(nodes[i], p);
                p += 1;
                p %= P;
            }

            return(partition);
        }
コード例 #22
0
        /// <summary>
        /// Compute distances.
        /// </summary>
        /// <typeparam name="TNode"></typeparam>
        /// <param name="graph"></param>
        /// <returns></returns>
        public static Experiment DistanceProbabilityMassFunction <TNode, TLabel>(MultiDirectedGraph <TNode, TLabel> graph)
        {
            var    distribution = new Dictionary <int, BigInteger>();
            object @lock        = new object();

            Parallel.ForEach(graph.Nodes, node =>
            {
                var distances = Utils.SingleSourceDistances(graph, node).Values.Where(distance => distance > 0 && distance < int.MaxValue);

                lock (@lock)
                {
                    Utils.UpdateDistribution(distribution, distances);
                }
            });

            double count = 0.0;

            foreach (var value in distribution.Values)
            {
                count += (double)value;
            }

            Experiment experiment = new Experiment(2)
            {
                Labels = new string[] { "Distance", "Probability" },
                Meta   = new string[] { "Distance-PMF", graph.Name },
                F      = d =>
                {
                    int distance = Convert.ToInt32(d);

                    if (distribution.ContainsKey(distance))
                    {
                        return(new double[] { d, (double)distribution[distance] / count });
                    }
                    else
                    {
                        return(new double[] { d, 0.0 });
                    }
                },
            };

            experiment.Run(distribution.Keys.Min(), distribution.Keys.Max(), 1, 1);
            return(experiment);
        }
コード例 #23
0
        /// <summary>
        /// Collapse a graph which contains parallel edges into a graph without parallel edges.
        /// Node labels are all set to 1.
        /// Edge labels indicate how many parallel edges there originally were from the source to the target.
        /// </summary>
        /// <typeparam name="TNode">Type of node.</typeparam>
        /// <typeparam name="TLabel">Type of label.</typeparam>
        /// <param name="graph">Graph to collapse.</param>
        /// <returns>A copy of the original graph with node labels set to 1 and edge labels indicating how often that edge occurred in the original graph.</returns>
        public static MultiDirectedGraph <TNode, int> Collapse <TNode, TLabel>(MultiDirectedGraph <TNode, TLabel> graph)
        {
            var edgeWeights = new Dictionary <Tuple <TNode, TNode>, int>();
            var transformed = new MultiDirectedGraph <TNode, int>();

            // Copy nodes
            foreach (var u in graph.Nodes)
            {
                transformed.AddNode(u, 1);
            }

            // Count edges from u to v
            foreach (var u in graph.Nodes)
            {
                foreach (var eo in graph.Out(u))
                {
                    var v = graph.Target(eo);
                    var t = Tuple.Create(u, v);

                    if (!edgeWeights.ContainsKey(t))
                    {
                        edgeWeights.Add(t, 0);
                    }

                    edgeWeights[t] += 1;
                }
            }

            // Add weighted edges to the transformed graph
            foreach (var kvp in edgeWeights)
            {
                var u = kvp.Key.Item1;
                var v = kvp.Key.Item2;
                var w = kvp.Value;

                transformed.AddEdge(u, v, w);
            }

            return(transformed);
        }
コード例 #24
0
        /// <summary>
        /// Count the number of partition blocks in a graph.
        /// </summary>
        /// <typeparam name="TNode"></typeparam>
        /// <typeparam name="TLabel"></typeparam>
        /// <param name="graph"></param>
        /// <param name="labels"></param>
        /// <returns></returns>
        public static Experiment BisimulationPartitionSize <TNode, TLabel>(MultiDirectedGraph <TNode, TLabel> graph)
        {
            var partitioner = new GraphPartitioner <TNode, TLabel>(graph);
            var partitions  = partitioner.MultilevelExactBisimulationReduction();

            Experiment experiment = new Experiment(2)
            {
                Labels = new string[] { "k", "Number of blocks" },
                Meta   = new string[] { "Partition-size", graph.Name },
                F      = i =>
                {
                    var k = Convert.ToInt32(i);
                    var partitionCount = partitions[k].Values.Distinct().Count();

                    return(new double[] { k, partitionCount });
                },
            };

            experiment.Run(0, partitions.Count - 1, 1, 1);
            return(experiment);
            // experiment.Save(@"..\..\..\..\Analytics\BisimBlocks-" + graph.Name.ToLower() + ".tsv");
        }
コード例 #25
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);
        }
コード例 #26
0
        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);
        }
コード例 #27
0
        /// <summary>
        /// Sample edges randomly uniformly.
        /// </summary>
        /// <typeparam name="TNode"></typeparam>
        /// <param name="graph"></param>
        /// <param name="m">Upper bound on the number of edges to sample.</param>
        /// <returns></returns>
        public static IEnumerable <TNode> RE <TNode, TLabel>(this MultiDirectedGraph <TNode, TLabel> graph, int m)
        {
            var edges = Utils.Shuffled(graph.Edges.ToArray()).Take(Math.Min(m, graph.NumEdges)).ToArray();
            var nodes = new HashSet <TNode>();

            foreach (var edge in edges)
            {
                var s = graph.Source(edge);
                var t = graph.Target(edge);

                if (!nodes.Contains(s))
                {
                    nodes.Add(s);
                }

                if (!nodes.Contains(t))
                {
                    nodes.Add(t);
                }
            }

            return(nodes);
        }
コード例 #28
0
        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);
        }
コード例 #29
0
        /// <summary>
        ///
        /// </summary>
        /// <param name="graph"></param>
        /// <param name="partition"></param>
        /// <returns></returns>
        public static ExactBisimulationWorker <TNode, TLabel>[] CreateWorkers(MultiDirectedGraph <TNode, TLabel> graph, IDictionary <TNode, int> partition)
        {
            var mapping = new Dictionary <int, int>();
            int counter = 0;

            foreach (var kvp in partition)
            {
                if (!mapping.ContainsKey(kvp.Value))
                {
                    mapping.Add(kvp.Value, counter);
                    counter += 1;
                }
            }

            var workers = new ExactBisimulationWorker <TNode, TLabel> [counter];

            for (int i = 0; i < counter; i++)
            {
                workers[i] = new ExactBisimulationWorker <TNode, TLabel>();
                workers[i].setGraph(graph);
            }

            var owner = new Dictionary <TNode, ExactBisimulationWorker <TNode, TLabel> >();

            foreach (var node in graph.Nodes)
            {
                owner.Add(node, workers[mapping[partition[node]]]);
            }

            for (int i = 0; i < counter; i++)
            {
                workers[i].setOwner(owner);
            }

            return(workers);
        }
コード例 #30
0
 /// <summary>
 /// Constructor.
 /// </summary>
 /// <param name="graph"></param>
 public GraphPartitioner(MultiDirectedGraph <TNode, TLabel> graph)
 {
     this.graph = graph;
 }
コード例 #31
0
 /// <summary>
 ///
 /// </summary>
 /// <param name="graph"></param>
 private void setGraph(MultiDirectedGraph <TNode, TLabel> graph)
 {
     this.graph = graph;
 }
コード例 #32
0
        /// <summary>
        /// Compute distances to all target nodes from all source nodes.
        /// </summary>
        /// <typeparam name="TNode"></typeparam>
        /// <param name="graph"></param>
        /// <returns></returns>
        public static Dictionary <TNode, Dictionary <TNode, int> > AllPairsDistances <TNode, TLabel>(MultiDirectedGraph <TNode, TLabel> graph)
        {
            var distance = new Dictionary <TNode, Dictionary <TNode, int> >();

            foreach (var source in graph.Nodes)
            {
                distance.Add(source, SingleSourceDistances(graph, source));
            }

            return(distance);
        }
コード例 #33
0
        public static void Foo()
        {
            // Process log generator petrinet dot conversion

            var inPath = Program.Input("In path?", string.Copy);
            var outPath = Program.Input("Out path?", string.Copy);
            var graph = new MultiDirectedGraph<int, int>();

            var nodeMap = new Dictionary<string, int>();
            int counter = 0;

            var lines = File.ReadAllLines(inPath);
            foreach (var line in lines)
            {
                var tokens = line.Split(new char[] { ' ', '\t', '[', ']' }, StringSplitOptions.RemoveEmptyEntries);

                if (tokens.Length <= 1)
                {
                    continue;
                }

                if (tokens[0][0] == 't')
                {
                    if (!nodeMap.ContainsKey(tokens[0]))
                    {
                        nodeMap.Add(tokens[0], counter++);
                        graph.AddNode(nodeMap[tokens[0]], 0);
                    }
                }

                if (tokens[0][0] == 'p')
                {
                    if (!nodeMap.ContainsKey(tokens[0]))
                    {
                        nodeMap.Add(tokens[0], counter++);
                        graph.AddNode(nodeMap[tokens[0]], 1);
                    }
                }

                if (tokens[1] == "->")
                {
                    var u = nodeMap[tokens[0]];
                    var v = nodeMap[tokens[2]];

                    graph.AddEdge(u, v);
                }
            }

            GraphConverter.SaveToGraphML(graph, outPath);
        }