public ProcessModel resolveConflictsOrRedundancies() {
    logger.info("Checking redundancies and conflicts of non-fully-supported constraints");

    this.checking = true;
    Automaton candidateAutomaton = null;
    for (Constraint candidateCon : this.notSurelySafeProcessConstraints) {
      if (!isConstraintAlreadyChecked(candidateCon)) {
        logger.trace("Checking consistency of " + candidateCon);
        // System.out.println("PRESENTATION -- The unsafe constraint: " + candidateCon + " supp: " +
        // candidateCon.support + "; conf: " + candidateCon.confidence + "; inf.f: " +
        // candidateCon.interestFactor);
        // System.out.println("PRESENTATION -- The unsafe constraint automaton: " + candidateCon + "
        // \n" + safeProcess.buildAlphabetAcceptingAutomaton().intersection(new
        // RegExp(candidateCon.getRegularExpression()).toAutomaton()).toDot());
        candidateAutomaton = new RegExp(candidateCon.getRegularExpression()).toAutomaton();
        if (!this.avoidingRedundancy || this.checkRedundancy(candidateAutomaton, candidateCon))
          resolveConflictsRecursively(candidateAutomaton, candidateCon);
      }
    }

    //		safeProcess.bag = safeProcess.bag.markSubsumptionRedundantConstraints();
    //		safeProcess.bag.removeMarkedConstraints();

    if (this.avoidingRedundancyWithDoubleCheck) {
      logger.info("Checking redundant constraints in a second pass...");

      this.doubleCheckRedundancies();
    }

    this.subMarker.setConstraintsBag(this.safeProcess.bag);
    this.subMarker.markSubsumptionRedundantConstraints();

    this.checking = false;

    return this.safeProcess;
  }
  public void init() {
    this.checking = false;
    this.conflictChecksPerformed = 0;
    this.redundancyChecksPerformed = 0;
    this.conflictingConstraints = new TreeSet<Constraint>();
    this.redundantConstraints = new TreeSet<Constraint>();
    this.redundantConstraintsAtSecondPass = new TreeSet<Constraint>();

    // Pre-processing: remove subsumption-redundant constraints, by all means
    this.originalBag = (ConstraintsBag) this.originalProcess.bag.clone();
    this.subMarker.setConstraintsBag(originalBag);
    this.subMarker.markSubsumptionRedundantConstraints();
    this.originalBag.removeMarkedConstraints();
    this.originalHierarchyUnredundantConstraints = this.originalBag.getAllConstraints();
    /*
     * The blackboard is meant to associate to all constraints a tick,
     * whenever the constraint has already been checked
     */
    this.sorter.setConstraints(originalHierarchyUnredundantConstraints);
    this.blackboard = new TreeSet<Constraint>(this.sorter.getComparator());
    ConstraintsBag safeBag = this.originalBag.getOnlyFullySupportedConstraintsInNewBag();
    //		safeBag.markSubsumptionRedundantConstraints();
    //		safeBag.removeMarkedConstraints();
    Collection<Constraint> safeConstraints = safeBag.getAllConstraints();
    this.sorter.setConstraints(safeConstraints);

    /*
     * Step 1: Consider as safe those constraints that have a support
     * of 100%: if they have a support of 100%, a model already exists for
     * them: the log itself. So, their conjunction cannot be unsatisfiable.
     */
    if (avoidingRedundancy) {
      logger.info("Checking redundancies of fully-supported constraints...");

      ConstraintsBag emptyBag = this.originalBag.createEmptyIndexedCopy();
      this.safeProcess = new ProcessModel(this.originalProcess.getTaskCharArchive(), emptyBag);
      Automaton candidateAutomaton = null;
      this.safeAutomaton = this.safeProcess.buildAlphabetAcceptingAutomaton();
      for (Constraint candidateCon : this.sorter.sort(this.rankingPolicies)) {
        logger.trace("Checking redundancy of " + candidateCon);
        candidateAutomaton = new RegExp(candidateCon.getRegularExpression()).toAutomaton();
        if (!candidateCon
                .isRedundant() // If this constraint was not already found to be redundant in some
                               // way before
            && !this.isConstraintAlreadyChecked(
                candidateCon) // If this constraint was not already checked
            && this.checkRedundancy(
                this.safeAutomaton, this.safeProcess.bag, candidateAutomaton, candidateCon)
        // and the check of redundancy has a negative response (namely, it is not redundant)
        ) {
          this.safeAutomaton = this.intersect(this.safeAutomaton, candidateAutomaton);
          this.safeProcess.bag.add(candidateCon.getBase(), candidateCon);
        }
        blackboard.add(candidateCon);
      }
    } else {
      this.safeProcess = new ProcessModel(this.originalProcess.getTaskCharArchive(), safeBag);
      this.safeAutomaton = this.safeProcess.buildAutomaton();
      for (Constraint c : LinearConstraintsIndexFactory.getAllConstraints(safeBag)) {
        // System.out.println("PRESENTATION -- The safe constraint: " + c + " supp: " + c.support +
        // "; conf: " + c.confidence + "; inf.f: " + c.interestFactor + " rex: " +
        // c.getRegularExpression());
        // System.out.println("PRESENTATION -- The safe constraint automaton: " + c + " \n" +
        // safeProcess.buildAlphabetAcceptingAutomaton().intersection(new
        // RegExp(c.getRegularExpression()).toAutomaton()).toDot());
        blackboard.add(c);
      }
    }

    // System.out.println("PRESENTATION -- The safe automaton:\n" + safeAutomaton.toDot());
    ConstraintsBag unsafeBag =
        this.originalBag.createComplementOfCopyPrunedByThreshold(Constraint.MAX_SUPPORT);
    //		for (Constraint c : LinearConstraintsIndexFactory.getAllConstraints(unsafeBag)) {
    //			blackboard.add(c);
    //		}
    this.sorter.setConstraints(unsafeBag.getAllConstraints());
    this.notSurelySafeProcessConstraints = this.sorter.sort(this.rankingPolicies);
  }
  public void resolveConflictsRecursively(Automaton candidateAutomaton, Constraint candidateCon) {
    if (isConstraintAlreadyChecked(candidateCon)) {
      logger.trace(candidateCon + " was already checked");
      return;
    } else {
      conflictChecksPerformed++;
      blackboard.add(candidateCon);
    }

    logger.trace(
        "Checking conflict with "
            + candidateCon
            + ": Conjuncting the safe automaton with Reg.exp: "
            + candidateCon.getRegularExpression());
    Automaton auxAutomaton = this.intersect(this.safeAutomaton, candidateAutomaton);
    Constraint relaxedCon = null;

    if (isAutomatonEmpty(auxAutomaton)) {
      logger.warn(candidateCon + " conflicts with the existing safe automaton!");
      //			logger.warn("Current set of safe constraints: " + this.safeProcess.bag);
      conflictingConstraints.add(candidateCon);

      relaxedCon = candidateCon.getConstraintWhichThisIsBasedUpon();
      if (relaxedCon == null) {
        relaxedCon = candidateCon.suggestConstraintWhichThisShouldBeBasedUpon();
        if (relaxedCon != null) {
          relaxedCon = candidateCon.createConstraintWhichThisShouldBeBasedUpon();
          logger.trace(
              relaxedCon + " included in process model as relaxation, replacing " + candidateCon);
        }
      }

      if (relaxedCon == null || relaxedCon == candidateCon) {
        logger.warn(candidateCon + " has to be removed at once");
      } else {
        logger.trace(candidateCon + " relaxed to " + relaxedCon);

        resolveConflictsRecursively(
            new RegExp(relaxedCon.getRegularExpression()).toAutomaton(), relaxedCon);
      }

      if (candidateCon.getSubFamily().equals(RelationConstraintSubFamily.COUPLING)) {
        MutualRelationConstraint coCandidateCon = (MutualRelationConstraint) candidateCon;
        Constraint forwardCon = coCandidateCon.getForwardConstraint(),
            backwardCon = coCandidateCon.getBackwardConstraint();

        if (forwardCon != null && backwardCon != null) {
          logger.trace(
              "Splitting the coupling relation constraint "
                  + coCandidateCon
                  + " into "
                  + coCandidateCon.getForwardConstraint()
                  + " and "
                  + coCandidateCon.getBackwardConstraint());
          this.resolveConflictsRecursively(
              new RegExp(forwardCon.getRegularExpression()).toAutomaton(), forwardCon);
          this.resolveConflictsRecursively(
              new RegExp(backwardCon.getRegularExpression()).toAutomaton(), backwardCon);
        }
      }

    } else {
      safeAutomaton = auxAutomaton;
      // System.out.println("PRESENTATION -- Safe automaton so far: " + safeAutomaton.toDot());
      safeProcess.bag.add(candidateCon.getBase(), candidateCon);
    }
  }