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).
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.
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.