private static bool HasAdjDirectionalLabels(Graph g, Edge e)
            {
                int u = e.Either();
                int v = e.Other(u);

                return(HasAdjDirectionalLabels(g, u) && HasAdjDirectionalLabels(g, v));
            }
Esempio n. 2
0
        /// <summary>
        /// Replace an edge in the graph.
        /// </summary>
        /// <param name="org">the original edge</param>
        /// <param name="rep">the replacement</param>
        internal void Replace(Edge org, Edge rep)
        {
            int u = org.Either();
            int v = org.Other(u);

            for (int i = 0; i < degrees[u]; i++)
            {
                if (edges[u][i] == org)
                {
                    edges[u][i] = rep;
                }
            }

            for (int i = 0; i < degrees[v]; i++)
            {
                if (edges[v][i] == org)
                {
                    edges[v][i] = rep;
                }
            }

            int ord = rep.Bond.Order - org.Bond.Order;

            valences[u] += ord;
            valences[v] += ord;
        }
Esempio n. 3
0
        private static bool HasAdjDirectionalLabels(Graph g, Edge e, BitArray cyclic)
        {
            int u = e.Either();
            int v = e.Other(u);

            return(HasAdjDirectionalLabels(g, u, cyclic) && HasAdjDirectionalLabels(g, v, cyclic));
        }
            private void Flip(Graph g, Edge e, BitArray dbAtoms)
            {
                var u = e.Either();
                var v = e.Other(u);

                if (ordering[u] < ordering[v])
                {
                    var first = FirstDirectionalLabel(g, u);
                    if (first != null)
                    {
                        Flip(first, u, dbAtoms);
                    }
                    else
                    {
                        first = FirstDirectionalLabel(g, v);
                        Flip(first, v, dbAtoms);
                    }
                }
                else
                {
                    var first = FirstDirectionalLabel(g, v);
                    if (first != null)
                    {
                        Flip(first, v, dbAtoms);
                    }
                    else
                    {
                        first = FirstDirectionalLabel(g, u);
                        Flip(first, u, dbAtoms);
                    }
                }
            }
Esempio n. 5
0
        private static bool IsRedundantDirectionalEdge(Graph g, Edge edge, BitArray unspecified)
        {
            if (!edge.Bond.IsDirectional)
            {
                return(false);
            }
            int u = edge.Either();
            int v = edge.Other(u);

            if (!unspecified[u])
            {
                foreach (Edge f in g.GetEdges(u))
                {
                    if (f.Bond.IsDirectional && edge != f)
                    {
                        return(true);
                    }
                }
            }
            else if (!unspecified[v])
            {
                foreach (Edge f in g.GetEdges(v))
                {
                    if (f.Bond.IsDirectional && edge != f)
                    {
                        return(true);
                    }
                }
            }
            return(false);
        }
Esempio n. 6
0
        /// <summary>
        /// Given a double bond edge traverse the neighbors of both endpoints and
        /// accumulate any explicit replacements in the 'acc' accumulator.
        /// </summary>
        /// <param name="g">  the chemical graph</param>
        /// <param name="e">  a edge in the graph </param>('double bond type')
        /// <param name="ordering"></param>
        /// <param name="acc">accumulator for new edges</param>
        /// <exception cref="InvalidSmilesException">thrown if the edge could not be converted</exception>
        private static void RemoveRedundant(Graph g,
                                            Edge e,
                                            int[] ordering,
                                            Dictionary <Edge, Edge> acc)
        {
            int u = e.Either(), v = e.Other(u);

            ReplaceImplWithExpl(g, e, u, ordering, acc);
            ReplaceImplWithExpl(g, e, v, ordering, acc);
        }
