Exemple #1
0
        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);
        }
        /// <summary>
        /// Add a match to the isomorphism
        /// </summary>
        /// <remarks>
        /// This is only a proposed match.  If it fails, the passed in BacktrackRecord
        /// will have all the actions taken as a consequence and they can be undone using
        /// that BacktrackRecord.
        /// </remarks>
        /// <param name="mtc">Proposed match</param>
        /// <param name="btr">BacktrackRecord to record actions into</param>
        /// <returns>True if match is locally consistent with a full isomorphism</returns>
        private bool FAddMatchToSolution(Match mtc, BacktrackRecord <TV, TE> btr)
        {
            var ivtx1 = mtc.Ivtx1;
            var ivtx2 = mtc.Ivtx2;

            // Record the match action in the backtrackRecord
            btr.SetMatch(mtc.Ivtx1, mtc.Ivtx2, this);

            // In and Out neighbors of the vertices in the match
            var lstIn1  = VfGraph1.InNeighbors(ivtx1);
            var lstIn2  = VfGraph2.InNeighbors(ivtx2);
            var lstOut1 = VfGraph1.OutNeighbors(ivtx1);
            var lstOut2 = VfGraph2.OutNeighbors(ivtx2);

            // Reclassify any neighbors of the added vertices that require it
            foreach (var ivtx in lstOut1)
            {
                if (((int)VfGraph1.GetGroup(ivtx) & (int)(Group.Disconnected | Group.ToMapping)) != 0)
                {
                    btr.MoveToGroup(1, ivtx, Group.FromMapping, this);
                }
            }
            foreach (var ivtx in lstIn1)
            {
                if (((int)VfGraph1.GetGroup(ivtx) & (int)(Group.Disconnected | Group.FromMapping)) != 0)
                {
                    btr.MoveToGroup(1, ivtx, Group.ToMapping, this);
                }
            }
            foreach (var ivtx in lstOut2)
            {
                if (((int)VfGraph2.GetGroup(ivtx) & (int)(Group.Disconnected | Group.ToMapping)) != 0)
                {
                    btr.MoveToGroup(2, ivtx, Group.FromMapping, this);
                }
            }
            foreach (var ivtx in lstIn2)
            {
                if (((int)VfGraph2.GetGroup(ivtx) & (int)(Group.Disconnected | Group.FromMapping)) != 0)
                {
                    btr.MoveToGroup(2, ivtx, Group.ToMapping, this);
                }
            }

            // If the total degrees into or out of the isomorphism don't match up properly (less for
            // subgraph isomorphism equal for exact isomorphism) then we can never match properly.
            if (!FnCompareDegrees(_outDegreeTotal1, _outDegreeTotal2) ||
                !FnCompareDegrees(_inDegreeTotal1, _inDegreeTotal2))
            {
                return(false);
            }

            // Also check the vertex counts which is a different check from the total degree above...
            return(FnCompareDegrees(lstOut1.Count, lstOut2.Count) && FnCompareDegrees(lstIn1.Count, lstIn2.Count));
        }
