Conversation
|
Yes, I would be happy to merge both versions of the interface! |
|
Updated the interface somewhat, it seems SCIP does not have the fancy Min/Max/Abs constraints built-in in its API : / Added the SOS1 and cardinality constraints to the interface too, these constraints are created when decomposing alldiff for example so definately usefull to have them imho. We should also add them to the Gurobi interface SolveAll is in a weird state for PySCIPOpt: SCIP does allow for retrieving all feasible solutions, but the Python interface does not seem to allow for collecting the solutions which are found... Added the issues to track in the code so we can add the specialized implementation when these are resolved. All tests are passing so ready for review I think. |
|
I get an error for optimization problems: |
cpmpy/solvers/scip.py
Outdated
| if self.has_objective(): | ||
| self.objective_value_ = scip_objective.getObjVal() | ||
|
|
||
| self.scip_model.freeTransform() # Mark Turner from SCIP told me you need to do this if you want to support adding additional vars/constraints later... |
There was a problem hiding this comment.
So a tiny summary for this: SCIP transforms the problem that you are actual solving into something it believes is easier to solve (presolve techniques etc). All solutions when found are then transformed back to the original space, because that is obviously what the user modelled and can interpret. Allowing the user to change the model during solving gets messy when balancing these things however, so it's forbidden. What self.scip_model.freeTransform() does is to remove all information from the transformed space, and just leave the original model. All solutions are kept, and the user can now change the model as they will. The downside is that potentially useful information for speeding up the next optimisation call is thrown out.
cpmpy/solvers/scip.py
Outdated
| sciplhs = self._make_numexpr(lhs) | ||
| self.scip_model.addCons(sciplhs <= sciprhs) | ||
|
|
||
| elif cpm_expr.name == '>=': |
There was a problem hiding this comment.
Just a general interest: Due to how the constraints are transformed are you certain that these constraints can't be multiplied by -1 to become cardinality constraints?
There was a problem hiding this comment.
Aha no, actually we are not... I will do a check for it here
cpmpy/solvers/scip.py
Outdated
| lhs = Operator("wsum", [[-w for w in lhs.args[0]], lhs.args[1]]) | ||
| else: | ||
| lhs = -lhs | ||
| self += cond.implies(lhs <= -rhs) |
There was a problem hiding this comment.
Does this constraint actually end up being added to the SCIP model?
There was a problem hiding this comment.
Yes, this line sends the new constraint cond => lhs <= -rhs through the entire __add__ pipeline again.
But coming to think of it, we probably pay quite a penalty by doing so as it also sends the constraint through the transformation pipeline...
I'll refactor this somewhat so we avoid unnecessary transformations...
cpmpy/solvers/scip.py
Outdated
| raise Exception(f"Unknown linear expression {sub_expr} name") | ||
|
|
||
| # True or False | ||
| elif isinstance(cpm_expr, BoolVal): |
There was a problem hiding this comment.
Don't really understand what this constraint means, always struggle a bit with the CP language. If you can explain then I can see if there's a more natural MIP approach.
There was a problem hiding this comment.
This is a very uncommon case where a user posts the constraint "False" to the solver, in essence making the solver status trivialy infeasible.
We run into this case sometimes when our expressions are simplified to "False"
| Returns: number of solutions found | ||
| """ | ||
|
|
||
| warnings.warn("Solution enumeration is not implemented in PyScipOPT, defaulting to CPMpy's naive implementation") |
There was a problem hiding this comment.
So I mentioned this is an email. I think it's just that very few MIP practitioners actually need such functionality. To mimic most of this:
- Call optimize for the
self.scip_model. - After solving is completed. Call
self.scip_model.getSols().
The potential problems with this is that SCIP automatically deletes the "worst" solutions in storage after it has found x many. This is by default 10. Seelimits/maxsolandlimits/maxorigsol. So to save memory SCIP will at times remove older solutions that it knows are suboptimal because it has clearly better ones. The number of solutions found in total can be retrieved withscip_model.getNSolsFound(), but unless you increase the limits you will not be able to retrieve all of them.
This should now be addressed in one of my points above |
|
@IgnaceBleukx @tias I haven't run anything, and truthfully haven't tried to understand the larger code base, but I've gone through and given comments that I think should make the interface work. |
with help of Mark Turner from SCIP.
Now... turns out that @IgnaceBleukx already worked on a SCIP interface too, about a year ago (e.g. SCIP branch
So maybe Ignace can now make a best of both worlds? : )
(current branch is up to date with current template, but the add part is minimal, e.g. reified linear is not properly tested/supported at the least).