bool FMatchRecursive() { Match mchCur; CandidateFinder cf; if (FCompleteMatch()) { return(true); } cf = new CandidateFinder(this); while ((mchCur = cf.NextCandidateMatch()) != null) { if (FFeasible(mchCur)) { BacktrackRecord btr = new BacktrackRecord(); AddMatchToSolution(mchCur, btr); if (FMatchRecursive()) { _fSuccessfulMatch = true; return(true); } btr.Backtrack(this); } } return(false); }
public void TestConstructor() { var vfs = VfsTest(); var cf = new CandidateFinder(vfs); var mch = cf.NextCandidateMatch(); Assert.AreEqual(0, mch.Ivtx1); Assert.AreEqual(0, mch.Ivtx2); mch = cf.NextCandidateMatch(); Assert.AreEqual(1, mch.Ivtx1); Assert.AreEqual(0, mch.Ivtx2); }
public void TestConstructor() { VfState vfs = VfsTest(); CandidateFinder cf = new CandidateFinder(vfs); Match mch = cf.NextCandidateMatch(); Assert.AreEqual(0, mch.Inod1); Assert.AreEqual(0, mch.Inod2); mch = cf.NextCandidateMatch(); Assert.AreEqual(1, mch.Inod1); Assert.AreEqual(0, mch.Inod2); }
// Find an isomorphism between a subgraph of _vfgr1 and the entirity of _vfgr2... public bool FMatch() { if (!FCompatibleDegrees()) { return(false); } Stack <CandidateFinder> stkcf = new Stack <CandidateFinder>(); Stack <BacktrackRecord> stkbr = new Stack <BacktrackRecord>(); Match mchCur; CandidateFinder cf; BacktrackRecord btr; bool fPopOut = false; #if GATHERSTATS int cSearchGuesses = 0; int cBackTracks = 0; int cInfeasible = 0; #endif if (_fMatched) { return(false); } _fMatched = true; // Since the subgraph of subgraph isomorphism is in _vfgr1, it must have at // least as many nodes as _vfgr2... if (!fnCmp(_vfgr1.NodeCount, _vfgr2.NodeCount)) { return(false); } if (FCompleteMatch()) { _fSuccessfulMatch = true; return(true); } // Non-recursive implementation of a formerly recursive function while (true) { if (fPopOut) { if (stkcf.Count <= 0) { break; // Out of the top level while loop and return false } cf = stkcf.Pop(); btr = stkbr.Pop(); #if GATHERSTATS cBackTracks++; #endif btr.Backtrack(this); } else { cf = new CandidateFinder(this); btr = new BacktrackRecord(); } fPopOut = true; while ((mchCur = cf.NextCandidateMatch()) != null) { if (FFeasible(mchCur)) { if (FAddMatchToSolution(mchCur, btr) && FCompleteMatch()) { _fSuccessfulMatch = true; #if GATHERSTATS Console.WriteLine("cBackTracks = {0}", cBackTracks); Console.WriteLine("cSearchGuesses = {0}", cSearchGuesses); Console.WriteLine("cInfeasible = {0}", cInfeasible); #endif if (_fFindAll) { // Record this match and simulate a failure... RecordCurrentMatch(); stkcf.Push(cf); stkbr.Push(btr); break; } else { return(true); } } #if GATHERSTATS // Made a bad guess, count it up... cSearchGuesses++; #endif stkcf.Push(cf); stkbr.Push(btr); fPopOut = false; break; // Out of the inner level while loop to "call" into the outer loop } #if GATHERSTATS else { cInfeasible++; } #endif } } #if GATHERSTATS Console.WriteLine("cBackTracks = {0}", cBackTracks); Console.WriteLine("cSearchGuesses = {0}", cSearchGuesses); Console.WriteLine("cInfeasible = {0}", cInfeasible); #endif return(_fSuccessfulMatch); }
public IEnumerable <FullMapping> Matches() { // Check for an empty second graph if (_ldr2.VertexCount == 0) { // If the second is empty, check for a successful "match" if (FnCompareDegrees(_ldr1.VertexCount, 0)) { // Return empty mapping - successful, but nothing to map to yield return(new FullMapping(new Dictionary <int, int>(), new Dictionary <int, int>())); } yield break; } // Quick easy check to make the degrees compatible. if (!FCompatibleDegrees()) { yield break; } var stkcf = new Stack <CandidateFinder <TV, TE> >(); var stkbr = new Stack <BacktrackRecord <TV, TE> >(); var fBacktrack = false; #if GATHERSTATS int cSearchGuesses = 0; int cBackTracks = 0; int cInfeasible = 0; #endif // The general structure here is: // While (true) // if (backtracking) // if there are no graph2 vertices to backtrack to, we can't find any other isomorphisms so return // pop off the previous graph2 vertex to continue it's match // perform backtrack actions // else // pick a new graph2 vertex to try to match // while (there are still potential graph1 vertices to match our current graph2 vertex) // if (the selected graph1 vertex is a feasible match to our current graph2 vertex) // Add the match (and record it if we later need to backtrack) // if (we've got a complete isomorphism) // yield the isomorphism // Push our current graph2 vertex so it will be popped off during backtracking // break the inner loop to trigger artificial backtrack // push the current graph2 vertex search and continue in outer loop with no backtracking // while (true) { CandidateFinder <TV, TE> cf; BacktrackRecord <TV, TE> btr; // If it's time to backtrack... if (fBacktrack) { // If there are no more candidates left, we've failed to find an isomorphism if (stkcf.Count <= 0) { break; // Out of the top level while loop and end enumeration } // Pop off the previous candidate finder so we can continue in our list cf = stkcf.Pop(); #if GATHERSTATS cBackTracks++; #endif // Get the backtrack record... btr = stkbr.Pop(); // ...and undo any actions that need to be backtracked btr.Backtrack(this); } else { // Moving forward - new candidate finder // Each new candidate finder we produce here picks a vertex in graph2 and works // at matching it to a vertex in graph1 until there are no possibile graph1 vertices left. // at that point we know that the current isomorphism is impossible since no // graph1 vertex can be matched to the selected graph2 vertex. At that point we // will pop the candidate finder, backtrack any changes we've made and move to // the next graph1 candidate in the previous candidate finder on the stack. cf = new CandidateFinder <TV, TE>(this); // Start a new backtracking record in case we fail to find a match for our // selected graph2 vertex. btr = new BacktrackRecord <TV, TE>(); } // Assume failure fBacktrack = true; Match mchCur; // For all the graph1 vertices that could potentially match up with the current // candidateFinder's graph2 vertex... while ((mchCur = cf.NextCandidateMatch()) != null) { // If the candidate match is feasible if (FFeasible(mchCur)) { // Add it to the isomorphism so far and see if we've completed the isomorphism if (FAddMatchToSolution(mchCur, btr) && FCompleteMatch()) { // Yay! Isomorphism found! #if GATHERSTATS Console.WriteLine("cBackTracks = {0}", cBackTracks); Console.WriteLine("cSearchGuesses = {0}", cSearchGuesses); Console.WriteLine("cInfeasible = {0}", cInfeasible); #endif // Record this match Dictionary <int, int> vidToVid1; Dictionary <int, int> vidToVid2; // Change the ivertex to ivertex VfGraph mapping in _vfGraphIvtx1To2Isomorphism // to an vid to vid mapping in the original graph... VfGraphVfGraphIvtxToGraphGraphVid( _vfGraphIvtx1To2Isomorphism, _degreeSortedToOriginal1, _degreeSortedToOriginal2, out vidToVid1, out vidToVid2); yield return(new FullMapping(vidToVid1, vidToVid2)); // This will cause a backtrack where this candidateFinder // will be popped off the stack and we'll continue // with this graph2 vertex looking for the next solution. stkcf.Push(cf); stkbr.Push(btr); break; } #if GATHERSTATS // Made a bad guess, count it up... cSearchGuesses++; #endif // Dang! No full isomorphism yet but our choices so far aren't infeasible. // Push candidate finder/backtrack record and break out of the inner loop which will // cause us to pick another candidate finder/graph2 vertex to be mapped. stkcf.Push(cf); stkbr.Push(btr); fBacktrack = false; break; // Out of the inner level while loop to "call" into the outer loop } #if GATHERSTATS else { cInfeasible++; } #endif } } #if GATHERSTATS Console.WriteLine("cBackTracks = {0}", cBackTracks); Console.WriteLine("cSearchGuesses = {0}", cSearchGuesses); Console.WriteLine("cInfeasible = {0}", cInfeasible); #endif }