/**
   * Takes a list of lower bounds and a list of corresponding upper bounds of ranges and checks if
   * there are overlapping ranges.
   *
   * <p>Note: lowerBounds and upperBounds must have the same length
   *
   * @param resultRanges the result ranges to check
   * @return true if at least one range overlaps another, false otherwise
   */
  private boolean rangesOverlapping(List<AlternativeResultRange> resultRanges) {
    // Sort by upper bound
    Collections.sort(
        resultRanges,
        new Comparator<AlternativeResultRange>() {
          @Override
          public int compare(AlternativeResultRange o1, AlternativeResultRange o2) {
            return Double.compare(o1.getUpperBound(), o2.getUpperBound());
          }
        });

    double lastUpperBound = Double.NEGATIVE_INFINITY;
    for (AlternativeResultRange resultRange : resultRanges) {
      if (resultRange.getLowerBound() < lastUpperBound) {
        return true;
      }
      lastUpperBound = resultRange.getUpperBound();
    }

    return false;
  }
  /**
   * Updates the lower and upper bounds for each alternative to reflect potential minimum and
   * maximum weighted results in case the provided leaves are set to their potential minimum and
   * maximum values respectively.
   *
   * @param leafSet leaves for the plan to consider
   * @param resultRanges the result ranges to update
   */
  private void updateBounds(
      final Set<VPlanLeaf> leafSet, List<AlternativeResultRange> resultRanges) {
    for (VPlanLeaf leaf : leafSet) {
      double leafMinimum = leaf.getPotentialMinimum();
      double leafMaximum = leaf.getPotentialMaximum();

      for (AlternativeResultRange resultRange : resultRanges) {
        resultRange.setLowerBound(
            resultRange.getLowerBound()
                - ((resultRange.getResult() - leafMinimum) * leaf.getTotalWeight()));
        resultRange.setUpperBound(
            resultRange.getUpperBound()
                + ((leafMaximum - resultRange.getResult()) * leaf.getTotalWeight()));
      }
    }
  }