Пример #1
0
            /// <inheritdoc/>
            public Cycles Find(IAtomContainer molecule, int length)
            {
                var bondMap    = EdgeToBondMap.WithSpaceFor(molecule);
                var graph      = GraphUtil.ToAdjList(molecule, bondMap);
                var ringSearch = new RingSearch(molecule, graph);

                var walks = new List <int[]>(6);

                // all isolated cycles are relevant - all we need to do is walk around
                // the vertices in the subset 'isolated'
                foreach (var isolated in ringSearch.Isolated())
                {
                    if (isolated.Length <= length)
                    {
                        walks.Add(GraphUtil.Cycle(graph, isolated));
                    }
                }

                // each biconnected component which isn't an isolated cycle is processed
                // separately as a subgraph.
                foreach (var fused in ringSearch.Fused())
                {
                    // make a subgraph and 'apply' the cycle computation - the walk
                    // (path) is then lifted to the original graph
                    foreach (var cycle in Apply(GraphUtil.Subgraph(graph, fused), length))
                    {
                        walks.Add(Lift(cycle, fused));
                    }
                }

                return(new Cycles(walks.ToArray(), molecule, bondMap));
            }
Пример #2
0
        /// <summary>
        /// Find and mark all cyclic atoms and bonds in the provided molecule. This optimised version
        /// allows the caller to optionally provided indexed fast access structure which would otherwise
        /// be created.
        /// </summary>
        /// <param name="mol">molecule</param>
        /// <param name="adjList"></param>
        /// <param name="bondMap"></param>
        /// <returns>Number of rings found (circuit rank)</returns>
        /// <seealso cref="IMolecularEntity.IsInRing"/>
        /// <seealso href="https://en.wikipedia.org/wiki/Circuit_rank">Circuit Rank</seealso>
        public static int MarkRingAtomsAndBonds(IAtomContainer mol, int[][] adjList, EdgeToBondMap bondMap)
        {
            var ringSearch = new RingSearch(mol, adjList);

            for (int v = 0; v < mol.Atoms.Count; v++)
            {
                mol.Atoms[v].IsInRing = false;
                foreach (var w in adjList[v])
                {
                    // note we only mark the bond on second visit (first v < w) and
                    // clear flag on first visit (or if non-cyclic)
                    if (v > w && ringSearch.Cyclic(v, w))
                    {
                        bondMap[v, w].IsInRing = true;
                        mol.Atoms[v].IsInRing  = true;
                        mol.Atoms[w].IsInRing  = true;
                    }
                    else
                    {
                        bondMap[v, w].IsInRing = false;
                    }
                }
            }
            return(ringSearch.NumRings);
        }
Пример #3
0
        public virtual void TestToAdjList_withMap()
        {
            IAtomContainer container = Simple;

            EdgeToBondMap map = new EdgeToBondMap();

            int[][] adjacent = GraphUtil.ToAdjList(container, map);
            Assert.AreEqual(5, adjacent.Length, "adjacency list should have 5 vertices");

            Assert.AreEqual(1, adjacent[0].Length, "vertex 'a' should have degree 1");
            Assert.AreEqual(3, adjacent[1].Length, "vertex 'b' should have degree 3");
            Assert.AreEqual(2, adjacent[2].Length, "vertex 'c' should have degree 2");
            Assert.AreEqual(1, adjacent[3].Length, "vertex 'd' should have degree 1");
            Assert.AreEqual(1, adjacent[4].Length, "vertex 'e' should have degree 1");

            Assert.IsTrue(Compares.AreDeepEqual(new int[] { 1 }, adjacent[0]));
            Assert.IsTrue(Compares.AreDeepEqual(new int[] { 0, 2, 4 }, adjacent[1]));
            Assert.IsTrue(Compares.AreDeepEqual(new int[] { 1, 3 }, adjacent[2]));
            Assert.IsTrue(Compares.AreDeepEqual(new int[] { 2 }, adjacent[3]));
            Assert.IsTrue(Compares.AreDeepEqual(new int[] { 1 }, adjacent[4]));

            Assert.IsNotNull(map[0, 1]);
            Assert.IsNotNull(map[1, 2]);

            Assert.AreSame(map[0, 1], map[1, 0]);
            Assert.AreSame(map[1, 2], map[2, 1]);
        }
Пример #4
0
 /// <summary>
 /// Obtain the bond between the atoms at index <paramref name="u"/> and 'v'. If the 'bondMap'
 /// is non-null it is used for direct lookup otherwise the slower linear
 /// lookup in 'container' is used.
 /// </summary>
 /// <param name="container">a structure</param>
 /// <param name="bondMap">optimised map of atom indices to bond instances</param>
 /// <param name="u">an atom index</param>
 /// <param name="v">an atom index (connected to u)</param>
 /// <returns>the bond between u and v</returns>
 private static IBond GetBond(IAtomContainer container, EdgeToBondMap bondMap, int u, int v)
 {
     if (bondMap != null)
     {
         return(bondMap[u, v]);
     }
     return(container.GetBond(container.Atoms[u], container.Atoms[v]));
 }
