@Override public void explain(ExplanationEngine xengine, Deduction d, Explanation e) { // return super.explain(d); if (d.getVar() == x) { e.add(xengine.getPropagatorActivation(this)); if (d.getmType() == Deduction.Type.ValRem) { y.explain(xengine, VariableState.REM, ((ValueRemoval) d).getVal() - cste, e); } else { throw new UnsupportedOperationException( "PropEqualXY only knows how to explain ValueRemovals"); } } else if (d.getVar() == y) { e.add(xengine.getPropagatorActivation(this)); if (d.getmType() == Deduction.Type.ValRem) { x.explain(xengine, VariableState.REM, ((ValueRemoval) d).getVal() + cste, e); } else { throw new UnsupportedOperationException( "PropEqualXY only knows how to explain ValueRemovals"); } } else { super.explain(xengine, d, e); } }
/** 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); }