简体   繁体   中英

how to check which constraints would be violated by a presumed solution?

In some cases the solver fails to find a solution for my model, which I think is there. So I would like to populate a solution, and then check which constraint is violated. How to do that with choco-solver?

Using choco-solver 4.10.6.

Forcing a solution

I ended up adding constraints to force variables to values of my presumed solution: eg

    // constraints to force given solution 
    vehicle2FirstStop[0].eq(model.intVar(4)).post();
    vehicle2FirstStop[1].eq(model.intVar(3)).post();
    nextStop[1].eq(model.intVar(0)).post();
    nextStop[2].eq(model.intVar(1)).post();
    ...

and then

 model.getSolver().showContradiction();
 if (model.getSolver().solve()) { ....

Shows the first contradiction of the presumed solution, eg

/!\ CONTRADICTION (PropXplusYeqZ(sum_exp_49, mul_exp_51, ...

So the next step is to find out where terms such as sum_exp_49 come from.

Matching the contradiction terms with the code

Here is a simple fix for constraints which will hopefully provide enough information. We can override the post() and associates() methods of model, so that it dumps the java source filename and line number when a constraint is posted/variable is created.

   Model model = new Model("Vrp1RpV") {
    /**
     * retrieve the filename and line number of first caller outside of choco-solver from stacktrace
     */
    String getSource() {
        String source = null;
        StackTraceElement[] stackTraceElements = Thread.currentThread().getStackTrace();            
        // starts from 3: thread.getStackTrace() + this.getSource() + caller (post() or associates())
        for (int i = 3; i < stackTraceElements.length; i++) {                
                // keep rewinding until we get out of choco-solver packages
                if (!stackTraceElements[i].getClassName().toString().startsWith("org.chocosolver")) {
                    source = stackTraceElements[i].getFileName() + ":" + stackTraceElements[i].getLineNumber();
                    break;
                }                
        }
        return source;
    }
    @Override
    public void post(Constraint... cs) throws SolverException {
        String source=getSource();
        // dump each constraint along source location
        for (Constraint c : cs) {
            System.err.println(source + " post: " + c);
        }
        super.post(cs);
    }
    
    @Override
    public void associates(Variable variable) {
        System.err.println(getSource() + " associates: " + variable.getName());
        super.associates(variable);
    }
};

This will dump things like:

Vrp1RpV2.java:182 post: ARITHM ([prop(EQ_exp_47.EQ.mul_exp_48)])
Vrp1RpV2.java:182 associates: sum_exp_49
Vrp1RpV2.java:182 post: ARITHM ([prop(mul_exp_48.EQ.sum_exp_49)])
Vrp1RpV2.java:182 associates: EQ_exp_50
Vrp1RpV2.java:182 post: BASIC_REIF ([(stop2vehicle[2] = 1) <=> EQ_exp_50])
...

From there it is possible to see where sum_exp_49 comes from.

EDIT: added associates() thanks to @cprudhom suggestion on https://gitter.im/chocoteam/choco-solver

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM