Пример #1
0
        /// <summary>
        /// Enumeration module. NB: If either of <paramref name="allMappings"/> or <paramref name="fileName"/> is null, the other will not be.
        /// </summary>
        /// <param name="allMappings"></param>
        /// <param name="inputGraph">G</param>
        /// <param name="queryGraph">H</param>
        /// <param name="expansionTree">T_k</param>
        /// <param name="parentQueryGraph"></param>
        /// <param name="fileName"></param>
        /// <param name="parentGraphMappings">NB: This param is still used even outside this method is call. So, be careful how you set/clear its values.</param>
        private static IList <Mapping> Algorithm3(Dictionary <QueryGraph, ICollection <Mapping> > allMappings, UndirectedGraph <int> inputGraph, QueryGraph queryGraph,
                                                  AdjacencyGraph <ExpansionTreeNode> expansionTree,
                                                  QueryGraph parentQueryGraph, out string newFileName, string fileName = null)
        {
            newFileName = null;
            ICollection <Mapping> parentGraphMappings;

            if (string.IsNullOrWhiteSpace(fileName))
            {
                if (!allMappings.TryGetValue(parentQueryGraph, out parentGraphMappings))
                {
                    return(new Mapping[0]);
                }
            }
            else
            {
                parentGraphMappings = parentQueryGraph.ReadMappingsFromFile(fileName);
            }
            if (parentGraphMappings.Count == 0)
            {
                return(new Mapping[0]);
            }

            var subgraphSize          = queryGraph.VertexCount;
            var parentQueryGraphEdges = new HashSet <Edge <int> >();

            foreach (var edge in parentQueryGraph.Edges)
            {
                parentQueryGraphEdges.Add(edge);
            }
            var newEdge = GetEdgeDifference(queryGraph, parentQueryGraph, parentQueryGraphEdges);

            parentQueryGraphEdges.Clear();
            parentQueryGraphEdges = null;

            // if it's NOT a valid edge
            if (newEdge.Source == Utils.DefaultEdgeNodeVal)
            {
                return(new Mapping[0]);
            }

            var list = new List <Mapping>();
            int oldCount = parentGraphMappings.Count, id = 0, queryGraphEdgeCount = queryGraph.EdgeCount;
            var queryGraphEdges = queryGraph.Edges.ToArray();

            var groupByGNodes = parentGraphMappings.GroupBy(x => x.Function.Values.ToArray(), MappingNodesComparer); //.ToDictionary(x => x.Key, x => x.ToArray(), MappingNodesComparer);

            foreach (var set in groupByGNodes)
            {
                // function.value (= set of G nodes) are all same here. So build the subgraph here and pass it dowm
                var subgraph = Utils.GetSubgraph(inputGraph, set.Key);
                foreach (var item in set)
                {
                    item.Id = id++;
                    // Remember, f(h) = g

                    // if (f(u), f(v)) ϵ G and meets the conditions, add to list
                    if (item.SubGraphEdgeCount == queryGraphEdgeCount)
                    {
                        var isMapping = Utils.IsMappingCorrect2(item.Function, subgraph, queryGraphEdges, true);
                        if (isMapping.IsCorrectMapping)
                        {
                            list.Add(item);
                        }
                        isMapping = null;
                    }
                    else if (item.SubGraphEdgeCount > queryGraphEdgeCount)
                    {
                        var newEdgeImage = item.GetImage(inputGraph, newEdge);

                        // if it's a valid edge...
                        if (newEdgeImage.Source != Utils.DefaultEdgeNodeVal &&
                            inputGraph.ContainsEdge(newEdgeImage.Source, newEdgeImage.Target))
                        {
                            list.Add(item);
                        }
                    }
                }
                subgraph = null;
            }
            Array.Clear(queryGraphEdges, 0, queryGraphEdges.Length);
            queryGraphEdges = null;
            var threadName = System.Threading.Thread.CurrentThread.ManagedThreadId;

            // Remove mappings from the parent qGraph that are found in this qGraph
            // This is because we're only interested in induced subgraphs
            var theRest = parentGraphMappings.Except(list).ToList();

            parentQueryGraph.RemoveNonApplicableMappings(theRest, inputGraph);
            parentGraphMappings.Clear();
            foreach (var item in theRest)
            {
                parentGraphMappings.Add(item);
            }
            theRest.Clear();
            theRest = null;
            // Now, remove duplicates
            queryGraph.RemoveNonApplicableMappings(list, inputGraph);
            if (!string.IsNullOrWhiteSpace(fileName) && oldCount > parentGraphMappings.Count)
            {
                // This means that some of the mappings from parent fit the current query graph
                newFileName = parentQueryGraph.WriteMappingsToFile(parentGraphMappings);
                try
                {
                    System.IO.File.Delete(fileName);
                }
                catch { } // we can afford to let this fail
            }

            Console.WriteLine("Thread {0}:\tAlgorithm 3: All tasks completed. Number of mappings found: {1}.\n", threadName, list.Count);
            return(list);
        }
Пример #2
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);
        }