public void Rank_all_equiv() { InvariantRanker ranker = new InvariantRanker(6); long[] prev = new long[] { 1, 1, 1, 1, 1, 1 }; long[] curr = new long[] { 42, 42, 42, 42, 42, 42 }; // no we leave extra space int[] vs = new int[] { 0, 1, 2, 3, 4, 5 }; int[] ws = new int[6]; int ranks = ranker.Rank(vs, ws, 6, curr, prev); Assert.AreEqual(1, ranks); // assigned ranks (note: unique assigned first) Assert.IsTrue(Compares.AreEqual(new long[] { 1, 1, 1, 1, 1, 1 }, prev)); // remaining non-unique vertices Assert.IsTrue(Compares.AreEqual(new int[] { 0, 1, 2, 3, 4, 5 }, ws)); }
public void Rank_all_unique() { InvariantRanker ranker = new InvariantRanker(7); long[] prev = new long[] { 1, 1, 1, 1, 1, 1, 1 }; long[] curr = new long[] { 7, 3, 1, 0, 91, 32, 67 }; // no we leave extra space int[] vs = new int[] { 0, 1, 2, 3, 4, 5, 6 }; int[] ws = new int[7]; int ranks = ranker.Rank(vs, ws, 7, curr, prev); Assert.AreEqual(7, ranks); // assigned ranks (note: unique assigned first) Assert.IsTrue(Compares.AreEqual(new long[] { 4, 3, 2, 1, 7, 5, 6 }, prev)); // no non-unique vertices Assert.IsTrue(Compares.AreEqual(new int[] { -1, 0, 0, 0, 0, 0, 0 }, ws)); }
/// <summary> /// Internal - refine invariants to a canonical labelling and symmetry classes. /// </summary> /// <param name="invariants">the invariants to refine (canonical labelling gets written here)</param> /// <param name="hydrogens">binary vector of terminal hydrogens</param> /// <returns>the symmetry classes</returns> private long[] Refine(long[] invariants, bool[] hydrogens) { int ord = g.Length; InvariantRanker ranker = new InvariantRanker(ord); // current/next vertices, these only hold the vertices which are // equivalent int[] currVs = new int[ord]; int[] nextVs = new int[ord]; // fill with identity (also set number of non-unique) int nnu = ord; for (int i = 0; i < ord; i++) { currVs[i] = i; } long[] prev = invariants; long[] curr = Arrays.CopyOf(invariants, ord); // initially all labels are 1, the input invariants are then used to // refine this coarse partition Arrays.Fill(prev, 1L); // number of ranks int n = 0, m = 0; // storage of symmetry classes long[] symmetry = null; while (n < ord) { // refine the initial invariants using product of primes from // adjacent ranks while ((n = ranker.Rank(currVs, nextVs, nnu, curr, prev)) > m && n < ord) { nnu = 0; for (int i = 0; i < ord && nextVs[i] >= 0; i++) { int v = nextVs[i]; currVs[nnu++] = v; curr[v] = hydrogens[v] ? prev[v] : PrimeProduct(g[v], prev, hydrogens); } m = n; } if (symmetry == null) { // After symmetry classes have been found without hydrogens we add // back in the hydrogens and assign ranks. We don't refine the // partition until the next time round the while loop to avoid // artificially splitting due to hydrogen representation, for example // the two hydrogens are equivalent in this SMILES for ethane '[H]CC' for (int i = 0; i < g.Length; i++) { if (hydrogens[i]) { curr[i] = prev[g[i][0]]; hydrogens[i] = false; } } n = ranker.Rank(currVs, nextVs, nnu, curr, prev); symmetry = Arrays.CopyOf(prev, ord); // Update the buffer of non-unique vertices as hydrogens next // to discrete heavy atoms are also discrete (and removed from // 'nextVs' during ranking. nnu = 0; for (int i = 0; i < ord && nextVs[i] >= 0; i++) { currVs[nnu++] = nextVs[i]; } } // partition is discrete or only symmetry classes are needed if (symOnly || n == ord) { return(symmetry); } // artificially split the lowest cell, we perturb the value // of all vertices with equivalent rank to the lowest non-unique // vertex int lo = nextVs[0]; for (int i = 1; i < ord && nextVs[i] >= 0 && prev[nextVs[i]] == prev[lo]; i++) { prev[nextVs[i]]++; } // could also swap but this is cleaner Array.Copy(nextVs, 0, currVs, 0, nnu); } return(symmetry); }