docs: public FingerprintSimilarity getFingerprintsSimilarity() {
          HashMap<Integer, Integer> offset_Score_Table = new HashMap<>(); // offset_Score_Table<offset,count>
          int numFrames;
          float score = 0;
          int mostSimilarFramePosition = Integer.MIN_VALUE;
  
          // one frame may contain several points, use the shorter one be the denominator
          if (fingerprint1.length > fingerprint2.length) {
              numFrames = FingerprintManager.getNumFrames(fingerprint2);
          } else {
              numFrames = FingerprintManager.getNumFrames(fingerprint1);
          }
  
          // get the pairs
          PairManager pairManager = new PairManager();
          HashMap<Integer, List<Integer>> this_Pair_PositionList_Table =
                          pairManager.getPair_PositionList_Table(fingerprint1);
          HashMap<Integer, List<Integer>> compareWave_Pair_PositionList_Table =
                          pairManager.getPair_PositionList_Table(fingerprint2);
  
          for (Integer compareWaveHashNumber : compareWave_Pair_PositionList_Table.keySet()) {
              // if the compareWaveHashNumber doesn't exist in both tables, no need to compare
              if (!this_Pair_PositionList_Table.containsKey(compareWaveHashNumber)
                              || !compareWave_Pair_PositionList_Table.containsKey(compareWaveHashNumber)) {
                  continue;
              }
  
              // for each compare hash number, get the positions
              List<Integer> wavePositionList = this_Pair_PositionList_Table.get(compareWaveHashNumber);
              List<Integer> compareWavePositionList = compareWave_Pair_PositionList_Table.get(compareWaveHashNumber);
  
              for (Integer thisPosition : wavePositionList) {
                  for (Integer compareWavePosition : compareWavePositionList) {
                      int offset = thisPosition - compareWavePosition;
                      if (offset_Score_Table.containsKey(offset)) {
                          offset_Score_Table.put(offset, offset_Score_Table.get(offset) + 1);
                      } else {
                          offset_Score_Table.put(offset, 1);
                      }
                  }
              }
          }
  
          // map rank
          MapRank mapRank = new MapRankInteger(offset_Score_Table, false);
  
          // get the most similar positions and scores	
          List<Integer> orderedKeyList = mapRank.getOrderedKeyList(100, true);
          if (orderedKeyList.size() > 0) {
              int key = orderedKeyList.get(0);
              // get the highest score position
              mostSimilarFramePosition = key;
              score = offset_Score_Table.get(key);
  
              // accumulate the scores from neighbours
              if (offset_Score_Table.containsKey(key - 1)) {
                  score += offset_Score_Table.get(key - 1) / 2;
              }
              if (offset_Score_Table.containsKey(key + 1)) {
                  score += offset_Score_Table.get(key + 1) / 2;
              }
          }
  
          /*
          Iterator<Integer> orderedKeyListIterator=orderedKeyList.iterator();
          while (orderedKeyListIterator.hasNext()){
          	int offset=orderedKeyListIterator.next();					
          	System.out.println(offset+": "+offset_Score_Table.get(offset));
          }
          */
  
          score /= numFrames;
          float similarity = score;
          // similarity >1 means in average there is at least one match in every frame
          if (similarity > 1) {
              similarity = 1;
          }
  
          fingerprintSimilarity.setMostSimilarFramePosition(mostSimilarFramePosition);
          fingerprintSimilarity.setScore(score);
          fingerprintSimilarity.setSimilarity(similarity);
  
          return fingerprintSimilarity;
      }