Skip to content

Add incremental flag for faster one-shot Exact and SCIP solves#1020

Open
tias wants to merge 1 commit into
masterfrom
issue-968-non-incremental-solve
Open

Add incremental flag for faster one-shot Exact and SCIP solves#1020
tias wants to merge 1 commit into
masterfrom
issue-968-non-incremental-solve

Conversation

@tias

@tias tias commented Jun 18, 2026

Copy link
Copy Markdown
Collaborator

Closes #968.

For one-shot solves via Model.solve(), Exact and SCIP were doing extra work meant for reusing the solver object. Exact always went through toOptimum(); SCIP always called freeTransform() after optimize(). Both are useful when you keep the solver and solve again, but Model.solve() throws the solver away anyway.

This adds an incremental flag on both interfaces (default True). Model.solve() passes incremental=False for exact and scip. Exact then uses runFull; SCIP skips freeTransform().

Left Model.solveAll() alone — SCIP's generic enumeration calls solve() in a loop and adds nogoods, so it still needs the incremental path.

Added a couple of tests that check Model.solve() gives the same result as SolverLookup.get(..., incremental=True).

Model.solve() can use faster non-incremental solver paths when the
solver object is discarded after a single call, while direct solver
reuse keeps incremental=True by default.

@IgnaceBleukx IgnaceBleukx left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seeing this, I'm not sure if we should add it to the constructor args? Maybe better to add a flag to the .solve function instead?

Comment thread cpmpy/solvers/exact.py


def __init__(self, cpm_model=None, subsolver=None, **kwargs):
def __init__(self, cpm_model=None, subsolver=None, incremental=True, **kwargs):

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I feel it's too specific; we have a call_from_model flag that we pass to solveAll, we could re-use something similar here? There it is used to determine whether we want to print a warning or not I believe, here we can use it so select the solve func of exact.

Comment thread cpmpy/solvers/exact.py
my_status, obj_val = self.xct_solver.toOptimum(timeout=timeout)
obj_val = None
if self.incremental:
my_status, obj_val = self.xct_solver.toOptimum(timeout=timeout)

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would not trust the objective val computed by exact in this special path? in the previous version, we would always just recompute it from the expresssion object, which I think is the right way

Comment thread cpmpy/solvers/scip.py
# 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.
self.scip_model.freeTransform()
if self.incremental:

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We could just always call freeTransform, no? If we do smt incremental then we should definetly, if its not incremental because we call from model, then it doesn't hurt either? Or can this call be expensive?

Comment thread cpmpy/model.py
if kwargs and solver is None:
raise NotSupportedError("Specify the solver when using kwargs, since they are solver-specific!")

if isinstance(solver, str):

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we decide to go the call_from_model flag-way then this is not needed

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Non-incremental solve function in solver interface

2 participants