Example #1
0
        public void Clone()
        {
            var graph = new UndirectedGraph <int, Edge <int> >();

            AssertEmptyGraph(graph);

            var clonedGraph = graph.Clone();

            Assert.IsNotNull(clonedGraph);
            AssertEmptyGraph(clonedGraph);

            clonedGraph = (UndirectedGraph <int, Edge <int> >)((ICloneable)graph).Clone();
            Assert.IsNotNull(clonedGraph);
            AssertEmptyGraph(clonedGraph);

            var edge1 = new Edge <int>(1, 2);
            var edge2 = new Edge <int>(1, 3);
            var edge3 = new Edge <int>(2, 3);

            graph.AddVerticesAndEdgeRange(new[] { edge1, edge2, edge3 });
            AssertHasVertices(graph, new[] { 1, 2, 3 });
            AssertHasEdges(graph, new[] { edge1, edge2, edge3 });

            clonedGraph = graph.Clone();
            Assert.IsNotNull(clonedGraph);
            AssertHasVertices(clonedGraph, new[] { 1, 2, 3 });
            AssertHasEdges(clonedGraph, new[] { edge1, edge2, edge3 });

            clonedGraph = (UndirectedGraph <int, Edge <int> >)((ICloneable)graph).Clone();
            Assert.IsNotNull(clonedGraph);
            AssertHasVertices(clonedGraph, new[] { 1, 2, 3 });
            AssertHasEdges(clonedGraph, new[] { edge1, edge2, edge3 });
        }
Example #2
0
        public void CloneTest()
        {
            var graph      = new UndirectedGraph();
            var newVertex1 = new Vertex("test-1");
            var newVertex2 = new Vertex("test-2");
            var newVertex3 = new Vertex("test-3");

            graph.AddVertex(newVertex1);
            graph.AddVertex(newVertex2);
            graph.AddVertex(newVertex3);
            var newEdge1 = new UndirectedEdge(newVertex1, newVertex2);
            var newEdge2 = new UndirectedEdge(newVertex1, newVertex3);

            graph.AddEdge(newEdge1);
            graph.AddEdge(newEdge2);

            var clonedGraph = graph.Clone() as IGraph;

            Assert.IsTrue(clonedGraph is UndirectedGraph);
            Assert.AreEqual(graph.VerticesCount, clonedGraph.VerticesCount);
            foreach (var vertex in graph.Vertices)
            {
                var clonedVertex = clonedGraph.Vertices.Single(v => v.Equals(vertex));
                Assert.AreNotSame(clonedVertex, vertex);
            }
            Assert.AreEqual(graph.EdgesCount, clonedGraph.EdgesCount);
            foreach (var clonedEdge in clonedGraph.Edges)
            {
                Assert.IsTrue(clonedEdge is UndirectedEdge);
                var edge = graph.Edges.Single(e => e.Equals(clonedEdge));
                Assert.AreNotSame(edge, clonedEdge);
            }
        }
        Triangulate(UndirectedGraph <int, IEdge <int> > tree, int root = 0)
        {
            Dictionary <(int source, int target), int> innerVerticesCount = new Dictionary <(int source, int target), int>();
            UndirectedGraph <int, IEdge <int> >        res = new UndirectedGraph <int, IEdge <int> >();

            if (tree.IsVerticesEmpty)
            {
                return(res, innerVerticesCount);
            }
            if (!tree.ContainsVertex(root))
            {
                throw new ArgumentException("root");
            }

            // create counter-clockwise combinatorial embedding
            // assumes vertices are numbered as in BFS
            // so it's proper to add them to list in order they are stored internally
            UndirectedGraph <int, IEdge <int> > G         = tree.Clone();
            Dictionary <int, List <int> >       embedding = new Dictionary <int, List <int> >(); // TODO: what if graph vertices are only subgraph? this assumption may be wrong

            foreach (int i in G.Vertices)
            {
                embedding.Add(i, new List <int>());
                foreach (int v in G.AdjacentVertices(i))
                {
                    embedding[i].Add(v);
                }
            }

            foreach (int v in tree.Vertices)
            {
                int[] neighbors = new int[embedding[v].Count];
                embedding[v].CopyTo(neighbors);

                int prev = neighbors[0];
                for (int i = 1; i < neighbors.Length; i++)
                {
                    int curr = neighbors[i];
                    TryAddEdge(prev, curr, v, ref G, ref res, ref embedding, ref innerVerticesCount);
                    prev = curr;
                }
                if (neighbors.Length > 2)
                {
                    TryAddEdge(prev, neighbors[0], v, ref G, ref res, ref embedding, ref innerVerticesCount);
                }
            }

            return(res, innerVerticesCount);
        }
        public GraphColor[] Find3Colorings(UndirectedGraph <int, IEdge <int> > graph)
        {
            //Initialize structures
            _graph           = graph.Clone();
            _availableColors = new HashSet <GraphColor> [_graph.VertexCount];
            for (int i = 0; i < _graph.VertexCount; i++)
            {
                _availableColors[i] = new HashSet <GraphColor>()
                {
                    GraphColor.Black, GraphColor.Gray, GraphColor.White
                }
            }
            ;
            _coloring = new GraphColor?[_graph.VertexCount];

            //Get all components of G
            List <UndirectedGraph <int, IEdge <int> > > G_components = FindComponents(_graph);

            foreach (UndirectedGraph <int, IEdge <int> > component in G_components)
            {
                //Find separator S for component
                HashSet <int> S = PlanarSeparator.FindSeparator(component);
                ////Split component into smaller components
                foreach (int v in S)
                {
                    component.RemoveVertex(v);
                }
                List <UndirectedGraph <int, IEdge <int> > > components = FindComponents(component);

                //One of components cannot be colored => whole G cannot be colored
                //Slow version
                if (!DnCColoring(components, S))
                {
                    return(null);
                }
                //Fast version
                //if (!BruteForceColoring(new List<UndirectedGraph<int, IEdge<int>>>(), _graph.Vertices.ToHashSet()))
                //    return null;
            }
            return(_coloring.Select(c => c.Value).ToArray());
        }
        public GraphColor[] Find3Colorings(UndirectedGraph <int, IEdge <int> > graph)
        {
            //Initialize structures
            _graph           = graph.Clone();
            _availableColors = new HashSet <GraphColor> [_graph.VertexCount];
            for (int i = 0; i < _graph.VertexCount; i++)
            {
                _availableColors[i] = new HashSet <GraphColor>()
                {
                    GraphColor.Black, GraphColor.Gray, GraphColor.White
                }
            }
            ;
            _coloring = new GraphColor?[_graph.VertexCount];

            //Get all components of G
            (List <UndirectedGraph <int, IEdge <int> > > list, Dictionary <int, int> dict)G_components = FindComponents(_graph);
            foreach (UndirectedGraph <int, IEdge <int> > component in G_components.list)
            {
                //Find separator S for component
                HashSet <int> S = PlanarSeparator.FindSeparator(component);
                ////Split component into smaller components
                foreach (int v in S)
                {
                    component.RemoveVertex(v);
                }
                (List <UndirectedGraph <int, IEdge <int> > >, Dictionary <int, int>)components = FindComponents(component);

                //One of components cannot be colored => whole G cannot be colored
                if (!DnCColoring(components, S).isColorable)
                {
                    return(null);
                }
            }
            return(_coloring.Select(c => c.Value).ToArray());
        }
