private static bool HasAdjDirectionalLabels(Graph g, Edge e) { int u = e.Either(); int v = e.Other(u); return(HasAdjDirectionalLabels(g, u) && HasAdjDirectionalLabels(g, v)); }
/// <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; }
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); } } }
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); }
/// <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); }
/// <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); }
private void SetDirection(Edge e, int u, Bond b) { if (e.Either() == u) { e.SetBond(b); } else { e.SetBond(b.Inverse()); } }
/// <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++; }
/// <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); }
/// <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"); } }
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))); }
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! } }