public static void EnsureIsAnalyzed(LGSPGraph this_) { if (this_.statistics.vstructs == null || this_.changesCounterAtLastAnalyze != this_.ChangesCounter) { this_.AnalyzeGraph(); } }
// Version to be used by IsIsomorph(IDictionary<IGraph, SetValueType> graphsToCheckAgainst), // which is comparing a candidate against an entire set. // Not changing the metadata of this, matching each that inside this, not for normal use! private bool IsIsomorph(LGSPGraph this_, LGSPGraph that, bool includingAttributes, int threadId) { ++that.matchingState.numChecks; if (((LGSPGraph)that).matchingState == null) { ((LGSPGraph)that).matchingState = new GraphMatchingState((LGSPGraph)that); } #if LOG_ISOMORPHY_CHECKING writer.WriteLine("Check " + this_.Name + " == " + that.Name + " on thread " + threadId); writer.Flush(); #endif // compare number of elements per type if (!AreNumberOfElementsEqual(this_, that)) { return(false); } #if LOG_ISOMORPHY_CHECKING writer.WriteLine("Undecided after type counts"); writer.Flush(); #endif // ensure that is analyzed, for this it was ensured by our caller if (that.statistics.vstructs == null || that.changesCounterAtLastAnalyze != that.ChangesCounter) { lock (that) { if (that.statistics.vstructs == null || that.changesCounterAtLastAnalyze != that.ChangesCounter) { that.AnalyzeGraph(); } } } // compare analyze statistics if (!AreVstructsEqual(this_, that)) { return(false); } #if LOG_ISOMORPHY_CHECKING writer.WriteLine("Undecided after vstructs comparison"); writer.Flush(); #endif // invalidate outdated interpretation plans and compiled matchers of that // not needed for this cause we always use the matchers of that, matching inside this if (that.matchingState.interpretationPlan != null && that.matchingState.changesCounterAtInterpretationPlanBuilding != that.ChangesCounter) { lock (that) { if (that.matchingState.interpretationPlan != null && that.matchingState.changesCounterAtInterpretationPlanBuilding != that.ChangesCounter) { that.matchingState.interpretationPlan = null; that.matchingState.patternGraph = null; lock (GraphMatchingState.compilationLock) { GraphMatchingState.candidatesForCompilation.Remove(that); } that.matchingState.compiledMatcher = null; that.matchingState.numMatchings = 0; that.matchingState.numChecks = 0; } } } // they were the same? then we must try to match that in this // if a compiled matcher is existing we use the compiled matcher // if an interpretation plan is existing we use the interpretation plan for matching // if none is existing, then we build an interpretation plan for that // and directly use it for matching thereafter // executing an interpretation plan or a compiled matcher is sufficient for isomorphy because // - element numbers are the same // - we match only exact types bool result; if (that.matchingState.compiledMatcher != null) { // lock(this_) was employed by our caller result = that.matchingState.compiledMatcher.IsIsomorph(that.matchingState.patternGraph, this_, includingAttributes, threadId); #if LOG_ISOMORPHY_CHECKING writer.WriteLine("Using compiled interpretation plan of that " + that.matchingState.compiledMatcher.Name); #endif } else if (that.matchingState.interpretationPlan != null) { // lock(this_) was employed by our caller result = that.matchingState.interpretationPlan.Execute(this_, includingAttributes, null, threadId); #if LOG_ISOMORPHY_CHECKING writer.WriteLine("Using interpretation plan of that " + ((InterpretationPlanStart)that.matchingState.interpretationPlan).ComparisonMatcherName); #endif } else { // we build the interpretation plan for that BuildInterpretationPlan(that); // lock(this_) was employed by our caller result = that.matchingState.interpretationPlan.Execute(this_, includingAttributes, null, threadId); } #if LOG_ISOMORPHY_CHECKING writer.WriteLine("Result of matching: " + (result ? "Isomorph" : "Different")); writer.Flush(); #endif // update the statistics, and depending on the statistics we // - add candidats to the set of the matchers to be compiled // - it's on our caller to trigger a compiler run ++that.matchingState.numMatchings; if (that.matchingState.numMatchings == GraphMatchingState.MATCHES_NEEDED_TO_BECOME_A_CANDIDATE_FOR_COMPILATION) { lock (GraphMatchingState.compilationLock) { GraphMatchingState.candidatesForCompilation.Add(that); } } return(result); }
public bool IsIsomorph(LGSPGraph this_, LGSPGraph that, bool includingAttributes) { ++this_.matchingState.numChecks; ++that.matchingState.numChecks; #if LOG_ISOMORPHY_CHECKING writer.WriteLine("Check " + this_.Name + " == " + that.Name); writer.Flush(); #endif if (this_ == that) { #if LOG_ISOMORPHY_CHECKING writer.WriteLine("this == that, identical graphs are isomorph"); writer.Flush(); #endif return(true); } // compare number of elements per type if (!AreNumberOfElementsEqual(this_, that)) { return(false); } #if LOG_ISOMORPHY_CHECKING writer.WriteLine("Undecided after type counts"); writer.Flush(); #endif // ensure graphs are analyzed if (this_.statistics.vstructs == null || this_.changesCounterAtLastAnalyze != this_.ChangesCounter) { lock (this_) { if (this_.statistics.vstructs == null || this_.changesCounterAtLastAnalyze != this_.ChangesCounter) { this_.AnalyzeGraph(); } } } if (that.statistics.vstructs == null || that.changesCounterAtLastAnalyze != that.ChangesCounter) { lock (that) { if (that.statistics.vstructs == null || that.changesCounterAtLastAnalyze != that.ChangesCounter) { that.AnalyzeGraph(); } } } // compare analyze statistics if (!AreVstructsEqual(this_, that)) { return(false); } #if LOG_ISOMORPHY_CHECKING writer.WriteLine("Undecided after vstructs comparison"); writer.Flush(); #endif // invalidate outdated interpretation plans and compiled matchers if (this_.matchingState.interpretationPlan != null && this_.matchingState.changesCounterAtInterpretationPlanBuilding != this_.ChangesCounter) { lock (this_) { if (this_.matchingState.interpretationPlan != null && this_.matchingState.changesCounterAtInterpretationPlanBuilding != this_.ChangesCounter) { this_.matchingState.interpretationPlan = null; this_.matchingState.patternGraph = null; lock (GraphMatchingState.compilationLock) { GraphMatchingState.candidatesForCompilation.Remove(this_); } this_.matchingState.compiledMatcher = null; this_.matchingState.numMatchings = 0; this_.matchingState.numChecks = 0; } } } if (that.matchingState.interpretationPlan != null && that.matchingState.changesCounterAtInterpretationPlanBuilding != that.ChangesCounter) { lock (that) { if (that.matchingState.interpretationPlan != null && that.matchingState.changesCounterAtInterpretationPlanBuilding != that.ChangesCounter) { that.matchingState.interpretationPlan = null; that.matchingState.patternGraph = null; lock (GraphMatchingState.compilationLock) { GraphMatchingState.candidatesForCompilation.Remove(that); } that.matchingState.compiledMatcher = null; that.matchingState.numMatchings = 0; that.matchingState.numChecks = 0; } } } // they were the same? then we must try to match this in that, or that in this // if a compiled matcher is existing we use the compiled matcher // if an interpretation plan is existing we use the interpretation plan for matching // if none is existing for neither of the graphs, then we build an interpretation plan // for the older graph and directly use it for matching thereafter // executing an interpretation plan or a compiled matcher is sufficient for isomorphy because // - element numbers are the same // - we match only exact types bool result; bool matchedWithThis; if (this_.matchingState.compiledMatcher != null) { lock (that) { result = this_.matchingState.compiledMatcher.IsIsomorph(this_.matchingState.patternGraph, that, includingAttributes); } matchedWithThis = true; #if LOG_ISOMORPHY_CHECKING writer.WriteLine("Using compiled interpretation plan of this " + this_.matchingState.compiledMatcher.Name); #endif } else if (that.matchingState.compiledMatcher != null) { lock (this_) { result = that.matchingState.compiledMatcher.IsIsomorph(that.matchingState.patternGraph, this_, includingAttributes); } matchedWithThis = false; #if LOG_ISOMORPHY_CHECKING writer.WriteLine("Using compiled interpretation plan of that " + that.matchingState.compiledMatcher.Name); #endif } else if (this_.matchingState.interpretationPlan != null) { lock (that) { result = this_.matchingState.interpretationPlan.Execute(that, includingAttributes, null); } matchedWithThis = true; #if LOG_ISOMORPHY_CHECKING writer.WriteLine("Using interpretation plan of this " + ((InterpretationPlanStart)this_.matchingState.interpretationPlan).ComparisonMatcherName); #endif } else if (that.matchingState.interpretationPlan != null) { lock (this_) { result = that.matchingState.interpretationPlan.Execute(this_, includingAttributes, null); } matchedWithThis = false; #if LOG_ISOMORPHY_CHECKING writer.WriteLine("Using interpretation plan of that " + ((InterpretationPlanStart)that.matchingState.interpretationPlan).ComparisonMatcherName); #endif } else { // we build the interpretation plan for the older graph, // assuming it will survive while the younger one is the candidate for purging if (this_.GraphId < that.GraphId) { BuildInterpretationPlan(this_); lock (that) { result = this_.matchingState.interpretationPlan.Execute(that, includingAttributes, null); } matchedWithThis = true; } else { BuildInterpretationPlan(that); lock (this_) { result = that.matchingState.interpretationPlan.Execute(this_, includingAttributes, null); } matchedWithThis = false; } } #if LOG_ISOMORPHY_CHECKING writer.WriteLine("Result of matching: " + (result ? "Isomorph" : "Different")); writer.Flush(); #endif // update the statistics, and depending on the statistics we // - add candidats to the set of the matchers to be compiled // - trigger a compiler run if (matchedWithThis) { ++this_.matchingState.numMatchings; if (this_.matchingState.numMatchings == GraphMatchingState.MATCHES_NEEDED_TO_BECOME_A_CANDIDATE_FOR_COMPILATION) { lock (GraphMatchingState.compilationLock) { GraphMatchingState.candidatesForCompilation.Add(this_); } } } else { ++that.matchingState.numMatchings; if (that.matchingState.numMatchings == GraphMatchingState.MATCHES_NEEDED_TO_BECOME_A_CANDIDATE_FOR_COMPILATION) { lock (GraphMatchingState.compilationLock) { GraphMatchingState.candidatesForCompilation.Add(that); } } } CompileComparisonMatchersAsNeeded(); return(result); }