From ea48858a3643942ee6df615922d9363014698177 Mon Sep 17 00:00:00 2001 From: smbadiwe Date: Sun, 12 Nov 2017 00:08:14 -0800 Subject: [PATCH] Great work to bring memory overhead down and stop OOM exceptions --- MODA.Impl/Extensions.cs | 3 +- MODA.Impl/GraphProcessor.cs | 3 +- MODA.Impl/Mapping.cs | 29 +++++---- MODA.Impl/ModaAlgorithms.1.cs | 34 ++++++---- MODA.Impl/ModaAlgorithms.2.Modified.cs | 28 +++++++-- MODA.Impl/ModaAlgorithms.2.cs | 14 +++-- MODA.Impl/ModaAlgorithms.3.cs | 10 ++- MODA.Impl/QueryGraph.cs | 38 +++++------ MODA.Impl/Utils.cs | 87 ++++++++++++++++---------- ParaMODA/MODATest.cs | 2 +- ParaMODA/ParaMODA.csproj | 2 +- ParaMODA/Program.cs | 6 +- QuickGraph/Alt/Edge.cs | 15 ++--- QuickGraph/Alt/UndirectedGraph.cs | 64 +++++++++---------- 14 files changed, 196 insertions(+), 139 deletions(-) diff --git a/MODA.Impl/Extensions.cs b/MODA.Impl/Extensions.cs index d203d38..3249884 100644 --- a/MODA.Impl/Extensions.cs +++ b/MODA.Impl/Extensions.cs @@ -23,9 +23,8 @@ public static IList GetNeighbors(this UndirectedGraph graph, int verte /// public static QueryGraph ToQueryGraph(this IEnumerable> edges, string graphLabel) { - var g = new QueryGraph + var g = new QueryGraph(graphLabel) { - Identifier = graphLabel }; g.AddVerticesAndEdgeRange(edges); return g; diff --git a/MODA.Impl/GraphProcessor.cs b/MODA.Impl/GraphProcessor.cs index 276b229..60558bc 100644 --- a/MODA.Impl/GraphProcessor.cs +++ b/MODA.Impl/GraphProcessor.cs @@ -57,9 +57,8 @@ public static UndirectedGraph LoadGraph(string filename, bool isQueryGraph UndirectedGraph newGraphInstance; if (isQueryGraph) { - newGraphInstance = new QueryGraph + newGraphInstance = new QueryGraph(Path.GetFileNameWithoutExtension(filename)) { - Identifier = Path.GetFileNameWithoutExtension(filename) }; } else diff --git a/MODA.Impl/Mapping.cs b/MODA.Impl/Mapping.cs index f7d2689..46a7d30 100644 --- a/MODA.Impl/Mapping.cs +++ b/MODA.Impl/Mapping.cs @@ -29,19 +29,19 @@ public Mapping(SortedList function, int subGraphEdgeCount) /// /// Usage is temporary - to help organize stuffs in Algorithm 3 /// - public int Id; + public int Id { get; set; } /// /// This represents the [f(h) = g] relation. Meaning key is h and value is g. /// - public SortedList Function; + public SortedList Function { get; set; } /// /// Count of all the edges in the input subgraph G that fit the query graph (---Function.Keys). /// This count is for the induced subgraph /// - public int SubGraphEdgeCount; - + public int SubGraphEdgeCount { get; set; } + /// /// Gets the corresponding image of the in the . /// Use only for when (InducedSubGraph.EdgeCount > currentQueryGraphEdgeCount) @@ -64,7 +64,7 @@ public override bool Equals(object obj) var other = obj as Mapping; if (other == null) return false; - if (Id >= 0 && Id != other.Id) return false; + if (Id >= 0 || other.Id >= 0) return Id == other.Id; int i = 0; foreach (var func in Function) @@ -82,7 +82,9 @@ public override bool Equals(object obj) public override int GetHashCode() { - return GetMappedNodes().GetHashCode(); + if (Id >= 0) return Id.GetHashCode(); + + return base.GetHashCode(); } /// @@ -92,13 +94,14 @@ public override int GetHashCode() /// public string GetMappedNodes() { - var sb = new StringBuilder(); - foreach (var item in Function) - { - sb.AppendFormat("{0}-", item.Value); - } - sb.Remove(sb.Length - 1, 1); - return sb.ToString(); + return string.Join("-", Function.Values); + //var sb = new StringBuilder(); + //foreach (var item in Function) + //{ + // sb.AppendFormat("{0}-", item.Value); + //} + //sb.Remove(sb.Length - 1, 1); + //return sb.ToString(); } public override string ToString() diff --git a/MODA.Impl/ModaAlgorithms.1.cs b/MODA.Impl/ModaAlgorithms.1.cs index c83c0e7..4e92381 100644 --- a/MODA.Impl/ModaAlgorithms.1.cs +++ b/MODA.Impl/ModaAlgorithms.1.cs @@ -34,19 +34,21 @@ public static Dictionary Algorithm1_C(UndirectedGraph i ICollection mappings; if (qGraph.EdgeCount == (subgraphSize - 1)) // i.e. if qGraph is a tree { - var inputGraphClone = inputGraph.Clone(); if (UseModifiedGrochow) { // Modified Mapping module - MODA and Grockow & Kellis - mappings = Algorithm2_Modified(qGraph, inputGraphClone, numIterations, false); + 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); + qGraph.RemoveNonApplicableMappings(mappings, inputGraph, false); treatedNodes.Add(qGraph); } else @@ -146,16 +148,18 @@ public static Dictionary> Algorithm1(Undirected ICollection mappings; if (qGraph.IsTree(subgraphSize)) { - var inputGraphClone = inputGraph.Clone(); if (UseModifiedGrochow) { // Modified Mapping module - MODA and Grockow & Kellis - mappings = Algorithm2_Modified(qGraph, inputGraphClone, numIterations, false); + 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 @@ -177,7 +181,7 @@ public static Dictionary> Algorithm1(Undirected // 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)) @@ -187,15 +191,20 @@ public static Dictionary> Algorithm1(Undirected } qGraph = null; } - while (true); + while (true); - foreach (var mapping in allMappings) + if (treatedNodes.Count > 0) { - if (mapping.Key.IsTree(subgraphSize) && !treatedNodes.Contains(mapping.Key)) + foreach (var mapping in allMappings) { - mapping.Key.RemoveNonApplicableMappings(mapping.Value, inputGraph); + if (mapping.Key.IsTree(subgraphSize) && !treatedNodes.Contains(mapping.Key)) + { + mapping.Key.RemoveNonApplicableMappings(mapping.Value, inputGraph); + } } + treatedNodes.Clear(); } + treatedNodes = null; #endregion } else @@ -214,10 +223,13 @@ public static Dictionary> Algorithm1(Undirected qGraph.RemoveNonApplicableMappings(mappings, inputGraph); allMappings = new Dictionary>(1) { { qGraph, mappings } }; + + // Do not call mappings.Clear() + mappings = null; } return allMappings; } - + } } diff --git a/MODA.Impl/ModaAlgorithms.2.Modified.cs b/MODA.Impl/ModaAlgorithms.2.Modified.cs index 4d34c4b..f6b58a6 100644 --- a/MODA.Impl/ModaAlgorithms.2.Modified.cs +++ b/MODA.Impl/ModaAlgorithms.2.Modified.cs @@ -3,6 +3,7 @@ using System; using System.Collections.Generic; using System.Linq; +using System.Runtime.CompilerServices; using System.Threading; namespace MODA.Impl @@ -25,7 +26,7 @@ private static ICollection Algorithm2_Modified(QueryGraph queryGraph, U { if (numberOfSamples <= 0) numberOfSamples = inputGraph.VertexCount / 3; - var theMappings = new Dictionary, List>(MappingNodesComparer); + var theMappings = new Dictionary>(MappingNodesComparer); var inputGraphDegSeq = inputGraph.GetNodesSortedByDegree(numberOfSamples); var threadName = Thread.CurrentThread.ManagedThreadId; @@ -47,6 +48,10 @@ private static ICollection Algorithm2_Modified(QueryGraph queryGraph, U { foreach (var item in mappings) { + if (item.Value.Count > 1) + { + queryGraph.RemoveNonApplicableMappings(item.Value, inputGraph, getInducedMappingsOnly); + } //Recall: f(h) = g List maps; if (theMappings.TryGetValue(item.Key, out maps)) @@ -58,8 +63,8 @@ private static ICollection Algorithm2_Modified(QueryGraph queryGraph, U theMappings[item.Key] = item.Value; } } + mappings.Clear(); } - mappings.Clear(); mappings = null; #endregion } @@ -71,13 +76,28 @@ private static ICollection Algorithm2_Modified(QueryGraph queryGraph, U queryGraphEdges = null; inputGraphDegSeq.Clear(); inputGraphDegSeq = null; - var toReturn = new HashSet(theMappings.Values.SelectMany(s => s)); - theMappings.Clear(); + + var toReturn = GetSet(theMappings); theMappings = null; Console.WriteLine("\nThread {0}:\tAlgorithm 2: All iteration tasks completed. Number of mappings found: {1}.\n", threadName, toReturn.Count); return toReturn; } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static HashSet GetSet(Dictionary> theMappings) + { + var toReturn = new HashSet(theMappings.Values.SelectMany(s => s)); + //foreach (var set in theMappings.Keys.ToArray()) + //{ + // foreach (var item in theMappings[set]) + // { + // toReturn.Add(item); + // } + // theMappings.Remove(set); + //} + theMappings.Clear(); // = null; + return toReturn; + } } } diff --git a/MODA.Impl/ModaAlgorithms.2.cs b/MODA.Impl/ModaAlgorithms.2.cs index ba50d19..496f685 100644 --- a/MODA.Impl/ModaAlgorithms.2.cs +++ b/MODA.Impl/ModaAlgorithms.2.cs @@ -19,7 +19,7 @@ internal static ICollection Algorithm2(QueryGraph queryGraph, Undirecte // Do we need this clone? Can't we just remove the node directly from the graph? // We do need it. - var theMappings = new Dictionary, List>(MappingNodesComparer); + var theMappings = new Dictionary>(MappingNodesComparer); var inputGraphDegSeq = inputGraphClone.GetNodesSortedByDegree(numberOfSamples); var queryGraphVertices = queryGraph.Vertices.ToArray(); var queryGraphEdges = queryGraph.Edges.ToArray(); @@ -45,6 +45,10 @@ internal static ICollection Algorithm2(QueryGraph queryGraph, Undirecte { foreach (var item in mappings) { + if (item.Value.Count > 1) + { + queryGraph.RemoveNonApplicableMappings(item.Value, inputGraphClone, getInducedMappingsOnly); + } //Recall: f(h) = g List maps; if (theMappings.TryGetValue(item.Key, out maps)) @@ -56,8 +60,8 @@ internal static ICollection Algorithm2(QueryGraph queryGraph, Undirecte theMappings[item.Key] = item.Value; } } + mappings.Clear(); } - mappings.Clear(); mappings = null; #endregion } @@ -65,14 +69,16 @@ internal static ICollection Algorithm2(QueryGraph queryGraph, Undirecte //Remove g inputGraphClone.RemoveVertex(g); + if (inputGraphClone.EdgeCount == 0) break; } Array.Clear(queryGraphEdges, 0, queryGraphEdges.Length); queryGraphEdges = null; + Array.Clear(queryGraphVertices, 0, subgraphSize); + queryGraphVertices = null; inputGraphDegSeq.Clear(); inputGraphDegSeq = null; - var toReturn = new HashSet(theMappings.Values.SelectMany(s => s)); - theMappings.Clear(); + var toReturn = GetSet(theMappings); theMappings = null; Console.WriteLine("Thread {0}:\tAlgorithm 2: All tasks completed. Number of mappings found: {1}.", threadName, toReturn.Count); diff --git a/MODA.Impl/ModaAlgorithms.3.cs b/MODA.Impl/ModaAlgorithms.3.cs index b07dbb8..f17dbbb 100644 --- a/MODA.Impl/ModaAlgorithms.3.cs +++ b/MODA.Impl/ModaAlgorithms.3.cs @@ -44,6 +44,8 @@ private static IList Algorithm3(Dictionary Algorithm3(Dictionary x.Function.Values, MappingNodesComparer); //.ToDictionary(x => x.Key, x => x.ToArray(), MappingNodesComparer); + 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; + item.Id = id++; // Remember, f(h) = g // if (f(u), f(v)) ϵ G and meets the conditions, add to list @@ -73,6 +75,7 @@ private static IList Algorithm3(Dictionary queryGraphEdgeCount) { @@ -86,7 +89,9 @@ private static IList Algorithm3(Dictionary Algorithm3(Dictionary { - public QueryGraph() : base() - { + //NB: Don't bother overriding .Equals and .GetHashCode + public QueryGraph(string label) : base() + { + Identifier = label; } - public QueryGraph(bool allowParralelEdges) : base(allowParralelEdges) + public QueryGraph(string label, bool allowParralelEdges) : base(allowParralelEdges) { - + Identifier = label; } /// /// A name to identify / refer to this query graph /// - public string Identifier { get; set; } + public string Identifier { get; } public bool IsFrequentSubgraph { get; set; } @@ -54,13 +56,13 @@ public string WriteMappingsToFile(ICollection mappings) return fileName; } - public void RemoveNonApplicableMappings(ICollection mappings, UndirectedGraph inputGraph) + public void RemoveNonApplicableMappings(ICollection mappings, UndirectedGraph inputGraph, bool checkInducedMappingOnly = true) { - if (mappings.Count == 0) return; + if (mappings.Count < 2) return; int subgraphSize = VertexCount; var mapGroups = mappings.GroupBy(x => x.Function.Values, ModaAlgorithms.MappingNodesComparer); //.ToDictionary(x => x.Key, x => x.ToArray()); - + var toAdd = new List(); var queryGraphEdges = Edges.ToArray(); foreach (var group in mapGroups) @@ -84,14 +86,20 @@ public void RemoveNonApplicableMappings(ICollection mappings, Undirecte subgraph.AddVerticesAndEdgeRange(inducedSubGraphEdges); foreach (var item in group) { - var result = Utils.IsMappingCorrect2(item.Function, subgraph, queryGraphEdges, true); + var result = Utils.IsMappingCorrect2(item.Function, subgraph, queryGraphEdges, checkInducedMappingOnly); if (result.IsCorrectMapping) { toAdd.Add(item); + result = null; break; } + result = null; } + subgraph = null; + inducedSubGraphEdges.Clear(); + inducedSubGraphEdges = null; } + mapGroups = null; mappings.Clear(); if (toAdd.Count > 0) { @@ -99,17 +107,9 @@ public void RemoveNonApplicableMappings(ICollection mappings, Undirecte { mappings.Add(item); } + toAdd.Clear(); } - } - - public override int GetHashCode() - { - return Identifier.GetHashCode(); - } - - public override bool Equals(object obj) - { - return Identifier.Equals(((QueryGraph)obj).Identifier); + toAdd = null; } } } diff --git a/MODA.Impl/Utils.cs b/MODA.Impl/Utils.cs index 7697b9f..0f7a748 100644 --- a/MODA.Impl/Utils.cs +++ b/MODA.Impl/Utils.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using System.Runtime.CompilerServices; using System.Linq; +using System; namespace MODA.Impl { @@ -20,7 +21,7 @@ public class Utils /// /// true if [is mapping correct] [the specified function]; otherwise, false. /// - internal static MappingTestResult IsMappingCorrect(SortedList function, Edge[] queryGraphEdges, UndirectedGraph inputGraph, bool checkInducedMappingOnly, int subGraphEdgeCount = 0) + private static MappingTestResult IsMappingCorrect(SortedList function, Edge[] queryGraphEdges, UndirectedGraph inputGraph, bool checkInducedMappingOnly, int subGraphEdgeCount = 0) { var subgraph = GetSubgraph(inputGraph, function.Values); @@ -30,24 +31,26 @@ internal static MappingTestResult IsMappingCorrect(SortedList function internal static MappingTestResult IsMappingCorrect2(SortedList function, UndirectedGraph subgraph, Edge[] queryGraphEdges, bool checkInducedMappingOnly) { // Gather the corresponding potential images of the parentQueryGraphEdges in the input graph - var edgeImages = new HashSet>(); - foreach (var x in queryGraphEdges) + int qgLen = queryGraphEdges.Length; + var edgeImages = new Edge[qgLen]; + for (int i = 0; i < qgLen; i++) { - edgeImages.Add(new Edge(function[x.Source], function[x.Target])); + var x = queryGraphEdges[i]; + edgeImages[i] = new Edge(function[x.Source], function[x.Target]); } - var result = new MappingTestResult { SubgraphEdgeCount = subgraph.EdgeCount }; - var compareEdgeCount = result.SubgraphEdgeCount.CompareTo(edgeImages.Count); + var compareEdgeCount = result.SubgraphEdgeCount.CompareTo(edgeImages.Length); if (compareEdgeCount < 0) { - edgeImages.Clear(); + Array.Clear(edgeImages, 0, qgLen); edgeImages = null; return result; } // if mapping is possible (=> if compareEdgeCount >= 0) var subgraphDegrees = subgraph.GetReverseDegreeSequence(); + var subgLen = subgraphDegrees.Length; var testG = new UndirectedGraph(); testG.AddVerticesAndEdgeRange(edgeImages); var testGdeg = testG.GetReverseDegreeSequence(); @@ -55,19 +58,21 @@ internal static MappingTestResult IsMappingCorrect2(SortedList functio { // Same node count, same edge count //TODO: All we now need to do is check that the node degrees match - for (int i = subgraphDegrees.Count - 1; i >= 0; i--) + for (int i = subgLen - 1; i >= 0; i--) { if (subgraphDegrees[i] != testGdeg[i]) { - edgeImages.Clear(); + Array.Clear(subgraphDegrees, 0, subgLen); + subgraphDegrees = null; + Array.Clear(edgeImages, 0, qgLen); edgeImages = null; result.IsCorrectMapping = false; return result; } } - subgraphDegrees.Clear(); + Array.Clear(subgraphDegrees, 0, subgLen); subgraphDegrees = null; - edgeImages.Clear(); + Array.Clear(edgeImages, 0, qgLen); edgeImages = null; result.IsCorrectMapping = true; return result; @@ -77,27 +82,29 @@ internal static MappingTestResult IsMappingCorrect2(SortedList functio { if (checkInducedMappingOnly) { - subgraphDegrees.Clear(); + Array.Clear(subgraphDegrees, 0, subgLen); subgraphDegrees = null; - edgeImages.Clear(); + Array.Clear(edgeImages, 0, qgLen); edgeImages = null; result.IsCorrectMapping = false; return result; } - for (int i = subgraphDegrees.Count - 1; i >= 0; i--) + for (int i = subgLen - 1; i >= 0; i--) { if (subgraphDegrees[i] < testGdeg[i]) // base should have at least the same value as test { - edgeImages.Clear(); + Array.Clear(subgraphDegrees, 0, subgLen); + subgraphDegrees = null; + Array.Clear(edgeImages, 0, qgLen); edgeImages = null; result.IsCorrectMapping = false; return result; } } - subgraphDegrees.Clear(); + Array.Clear(subgraphDegrees, 0, subgLen); subgraphDegrees = null; - edgeImages.Clear(); + Array.Clear(edgeImages, 0, qgLen); edgeImages = null; result.IsCorrectMapping = true; return result; @@ -142,7 +149,7 @@ internal static UndirectedGraph GetSubgraph(UndirectedGraph inputGraph /// H /// If true, then the querygraph must match exactly to the input subgraph. In other words, only induced subgraphs will be returned /// List of isomorphisms. Remember, Key is h, Value is g - internal static Dictionary, List> IsomorphicExtension(Dictionary partialMap, QueryGraph queryGraph + internal static Dictionary> IsomorphicExtension(Dictionary partialMap, QueryGraph queryGraph , Edge[] queryGraphEdges, UndirectedGraph inputGraph, bool getInducedMappingsOnly) { if (partialMap.Count == queryGraph.VertexCount) @@ -153,8 +160,10 @@ internal static Dictionary, List> IsomorphicExtension(Dictio var result = IsMappingCorrect(function, queryGraphEdges, inputGraph, getInducedMappingsOnly); if (result.IsCorrectMapping) { - return new Dictionary, List>(1) { { function.Values, new List { new Mapping(function, result.SubgraphEdgeCount) } } }; + return new Dictionary>(1) { { function.Values.ToArray(), new List(1) { new Mapping(function, result.SubgraphEdgeCount) } } }; } + function.Clear(); + function = null; return null; #endregion @@ -167,7 +176,7 @@ internal static Dictionary, List> IsomorphicExtension(Dictio int m = GetMostConstrainedNeighbour(partialMap.Keys, queryGraph); if (m < 0) return null; - var listOfIsomorphisms = new Dictionary, List>(ModaAlgorithms.MappingNodesComparer); + var listOfIsomorphisms = new Dictionary>(ModaAlgorithms.MappingNodesComparer); var neighbourRange = ChooseNeighboursOfRange(partialMap.Values, inputGraph); @@ -196,6 +205,10 @@ internal static Dictionary, List> IsomorphicExtension(Dictio { foreach (var item in subList) { + if (item.Value.Count > 1) + { + queryGraph.RemoveNonApplicableMappings(item.Value, inputGraph, getInducedMappingsOnly); + } List maps; if (listOfIsomorphisms.TryGetValue(item.Key, out maps)) { @@ -207,8 +220,8 @@ internal static Dictionary, List> IsomorphicExtension(Dictio } } subList.Clear(); - subList = null; } + subList = null; } } @@ -232,7 +245,7 @@ internal static Dictionary, List> IsomorphicExtension(Dictio /// neighbors of h_node in the /> /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal static bool IsNeighbourIncompatible(UndirectedGraph inputGraph, + private static bool IsNeighbourIncompatible(UndirectedGraph inputGraph, int n, Dictionary partialMap, QueryGraph queryGraph, IList neighborsOfM) { // RECALL: m is for Domain, the Key => the query graph @@ -242,7 +255,7 @@ internal static bool IsNeighbourIncompatible(UndirectedGraph inputGraph, } //If there is a neighbor d ∈ D of m such that n is NOT neighbors with f(d), - var neighboursOfN = new HashSet(inputGraph.GetNeighbors(n, true)); + var neighboursOfN = inputGraph.GetNeighbors(n, true); // new HashSet(inputGraph.GetNeighbors(n, true)); bool doNext = false; int val; // f(d) @@ -255,6 +268,7 @@ internal static bool IsNeighbourIncompatible(UndirectedGraph inputGraph, } if (!neighboursOfN.Contains(val)) { + //neighboursOfN.Clear(); neighboursOfN = null; return true; } @@ -267,16 +281,19 @@ internal static bool IsNeighbourIncompatible(UndirectedGraph inputGraph, { if (!partialMap.TryGetValue(d, out val)) { + //neighboursOfN.Clear(); neighboursOfN = null; return false; } if (neighboursOfN.Contains(val)) { + //neighboursOfN.Clear(); neighboursOfN = null; return true; } } } + //neighboursOfN.Clear(); neighboursOfN = null; return false; } @@ -288,18 +305,19 @@ internal static bool IsNeighbourIncompatible(UndirectedGraph inputGraph, /// G /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal static List ChooseNeighboursOfRange(IEnumerable usedRange, UndirectedGraph inputGraph) + private static List ChooseNeighboursOfRange(IEnumerable usedRange, UndirectedGraph inputGraph) { List toReturn = new List(); - var usedRangeSet = new HashSet(usedRange); - foreach (var range in usedRangeSet) + //var usedRangeSet = new HashSet(usedRange); + foreach (var range in usedRange) //usedRangeSet) { var local = inputGraph.GetNeighbors(range, true); if (local.Count > 0) { foreach (var loc in local) { - if (!usedRangeSet.Contains(loc)) + //if (!usedRangeSet.Contains(loc)) + if (!usedRange.Contains(loc)) { toReturn.Add(loc); } @@ -310,7 +328,7 @@ internal static List ChooseNeighboursOfRange(IEnumerable usedRange, Un break; } } - usedRangeSet = null; + //usedRangeSet = null; return toReturn; } @@ -320,7 +338,7 @@ internal static List ChooseNeighboursOfRange(IEnumerable usedRange, Un /// Domain, D, of fumction f. Meaning that we're only interested in the Keys. Remember: f(h) = g /// H [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal static int GetMostConstrainedNeighbour(IEnumerable domain, UndirectedGraph queryGraph) + private static int GetMostConstrainedNeighbour(IEnumerable domain, UndirectedGraph queryGraph) { /* * As is standard in backtracking searches, the algorithm uses the most constrained neighbor @@ -329,15 +347,16 @@ internal static int GetMostConstrainedNeighbour(IEnumerable domain, Undirec * the nodes with the most already-mapped neighbors, and amongst those we select the nodes with * the highest degree and largest neighbor degree sequence. * */ - var domainDict = new HashSet(domain); - foreach (var dom in domainDict) + //var domainDict = new HashSet(domain); + foreach (var dom in domain) //domainDict) { var local = queryGraph.GetNeighbors(dom, false); if (local.Count > 0) { foreach (var loc in local) { - if (!domainDict.Contains(loc)) + //if (!domainDict.Contains(loc)) + if (!domain.Contains(loc)) { return loc; } @@ -345,8 +364,8 @@ internal static int GetMostConstrainedNeighbour(IEnumerable domain, Undirec } local = null; // DO NOT clear } - domainDict.Clear(); - domainDict = null; + //domainDict.Clear(); + //domainDict = null; return -1; } diff --git a/ParaMODA/MODATest.cs b/ParaMODA/MODATest.cs index 9aa8c6d..cae6724 100644 --- a/ParaMODA/MODATest.cs +++ b/ParaMODA/MODATest.cs @@ -67,7 +67,7 @@ internal static void Run(string[] args) Console.ForegroundColor = ConsoleColor.Red; Console.WriteLine("Error. For more details, run the command: MODA.Console --help"); - Console.ForegroundColor = ConsoleColor.White; + Console.ForegroundColor = fgColor; return; } diff --git a/ParaMODA/ParaMODA.csproj b/ParaMODA/ParaMODA.csproj index d92bc13..53d16c6 100644 --- a/ParaMODA/ParaMODA.csproj +++ b/ParaMODA/ParaMODA.csproj @@ -45,7 +45,7 @@ TRACE prompt 4 - false + true diff --git a/ParaMODA/Program.cs b/ParaMODA/Program.cs index 5984041..6ff0954 100644 --- a/ParaMODA/Program.cs +++ b/ParaMODA/Program.cs @@ -9,15 +9,13 @@ static void Main(string[] args) { #if DEBUG string argsStr = ""; - argsStr = @"runall -g ..\Release\Inputs\SampleInputGraph.txt -n 5 -k"; // -k uses expansion tree - //argsStr = @"runall -g ..\Release\Inputs\Ecoli20141001CR_idx.txt -n 5 -k"; // -k uses expansion tree + //argsStr = @"runall -g ..\Release\Inputs\SampleInputGraph.txt -n 3 -k"; // -k uses expansion tree + argsStr = @"runall -g ..\Release\Inputs\Ecoli20141001CR_idx.txt -n 5"; // -k uses expansion tree //argsStr = @"runone -g ..\Release\Inputs\SampleInputGraph.txt -h ..\Release\QueryGraphs\4\qg-5a.txt -n 4 -k"; args = argsStr.Split(' '); Console.WriteLine("args = {0}", string.Join(" ", args)); #endif - var fgColor = Console.ForegroundColor; MODATest.Run(args); - Console.ForegroundColor = fgColor; #if DEBUG Console.ReadKey(); #endif diff --git a/QuickGraph/Alt/Edge.cs b/QuickGraph/Alt/Edge.cs index 0b3d82c..fe5f9a3 100644 --- a/QuickGraph/Alt/Edge.cs +++ b/QuickGraph/Alt/Edge.cs @@ -10,6 +10,8 @@ namespace QuickGraph //.Alt [DebuggerDisplay("{Source}->{Target}")] public struct Edge { + //NB: Really, there's no point overriding .GetHashCode + public readonly TVertex Source; public readonly TVertex Target; @@ -40,15 +42,10 @@ public override string ToString() public override bool Equals(object obj) { - var otherStr = obj?.ToString(); - return !string.IsNullOrWhiteSpace(otherStr) && - (string.Equals($"{Source}->{Target}", otherStr) - || string.Equals($"{Target}->{Source}", otherStr)); - } - - public override int GetHashCode() - { - return Source.GetHashCode() + Target.GetHashCode(); + var other = (Edge)obj; + return (Source.Equals(other.Source) && Target.Equals(other.Target)) + || (Source.Equals(other.Target) && Target.Equals(other.Source)); } + } } diff --git a/QuickGraph/Alt/UndirectedGraph.cs b/QuickGraph/Alt/UndirectedGraph.cs index f4bbba1..24299bf 100644 --- a/QuickGraph/Alt/UndirectedGraph.cs +++ b/QuickGraph/Alt/UndirectedGraph.cs @@ -1,4 +1,5 @@ -using System.Collections.Generic; +using System; +using System.Collections.Generic; using System.Diagnostics; using System.Linq; @@ -42,13 +43,14 @@ public IEnumerable> Edges { get { - var edgeColors = new HashSet>(); + var edgeColors = new List>(); //HashSet foreach (var vertsSet in this.edges) { foreach (var vert in vertsSet.Value) { Edge edge = new Edge(vertsSet.Key, vert); - edgeColors.Add(edge); + if (!edgeColors.Contains(edge)) + edgeColors.Add(edge); } } return edgeColors; @@ -72,7 +74,7 @@ public IList GetNeighbors(TVertex vertex) /// /// NB: The degree sequence of an undirected graph is the non-increasing sequence of its vertex degrees; - /// We return the vertices + /// We return the vertices here instead of the vertex degrees /// /// The expected number of items to return. This value is usually less than the /// @@ -101,21 +103,29 @@ public IList GetNodesSortedByDegree(int count) /// the order direction /// /// - public List GetReverseDegreeSequence() + public int[] GetReverseDegreeSequence() { - var tempList = new List(VertexCount); + var tempList = new int[VertexCount]; + int i = 0; foreach (var node in Vertices) { - tempList.Add(this.GetDegree(node)); + tempList[i++] = GetDegree(node); } - tempList.Sort(); + Array.Sort(tempList); return tempList; } public UndirectedGraph Clone() { - var inputGraphClone = new UndirectedGraph(); - inputGraphClone.AddVerticesAndEdgeRange(this.Edges); + var inputGraphClone = new UndirectedGraph(allowParallelEdges) + { + edgeCount = edgeCount, + }; + foreach (var edge in edges) + { + inputGraphClone.edges.Add(edge.Key, new List(edge.Value)); + } + return inputGraphClone; } @@ -137,6 +147,13 @@ public bool RemoveVertex(TVertex v) return this.edges.Remove(v); } + public void Clear() + { + this.edgeCount = 0; + this.edges.Clear(); + this.edges = null; + } + public void ClearAdjacentEdges(TVertex v) { List ends = new List(this.edges[v]); @@ -194,7 +211,7 @@ public bool AddVerticesAndEdge(TVertex source, TVertex target) } else { - edges[target] = new List { source }; + edges[target] = new List(1) { source }; } } // since we don't care about direction, chech againby reversing them @@ -221,8 +238,8 @@ public bool AddVerticesAndEdge(TVertex source, TVertex target) } else // neither exists. So, add them { - edges[source] = new List { target }; - edges[target] = new List { source }; + edges[source] = new List(1) { target }; + edges[target] = new List(1) { source }; } this.edgeCount++; @@ -237,32 +254,13 @@ public bool AddVerticesAndEdge(Edge edge) public int AddVerticesAndEdgeRange(IEnumerable> edges) { int count = 0; - //foreach (var edge in edges) - //{ - // if (this.AddVerticesAndEdge(edge.Source, edge.Target)) - // { - // count++; - // } - //} - var keys = new HashSet(); foreach (var edge in edges) { - if (this.AddVerticesAndEdgeStraight(edge)) + if (this.AddVerticesAndEdge(edge.Source, edge.Target)) { - keys.Add(edge.Source); - keys.Add(edge.Target); count++; } } - foreach (var key in keys) - { - List vals; - if (this.edges.TryGetValue(key, out vals)) - { - var set = new HashSet(); - vals.RemoveAll(x => !set.Add(x)); - } - } return count; }