jump-dev / HiGHS.jl

A Julia interface to the HiGHS solver
https://highs.dev
MIT License
103 stars 14 forks source link

Error when nonzero coefficient close to zero #73

Closed guberger closed 2 years ago

guberger commented 2 years ago

Hello! I get an error when I run the following code:

using JuMP
using HiGHS
model = Model(HiGHS.Optimizer)
@variable(model, x)
@constraint(model, 1e-9*x <= 1) # works with @constraint(model, 0*x <= 1)
optimize!(model)
WARNING: LP matrix packed vector contains 1 |values| in [1e-09, 1e-09] less than 1e-09: ignored
ERROR: Encountered an error in HiGHS (Status 1). Check the log for details.

(log file empty) Version info:

Julia Version 1.7.0
Commit 3bf9d17731 (2021-11-30 12:12 UTC)
Platform Info:
  OS: Windows (x86_64-w64-mingw32)
  CPU: Intel(R) Core(TM) i7-7600U CPU @ 2.80GHz
  WORD_SIZE: 64
  LIBM: libopenlibm
  LLVM: libLLVM-12.0.1 (ORCJIT, skylake)
  [87dc4568] HiGHS v0.3.0
  [4076af6c] JuMP v0.22.1
odow commented 2 years ago

Interesting edge case. I guess this makes sense. HiGHS ignores very small coefficients, and then once you've ignored the small coefficient it's left with a constraint matrix that has no non-zeros.

What happens if you have other non-zeros? i.e., other variables or constraints with coefficients > 1e-09

cc @jajhall

guberger commented 2 years ago

Similar code with

@variable(model, x[1:2])
@constraint(model, [1, 1e-9]'*x <= 1)

fails as well :-/ (same for

@variable(model, x)
@variable(model, y)
@constraint(model, x + 1e-9*y <= 1)

)

jajhall commented 2 years ago

Anything less than or equal to small_matrix_value (which is 1e-9 by default) is ignored by HiGHS. The wording of the warning message could be better.

If you really want values of 1e-9 to be used, reduce the value of small_matrix_value using a setOptions call

odow commented 2 years ago

I think the problem is the error code at some point. I'll need to come up with a reproducible example in C, but it shouldn't be too difficult.

odow commented 2 years ago

@guberger do you have the full stack trace?

guberger commented 2 years ago

Here :-)