Пример #5
0
        /// <summary>
        /// Internal - convert a set of cycles to an ring set.
        /// </summary>
        /// <param name="container">molecule</param>
        /// <param name="cycles">a cycle of the chemical graph</param>
        /// <param name="bondMap">mapping of the edges (int,int) to the bonds of the container</param>
        /// <returns>the ring set</returns>
        private static IRingSet ToRingSet(IAtomContainer container, int[][] cycles, EdgeToBondMap bondMap)
        {
            // note currently no way to say the size of the RingSet
            // even through we know it
            var builder = container.Builder;
            var rings   = builder.NewRingSet();

            foreach (var cycle in cycles)
            {
                rings.Add(ToRing(container, cycle, bondMap));
            }

            return(rings);
        }
Пример #6
0
        /// <summary>
        /// Internal - convert a set of cycles to a ring.
        /// </summary>
        /// <param name="container">molecule</param>
        /// <param name="cycle">a cycle of the chemical graph</param>
        /// <param name="bondMap">mapping of the edges (int,int) to the bonds of the container</param>
        /// <returns>the ring for the specified cycle</returns>
        private static IRing ToRing(IAtomContainer container, int[] cycle, EdgeToBondMap bondMap)
        {
            var atoms = new IAtom[cycle.Length - 1];
            var bonds = new IBond[cycle.Length - 1];

            for (int i = 1; i < cycle.Length; i++)
            {
                int v = cycle[i];
                int u = cycle[i - 1];
                atoms[i - 1] = container.Atoms[u];
                bonds[i - 1] = GetBond(container, bondMap, u, v);
            }

            var builder = container.Builder;
            var ring    = builder.NewAtomContainer(atoms, bonds);

            return(builder.NewRing(ring));
        }
Пример #7
0
        /// <summary>
        /// Create an adjacent list representation of the <paramref name="container"/> and
        /// fill in the <paramref name="bondMap"/> for quick lookup.
        /// </summary>
        /// <param name="container">the molecule</param>
        /// <param name="bondMap">a map to index the bonds into</param>
        /// <returns>adjacency list representation stored as an <see cref="int"/>[][].</returns>
        /// <exception cref="ArgumentNullException">the container was null</exception>
        /// <exception cref="ArgumentException">a bond was found which contained atoms not in the molecule</exception>
        public static int[][] ToAdjList(IAtomContainer container, EdgeToBondMap bondMap)
        {
            if (container == null)
            {
                throw new ArgumentNullException(nameof(container));
            }

            int n = container.Atoms.Count;

            var graph = new List <int> [n];

            for (var i = 0; i < n; i++)
            {
                graph[i] = new List <int>();
            }

            foreach (var bond in container.Bonds)
            {
                int v = container.Atoms.IndexOf(bond.Begin);
                int w = container.Atoms.IndexOf(bond.End);

                if (v < 0 || w < 0)
                {
                    throw new ArgumentException($"bond at index {container.Bonds.IndexOf(bond)} contained an atom not present in molecule");
                }

                graph[v].Add(w);
                graph[w].Add(v);

                bondMap?.Add(v, w, bond);
            }

            var agraph = new int[n][];

            for (int v = 0; v < n; v++)
            {
                agraph[v] = graph[v].ToArray();
            }

            return(agraph);
        }
Пример #8
0
 /// <summary>
 /// Internal constructor - may change in future but currently just takes the
 /// cycle paths and the container from which they came.
 /// </summary>
 /// <param name="paths">the cycle paths (closed vertex walks)</param>
 /// <param name="container">the input container</param>
 /// <param name="bondMap"></param>
 private Cycles(int[][] paths, IAtomContainer container, EdgeToBondMap bondMap)
 {
     this.paths     = paths;
     this.container = container;
     this.bondMap   = bondMap;
 }
Пример #9
0
        /// <summary>
        /// Find and mark all cyclic atoms and bonds in the provided molecule.
        /// </summary>
        /// <param name="mol">molecule</param>
        /// <returns>Number of rings found (circuit rank)</returns>
        /// <seealso cref="IMolecularEntity.IsInRing"/>
        /// <seealso href="https://en.wikipedia.org/wiki/Circuit_rank">Circuit Rank</seealso>
        public static int MarkRingAtomsAndBonds(IAtomContainer mol)
        {
            var bonds = EdgeToBondMap.WithSpaceFor(mol);

            return(MarkRingAtomsAndBonds(mol, GraphUtil.ToAdjList(mol, bonds), bonds));
        }