예제 #1
0
        /// <summary>Contrived example to test blossoming.</summary>
        [TestMethod()] public void Blossom()
        {
            Graph    g = Graph.FromSmiles("CCCCCC1CCCC1CC");
            Matching m = Matching.CreateEmpty(g);

            // initial matching from double-bonds (size = 5)
            m.Match(1, 2);
            m.Match(3, 4);
            m.Match(5, 6);
            m.Match(7, 8);
            m.Match(9, 10);

            MaximumMatching.Maximise(g, m, 10);

            // once maximised the matching has been augmented such that there
            // are now six disjoint edges (only possibly by contracting blossom)
            Assert.AreEqual(6, m.GetMatches().Count());
            Assert.IsTrue(Compares.AreOrderLessDeepEqual(
                              new[] {
                Tuple.Of(0, 1),
                Tuple.Of(2, 3),
                Tuple.Of(4, 5),
                Tuple.Of(6, 7),
                Tuple.Of(8, 9),
                Tuple.Of(10, 11),
            },
                              m.GetMatches()));
        }
예제 #2
0
        /// <summary>
        /// An edge was found which connects two 'even' vertices in the forest. If
        /// the vertices have the same root we have a blossom otherwise we have
        /// identified an augmenting path. This method checks for these cases and
        /// responds accordingly.
        /// <para>
        /// If an augmenting path was found - then it's edges are alternated and the
        /// method returns true. Otherwise if a blossom was found - it is contracted
        /// and the search continues.
        /// </para>
        /// </summary>
        /// <param name="v">endpoint of an edge</param>
        /// <param name="w">another endpoint of an edge</param>
        /// <returns>a path was augmented</returns>
        private bool Check(int v, int w)
        {
            // self-loop (within blossom) ignored
            if (uf.Connected(v, w))
            {
                return(false);
            }

            vAncestors.SetAll(false);
            wAncestors.SetAll(false);
            int vCurr = v;
            int wCurr = w;

            // walk back along the trees filling up 'vAncestors' and 'wAncestors'
            // with the vertices in the tree -  vCurr and wCurr are the 'even' parents
            // from v/w along the tree
            while (true)
            {
                vCurr = Parent(vAncestors, vCurr);
                wCurr = Parent(wAncestors, wCurr);

                // v and w lead to the same root - we have found a blossom. We
                // travelled all the way down the tree thus vCurr (and wCurr) are
                // the base of the blossom
                if (vCurr == wCurr)
                {
                    Blossom(v, w, vCurr);
                    return(false);
                }

                // we are at the root of each tree and the roots are different, we
                // have found and augmenting path
                if (uf.Find(even[vCurr]) == vCurr && uf.Find(even[wCurr]) == wCurr)
                {
                    Augment(v);
                    Augment(w);
                    matching.Match(v, w);
                    return(true);
                }

                // the current vertex in 'v' can be found in w's ancestors they must
                // share a root - we have found a blossom whose base is 'vCurr'
                if (wAncestors[vCurr])
                {
                    Blossom(v, w, vCurr);
                    return(false);
                }

                // the current vertex in 'w' can be found in v's ancestors they must
                // share a root, we have found a blossom whose base is 'wCurr'
                if (vAncestors[wCurr])
                {
                    Blossom(v, w, wCurr);
                    return(false);
                }
            }
        }
예제 #3
0
        public void Adjusted_other_invalid()
        {
            Matching matching = Matching.CreateEmpty(Graph.FromSmiles("CCCCC"));

            matching.Match(0, 1);
            matching.Match(2, 3);
            matching.Match(1, 2); // 0-1 and 2-3 should not be

            matching.Other(0);
        }
예제 #4
0
        [TestMethod()] public void Adjusted_other()
        {
            Matching matching = Matching.CreateEmpty(Graph.FromSmiles("CCCCC"));

            matching.Match(0, 1);
            matching.Match(2, 3);
            matching.Match(1, 2); // 0-1 and 2-3 should not be

            Assert.AreEqual(matching.Other(1), 2);
            Assert.AreEqual(matching.Other(2), 1);
        }
예제 #5
0
        [TestMethod()] public void Basic()
        {
            Matching matching = Matching.CreateEmpty(Graph.FromSmiles("CCCCC"));

            matching.Match(0, 1);
            matching.Match(2, 3);
            Assert.AreEqual(2, matching.GetMatches().Count());
            Assert.IsTrue(Compares.AreOrderLessDeepEqual(
                              new[] { Tuple.Of(0, 1), Tuple.Of(2, 3) },
                              matching.GetMatches()));
        }
예제 #6
0
        [TestMethod()] public void Adjusted_contains()
        {
            Matching matching = Matching.CreateEmpty(Graph.FromSmiles("CCCCC"));

            matching.Match(0, 1);
            matching.Match(2, 3);
            matching.Match(1, 2); // 0-1 and 2-3 should not be

            Assert.IsFalse(matching.Unmatched(1));
            Assert.IsFalse(matching.Unmatched(2));
            Assert.IsTrue(matching.Unmatched(0));
            Assert.IsTrue(matching.Unmatched(3));
        }
예제 #7
0
        public void Adjusted()
        {
            Matching matching = Matching.CreateEmpty(Graph.FromSmiles("CCCCC"));

            matching.Match(0, 1);
            matching.Match(2, 3);
            matching.Match(1, 2); // 0-1 and 2-3 should not be

            Assert.IsFalse(Compares.AreOrderLessDeepEqual(
                               new[] { Tuple.Of(0, 1), Tuple.Of(2, 3) },
                               matching.GetMatches()));
            Assert.AreEqual(1, matching.GetMatches().Count());
            Assert.IsTrue(Compares.AreOrderLessDeepEqual(
                              new[] { Tuple.Of(1, 2) },
                              matching.GetMatches()));
        }