Esempio n. 7
0
        /// <summary>
        /// Given a double bond edge traverse the neighbors of both endpoints and
        /// accumulate any explicit replacements in the <paramref name="e"/> accumulator.
        /// </summary>
        /// <param name="g">  the chemical graph</param>
        /// <param name="e">  a edge in the graph </param>('double bond type')
        /// <param name="acc">accumulator for new edges</param>
        /// <exception cref="InvalidSmilesException">thrown if the edge could not be converted</exception>
        private bool ReplaceImplWithExpl(Graph g,
                                         Edge e,
                                         Dictionary <Edge, Edge> acc)
        {
            int u = e.Either(), v = e.Other(u);

            bool uDone = ReplaceImplWithExpl(g, e, u, acc);
            bool vDone = ReplaceImplWithExpl(g, e, v, acc);

            return(uDone || vDone);
        }
Esempio n. 8
0
 private void SetDirection(Edge e, int u, Bond b)
 {
     if (e.Either() == u)
     {
         e.SetBond(b);
     }
     else
     {
         e.SetBond(b.Inverse());
     }
 }
Esempio n. 9
0
        /// <summary>
        /// Add an labelled edge to the graph.
        /// </summary>
        /// <param name="e">new edge</param>
        public void AddEdge(Edge e)
        {
            int u = e.Either(), v = e.Other(u);

            EnsureEdgeCapacity(u);
            EnsureEdgeCapacity(v);
            edges[u][degrees[u]++] = e;
            edges[v][degrees[v]++] = e;
            int ord = e.Bond.Order;

            valences[u] += ord;
            valences[v] += ord;
            size++;
        }
Esempio n. 10
0
        /// <summary>
        /// Add an edge to the graph.
        /// </summary>
        /// <param name="e">the edge to add</param>
        /// <returns>graph builder for adding more atoms/connections</returns>
        public GraphBuilder Add(Edge e)
        {
            Bond b = e.Bond;
            int  u = e.Either();
            int  v = e.Other(u);

            if (b == Bond.Single && (!g.GetAtom(u).IsAromatic() || !g.GetAtom(v).IsAromatic()))
            {
                e.SetBond(Bond.Implicit);
            }
            else if (b == Bond.Aromatic && g.GetAtom(u).IsAromatic() && g.GetAtom(v).IsAromatic())
            {
                e.SetBond(Bond.Implicit);
            }
            g.AddEdge(e);
            valence[u] += b.Order;
            valence[v] += b.Order;
            return(this);
        }
Esempio n. 11
0
        /// <summary>
        /// Given a double bond edge traverse the neighbors of one of the endpoints
        /// and accumulate any explicit replacements in the 'acc' accumulator.
        /// </summary>
        /// <param name="g">  the chemical graph</param>
        /// <param name="e">  a edge in the graph </param>('double bond type')
        /// <param name="u">  a endpoint of the edge 'e'</param>
        /// <param name="ordering"></param>
        /// <param name="acc">accumulator for new edges</param>
        /// <exception cref="InvalidSmilesException">thrown if the edge could not be converted</exception>
        private static void ReplaceImplWithExpl(Graph g,
                                                Edge e,
                                                int u,
                                                int[] ordering,
                                                Dictionary <Edge, Edge> acc)
        {
            ICollection <Edge> edges = new SortedSet <Edge>(new S(e, u, ordering));

            foreach (var f in g.GetEdges(u))
            {
                var aa = f.Bond;
                if (aa == Bond.Double)
                {
                    if (!f.Equals(e))
                    {
                        return;
                    }
                }
                else if (aa == Bond.Up || aa == Bond.Down)
                {
                    edges.Add(f);
                }
            }

            if (edges.Count == 2)
            {
                Edge explicit_ = edges.First();
                int  v         = explicit_.Either();
                int  w         = explicit_.Other(v);
                acc[explicit_] = new Edge(v, w, Bond.Implicit);
            }
            else if (edges.Count > 2)
            {
                throw new InvalidSmilesException("Too many up/down bonds on double bonded atom");
            }
        }