Example #6
0
        Triangulate(UndirectedGraph <int, IEdge <int> > tree, int root = 0)
        {
            UndirectedGraph <int, IEdge <int> >        res = new UndirectedGraph <int, IEdge <int> >();
            Dictionary <(int source, int target), int> innerVerticesCount = new Dictionary <(int source, int target), int>();

            if (tree.IsVerticesEmpty)
            {
                return(res, innerVerticesCount);
            }
            if (!tree.ContainsVertex(root))
            {
                throw new ArgumentException("root");
            }

            UndirectedGraph <int, IEdge <int> > G = tree.Clone();
            // create counter-clockwise combinatorial embedding
            // assumes vertices are numbered as in BFS
            // so it's proper to add them to list in order they are stored internally
            Dictionary <int, List <int> > embedding = new Dictionary <int, List <int> >();

            for (int i = 0; i < G.VertexCount; i++)
            {
                embedding.Add(i, new List <int>());
                foreach (int v in G.AdjacentVertices(i))
                {
                    embedding[i].Add(v);
                }
            }

            // BFS
            Queue <int> q = new Queue <int>();

            bool[] enqueued = new bool[G.VertexCount];
            q.Enqueue(root);
            enqueued[root] = true;
            while (q.Count > 0)
            {
                int p = q.Dequeue();

                int[] neighbors = new int[embedding[p].Count];
                embedding[p].CopyTo(neighbors);

                int first = neighbors[0];
                if (!enqueued[first])
                {
                    q.Enqueue(first);
                    enqueued[first] = true;
                }
                int prev = first;
                int curr = -1;
                for (int i = 1; i < neighbors.Length; i++)
                {
                    curr = neighbors[i];
                    TryAddEdge(prev, curr, p, ref G, ref res, ref embedding, ref innerVerticesCount);
                    prev = curr;

                    if (!enqueued[curr])
                    {
                        q.Enqueue(curr);
                        enqueued[curr] = true;
                    }
                }
                if (neighbors.Length > 2)
                {
                    TryAddEdge(curr, first, p, ref G, ref res, ref embedding, ref innerVerticesCount);
                }
            }
            return(res, innerVerticesCount);
        }
