Issue using Convex with HiGHS for QP

I’ve been using HiGHS with Convex.jl lately for some MILPs and needed also to solve a simple continuous sum of squares minimisation. HiGHS can do this and HiGHS.jl should support this since https://github.com/jump-dev/HiGHS.jl/pull/56 was merged.

However, with a trivial problem:

using Convex, HiGHS

v = Variable(Positive())
problem = minimize(square(v))
solve!(problem, HiGHS.Optimizer())

here’s what I get:

ERROR: MathOptInterface.UnsupportedConstraint{MathOptInterface.VectorAffineFunction{Float64}, MathOptInterface.SecondOrderCone}: `MathOptInterface.VectorAffineFunction{Float64}`-in-`MathOptInterface.SecondOrderCone` constraint is not supported by the model.
Stacktrace:
  [1] bridge_type(b::MathOptInterface.Bridges.LazyBridgeOptimizer{MathOptInterface.Utilities.CachingOptimizer{HiGHS.Optimizer, MathOptInterface.Utilities.UniversalFallback{MathOptInterface.Utilities.Model{Float64}}}}, F::Type{MathOptInterface.VectorAffineFunction{Float64}}, S::Type{MathOptInterface.SecondOrderCone})
    @ MathOptInterface.Bridges ~/.julia/packages/MathOptInterface/Iu5eI/src/Bridges/lazy_bridge_optimizer.jl:441
  [2] concrete_bridge_type(b::MathOptInterface.Bridges.LazyBridgeOptimizer{MathOptInterface.Utilities.CachingOptimizer{HiGHS.Optimizer, MathOptInterface.Utilities.UniversalFallback{MathOptInterface.Utilities.Model{Float64}}}}, F::Type{MathOptInterface.VectorAffineFunction{Float64}}, S::Type{MathOptInterface.SecondOrderCone})
    @ MathOptInterface.Bridges.Constraint ~/.julia/packages/MathOptInterface/Iu5eI/src/Bridges/Constraint/bridge.jl:145
  [3] add_constraint(b::MathOptInterface.Bridges.LazyBridgeOptimizer{MathOptInterface.Utilities.CachingOptimizer{HiGHS.Optimizer, MathOptInterface.Utilities.UniversalFallback{MathOptInterface.Utilities.Model{Float64}}}}, f::MathOptInterface.VectorAffineFunction{Float64}, s::MathOptInterface.SecondOrderCone)
    @ MathOptInterface.Bridges ~/.julia/packages/MathOptInterface/Iu5eI/src/Bridges/bridge_optimizer.jl:1599
  [4] _broadcast_getindex_evalf(::typeof(MathOptInterface.add_constraint), ::MathOptInterface.Bridges.LazyBridgeOptimizer{MathOptInterface.Utilities.CachingOptimizer{HiGHS.Optimizer, MathOptInterface.Utilities.UniversalFallback{MathOptInterface.Utilities.Model{Float64}}}}, ::MathOptInterface.VectorAffineFunction{Float64}, ::MathOptInterface.SecondOrderCone)
    @ Base.Broadcast ./broadcast.jl:670
  [5] _broadcast_getindex
    @ ./broadcast.jl:643 [inlined]
  [6] getindex
    @ ./broadcast.jl:597 [inlined]
  [7] copyto_nonleaf!(dest::Vector{MathOptInterface.ConstraintIndex{MathOptInterface.VectorAffineFunction{Float64}, MathOptInterface.Nonnegatives}}, bc::Base.Broadcast.Broadcasted{Base.Broadcast.DefaultArrayStyle{1}, Tuple{Base.OneTo{Int64}}, typeof(MathOptInterface.add_constraint), Tuple{Base.RefValue{MathOptInterface.Bridges.LazyBridgeOptimizer{MathOptInterface.Utilities.CachingOptimizer{HiGHS.Optimizer, MathOptInterface.Utilities.UniversalFallback{MathOptInterface.Utilities.Model{Float64}}}}}, Base.Broadcast.Extruded{Vector{Union{MathOptInterface.VariableIndex, MathOptInterface.VectorAffineFunction{Float64}}}, Tuple{Bool}, Tuple{Int64}}, Base.Broadcast.Extruded{Vector{Any}, Tuple{Bool}, Tuple{Int64}}}}, iter::Base.OneTo{Int64}, state::Int64, count::Int64)
    @ Base.Broadcast ./broadcast.jl:1055
  [8] copy
    @ ./broadcast.jl:907 [inlined]
  [9] materialize
    @ ./broadcast.jl:860 [inlined]
 [10] add_constraints(model::MathOptInterface.Bridges.LazyBridgeOptimizer{MathOptInterface.Utilities.CachingOptimizer{HiGHS.Optimizer, MathOptInterface.Utilities.UniversalFallback{MathOptInterface.Utilities.Model{Float64}}}}, funcs::Vector{Union{MathOptInterface.VariableIndex, MathOptInterface.VectorAffineFunction{Float64}}}, sets::Vector{Any})
    @ MathOptInterface ~/.julia/packages/MathOptInterface/Iu5eI/src/constraints.jl:228
 [11] load_MOI_model!(model::MathOptInterface.Bridges.LazyBridgeOptimizer{MathOptInterface.Utilities.CachingOptimizer{HiGHS.Optimizer, MathOptInterface.Utilities.UniversalFallback{MathOptInterface.Utilities.Model{Float64}}}}, problem::Problem{Float64})
    @ Convex ~/.julia/packages/Convex/FQF1R/src/solution.jl:259
 [12] solve!(problem::Problem{Float64}, optimizer::HiGHS.Optimizer; check_vexity::Bool, verbose::Bool, warmstart::Bool, silent_solver::Bool)
    @ Convex ~/.julia/packages/Convex/FQF1R/src/solution.jl:313
 [13] solve!(problem::Problem{Float64}, optimizer::HiGHS.Optimizer)
    @ Convex ~/.julia/packages/Convex/FQF1R/src/solution.jl:301
 [14] top-level scope
    @ REPL[5]:1

When using JuMP instead of Convex, the equivalent formulation of the problem solves correctly.

Am I doing something wrong or is Convex transforming square(v) in a way incompatible with HiGHS QP solver?

It’s the latter. You can’t use HiGHS for this problem because it does not support second order cone constraints.

2 Likes