docs: static BLANCResult fromSetCounts(boolean itemSetsMatch, double corefLinksInBoth,
        double corefLinksInKey, double corefLinksInResponse, double nonCorefLinksInBoth,
        double nonCorefLinksInKey, double nonCorefLinksInResponse)
    {
      final double R_C = corefLinksInBoth / ((double) corefLinksInKey);
      final double P_C = corefLinksInBoth / ((double) corefLinksInResponse);
      final double R_N = nonCorefLinksInBoth / ((double) nonCorefLinksInKey);
      final double P_N = nonCorefLinksInBoth / ((double) nonCorefLinksInResponse);
  
      double blancScore;
  
      // this way of computing handles certain edge cases the P and R way does not
      final double F_C = 2*corefLinksInBoth/(corefLinksInKey+corefLinksInResponse);
      final double F_N = 2*nonCorefLinksInBoth/(nonCorefLinksInKey+nonCorefLinksInResponse);
  
      // handle special cases - section 4.1 of Luo et al.
      final boolean noCorefLinksOnEitherSide = corefLinksInKey == 0.0 && corefLinksInResponse == 0.0;
      final boolean noNonCorefLinksOnEitherSide =
          nonCorefLinksInKey == 0.0 && nonCorefLinksInResponse == 0.0;
      if (noCorefLinksOnEitherSide && noNonCorefLinksOnEitherSide) {
        // only a single item on both sides
        // is it the same?
        if (itemSetsMatch) {
          blancScore = 1.0;
        } else {
          blancScore = 0.0;
        }
      } else if (noCorefLinksOnEitherSide) {
        // only singletons on both sides
        blancScore = F_N;
      } else if (noNonCorefLinksOnEitherSide) {
        // both sides have one big cluster
        blancScore = F_C;
      } else {
        blancScore = 0.5*(F_N+F_C);
      }
  
      return new BLANCResult(P_C, P_N, R_C, R_N, F_C, F_N, blancScore);
    }