public static int getSymmetryOrder ( Map < Integer , Integer > alignment , Map < Integer , Integer > identity , final int maxSymmetry , final float minimumMetricChange ) { List < Integer > preimage = new ArrayList < Integer > ( alignment . keySet ( ) ) ; // currently unmodified List < Integer > image = new ArrayList < Integer > ( preimage ) ; int bestSymmetry = 1 ; double bestMetric = Double . POSITIVE_INFINITY ; //lower is better boolean foundSymmetry = false ; if ( debug ) { logger . trace ( "Symm\tPos\tDelta" ) ; } for ( int n = 1 ; n <= maxSymmetry ; n ++ ) { int deltasSq = 0 ; int numDeltas = 0 ; // apply alignment for ( int i = 0 ; i < image . size ( ) ; i ++ ) { Integer pre = image . get ( i ) ; Integer intermediate = ( pre == null ? null : alignment . get ( pre ) ) ; Integer post = ( intermediate == null ? null : identity . get ( intermediate ) ) ; image . set ( i , post ) ; if ( post != null ) { int delta = post - preimage . get ( i ) ; deltasSq += delta * delta ; numDeltas ++ ; if ( debug ) { logger . debug ( "%d\t%d\t%d\n" , n , preimage . get ( i ) , delta ) ; } } } // Metrics: RMS compensates for the trend of smaller numDeltas with higher order // Not normalizing by numDeltas favors smaller orders double metric = Math . sqrt ( ( double ) deltasSq / numDeltas ) ; // root mean squared distance if ( ! foundSymmetry && metric < bestMetric * minimumMetricChange ) { // n = 1 is never the best symmetry if ( bestMetric < Double . POSITIVE_INFINITY ) { foundSymmetry = true ; } bestSymmetry = n ; bestMetric = metric ; } // When debugging need to loop over everything. Unneeded in production if ( ! debug && foundSymmetry ) { break ; } } if ( foundSymmetry ) { return bestSymmetry ; } else { return 1 ; } }
Tries to detect symmetry in an alignment .