Should models revert to "unoptimized" if they are modified?

If I optimize! a model with GLPK, then add a constraint, I can still access the solution:

using JuMP, GLPK, Clp;
M = Model();
@variable M A[1:2] >= 0;
@constraint M limit1 sum(a for a in A) <= 1;
@objective M Max sum(a for a in A);
set_optimizer(M, GLPK.Optimizer);
optimize!(M);
@constraint M limit2 sum(a for a in A) <= 2;
value(M[:A][1])
1.0

But if I do the same thing in Clp, I get OptimizeNotCalled():

using JuMP, GLPK, Clp;
M = Model();
@variable M A[1:2] >= 0;
@constraint M limit1 sum(a for a in A) <= 1;
@objective M Max sum(a for a in A);
set_optimizer(M, Clp.Optimizer);
optimize!(M);
@constraint M limit2 sum(a for a in A) <= 2;
value(M[:A][1])
ERROR: OptimizeNotCalled()

Should this be consistent? Is it solver specific? Do we care?

(I had inadvertently been relying on GLPK’s behaviour, but I can work with Clp’s).

Thanks!
Geoff

1 Like

This is really hard to do consistently. Some solvers still let you access the solution, others don’t. Resolving this would mean adding a check to solvers like GLPK so that at every value, dual, or objective_value call, they check if the problem had been modified since the last solve.

This problem keeps coming up, however, so it looks like we might have to.

2 Likes

Thanks @odow! Apologies for missing that the documentation.

(And I think I’ll expand my test suite to more than one optimiser)

We could probably fix (i.e., throw an error in all cases) this at the JuMP level: Error on modify-then-query · Issue #2566 · jump-dev/JuMP.jl · GitHub

It would be interesting to track how the model was modified (was a variable added? A constraint? The objective?) in order to improve the “reoptimizing phase”:

  • if the feasible set didn’t change, you can warm start the new problem with the old problem’s solution ;
  • if constraints were added, you can use duality (if applicable) to warm start the dual problem.