예제 #8
0
        /// <summary>
        /// Create an arbitrary matching on the subset of vertices ('s') of provided
        /// graph. The provided matching should be empty.
        ///
        /// <param name="g">graph to match</param>
        /// <param name="m">empty matching (presumed)</param>
        /// <param name="s">subset of vertices</param>
        /// <returns>number of vertices matched</returns>
        /// </summary>
        public static int Initial(Graph g, Matching m, BitArray s)
        {
            int nMatched = 0;

            for (int v = BitArrays.NextSetBit(s, 0); v >= 0; v = BitArrays.NextSetBit(s, v + 1))
            {
                // skip if already matched
                if (m.Matched(v))
                {
                    continue;
                }

                // find a single edge which is not matched and match it
                int d = g.Degree(v);
                for (int j = 0; j < d; ++j)
                {
                    Edge e = g.EdgeAt(v, j);
                    int  w = e.Other(v);
                    if ((e.Bond != Bond.Single) && m.Unmatched(w) && s[w])
                    {
                        m.Match(v, w);
                        nMatched += 2;
                        break;
                    }
                }
            }

            return(nMatched);
        }
예제 #9
0
        [TestMethod()] public void Simple_augment()
        {
            Graph    g = Graph.FromSmiles("cccc");
            Matching m = Matching.CreateEmpty(g);

            m.Match(1, 2);
            MaximumMatching.Maximise(g, m, 2);
            Assert.IsTrue(Compares.AreOrderLessDeepEqual(
                              new[] { Tuple.Of(0, 1), Tuple.Of(2, 3) },
                              m.GetMatches()));
        }
예제 #10
0
        public void Napthalene_augment()
        {
            Graph    g = Graph.FromSmiles("C1C=CC2=CCC=CC2=C1");
            Matching m = Matching.CreateEmpty(g);

            m.Match(1, 2);
            m.Match(3, 4);
            m.Match(6, 7);
            m.Match(8, 9);
            MaximumMatching.Maximise(g, m, 8);
            Assert.IsTrue(Compares.AreOrderLessDeepEqual(
                              new[] {
                Tuple.Of(0, 1),
                Tuple.Of(2, 3),
                Tuple.Of(4, 5),
                Tuple.Of(6, 7),
                Tuple.Of(8, 9),
            },
                              m.GetMatches()));
        }
예제 #11
0
        [TestMethod()] public void Furan_augment()
        {
            Graph    g = Graph.FromSmiles("o1cccc1");
            IntSet   s = IntSet.AllOf(1, 2, 3, 4); // exclude the oxygen
            Matching m = Matching.CreateEmpty(g);

            m.Match(2, 3);
            MaximumMatching.Maximise(g, m, 2, s);
            Assert.IsTrue(Compares.AreOrderLessDeepEqual(
                              new[] { Tuple.Of(1, 2), Tuple.Of(3, 4) },
                              m.GetMatches()));
        }
예제 #12
0
        [TestMethod()] public void Simple_augment_subset()
        {
            Graph    g = Graph.FromSmiles("cccc");
            Matching m = Matching.CreateEmpty(g);

            m.Match(1, 2);
            // no vertex '3' matching can not be improved
            MaximumMatching.Maximise(g, m, 2, IntSet.AllOf(0, 1, 2));
            Assert.IsTrue(Compares.AreOrderLessDeepEqual(
                              new[] { Tuple.Of(1, 2) },
                              m.GetMatches()));
        }
예제 #13
0
        /// <summary>
        /// When precisely two vertices are unmatched we only need to find a single
        /// augmenting path. Rather than run through edmonds with blossoms etc we
        /// simple do a targest DFS for the path.
        ///
        /// <param name="g">graph</param>
        /// <param name="m">matching</param>
        /// <param name="nMatched">current matching cardinality must be |s|-nMathced == 2</param>
        /// <param name="s">subset size</param>
        /// <returns>new match cardinality</returns>
        /// </summary>
        public static int AugmentOnce(Graph g, Matching m, int nMatched, BitArray s)
        {
            int vStart = BitArrays.NextSetBit(s, 0);

            while (vStart >= 0)
            {
                if (!m.Matched(vStart))
                {
                    break;
                }
                vStart = BitArrays.NextSetBit(s, vStart + 1);
            }
            int vEnd = BitArrays.NextSetBit(s, vStart + 1);

            while (vEnd >= 0)
            {
                if (!m.Matched(vEnd))
                {
                    break;
                }
                vEnd = BitArrays.NextSetBit(s, vEnd + 1);
            }

            // find an augmenting path between vStart and vEnd
            int[] path = new int[g.Order];
            int   len  = FindPath(g, vStart, vEnd, s, path, 0, m, false);

            if (len > 0)
            {
                // augment
                for (int i = 0; i < len; i += 2)
                {
                    m.Match(path[i], path[i + 1]);
                }
                nMatched += 2;
            }

            return(nMatched);
        }
예제 #14
0
        public static int DfsVisit(Graph g, int v, Matching m, BitArray unvisited, bool match)
        {
            unvisited.Set(v, false);
            int nMatched = 0;
            int d        = g.Degree(v);

            while (--d >= 0)
            {
                int w = g.EdgeAt(v, d).Other(v);
                if (unvisited[w])
                {
                    if (match)
                    {
                        m.Match(v, w);
                        return(2 + DfsVisit(g, w, m, unvisited, false));
                    }
                    else
                    {
                        nMatched += DfsVisit(g, w, m, unvisited, true);
                    }
                }
            }
            return(nMatched);
        }