/// <summary> /// Create a stereo encoder for all potential 2D and 3D double bond stereo /// configurations. /// </summary> /// <param name="container">an atom container</param> /// <param name="graph">adjacency list representation of the container</param> /// <returns>a new encoder for tetrahedral elements</returns> public IStereoEncoder Create(IAtomContainer container, int[][] graph) { var encoders = new List <IStereoEncoder>(5); foreach (var bond in container.Bonds) { // if double bond and not E or Z query bond if (BondOrder.Double.Equals(bond.Order) && !BondStereo.EOrZ.Equals(bond.Stereo)) { IAtom left = bond.Begin; IAtom right = bond.End; // skip -N=N- double bonds which exhibit inversion if (7.Equals(left.AtomicNumber) && 7.Equals(right.AtomicNumber)) { continue; } IStereoEncoder encoder = NewEncoder(container, left, right, right, left, graph); if (encoder != null) { encoders.Add(encoder); } } } return(encoders.Count == 0 ? StereoEncoder.Empty : new MultiStereoEncoder(encoders)); }
/// <summary> /// Package-private method for generating the hash for the given molecule. /// The initial invariants are passed as to the method along with an /// adjacency list representation of the graph. /// </summary> /// <param name="current">initial invariants</param> /// <param name="encoder"></param> /// <param name="graph">adjacency list representation</param> /// <param name="suppressed"></param> /// <returns>hash codes for atoms</returns> public override long[] Generate(long[] current, IStereoEncoder encoder, int[][] graph, Suppressed suppressed) { int n = graph.Length; var next = Copy(current); // buffers for including adjacent invariants var unique = new long[n]; var included = new long[n]; while (encoder.Encode(current, next)) { Copy(next, current); } for (int d = 0; d < depth; d++) { for (int v = 0; v < n; v++) { next[v] = Next(graph, v, current, unique, included); } Copy(next, current); while (encoder.Encode(current, next)) { Copy(next, current); } } return(current); }
private long[] Generate(IAtomContainer container, long[] seeds, IStereoEncoder encoder, int[][] graph) { Suppressed suppressed = suppression.Suppress(container); // compute original values then find indices equivalent values long[] original = simple.Generate(seeds, encoder, graph, suppressed); var equivalentSet = finder.Find(original, container, graph); var equivalents = equivalentSet.ToArray(); // size of the matrix we need to make int n = original.Length; int m = equivalents.Length; // skip when there are no equivalent atoms if (m < 2) { return(original); } // matrix of perturbed values and identity values long[][] perturbed = Arrays.CreateJagged <long>(n, m + 1); // set the original values in the first column for (int i = 0; i < n; i++) { perturbed[i][0] = original[i]; } // systematically perturb equivalent vertex for (int i = 0; i < m; i++) { int equivalentIndex = equivalents[i]; // perturb the value and reset stereo configuration original[equivalentIndex] = Rotate(original[equivalentIndex]); encoder.Reset(); // compute new hash codes and copy the values a column in the matrix long[] tmp = simple.Generate(Copy(original), encoder, graph, suppressed); for (int j = 0; j < n; j++) { perturbed[j][i + 1] = tmp[j]; } // reset value original[equivalentIndex] = perturbed[equivalentIndex][0]; } return(Combine(perturbed)); }
private static IList <IStereoEncoder> ExtractEncoders(IStereoEncoder encoder) { if (encoder is MultiStereoEncoder) { FieldInfo field = null; field = encoder.GetType().GetField("encoders", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance); if (field == null) { Console.Error.WriteLine("Error on accessing encoders field."); return(null); } return((IList <IStereoEncoder>)field.GetValue(encoder)); } return(new IStereoEncoder[0]); }
private static GeometricParity GetGeometricParity(IStereoEncoder encoder) { if (encoder is GeometryEncoder) { FieldInfo field = null; field = encoder.GetType().GetField("geometric", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance); if (field == null) { Console.Error.WriteLine("Error on accessing geometric field."); return(null); } return((GeometricParity)field.GetValue(encoder)); } return(null); }
/// <summary> /// Package-private method for generating the hash for the given molecule. /// The initial invariants are passed as to the method along with an /// adjacency list representation of the graph. /// </summary> /// <param name="current">initial invariants</param> /// <param name="encoder"></param> /// <param name="graph">adjacency list representation</param> /// <param name="suppressed"></param> /// <returns>hash codes for atoms</returns> public override long[] Generate(long[] current, IStereoEncoder encoder, int[][] graph, Suppressed suppressed) { // for the stereo perception depending on how the // (BasicPermutationParity) is done we need to set the value to be as // high (or low) as possible foreach (var i in suppressed.ToArray()) { current[i] = long.MaxValue; } int n = graph.Length; long[] next = Copy(current); // buffers for including adjacent invariants long[] unique = new long[n]; long[] included = new long[n]; while (encoder.Encode(current, next)) { Copy(next, current); } for (int d = 0; d < depth; d++) { for (int v = 0; v < n; v++) { next[v] = Next(graph, v, current, unique, included, suppressed); } Copy(next, current); while (encoder.Encode(current, next)) { Copy(next, current); } } // zero all suppressed values so they are not combined in any molecule // hash foreach (var i in suppressed.ToArray()) { current[i] = 0L; } return(current); }
private static GeometricParity GetGeometricParity(IStereoEncoder encoder) { if (encoder is MultiStereoEncoder) { return(GetGeometricParity(ExtractEncoders(encoder)[0])); } else if (encoder is GeometryEncoder) { FieldInfo field = null; field = encoder.GetType().GetField("geometric", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance); if (field == null) { Console.Error.WriteLine("No geometric field found."); return(null); } return((GeometricParity)field.GetValue(encoder)); } return(null); }
public void TestCreate() { var m = new AtomContainer(); m.Atoms.Add(CarbonAt(-0.2994, 3.2084)); m.Atoms.Add(CarbonAt(-1.1244, 3.2084)); m.Atoms.Add(CarbonAt(-1.9494, 3.2084)); m.Atoms.Add(CarbonAt(-2.3619, 2.4939)); m.Atoms.Add(CarbonAt(0.1131, 3.9228)); m.Bonds.Add(new Bond(m.Atoms[0], m.Atoms[1], BondOrder.Double)); m.Bonds.Add(new Bond(m.Atoms[1], m.Atoms[2], BondOrder.Double)); m.Bonds.Add(new Bond(m.Atoms[2], m.Atoms[3])); m.Bonds.Add(new Bond(m.Atoms[0], m.Atoms[4])); IStereoEncoderFactory factory = new GeometricCumulativeDoubleBondFactory(); // graph not used IStereoEncoder encoder = factory.Create(m, null); Assert.IsInstanceOfType(encoder, typeof(MultiStereoEncoder)); }
/// <summary> /// Create a new conjugated encoder from a left and right encoder. /// </summary> /// <param name="left">encoder</param> /// <param name="right">encoder</param> public ConjugatedEncoder(IStereoEncoder left, IStereoEncoder right) { this.left = left; this.right = right; }
/// <summary> /// Internal method invoked by 'molecule' hash generators. /// </summary> /// <param name="current">the current invariants</param> /// <param name="encoder">encoder used for encoding stereo-chemistry</param> /// <param name="graph">adjacency list representation of the molecule</param> /// <param name="suppressed">bit set marks vertices which are 'suppressed' (may be ignored)</param> /// <returns>the atom hash values</returns> public abstract long[] Generate(long[] current, IStereoEncoder encoder, int[][] graph, Suppressed suppressed);
/// <summary> /// Create a stereo encoder for cumulative double bonds. /// </summary> /// <param name="container">the container</param> /// <param name="graph">adjacency list representation of the container</param> /// <returns>a stereo encoder</returns> public IStereoEncoder Create(IAtomContainer container, int[][] graph) { int n = container.Atoms.Count; BondMap map = new BondMap(n); var encoders = new List <IStereoEncoder>(1); // index double bonds by their atoms foreach (var bond in container.Bonds) { if (IsDoubleBond(bond)) { map.Add(bond); } } var visited = new HashSet <IAtom>(); // find atoms which are connected between two double bonds foreach (var a in map.Atoms) { var bonds = map.bonds[a]; if (bonds.Count == 2) { // (s)tart/(e)nd of cumulated system: -s=a=e- IAtom s = bonds[0].GetOther(a); IAtom e = bonds[1].GetOther(a); // need the parents to re-use the double bond encoder IAtom sParent = a; IAtom eParent = a; visited.Add(a); visited.Add(s); visited.Add(e); int size = 2; // expand out from 'l' while (s != null && map.Cumulated(s)) { IAtom p = map.bonds[s][0].GetOther(s); IAtom q = map.bonds[s][1].GetOther(s); sParent = s; s = visited.Add(p) ? p : visited.Add(q) ? q : null; size++; } // expand from 'r' while (e != null && map.Cumulated(e)) { IAtom p = map.bonds[e][0].GetOther(e); IAtom q = map.bonds[e][1].GetOther(e); eParent = e; e = visited.Add(p) ? p : visited.Add(q) ? q : null; size++; } // s and e are null if we had a cumulative cycle... if (s != null && e != null) { // system has now be expanded, size is the number of double // bonds. For odd numbers we use E/Z whilst for even are // axial M/P. // \ / // s = = = = e // / \ if (IsOdd(size)) { IStereoEncoder encoder = GeometricDoubleBondEncoderFactory.NewEncoder(container, s, sParent, e, eParent, graph); if (encoder != null) { encoders.Add(encoder); } } else { IStereoEncoder encoder = AxialEncoder(container, s, e); if (encoder != null) { encoders.Add(encoder); } } } } } return(encoders.Count == 0 ? StereoEncoder.Empty : new MultiStereoEncoder(encoders)); }