예제 #1
0
        public static Graph GenerateKekuleForm(Graph g, BitArray subset, BitArray aromatic, bool inplace)
        {
            // make initial (empty) matching - then improve it, first
            // by matching the first edges we find, most of time this
            // gives us a perfect matching if not we maximise it
            // with Edmonds' algorithm

            Matching m        = Matching.CreateEmpty(g);
            int      n        = BitArrays.Cardinality(subset);
            int      nMatched = ArbitraryMatching.Initial(g, m, subset);

            if (nMatched < n)
            {
                if (n - nMatched == 2)
                {
                    nMatched = ArbitraryMatching.AugmentOnce(g, m, nMatched, subset);
                }
                if (nMatched < n)
                {
                    nMatched = MaximumMatching.Maximise(g, m, nMatched, IntSet.FromBitArray(subset));
                }
                if (nMatched < n)
                {
                    throw new InvalidSmilesException("Could not Kekulise");
                }
            }
            return(inplace ? Assign(g, subset, aromatic, m)
                           : CopyAndAssign(g, subset, aromatic, m));
        }
예제 #2
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()));
        }
예제 #3
0
        public void Simple_maximal()
        {
            Graph    g = Graph.FromSmiles("cccc");
            Matching m = MaximumMatching.Maximal(g);

            Assert.IsTrue(Compares.AreOrderLessDeepEqual(
                              new[] { Tuple.Of(0, 1), Tuple.Of(2, 3) },
                              m.GetMatches()));
        }
예제 #4
0
        public void Furan()
        {
            Graph    g = Graph.FromSmiles("o1cccc1");
            IntSet   s = IntSet.AllOf(1, 2, 3, 4); // exclude the oxygen
            Matching m = Matching.CreateEmpty(g);

            MaximumMatching.Maximise(g, m, 0, s);
            Assert.IsTrue(Compares.AreOrderLessDeepEqual(
                              new[] { Tuple.Of(1, 2), Tuple.Of(3, 4) },
                              m.GetMatches()));
        }
예제 #5
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()));
        }
예제 #6
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()));
        }
예제 #7
0
        [TestMethod()] public void Imidazole()
        {
            Graph    g = Graph.FromSmiles("[nH]1ccnc1");
            Matching m = Matching.CreateEmpty(g);

            MaximumMatching.Maximise(g,
                                     m,
                                     0,
                                     IntSet.AllOf(1, 2, 3, 4)); // not the 'nH'
            Assert.IsTrue(Compares.AreOrderLessDeepEqual(
                              new[] { Tuple.Of(1, 2), Tuple.Of(3, 4) },
                              m.GetMatches()));
        }
예제 #8
0
        [TestMethod()] public void Quinone()
        {
            Graph    g = Graph.FromSmiles("Oc1ccc(o)cc1");
            Matching m = MaximumMatching.Maximal(g);

            Assert.IsTrue(Compares.AreOrderLessDeepEqual(
                              new[] {
                Tuple.Of(0, 1),
                Tuple.Of(2, 3),
                Tuple.Of(4, 5),
                Tuple.Of(6, 7),
            },
                              m.GetMatches()));
        }
예제 #9
0
        public void Quinone_subset()
        {
            Graph g = Graph.FromSmiles("Oc1ccc(o)cc1");
            // mocks the case where the oxygen atoms are already double bonded - we
            // therefore don't include those of the adjacent carbons in the vertex
            // subset to be matched
            Matching m = Matching.CreateEmpty(g);

            MaximumMatching.Maximise(g, m, 0, IntSet.AllOf(2, 3, 6, 7));
            Assert.IsTrue(Compares.AreOrderLessDeepEqual(
                              new[] {
                Tuple.Of(2, 3),
                Tuple.Of(6, 7),
            },
                              m.GetMatches()));
        }