Example #7
0
        /// <summary>
        /// Algo 1: Find subgraph frequency (mappings found are saved to disk to be retrieved later during Algo 3).
        /// The value of the dictionary returned is in the form: $"{mappings.Count}#{qGraph.Label}.ser"
        /// </summary>
        /// <param name="inputGraph"></param>
        /// <param name="qGraph">The query graph to be searched for. If not available, we use expansion trees (MODA). Otherwise, we use Grochow's (Algo 2)</param>
        /// <param name="subgraphSize"></param>
        /// <param name="thresholdValue">Frequency value, above which we can comsider the subgraph a "frequent subgraph"</param>
        /// <returns></returns>
        public static Dictionary <QueryGraph, string> Algorithm1_C(UndirectedGraph <int> inputGraph, QueryGraph qGraph, int subgraphSize, int thresholdValue)
        {
            // The enumeration module (Algo 3) needs the mappings generated from the previous run(s)
            Dictionary <QueryGraph, string> allMappings;
            int numIterations = -1;

            if (inputGraph.VertexCount < 121)
            {
                numIterations = inputGraph.VertexCount;
            }

            if (qGraph == null) // Use MODA's expansion tree
            {
                #region Use MODA's expansion tree
                var treatedNodes = new HashSet <QueryGraph>();
                allMappings = new Dictionary <QueryGraph, string>(_builder.NumberOfQueryGraphs);
                do
                {
                    qGraph = GetNextNode()?.QueryGraph;
                    if (qGraph == null)
                    {
                        break;
                    }
                    ICollection <Mapping> mappings;
                    if (qGraph.EdgeCount == (subgraphSize - 1)) // i.e. if qGraph is a tree
                    {
                        if (UseModifiedGrochow)
                        {
                            // Modified Mapping module - MODA and Grockow & Kellis
                            mappings = Algorithm2_Modified(qGraph, inputGraph, numIterations, false);
                        }
                        else
                        {
                            var inputGraphClone = inputGraph.Clone();
                            mappings = Algorithm2(qGraph, inputGraphClone, numIterations, false);
                            inputGraphClone.Clear();
                            inputGraphClone = null;
                        }

                        // Because we're saving to file, we're better off doing this now
                        qGraph.RemoveNonApplicableMappings(mappings, inputGraph, false);
                        treatedNodes.Add(qGraph);
                    }
                    else
                    {
                        // Enumeration moodule - MODA
                        // This is part of Algo 3; but performance tweaks makes it more useful to get it here
                        var parentQueryGraph = GetParent(qGraph, _builder.ExpansionTree);
                        if (parentQueryGraph.EdgeCount == (subgraphSize - 1))
                        {
                            treatedNodes.Add(parentQueryGraph);
                        }
                        string _filename;
                        if (allMappings.TryGetValue(parentQueryGraph, out _filename))
                        {
                            string newFileName; // for parentQueryGraph
                            mappings = Algorithm3(null, inputGraph, qGraph, _builder.ExpansionTree, parentQueryGraph, out newFileName, _filename);
                            if (!string.IsNullOrWhiteSpace(newFileName))
                            {
                                // We change the _filename value in the dictionary since this means some of the mappings from parent fit the child
                                allMappings[parentQueryGraph] = newFileName;
                            }
                        }
                        else
                        {
                            mappings = new Mapping[0];
                        }
                    }

                    if (mappings.Count > thresholdValue)
                    {
                        qGraph.IsFrequentSubgraph = true;
                    }

                    // Save mappings.
                    var fileName = qGraph.WriteMappingsToFile(mappings);
                    if (mappings.Count > 0)
                    {
                        mappings.Clear();
                    }
                    allMappings.Add(qGraph, fileName);

                    // Check for complete-ness; if complete, break
                    if (qGraph.IsComplete(subgraphSize))
                    {
                        qGraph = null;
                        break;
                    }
                    qGraph = null;
                }while (true);
                #endregion
            }
            else
            {
                ICollection <Mapping> mappings;
                if (UseModifiedGrochow)
                {
                    // Modified Mapping module - MODA and Grockow & Kellis
                    mappings = Algorithm2_Modified(qGraph, inputGraph, numIterations, true);
                }
                else
                {
                    mappings = Algorithm2(qGraph, inputGraph, numIterations, true);
                }
                qGraph.RemoveNonApplicableMappings(mappings, inputGraph);
                var fileName = $"{mappings.Count}#{qGraph.Identifier}.ser";
                System.IO.File.WriteAllText(fileName, Extensions.CompressString(Newtonsoft.Json.JsonConvert.SerializeObject(mappings)));
                if (mappings.Count > 0)
                {
                    mappings.Clear();
                }
                allMappings = new Dictionary <QueryGraph, string>(1)
                {
                    { qGraph, fileName }
                };
            }

            return(allMappings);
        }
