private void notifyHard(MultiSet<String> exploredSet) {
    // exclude all constraints that are in exploredSet from the set of
    // constraints
    // first impose all

    int targetWeight = getWeight(exploredSet);
    if (upperCostBound >= 0 && targetWeight >= upperCostBound) {
      if (debug) {
        System.out.println(
            "Infeasible: Target upper bound "
                + targetWeight
                + " but upper bound for problem is "
                + upperCostBound);
      }
      enumerator.foundSolutionOrInfeasibility();
      wasSolved = false;
      return;
    }

    // System.out.println("Trying ... "+exploredSet + " -> weight: "+targetWeight);
    for (org.jacop.constraints.Constraint c : idToConstraintMap.values()) {
      if (!exploredSet.contains(c.id)) c.impose(store);
    }

    // now exclude the perhaps unnecessary ones
    for (String s : exploredSet) {
      org.jacop.constraints.Constraint c = idToConstraintMap.get(s);
      c.removeConstraint();
    }

    // now do some actual solving

    store.setLevel(store.level + 1);
    boolean result = search.labeling(store, select);

    if (result) {
      wasSolved = true;
      objectiveValue = targetWeight;
      enumerator.foundSolutionOrInfeasibility();

      if (debug) {
        System.out.println("Found a best solution with cost " + targetWeight);
        System.out.println(store);
      }
    }

    store.removeLevel(store.level);
    store.setLevel(store.level - 1);
  }
  private void notifyReified(MultiSet<String> exploredSet) {

    if (debug) {
      System.out.println("Checking ... " + exploredSet);
    }
    satisfiedConstraints = new ArrayList<PrimitiveConstraint>(constraintMap.size());
    violatedConstraints = new ArrayList<PrimitiveConstraint>(constraintMap.size());

    HashSet<String> violatedIds = new HashSet<String>(exploredSet.size() * 2);

    for (String violatedConstraint : exploredSet) {
      WrappedPrimitiveConstraint wpc = constraintMap.get(violatedConstraint);
      BooleanVar indicator = wpc.getViolationIndicator();

      // violation indicator must be true!
      PrimitiveConstraint nextIndicatorForce = new XeqY(indicator, constantOne);
      nextIndicatorForce.impose(store);
      // try constant
      PrimitiveConstraint nextIndicatorConst = new XeqC(indicator, 1);
      store.impose(nextIndicatorConst);

      violatedIds.add(violatedConstraint);

      violatedConstraints.add(nextIndicatorForce);
      violatedConstraints.add(nextIndicatorConst);
    }

    for (Entry<String, WrappedPrimitiveConstraint> remainingEntry : constraintMap.entrySet()) {
      if (!violatedIds.contains(remainingEntry.getKey())) {
        BooleanVar indicator = remainingEntry.getValue().getViolationIndicator();

        PrimitiveConstraint nextIndicatorForce =
            new XeqY(indicator, constantZero); // no penalty for those
        nextIndicatorForce.impose(store);
        // try constant
        PrimitiveConstraint nextForce = new XeqC(indicator, 0);
        nextForce.impose(store);

        satisfiedConstraints.add(nextIndicatorForce);
        satisfiedConstraints.add(nextForce);
      }
    }

    // now do some actual solving

    store.setLevel(store.level + 1);

    boolean result = search.labeling(store, select);

    if (result) {
      objectiveValue = objective.value();
      wasSolved = true;
      enumerator.foundSolutionOrInfeasibility();
      if (debug) {
        System.out.println("Found a best solution with cost: " + objective.value());
        System.out.println(store);
      }
    }

    store.removeLevel(store.level);
    store.setLevel(store.level - 1);

    // now cleanup
    for (PrimitiveConstraint pc : satisfiedConstraints) {
      pc.removeConstraint();
    }

    for (PrimitiveConstraint pc : violatedConstraints) {
      pc.removeConstraint();
    }
  }