public void MergeSort() { int n = 100; // random (unique) values in random order Random rnd = new Random(); ICollection <long> values = new HashSet <long>(); while (values.Count < n) { values.Add((long)(((ulong)((uint)rnd.Next()) << 32) + ((uint)rnd.Next()))); } long[] prev = values.ToArray(); // ident array int[] vs = new int[n]; for (int i = 0; i < n; i++) { vs[i] = i; } InvariantRanker invRanker = new InvariantRanker(n); invRanker.SortBy(vs, 0, n, prev, prev); // check they are sorted for (int i = 1; i < n; i++) { Assert.IsTrue(prev[vs[i]] > prev[vs[i - 1]]); } }
public void InsertionSort_range() { long[] prev = new long[] { 12, 11, 10, 9, 8, 7 }; long[] curr = new long[] { 12, 11, 10, 9, 8, 7 }; int[] vs = new int[] { 0, 1, 2, 3, 4, 5 }; InvariantRanker.InsertionSortBy(vs, 2, 3, curr, prev); Assert.IsTrue(Compares.AreEqual(new int[] { 0, 1, 4, 3, 2, 5 }, vs)); }
public void Less() { long[] prev = new long[] { 1, 1, 2, 2 }; long[] curr = new long[] { 1, 1, 2, 2 }; Assert.IsFalse(InvariantRanker.Less(0, 1, curr, prev)); Assert.IsFalse(InvariantRanker.Less(2, 3, curr, prev)); Assert.IsTrue(InvariantRanker.Less(0, 2, curr, prev)); Assert.IsTrue(InvariantRanker.Less(0, 3, curr, prev)); Assert.IsTrue(InvariantRanker.Less(1, 2, curr, prev)); Assert.IsTrue(InvariantRanker.Less(1, 3, curr, prev)); }
public void LessUsingPrev() { long[] prev = new long[] { 1, 1, 2, 2 }; long[] curr = new long[] { 1, 2, 1, 2 }; // 0,1 and 2,3 are only less is we inspect the 'curr' invariants Assert.IsTrue(InvariantRanker.Less(0, 1, curr, prev)); Assert.IsTrue(InvariantRanker.Less(2, 3, curr, prev)); // these values are only less inspecting the first invariants Assert.IsTrue(InvariantRanker.Less(0, 2, curr, prev)); Assert.IsTrue(InvariantRanker.Less(0, 3, curr, prev)); Assert.IsTrue(InvariantRanker.Less(1, 2, curr, prev)); Assert.IsTrue(InvariantRanker.Less(1, 3, curr, prev)); }
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)); }
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)); }
/// <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); }