ERGO-Code / HiGHS

Linear optimization software
MIT License
996 stars 187 forks source link

QP solver infinite loop #1583

Open jajhall opened 10 months ago

jajhall commented 10 months ago

For the following very simple QP, the solver gets into an infinite loop

include "Highs.h"

int main() { HighsModel model; HighsLp& lp = model.lp; HighsHessian& hessian = model.hessian; lp.numcol = 2; lp.numrow = 2; lp.colcost = {0, 1}; lp.collower = {0, 0}; lp.colupper = {kHighsInf, kHighsInf}; lp.amatrix.start_ = {0, 2, 4}; lp.amatrix.index_ = {0, 1, 0, 1}; lp.amatrix.value_ = {800, 400, 1, 1}; lp.rowlower = {40000, 30000}; lp.rowupper = {kHighsInf, kHighsInf}; hessian.dim_ = lp.numcol; hessian.start = {0, 1, 1}; hessian.index = {0}; hessian.value_ = {6}; Highs highs; highs.passModel(model); highs.setOptionValue("time_limit", 0.1); highs.run(); exit(1); }

It also exposes a bug when the time limit is reached for a QP

feldmeier commented 10 months ago

Thanks, will try to reproduce and fix

feldmeier commented 10 months ago

The loop arises as the QP solver wrongly thinks that the search direction in the second iteration doesn't have curvature (p'Qp is less than a threshold) and thus oversteps. It is fixed by tightening the threshold in computemaxsteplength() in quass.cpp to e.g. 10E-8. I'll need to check whether this potential fix negatively impacts any other instances. I'll also move the hard coded threshold into a solver setting.

What's the issue with the time limit?

odow commented 10 months ago

I think the time limit is just that the solver doesn't terminate until it hits the time limit.

We don't necessarily need to fix the tolerance (the model is arguably poorly scaled), but if it starts to cycle ideally we should detect that and terminate.

jajhall commented 10 months ago

The QP solver stops OK on the time limit, but the next level of HiGHS doesn't handle the situation correctly

That's for me to fix

feldmeier commented 10 months ago

I'll see what I can do. Detecting overstepping (objective getting worse) is easy, Detecting a loop of length 2 should be doable, but arbitrary length loops without objective change takes massive housekeeping to detect

jajhall commented 10 months ago

The simplex solvers have a system for identifying cycling - written by @lgottwald - that hashes a basis to see whether there is a possible repetition. Still non-trivial, though

feldmeier commented 10 months ago

Tightening the tolerance doesn't appear to break any other QP instances. I'll leave cycle detection for when I'm done with my dissertation

sstroemer commented 1 month ago

I'm not sure if this is the right place, since I've seen that the related fix has been merged - but it's still open so I didn't want to start a new one.

I'm using HiGHS.jl v1.9.3 to solve a simple quadratic model. It seems like the solution is found immediately, since the ObjVal does not change anymore after iteration 0. Afterwards it gets stuck in an endless loop.

Code snippet

using JuMP
import HiGHS

m = read_from_file("qp_loop_mwe.mps")
set_optimizer(m, HiGHS.Optimizer)
optimize!(m)

Model MPS file

gist: sstroemer/cb9daf