@Override public void fixSomeVariables(ICause cause) throws ContradictionException { // this is called after restart // if required, force the cut and explain the cut if (forceCft) { explainCut(); nbFixedVariables = related2cut.cardinality(); nbCall = 0; increaseLimit(); } // then fix variables // this part is specific: a fake decision path has to be created nbCall++; restrictLess(); notFrozen.clear(); notFrozen.or(related2cut); for (; !notFrozen.isEmpty() && notFrozen.cardinality() > nbFixedVariables; ) { int idx = selectVariable(); notFrozen.clear(idx); } assert mSolver.getSearchLoop().getLastDecision() == RootDecision.ROOT; // add the first refuted decisions int first = notFrozen.nextSetBit(0); for (int i = (first > -1 ? refuted.nextSetBit(first) : first); i > -1; i = refuted.nextSetBit(i + 1)) { notFrozen.clear(i); } // add unrelated notFrozen.or(unrelated); // then build the fake decision path last = null; // LOGGER.debug("relax cut {}", notFrozen.cardinality()); for (int id = notFrozen.nextSetBit(0); id >= 0 && id < path.size(); id = notFrozen.nextSetBit(id + 1)) { // last = ExplanationToolbox.mimic(path.get(id)); // required because some // unrelated decisions can be refuted if (path.get(id).hasNext()) { last = path.get(id).duplicate(); if (refuted.get(id)) last.buildNext(); ExplanationToolbox.imposeDecisionPath(mSolver, last); } } }
/** Force the failure, apply decisions to the last solution + cut => failure! */ private void explainCut() { // Goal: force the failure to get the set of decisions related to the cut forceCft = false; // 1. make a backup mSolver.getEnvironment().worldPush(); Decision d; try { Decision previous = mSolver.getSearchLoop().getLastDecision(); assert previous == RootDecision.ROOT; // 2. apply the decisions mExplanationEngine.getSolver().getObjectiveManager().postDynamicCut(); for (int i = 0; i < path.size(); i++) { d = path.get(i); d.setPrevious(previous); d.buildNext(); if (refuted.get(i)) d.buildNext(); d.apply(); mSolver.propagate(); previous = d; } // mSolver.propagate(); assert false : "SHOULD FAIL!"; } catch (ContradictionException cex) { if ((cex.v != null) || (cex.c != null)) { // contradiction on domain wipe out tmpDeductions.clear(); tmpValueDeductions.clear(); related2cut.clear(); unrelated.clear(); // 3. explain the failure Explanation expl = new Explanation(); if (cex.v != null) { cex.v.explain(mExplanationEngine, VariableState.DOM, expl); } else { cex.c.explain(mExplanationEngine, null, expl); } Explanation complete = mExplanationEngine.flatten(expl); ExplanationToolbox.extractDecision(complete, tmpValueDeductions); tmpDeductions.addAll(tmpValueDeductions); if (tmpDeductions.isEmpty()) { // if (LOGGER.isErrorEnabled()) { // LOGGER.error("2 cases: (a) optimality proven or (b) bug in // explanation"); // } // throw new SolverException("2 cases: (a) optimality proven or (b) bug // in explanation"); isTerminated = true; } for (int i = 0; i < tmpDeductions.size(); i++) { int idx = path.indexOf(((BranchingDecision) tmpDeductions.get(i)).getDecision()); related2cut.set(idx); } // 4. need to replace the duplicated decision with the correct one for (int i = 0; i < path.size(); i++) { Decision dec = path.get(i); boolean forceNext = !dec.hasNext(); dec.rewind(); if (forceNext) dec.buildNext(); dec.setPrevious(null); // useless .. but ... you know } } else { throw new UnsupportedOperationException( this.getClass().getName() + ".onContradiction incoherent state"); } } mSolver.getEnvironment().worldPop(); mSolver.getEngine().flush(); unrelated.andNot(related2cut); unrelated.andNot(refuted); }