@Override
  public boolean add(EnforcedRelation enf) {
    if (!this.subsubmedEnf(enf)) {

      enfs.add(enf);

      TIntHashSet type1 = enf.getType1();
      TIntIterator type1Iterator = type1.iterator();
      while (type1Iterator.hasNext()) {
        int key = type1Iterator.next();
        ensureContainsKey(type1Index, key);
        type1Index.get(key).add(enf);
      }

      TIntHashSet type2 = enf.getType2();
      TIntIterator type2Iterator = type2.iterator();
      while (type2Iterator.hasNext()) {
        int key = type2Iterator.next();
        ensureContainsKey(type2Index, key);
        type2Index.get(key).add(enf);
      }

      TIntHashSet roles = enf.getRoles();
      TIntIterator rolesIterator = roles.iterator();
      while (rolesIterator.hasNext()) {
        int key = rolesIterator.next();
        ensureContainsKey(rolesIndex, key);
        rolesIndex.get(key).add(enf);
      }

      return true;
    } else {
      return false;
    }
  }
  @Override
  public boolean remove(Object o) {
    EnforcedRelation enf = (EnforcedRelation) o;
    enfs.remove(enf);

    TIntHashSet type1 = enf.getType1();
    TIntIterator type1Iterator = type1.iterator();
    while (type1Iterator.hasNext()) {
      int key = type1Iterator.next();
      ensureContainsKey(type1Index, key);
      type1Index.get(key).remove(enf);
    }

    TIntHashSet type2 = enf.getType2();
    TIntIterator type2Iterator = type2.iterator();
    while (type2Iterator.hasNext()) {
      int key = type2Iterator.next();
      ensureContainsKey(type2Index, key);
      type2Index.get(key).remove(enf);
    }

    TIntHashSet roles = enf.getRoles();
    TIntIterator rolesIterator = roles.iterator();
    while (rolesIterator.hasNext()) {
      int key = rolesIterator.next();
      ensureContainsKey(rolesIndex, key);
      rolesIndex.get(key).remove(enf);
    }

    return true;
  }
  public boolean updateNewImpl(HornImplication impl) {

    Collection<EnforcedRelation> list = this.matchType2(impl.getBody());

    for (EnforcedRelation enf : list) {
      remove(enf);
      if (enf.getType2().add(impl.getHead())) {
        enf.computeImplicationClosure();
      }
      add(enf);
    }

    return !list.isEmpty();
  }
  private boolean subsubmedEnf(EnforcedRelation enf) {

    for (EnforcedRelation i : this.enfs) {
      if (i.getRoles().containsAll(enf.getRoles())
          && i.getType2().containsAll(enf.getType2())
          && enf.getType1().containsAll(i.getType1())
          && i.getType1().containsAll(enf.getType1())) return true;
    }

    return false;
  }