/**
   * @param model another ConjuctiveRuleModel
   * @return true, if this rule is a refinement of the specified rule, or if both rules are equal. A
   *     rule refines another one, if it conatains all of its lietrals and predicts the same label.
   */
  public boolean isRefinementOf(ConjunctiveRuleModel model) {
    if (this == model) {
      return true;
    }

    int numLiterals = model.getRuleLength();

    if (this.getRuleLength() < numLiterals || this.getConclusion() != model.getConclusion()) {
      return false;
    }

    for (int i = 0; i < numLiterals; i++) {
      Attribute attribute = model.getAttributeOfLiteral(i);
      int pos;
      if ((pos = this.getPositionOfAttributeInRule(attribute)) == -1) {
        return false;
      }
      // Any attribute is tested at most once, which simplifies
      // comparisons:
      if (model.getTestedValueAtLiteral(i) != this.getTestedValueAtLiteral(pos)) {
        return false;
      }
    }

    return true;
  }
  /** Constructor to create an empty rule that makes a default prediction */
  public ConjunctiveRuleModel(
      ConjunctiveRuleModel ruleToExtend, Attribute attribute, double testValue)
      throws OperatorException {
    super(ruleToExtend.getTrainingHeader());

    if (ruleToExtend.getPositionOfAttributeInRule(attribute) != -1) {
      throw new OperatorException(
          "ConjunctiveRuleModels may not contain the same attribute twice!");
    }

    this.predictedLabel = ruleToExtend.predictedLabel;
    this.myLiterals.addAll(ruleToExtend.myLiterals);
    Literal literalToAdd = new Literal(attribute, testValue);
    this.myLiterals.add(literalToAdd);
  }
  /**
   * Two rules are equal, if they are both permutations of the same set of literals and predict the
   * same label.
   */
  public boolean equals(Object object) {
    if (object == null) return false;
    if (this == object) return true;

    if (!(object instanceof ConjunctiveRuleModel)) return false;

    ConjunctiveRuleModel rule = (ConjunctiveRuleModel) object;

    if (this.getRuleLength() != rule.getRuleLength()
        || this.getConclusion() != rule.getConclusion()) return false;

    for (int i = 0; i < this.getRuleLength(); i++) {
      Attribute att = this.getAttributeOfLiteral(i);
      int pos;
      if ((pos = rule.getPositionOfAttributeInRule(att)) == -1
          || this.getTestedValueAtLiteral(i) != rule.getTestedValueAtLiteral(pos)) return false;
    }

    return true;
  }
 /** Constructor to clone a rule, but to change the head (prediction) */
 public ConjunctiveRuleModel(ConjunctiveRuleModel ruleToClone, int predictedLabel) {
   super(ruleToClone.getTrainingHeader());
   this.predictedLabel = predictedLabel;
   this.myLiterals.addAll(ruleToClone.myLiterals);
 }