Exemple #3
0
        private bool FAddMatchToSolution(Match mtc, BacktrackRecord btr)
        {
            int inod1 = mtc.Inod1;
            int inod2 = mtc.Inod2;

            btr.SetMatch(mtc.Inod1, mtc.Inod2, this);

            List <int> lstIn1  = _vfgr1.InNeighbors(inod1);
            List <int> lstIn2  = _vfgr2.InNeighbors(inod2);
            List <int> lstOut1 = _vfgr1.OutNeighbors(inod1);
            List <int> lstOut2 = _vfgr2.OutNeighbors(inod2);

            foreach (int inod in lstOut1)
            {
                if (((int)_vfgr1.GetGroup(inod) & (int)(Groups.Disconnected | Groups.ToMapping)) != 0)
                {
                    btr.MoveToGroup(1, inod, Groups.FromMapping, this);
                }
            }
            foreach (int inod in lstIn1)
            {
                if (((int)_vfgr1.GetGroup(inod) & (int)(Groups.Disconnected | Groups.FromMapping)) != 0)
                {
                    btr.MoveToGroup(1, inod, Groups.ToMapping, this);
                }
            }
            foreach (int inod in lstOut2)
            {
                if (((int)_vfgr2.GetGroup(inod) & (int)(Groups.Disconnected | Groups.ToMapping)) != 0)
                {
                    btr.MoveToGroup(2, inod, Groups.FromMapping, this);
                }
            }
            foreach (int inod in lstIn2)
            {
                if (((int)_vfgr2.GetGroup(inod) & (int)(Groups.Disconnected | Groups.FromMapping)) != 0)
                {
                    btr.MoveToGroup(2, inod, Groups.ToMapping, this);
                }
            }

            if (!fnCmp(_outDegreeTotal1, _outDegreeTotal2) ||
                !fnCmp(_inDegreeTotal1, _inDegreeTotal2))
            {
                return(false);
            }
            return(fnCmp(lstOut1.Count, lstOut2.Count) && fnCmp(lstIn1.Count, lstIn2.Count));
        }
        public void TestMatchBacktrack()
        {
            var vfs = VfsTest();
            var btr = new BacktrackRecord();

            btr.SetMatch(0, 1, vfs);
            var grp1 = vfs.VfGraph1.GetGroup(0);
            var grp2 = vfs.VfGraph2.GetGroup(1);

            Assert.IsTrue((((int)grp1 & (int)Group.ContainedInMapping)) != 0);
            Assert.IsTrue((((int)grp2 & (int)Group.ContainedInMapping)) != 0);
            Assert.AreEqual(Group.ContainedInMapping, vfs.VfGraph1.GetGroup(0));
            Assert.AreEqual(Group.ContainedInMapping, vfs.VfGraph2.GetGroup(1));
            btr.Backtrack(vfs);
            grp1 = vfs.VfGraph1.GetGroup(0);
            grp2 = vfs.VfGraph2.GetGroup(1);

            Assert.IsFalse((((int)grp1 & (int)Group.ContainedInMapping)) != 0);
            Assert.IsFalse((((int)grp2 & (int)Group.ContainedInMapping)) != 0);
            Assert.AreEqual(Group.Disconnected, vfs.VfGraph1.GetGroup(0));
            Assert.AreEqual(Group.Disconnected, vfs.VfGraph2.GetGroup(1));
        }
Exemple #5
0
            public void TestMatchBacktrack()
            {
                VfState         vfs = VfsTest();
                BacktrackRecord btr = new BacktrackRecord();

                btr.SetMatch(0, 1, vfs);
                Groups grp1 = vfs.Vfgr1.GetGroup(0);
                Groups grp2 = vfs.Vfgr2.GetGroup(1);

                Assert.IsTrue((((int)grp1 & (int)Groups.ContainedInMapping)) != 0);
                Assert.IsTrue((((int)grp2 & (int)Groups.ContainedInMapping)) != 0);
                Assert.AreEqual(Groups.ContainedInMapping, vfs.Vfgr1.GetGroup(0));
                Assert.AreEqual(Groups.ContainedInMapping, vfs.Vfgr2.GetGroup(1));
                btr.Backtrack(vfs);
                grp1 = vfs.Vfgr1.GetGroup(0);
                grp2 = vfs.Vfgr2.GetGroup(1);

                Assert.IsFalse((((int)grp1 & (int)Groups.ContainedInMapping)) != 0);
                Assert.IsFalse((((int)grp2 & (int)Groups.ContainedInMapping)) != 0);
                Assert.AreEqual(Groups.Disconnected, vfs.Vfgr1.GetGroup(0));
                Assert.AreEqual(Groups.Disconnected, vfs.Vfgr2.GetGroup(1));
            }
Exemple #6
0
        // 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
        }