private static int compareUpperLower(ContinuousRealInterval a, ContinuousRealInterval b) {
   int ul;
   if (!a.boundUpper()) ul = 1;
   else if (!b.boundLower()) ul = 1;
   else ul = OWLRealUtils.compare(a.getUpper(), b.getLower());
   return ul;
 }
 private static int compareLowerLower(ContinuousRealInterval a, ContinuousRealInterval other) {
   int ll;
   if (!a.boundLower()) {
     if (!other.boundLower()) ll = 0;
     else ll = -1;
   } else {
     if (!other.boundLower()) ll = 1;
     else {
       ll = OWLRealUtils.compare(a.getLower(), other.getLower());
       if (ll == 0) {
         if (a.inclusiveLower()) {
           if (!other.inclusiveLower()) ll = -1;
         } else if (other.inclusiveLower()) ll = 1;
       }
     }
   }
   return ll;
 }
  public List<ContinuousRealInterval> union(ContinuousRealInterval other) {

    switch (compare(other)) {
      case CONTAINS:
      case EQUALS:
      case FINISHED_BY:
      case STARTED_BY:
        return Collections.singletonList(this);

      case DURING:
      case FINISHES:
      case STARTS:
        return Collections.singletonList(other);

      case MEETS:
        return Collections.singletonList(
            new ContinuousRealInterval(
                getLower(), other.getUpper(), inclusiveLower(), other.inclusiveUpper()));

      case MET_BY:
        return Collections.singletonList(
            new ContinuousRealInterval(
                other.getLower(), getUpper(), other.inclusiveLower(), inclusiveUpper()));

      case OVERLAPPED_BY:
        return Collections.singletonList(
            new ContinuousRealInterval(
                other.getLower(), getUpper(), other.inclusiveLower(), inclusiveUpper()));

      case OVERLAPS:
        return Collections.singletonList(
            new ContinuousRealInterval(
                getLower(), other.getUpper(), inclusiveLower(), other.inclusiveUpper()));

      case PRECEDED_BY:
      case PRECEDES:
        return Arrays.asList(this, other);

      default:
        throw new IllegalStateException();
    }
  }
  public List<ContinuousRealInterval> remove(ContinuousRealInterval other) {

    ContinuousRealInterval before, after;
    switch (compare(other)) {
      case CONTAINS:
        before =
            new ContinuousRealInterval(
                this.getLower(), other.getLower(), inclusiveLower(), !other.inclusiveLower());
        after =
            new ContinuousRealInterval(
                other.getUpper(), this.getUpper(), !other.inclusiveUpper(), this.inclusiveUpper());
        break;

      case DURING:
      case EQUALS:
      case FINISHES:
      case STARTS:
        return Collections.emptyList();

      case MEETS:
        before =
            new ContinuousRealInterval(
                this.getLower(), this.getUpper(), this.inclusiveLower(), false);
        after = null;
        break;

      case MET_BY:
        before = null;
        after =
            new ContinuousRealInterval(
                this.getLower(), this.getUpper(), false, this.inclusiveUpper());
        break;

      case OVERLAPPED_BY:
      case STARTED_BY:
        before = null;
        after =
            new ContinuousRealInterval(
                other.getUpper(), this.getUpper(), !other.inclusiveUpper(), this.inclusiveUpper());
        break;

      case OVERLAPS:
      case FINISHED_BY:
        before =
            new ContinuousRealInterval(
                this.getLower(), other.getLower(), this.inclusiveLower(), !other.inclusiveLower());
        after = null;
        break;

      case PRECEDED_BY:
      case PRECEDES:
        return Collections.singletonList(this);

      default:
        throw new IllegalStateException();
    }

    List<ContinuousRealInterval> ret = new ArrayList<ContinuousRealInterval>();
    if (before != null) ret.add(before);
    if (after != null) ret.add(after);

    return ret;
  }
  public ContinuousRealInterval intersection(ContinuousRealInterval that) {
    Number lower, upper;
    boolean inclusiveUpper, inclusiveLower;

    switch (compare(that)) {
      case CONTAINS:
      case STARTED_BY:
        lower = that.getLower();
        inclusiveLower = that.inclusiveLower();
        upper = that.getUpper();
        inclusiveUpper = that.inclusiveUpper();
        break;

      case EQUALS:
        lower = this.getLower();
        inclusiveLower = this.inclusiveLower();
        upper = this.getUpper();
        inclusiveUpper = this.inclusiveUpper();
        break;

      case DURING:
      case STARTS:
        lower = this.getLower();
        inclusiveLower = this.inclusiveLower();
        upper = this.getUpper();
        inclusiveUpper = this.inclusiveUpper();
        break;

      case FINISHED_BY:
        lower = that.getLower();
        inclusiveLower = that.inclusiveLower();
        upper = that.getUpper();
        inclusiveUpper = (this.inclusiveUpper() && that.inclusiveUpper());
        break;

      case FINISHES:
        lower = this.getLower();
        inclusiveLower = this.inclusiveLower();
        upper = this.getUpper();
        inclusiveUpper = (this.inclusiveUpper() && that.inclusiveUpper());
        break;

      case MEETS:
      case MET_BY:
        return null;

      case OVERLAPPED_BY:
        lower = this.getLower();
        inclusiveLower = this.inclusiveLower();
        upper = that.getUpper();
        inclusiveUpper = that.inclusiveUpper();
        break;

      case OVERLAPS:
        lower = that.getLower();
        inclusiveLower = that.inclusiveLower();
        upper = this.getUpper();
        inclusiveUpper = this.inclusiveUpper();
        break;

      case PRECEDED_BY:
      case PRECEDES:
        return null;

      default:
        throw new IllegalStateException();
    }

    return new ContinuousRealInterval(lower, upper, inclusiveLower, inclusiveUpper);
  }