Esempio n. 12
0
        internal static bool InSmallRing(Graph g, Edge e)
        {
            BitArray visit = new BitArray(g.Order);

            return(InSmallRing(g, e.Either(), e.Other(e.Either()), e.Other(e.Either()), 1, new BitArray(g.Order)));
        }
Esempio n. 13
0
        private void AssignDirectionalLabels()
        {
            if (!builders.Any())
            {
                return;
            }

            // handle extended geometric configurations first

            var buildersToRemove = new List <GeometricBuilder>();

            foreach (var builder in builders)
            {
                if (!builder.Extended)
                {
                    continue;
                }
                buildersToRemove.Add(builder);
                Edge e = FindDoubleBond(g, builder.u);
                Edge f = FindDoubleBond(g, builder.v);
                if (e == null || f == null)
                {
                    continue;
                }
                Edge eRef = g.CreateEdge(builder.u, builder.X);
                Edge fRef = g.CreateEdge(builder.v, builder.Y);
                Edge eLab = FindBondToLabel(g, builder.u);
                Edge fLab = FindBondToLabel(g, builder.v);
                // adjust for reference
                Configuration.ConfigurationDoubleBond config = builder.c;
                if ((eLab == eRef) != (fRef == fLab))
                {
                    if (config == Configuration.ConfigurationDoubleBond.Together)
                    {
                        config = Configuration.ConfigurationDoubleBond.Opposite;
                    }
                    else if (config == Configuration.ConfigurationDoubleBond.Opposite)
                    {
                        config = Configuration.ConfigurationDoubleBond.Together;
                    }
                }
                if (eLab.Bond.IsDirectional)
                {
                    if (fLab.Bond.IsDirectional)
                    {
                        // can't do anything, may be incorrect
                    }
                    else
                    {
                        if (config == Configuration.ConfigurationDoubleBond.Together)
                        {
                            SetDirection(fLab, builder.v, eLab.GetBond(builder.u));
                        }
                        else if (config == Configuration.ConfigurationDoubleBond.Opposite)
                        {
                            SetDirection(fLab, builder.v, eLab.GetBond(builder.u));
                        }
                    }
                }
                else
                {
                    if (fLab.Bond.IsDirectional)
                    {
                        if (config == Configuration.ConfigurationDoubleBond.Together)
                        {
                            SetDirection(eLab, builder.v, fLab.GetBond(builder.u));
                        }
                        else if (config == Configuration.ConfigurationDoubleBond.Opposite)
                        {
                            SetDirection(eLab, builder.v, fLab.GetBond(builder.u));
                        }
                    }
                    else
                    {
                        SetDirection(eLab, builder.u, Bond.Down);
                        if (config == Configuration.ConfigurationDoubleBond.Together)
                        {
                            SetDirection(fLab, builder.v, Bond.Down);
                        }
                        else if (config == Configuration.ConfigurationDoubleBond.Opposite)
                        {
                            SetDirection(fLab, builder.v, Bond.Up);
                        }
                    }
                }
            }
            foreach (var builder in buildersToRemove)
            {
                builders.Remove(builder);
            }

            if (!builders.Any())
            {
                return;
            }

            // store the vertices which are adjacent to pi bonds with a config
            BitArray pibonded    = new BitArray(g.Order);
            BitArray unspecified = new BitArray(g.Order);
            var      unspecEdges = new HashSet <Edge>();

            // clear existing directional labels, if build is called multiple times
            // this can cause problems
            if (g.GetFlags(Graph.HAS_BND_STRO) != 0)
            {
                foreach (Edge edge in g.Edges)
                {
                    if (edge.Bond.IsDirectional)
                    {
                        edge.SetBond(Bond.Implicit);
                    }
                }
            }

            foreach (Edge e in g.Edges)
            {
                int u = e.Either();
                int v = e.Other(u);
                if (e.Bond.Order == 2 && g.Degree(u) >= 2 && g.Degree(v) >= 2)
                {
                    unspecified.Set(u, true);
                    unspecified.Set(v, true);
                    pibonded.Set(u, true);
                    pibonded.Set(v, true);
                    unspecEdges.Add(e);
                }
            }

            foreach (var builder in builders)
            {
                g.AddFlags(Graph.HAS_BND_STRO);

                // unspecified only used for getting not setting configuration
                if (builder.c == Configuration.ConfigurationDoubleBond.Unspecified)
                {
                    continue;
                }
                CheckGeometricBuilder(builder); // check required vertices are adjacent

                int u = builder.u, v = builder.v, x = builder.X, y = builder.Y;

                if (x == y)
                {
                    continue;
                }

                unspecEdges.Remove(g.CreateEdge(u, v));
                unspecified.Set(u, false);
                unspecified.Set(v, false);

                Fix(g, u, v, pibonded);
                Fix(g, v, u, pibonded);

                Bond first  = FirstDirectionalLabel(u, x, pibonded);
                Bond second = builder.c == Configuration.ConfigurationDoubleBond.Together ? first : first.Inverse();

                // check if the second label would cause a conflict
                if (CheckDirectionalAssignment(second, v, y, pibonded))
                {
                    // okay to assign the labels as they are
                    g.Replace(g.CreateEdge(u, x), new Edge(u, x, first));
                    g.Replace(g.CreateEdge(v, y), new Edge(v, y, second));
                }
                // there will be a conflict - check if we invert the first one...
                else if (CheckDirectionalAssignment(first.Inverse(), u, x, pibonded))
                {
                    g.Replace(g.CreateEdge(u, x), new Edge(u, x, (first = first.Inverse())));
                    g.Replace(g.CreateEdge(v, y), new Edge(v, y, (second = second.Inverse())));
                }
                else
                {
                    BitArray visited = new BitArray(g.Order);
                    visited.Set(v, true);
                    InvertExistingDirectionalLabels(pibonded, visited, v, u);
                    if (!CheckDirectionalAssignment(first, u, x, pibonded) ||
                        !CheckDirectionalAssignment(second, v, y, pibonded))
                    {
                        throw new ArgumentException("cannot assign geometric configuration");
                    }
                    g.Replace(g.CreateEdge(u, x), new Edge(u, x, first));
                    g.Replace(g.CreateEdge(v, y), new Edge(v, y, second));
                }

                // propagate bond directions to other adjacent bonds
                foreach (var e in g.GetEdges(u))
                {
                    if (e.Bond != Bond.Double && !e.Bond.IsDirectional)
                    {
                        e.SetBond(e.Either() == u ? first.Inverse() : first);
                    }
                }
                foreach (var e in g.GetEdges(v))
                {
                    if (e.Bond != Bond.Double && !e.Bond.IsDirectional)
                    {
                        e.SetBond(e.Either() == v ? second.Inverse() : second);
                    }
                }
            }

            // unspecified pibonds should "not" have a configuration, if they
            // do we try to eliminate it
            foreach (Edge unspecEdge in unspecEdges)
            {
                int u = unspecEdge.Either();
                int v = unspecEdge.Other(u);
                // no problem if one side isn't defined
                if (!HasDirectional(g, u) || !HasDirectional(g, v))
                {
                    continue;
                }
                foreach (Edge e in g.GetEdges(u))
                {
                    if (IsRedundantDirectionalEdge(g, e, unspecified))
                    {
                        e.SetBond(Bond.Implicit);
                    }
                }
                if (!HasDirectional(g, u))
                {
                    continue;
                }
                foreach (Edge e in g.GetEdges(v))
                {
                    if (IsRedundantDirectionalEdge(g, e, unspecified))
                    {
                        e.SetBond(Bond.Implicit);
                    }
                }
                // if (hasDirectional(g, v))
                // could generate warning!
            }
        }