WARNING: LP matrix packed vector contains 1 |values| in [1e-09, 1e-09] less than 1e-09: ignored
ERROR: Encountered an error in HiGHS (Status 1). Check the log for details.
Stacktrace:
  [1] error(s::String)
    @ Base .\error.jl:33
  [2] _check_ret
    @ C:\Users\guberger\.julia\packages\HiGHS\gxmTb\src\MOI_wrapper.jl:347 [inlined]
  [3] add_constraint(model::HiGHS.Optimizer, f::MathOptInterface.ScalarAffineFunction{Float64}, s::MathOptInterface.LessThan{Float64})
    @ HiGHS C:\Users\guberger\.julia\packages\HiGHS\gxmTb\src\MOI_wrapper.jl:1279
  [4] _copy_constraints(dest::HiGHS.Optimizer, src::MathOptInterface.Utilities.UniversalFallback{MathOptInterface.Utilities.Model{Float64}}, index_map::MathOptInterface.Utilities.IndexMap, cis_src::Vector{MathOptInterface.ConstraintIndex{MathOptInterface.ScalarAffineFunction{Float64}, MathOptInterface.LessThan{Float64}}})
    @ MathOptInterface.Utilities C:\Users\guberger\.julia\packages\MathOptInterface\eoIu0\src\Utilities\copy.jl:248
  [5] pass_nonvariable_constraints_fallback(dest::HiGHS.Optimizer, src::MathOptInterface.Utilities.UniversalFallback{MathOptInterface.Utilities.Model{Float64}}, index_map::MathOptInterface.Utilities.IndexMap, constraint_types::Vector{Any})
    @ MathOptInterface.Utilities C:\Users\guberger\.julia\packages\MathOptInterface\eoIu0\src\Utilities\copy.jl:261
  [6] pass_nonvariable_constraints
    @ C:\Users\guberger\.julia\packages\MathOptInterface\eoIu0\src\Utilities\copy.jl:287 [inlined]
  [7] pass_nonvariable_constraints(dest::MathOptInterface.Bridges.LazyBridgeOptimizer{HiGHS.Optimizer}, src::MathOptInterface.Utilities.UniversalFallback{MathOptInterface.Utilities.Model{Float64}}, idxmap::MathOptInterface.Utilities.IndexMap, constraint_types::Vector{Any})
    @ MathOptInterface.Bridges C:\Users\guberger\.julia\packages\MathOptInterface\eoIu0\src\Bridges\bridge_optimizer.jl:406
  [8] _pass_constraints(dest::MathOptInterface.Bridges.LazyBridgeOptimizer{HiGHS.Optimizer}, src::MathOptInterface.Utilities.UniversalFallback{MathOptInterface.Utilities.Model{Float64}}, index_map::MathOptInterface.Utilities.IndexMap, variable_constraints_not_added::Vector{Any})
    @ MathOptInterface.Utilities C:\Users\guberger\.julia\packages\MathOptInterface\eoIu0\src\Utilities\copy.jl:309
  [9] default_copy_to(dest::MathOptInterface.Bridges.LazyBridgeOptimizer{HiGHS.Optimizer}, src::MathOptInterface.Utilities.UniversalFallback{MathOptInterface.Utilities.Model{Float64}})
    @ MathOptInterface.Utilities C:\Users\guberger\.julia\packages\MathOptInterface\eoIu0\src\Utilities\copy.jl:442
 [10] #copy_to#7
    @ C:\Users\guberger\.julia\packages\MathOptInterface\eoIu0\src\Bridges\bridge_optimizer.jl:421 [inlined]
 [11] copy_to
    @ C:\Users\guberger\.julia\packages\MathOptInterface\eoIu0\src\Bridges\bridge_optimizer.jl:421 [inlined]
 [12] optimize!
    @ C:\Users\guberger\.julia\packages\MathOptInterface\eoIu0\src\MathOptInterface.jl:80 [inlined]
 [13] optimize!(m::MathOptInterface.Utilities.CachingOptimizer{MathOptInterface.Bridges.LazyBridgeOptimizer{HiGHS.Optimizer}, MathOptInterface.Utilities.UniversalFallback{MathOptInterface.Utilities.Model{Float64}}})
    @ MathOptInterface.Utilities C:\Users\guberger\.julia\packages\MathOptInterface\eoIu0\src\Utilities\cachingoptimizer.jl:285
 [14] optimize!(model::Model, optimizer_factory::Nothing; bridge_constraints::Bool, ignore_optimize_hook::Bool, kwargs::Base.Pairs{Symbol, Union{}, Tuple{}, NamedTuple{(), Tuple{}}})
    @ JuMP C:\Users\guberger\.julia\packages\JuMP\2IF9U\src\optimizer_interface.jl:195
 [15] optimize! (repeats 2 times)
    @ C:\Users\guberger\.julia\packages\JuMP\2IF9U\src\optimizer_interface.jl:167 [inlined]
 [16] top-level scope
    @ REPL[13]:1
guberger commented 2 years ago

The problem seems to be in addRow in the C code of HiGHS, which returns an error code, following which _check_ret throws an error.

jajhall commented 2 years ago

The problem seems to be in addRow in the C code of HiGHS, which returns an error code, following which _check_ret throws an error.

I've reproduced your example with a C++ call to HiGHS. It loads the problem using a call to addCol and then addRow, and then solves it OK. For sure, addRow will return 1=(int)HighsStatus::kWarning rather than 0=HighsStatus::kOk, since we want to warn users that at least one of their values has been ignored. Maybe the Julia interface didn't anticipate having to handle anything other than kOk.

I've inserted "or equal to" into the warning message. :-)

odow commented 2 years ago

Okay, we need to update https://github.com/jump-dev/HiGHS.jl/blob/567ed76f40fe4fa0e65979219367054afca6b287/src/MOI_wrapper.jl#L345-L353 to not error on warnings. But potentially double check all usages to check there aren't any instances where 1 is a boolean error code.

Mastomaki commented 2 years ago

Hello!

I get this same error. It would help if I knew which coefficient is causing the problem. Is the coefficient as given by the user or is there already some automatic scaling?

WARNING: LP matrix packed vector contains 1 |values| in [2.14431e-10, 2.14431e-10] less than 1e-09: ignored
ERROR: LoadError: Encountered an error in HiGHS (Status 1). Check the log for details.
jajhall commented 2 years ago

This coefficient is given by the user. When there's only one small coefficient, clearly its row and column indices could be given, but if there are vast numbers, it doesn't seem sensible to report them all individually.

What might be helpful is a message that coefficient (row, col) is in [a, b] less than 1e-09, as are N others. Then a user would have somewhere to go to look for the small value, and that might explain all the rest?

Mastomaki commented 2 years ago

That's one possiblity. But I suppose it is possible to list more coefficients in the log file?

jajhall commented 2 years ago

If all small coefficients were listed by default, we'd be sure to have users complaining about excessive reporting. There is the option log_dev_level that is primarily for development logging so has a default value of zero. I could put out a full list of small values if it were set to a positive value. It wouldn't yield excessive development logging - principally a statement of feasibility etc every time the simplex basis matrix is refactorized - which was too "chatty" for some users to see by default!