예제 #10
0
        [TestMethod()] public void Benzimidazole()
        {
            Graph    g = Graph.FromSmiles("c1nc2ccccc2[nH]1");
            Matching m = Matching.CreateEmpty(g);

            MaximumMatching.Maximise(g,
                                     m,
                                     0,
                                     IntSet.NoneOf(8)); // not the 'nH'
            Assert.IsTrue(Compares.AreOrderLessDeepEqual(
                              new[] {
                Tuple.Of(0, 1),
                Tuple.Of(2, 3),
                Tuple.Of(4, 5),
                Tuple.Of(6, 7),
            },
                              m.GetMatches()));
        }
예제 #11
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()));
        }
예제 #12
0
        public static Graph Resonate(Graph g, BitArray cyclic, bool ordered)
        {
            BitArray subset = new BitArray(g.Order);

            for (int u = BitArrays.NextSetBit(cyclic, 0); u >= 0; u = BitArrays.NextSetBit(cyclic, u + 1))
            {
                // candidates must have a bonded
                // valence of one more than their degree
                // and in a ring
                int uExtra = g.BondedValence(u) - g.Degree(u);
                if (uExtra > 0)
                {
                    int  other  = -1;
                    Edge target = null;

                    int d = g.Degree(u);
                    for (int j = 0; j < d; ++j)
                    {
                        Edge e = g.EdgeAt(u, j);
                        int  v = e.Other(u);
                        // check for bond validity
                        if (e.Bond.Order == 2)
                        {
                            int vExtra = g.BondedValence(v) - g.Degree(v);
                            if (cyclic[v] && vExtra > 0)
                            {
                                if (HasAdjDirectionalLabels(g, e, cyclic) && !InSmallRing(g, e))
                                {
                                    other = -1;
                                    break;
                                }
                                if (vExtra > 1 && HasAdditionalCyclicDoubleBond(g, cyclic, u, v))
                                {
                                    other = -1;
                                    break;
                                }
                                if (other == -1)
                                {
                                    other  = v; // first one
                                    target = e;
                                }
                                else
                                {
                                    other = -2; // found more than one
                                }
                            }
                            // only one double bond don't check any more
                            if (uExtra == 1)
                            {
                                break;
                            }
                        }
                    }

                    if (other >= 0)
                    {
                        subset.Set(u, true);
                        subset.Set(other, true);
                        target.SetBond(Bond.Implicit);
                    }
                }
            }

            if (!ordered)
            {
                g = g.Sort(new Graph.CanOrderFirst());
            }

            Matching m        = Matching.CreateEmpty(g);
            int      n        = BitArrays.Cardinality(subset);
            int      nMatched = ArbitraryMatching.Dfs(g, m, subset);

            if (nMatched < n)
            {
                if (n - nMatched == 2)
                {
                    nMatched = ArbitraryMatching.AugmentOnce(g, m, nMatched, subset);
                }
                if (nMatched < n)
                {
                    nMatched = MaximumMatching.Maximise(g, m, nMatched, IntSet.FromBitArray(subset));
                }
                if (nMatched < n)
                {
                    throw new ApplicationException("Could not Kekulise");
                }
            }

            // assign new double bonds
            for (int v = BitArrays.NextSetBit(subset, 0); v >= 0; v = BitArrays.NextSetBit(subset, v + 1))
            {
                int w = m.Other(v);
                subset.Set(w, false);
                g.CreateEdge(v, w).SetBond(Bond.Double);
            }

            return(g);
        }
예제 #13
0
        /// <summary>
        /// Utility to maximise an existing matching of the provided graph.
        /// </summary>
        /// <param name="g">a graph</param>
        /// <param name="m">matching on the graph, will me modified</param>
        /// <param name="n">current matching cardinality</param>
        /// <param name="s">subset of vertices to match</param>
        /// <returns>the maximal matching on the graph</returns>
        public static int Maximise(Graph g, Matching m, int n, IntSet s)
        {
            MaximumMatching mm = new MaximumMatching(g, m, n, s);

            return(mm.nMatched);
        }