private long [ ] refine ( long [ ] invariants , boolean [ ] 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 System . arraycopy ( nextVs , 0 , currVs , 0 , nnu ) ; } return symmetry ; }
Internal - refine invariants to a canonical labelling and symmetry classes .