Example #8
0
        /// <summary>
        /// Algo 1: Find subgraph frequency (mappings help in memory)
        /// </summary>
        /// <param name="inputGraph"></param>
        /// <param name="qGraph">The query graph to be searched for. If not available, we use expansion trees (MODA). Otherwise, we use Grochow's (Algo 2)</param>
        /// <param name="subgraphSize"></param>
        /// <param name="thresholdValue">Frequency value, above which we can comsider the subgraph a "frequent subgraph"</param>
        /// <returns></returns>
        public static Dictionary <QueryGraph, ICollection <Mapping> > Algorithm1(UndirectedGraph <int> inputGraph, QueryGraph qGraph, int subgraphSize = -1, int thresholdValue = 0)
        {
            // The enumeration module (Algo 3) needs the mappings generated from the previous run(s)
            Dictionary <QueryGraph, ICollection <Mapping> > allMappings;
            int numIterations = -1;

            if (inputGraph.VertexCount < 121)
            {
                numIterations = inputGraph.VertexCount;
            }

            if (qGraph == null) // Use MODA's expansion tree
            {
                #region Use MODA's expansion tree
                var treatedNodes = new HashSet <QueryGraph>();
                allMappings = new Dictionary <QueryGraph, ICollection <Mapping> >(_builder.NumberOfQueryGraphs);
                do
                {
                    qGraph = GetNextNode()?.QueryGraph;
                    if (qGraph == null)
                    {
                        break;
                    }
                    ICollection <Mapping> mappings;
                    if (qGraph.IsTree(subgraphSize))
                    {
                        if (UseModifiedGrochow)
                        {
                            // Modified Mapping module - MODA and Grockow & Kellis
                            mappings = Algorithm2_Modified(qGraph, inputGraph, numIterations, false);
                        }
                        else
                        {
                            // Mapping module - MODA and Grockow & Kellis.
                            var inputGraphClone = inputGraph.Clone();
                            mappings = Algorithm2(qGraph, inputGraphClone, numIterations, false);
                            inputGraphClone.Clear();
                            inputGraphClone = null;
                        }
                    }
                    else
                    {
                        // Enumeration moodule - MODA
                        // This is part of Algo 3; but performance tweaks makes it more useful to get it here
                        var parentQueryGraph = GetParent(qGraph, _builder.ExpansionTree);
                        if (parentQueryGraph.IsTree(subgraphSize))
                        {
                            treatedNodes.Add(parentQueryGraph);
                        }
                        string file;
                        mappings = Algorithm3(allMappings, inputGraph, qGraph, _builder.ExpansionTree, parentQueryGraph, out file);
                    }
                    if (mappings != null && mappings.Count > thresholdValue)
                    {
                        qGraph.IsFrequentSubgraph = true;
                    }
                    // Save mappings. Do we need to save to disk? Maybe not!

                    allMappings.Add(qGraph, mappings);
                    // Do not call mappings.Clear()
                    mappings = null;
                    // Check for complete-ness; if complete, break
                    if (qGraph.IsComplete(subgraphSize))
                    {
                        qGraph = null;
                        break;
                    }
                    qGraph = null;
                }while (true);

                if (treatedNodes.Count > 0)
                {
                    foreach (var mapping in allMappings)
                    {
                        if (mapping.Key.IsTree(subgraphSize) && !treatedNodes.Contains(mapping.Key))
                        {
                            mapping.Key.RemoveNonApplicableMappings(mapping.Value, inputGraph);
                        }
                    }
                    treatedNodes.Clear();
                }
                treatedNodes = null;
                #endregion
            }
            else
            {
                ICollection <Mapping> mappings;
                if (UseModifiedGrochow)
                {
                    // Modified Mapping module - MODA and Grockow & Kellis
                    mappings = Algorithm2_Modified(qGraph, inputGraph, numIterations, true);
                    // mappings = ModaAlgorithm2Parallelized.Algorithm2_Modified(qGraph, inputGraph, numIterations);
                }
                else
                {
                    mappings = Algorithm2(qGraph, inputGraph, numIterations, true);
                }

                qGraph.RemoveNonApplicableMappings(mappings, inputGraph);
                allMappings = new Dictionary <QueryGraph, ICollection <Mapping> >(1)
                {
                    { qGraph, mappings }
                };

                // Do not call mappings.Clear()
                mappings = null;
            }

            return(allMappings);
        }