Solver agnostic way to control warm starting

Is there a way to control/prevent how a LP solver may use information from a previous solve to warm start? I know, e.g., for Gurobi there is LPWarmStart, but I struggle to prevent that for example when using HiGHS.

What happens?
See the MWE at the end. I’d like to use some kind of force_fresh_solve parameter, but could not find anything (even though I vaguely remembered to have seen something similar some time ago…).

Background
Maybe also important why I’m stuck at this: I’m repeatedly solving a model while switching around some settings based on an (un)educated guess of what I expect to be working better for the next solve. Unfortunately, the previous solve prevents a presolve, which hurts more than the warm start helps.

Thanks!


Code for MWE

The following constructs a model, solves it, changes the objective, and re-solves. Not having a previous solution - can be tested by not executing “line 42” - requires 241 simplex iterations, compared to 410 when optimize! was called before.

Note: Happens for dual simplex, or other settings that are changed too.

using JuMP
import HiGHS
import Random: seed!

# Random data.
seed!(12345)
N, M = (500, 500)
A = abs.(randn(N, M))
b = randn(N)
c = abs.(randn(M)), abs.(randn(M))
r = randn(M) .* 100

# Model setup.
m = Model(HiGHS.Optimizer)
set_attribute(m, "simplex_strategy", 4)
@variable(m, r[i] <= x[i = 1:M] <= (r .+ 100)[i])
@constraint(m, A * x .>= b)
@objective(m, Min, c[1]' * x)

# Solve 1.
optimize!(m)      # := line 42

# Modify.
@objective(m, Min, c[2]' * x)

# Solve 2.
optimize!(m)

There is no solver-agnostic way to prevent LP warm-starts.

There’s a open upstream issue to add support to HiGHS: Enable forced simplex refactorization · Issue #1598 · ERGO-Code/HiGHS · GitHub

As a high level comment, I get the sense that you are trying too hard to tune the solvers. Worrying about whether it takes 241 or 410 simplex iterations can make a difference for HiGHS and your current test set, but you might find that your parameters etc are suboptimal if you update HiGHS, or if you use some new data in a couple of months. In most cases, letting HiGHS decide to warmstart is probably a good thing.

1 Like

Having said that, if you are using Model (this won’t work in direct mode), you could try:

model = Model(HiGHS.Optimizer)
# create
optimize!(model)
# modify
MOI.Utilities.reset_optimizer(model)
optimize!(model)

You are totally right with that!


Background

With that said, the MWE was probably chosen too simple (but it was the only one I could quickly draft). One example for a setting that is a “no-brainer” (ok… under specific circumstances), is presolve: off.

It’s really hard convincing HiGHS to turn presolve on again, for example:

  1. solve (ret: infeasible)
  2. presolve: off
  3. resolve => dualray
  4. ensure feasibility
  5. presolve: on
  6. turn on presolve
  7. try resolve.

Having presolve skipped (even though it’s set to on) - based on an infeasible previous run - may (worst case) prevent HiGHS from finding a solution to the now feasible model.

1 Like

That works - nice!

Buuut… yeah, the actual “performance” code makes use of direct_model. I’ll just refactor to using non direct mode for HiGHS for now, and see if that helps. Maybe I don’t need direct mode at all afterwards.

Thanks a lot (as always) :tada:

1 Like