/*@  public normal_behavior
 @    requires rng != null;
 @    ensures \result.equals(inverse().image(rng));
 @
 @ implies_that
 @    ensures \result != null && !\result.containsNull;
 @*/
 public /*@ non_null @*/ JMLEqualsSet inverseImage(/*@ non_null @*/ JMLEqualsSet rng) {
   JMLEqualsSet invImg = new JMLEqualsSet();
   JMLEqualsToEqualsRelationImageEnumerator imagePairEnum = this.imagePairs();
   JMLEqualsValuePair imagePair;
   // @ loop_invariant !invImg.containsNull;
   while (imagePairEnum.hasMoreElements()) { // @ nowarn LoopInv;
     imagePair = imagePairEnum.nextImagePair();
     // @ assume imagePair.value != null && imagePair.key != null;
     // @ assume imagePair.value instanceof JMLEqualsSet;
     JMLEqualsSet img = (JMLEqualsSet) imagePair.value;
     if (!img.intersection(rng).isEmpty()) {
       invImg = invImg.insert(imagePair.key);
     }
   }
   return invImg;
 } // @ nowarn Exception;
  /*@  public normal_behavior
  @    requires dom != null;
  @    ensures (\forall JMLEqualsEqualsPair pair; pair != null;
  @                      \result.theRelation.has(pair) == dom.has(pair.key)
  @                    && elementImage(pair.key).has(pair.value)
  @                );
  @*/
  public /*@ non_null @*/ JMLEqualsToEqualsRelation restrictDomainTo(
      /*@ non_null @*/ JMLEqualsSet dom) {
    JMLValueSet newImagePairSet = new JMLValueSet();
    JMLEqualsSet newDom = domain_.intersection(dom);
    // @ assume (\forall Object dv; newDom.has(dv); dv != null);
    int newSize = 0;

    JMLEqualsToEqualsRelationImageEnumerator imagePairEnum = this.imagePairs();
    JMLEqualsValuePair imagePair;
    JMLEqualsSet img;
    while (imagePairEnum.hasMoreElements()) {
      imagePair = imagePairEnum.nextImagePair();
      // @ assume imagePair.value != null;
      // @ assume imagePair.value instanceof JMLEqualsSet;
      if (newDom.has(imagePair.key)) {
        newImagePairSet = newImagePairSet.insert(imagePair);
        img = (JMLEqualsSet) imagePair.value;
        newSize = newSize + img.int_size();
      }
    }
    return new JMLEqualsToEqualsRelation(newImagePairSet, newDom, newSize);
  } // @ nowarn Exception;
  /*@  public normal_behavior
  @    requires othRel != null;
  @    ensures \result.theRelation.equals(
  @                    this.theRelation.intersection(othRel.theRelation));
  @*/
  public /*@ non_null @*/ JMLEqualsToEqualsRelation intersection(
      /*@ non_null @*/ JMLEqualsToEqualsRelation othRel) {
    JMLValueSet newImagePairSet = new JMLValueSet();
    JMLEqualsSet newDom = new JMLEqualsSet();
    int newSize = 0;

    JMLEqualsToEqualsRelationImageEnumerator imagePairEnum = this.imagePairs();
    JMLEqualsValuePair imagePair;
    JMLEqualsSet img;
    while (imagePairEnum.hasMoreElements()) {
      imagePair = imagePairEnum.nextImagePair();
      // @ assume imagePair.value != null;
      // @ assume imagePair.value instanceof JMLEqualsSet;
      img = (JMLEqualsSet) imagePair.value;
      img = img.intersection(othRel.elementImage(imagePair.key));
      if (!img.isEmpty()) {
        newImagePairSet = newImagePairSet.insert(new JMLEqualsValuePair(imagePair.key, img));
        newDom = newDom.insert(imagePair.key);
        newSize = newSize + img.int_size();
      }
    }
    return new JMLEqualsToEqualsRelation(newImagePairSet, newDom, newSize);
  } // @ nowarn Exception;