Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Querying objective_value errors when quadratic objective has no quadratic term (conic solvers only) #2239

Closed
mtanneau opened this issue Jul 28, 2023 · 2 comments · Fixed by #2240

Comments

@mtanneau
Copy link
Contributor

mtanneau commented Jul 28, 2023

I encountered an error when querying the objective value of an optimization problem in the following circumstances:

  • The objective is quadratic, but all the quadratic terms are zero
  • The solver supports SOC constraints but not quadratic objective (nor quadratic constraints I guess)
    --> the example below use ECOS, and I got the same error with Mosek
    (FYI, Hypatia also errored, but for a different reason; I'll open an issue there)
  • The model uses bridges (ECOS and Mosek do not support quadratic objectives)

For more context: I was solving SOC relaxations of Optimal Power Flow problems.
The objective function, in general, is quadratic, it just happens that certain tests cases have no quadratic objective.
The example below is a much reduced test case.

__

Minimal reproducible example:

using JuMP
using ECOS

model = Model(ECOS.Optimizer);
@variable(model, x >= 0)
@constraint(model, con, x == 1)  # not needed for the error, just to show that dual variables can be queried
@objective(model, Min, 0*x*x + x)
optimize!(model)

@show termination_status(model)
@show primal_status(model)
@show dual_status(model)
@show value(x)
@show dual(con)
@show dual_objective_value(model)  # weirdly enough this works fine
@show objective_value(model)       # 💥

Note that objective_function(model) has the type QuadExpr.

All termination/primal/dual statuses are green, and I am able to query the value of primal and dual variables.
So far so good. However, querying objective_value(model) leads to this error:

ERROR: MethodError: reducing over an empty collection is not allowed; consider supplying `init` to the reducer
Stacktrace:
  [1] reduce_empty(op::Base.MappingRF{MathOptInterface.Bridges.Constraint.var"#114#115"{Vector{Float64}}, Base.BottomRF{typeof(Base.add_sum)}}, #unused#::Type{Int64})
    @ Base ./reduce.jl:356
  [2] reduce_empty_iter
    @ ./reduce.jl:379 [inlined]
  [3] reduce_empty_iter
    @ ./reduce.jl:378 [inlined]
  [4] foldl_impl
    @ ./reduce.jl:49 [inlined]
  [5] mapfoldl_impl
    @ ./reduce.jl:44 [inlined]
  [6] #mapfoldl#288
    @ ./reduce.jl:170 [inlined]
  [7] mapfoldl
    @ ./reduce.jl:170 [inlined]
  [8] #mapreduce#292
    @ ./reduce.jl:302 [inlined]
  [9] mapreduce
    @ ./reduce.jl:302 [inlined]
 [10] #sum#295
    @ ./reduce.jl:530 [inlined]
 [11] sum
    @ ./reduce.jl:530 [inlined]
 [12] #sum#296
    @ ./reduce.jl:559 [inlined]
 [13] sum(a::Base.Generator{UnitRange{Int64}, MathOptInterface.Bridges.Constraint.var"#114#115"{Vector{Float64}}})
    @ Base ./reduce.jl:559
 [14] get(model::MathOptInterface.Bridges.LazyBridgeOptimizer{MathOptInterface.Utilities.CachingOptimizer{ECOS.Optimizer, MathOptInterface.Utilities.UniversalFallback{ECOS.OptimizerCache}}}, attr::MathOptInterface.ConstraintPrimal, bridge::MathOptInterface.Bridges.Constraint.QuadtoSOCBridge{Float64})
    @ MathOptInterface.Bridges.Constraint ~/.julia/packages/MathOptInterface/864xP/src/Bridges/Constraint/bridges/quad_to_soc.jl:245
 [15] (::MathOptInterface.Bridges.var"#3#4"{typeof(MathOptInterface.get), MathOptInterface.Bridges.LazyBridgeOptimizer{MathOptInterface.Utilities.CachingOptimizer{ECOS.Optimizer, MathOptInterface.Utilities.UniversalFallback{ECOS.OptimizerCache}}}, MathOptInterface.ConstraintPrimal, Tuple{}})(bridge::MathOptInterface.Bridges.Constraint.QuadtoSOCBridge{Float64})
    @ MathOptInterface.Bridges ~/.julia/packages/MathOptInterface/864xP/src/Bridges/bridge_optimizer.jl:333
 [16] (::MathOptInterface.Bridges.var"#1#2"{MathOptInterface.Bridges.LazyBridgeOptimizer{MathOptInterface.Utilities.CachingOptimizer{ECOS.Optimizer, MathOptInterface.Utilities.UniversalFallback{ECOS.OptimizerCache}}}, MathOptInterface.ConstraintIndex{MathOptInterface.ScalarQuadraticFunction{Float64}, MathOptInterface.LessThan{Float64}}, MathOptInterface.Bridges.var"#3#4"{typeof(MathOptInterface.get), MathOptInterface.Bridges.LazyBridgeOptimizer{MathOptInterface.Utilities.CachingOptimizer{ECOS.Optimizer, MathOptInterface.Utilities.UniversalFallback{ECOS.OptimizerCache}}}, MathOptInterface.ConstraintPrimal, Tuple{}}})()
    @ MathOptInterface.Bridges ~/.julia/packages/MathOptInterface/864xP/src/Bridges/bridge_optimizer.jl:318
 [17] call_in_context(map::MathOptInterface.Bridges.Variable.Map, bridge_index::Int64, f::MathOptInterface.Bridges.var"#1#2"{MathOptInterface.Bridges.LazyBridgeOptimizer{MathOptInterface.Utilities.CachingOptimizer{ECOS.Optimizer, MathOptInterface.Utilities.UniversalFallback{ECOS.OptimizerCache}}}, MathOptInterface.ConstraintIndex{MathOptInterface.ScalarQuadraticFunction{Float64}, MathOptInterface.LessThan{Float64}}, MathOptInterface.Bridges.var"#3#4"{typeof(MathOptInterface.get), MathOptInterface.Bridges.LazyBridgeOptimizer{MathOptInterface.Utilities.CachingOptimizer{ECOS.Optimizer, MathOptInterface.Utilities.UniversalFallback{ECOS.OptimizerCache}}}, MathOptInterface.ConstraintPrimal, Tuple{}}})
    @ MathOptInterface.Bridges.Variable ~/.julia/packages/MathOptInterface/864xP/src/Bridges/Variable/map.jl:469
 [18] call_in_context
    @ ~/.julia/packages/MathOptInterface/864xP/src/Bridges/Variable/map.jl:500 [inlined]
 [19] call_in_context
    @ ~/.julia/packages/MathOptInterface/864xP/src/Bridges/bridge_optimizer.jl:315 [inlined]
 [20] call_in_context
    @ ~/.julia/packages/MathOptInterface/864xP/src/Bridges/bridge_optimizer.jl:330 [inlined]
 [21] get(b::MathOptInterface.Bridges.LazyBridgeOptimizer{MathOptInterface.Utilities.CachingOptimizer{ECOS.Optimizer, MathOptInterface.Utilities.UniversalFallback{ECOS.OptimizerCache}}}, attr::MathOptInterface.ConstraintPrimal, ci::MathOptInterface.ConstraintIndex{MathOptInterface.ScalarQuadraticFunction{Float64}, MathOptInterface.LessThan{Float64}})
    @ MathOptInterface.Bridges ~/.julia/packages/MathOptInterface/864xP/src/Bridges/bridge_optimizer.jl:1422
 [22] get(model::MathOptInterface.Bridges.LazyBridgeOptimizer{MathOptInterface.Utilities.CachingOptimizer{ECOS.Optimizer, MathOptInterface.Utilities.UniversalFallback{ECOS.OptimizerCache}}}, attr::MathOptInterface.Bridges.ObjectiveFunctionValue{MathOptInterface.ScalarQuadraticFunction{Float64}}, bridge::MathOptInterface.Bridges.Objective.SlackBridge{Float64, MathOptInterface.ScalarQuadraticFunction{Float64}, MathOptInterface.ScalarQuadraticFunction{Float64}})
    @ MathOptInterface.Bridges.Objective ~/.julia/packages/MathOptInterface/864xP/src/Bridges/Objective/bridges/slack.jl:158
 [23] get(b::MathOptInterface.Bridges.LazyBridgeOptimizer{MathOptInterface.Utilities.CachingOptimizer{ECOS.Optimizer, MathOptInterface.Utilities.UniversalFallback{ECOS.OptimizerCache}}}, attr::MathOptInterface.Bridges.ObjectiveFunctionValue{MathOptInterface.ScalarQuadraticFunction{Float64}})
    @ MathOptInterface.Bridges ~/.julia/packages/MathOptInterface/864xP/src/Bridges/bridge_optimizer.jl:1056
 [24] get(b::MathOptInterface.Bridges.LazyBridgeOptimizer{MathOptInterface.Utilities.CachingOptimizer{ECOS.Optimizer, MathOptInterface.Utilities.UniversalFallback{ECOS.OptimizerCache}}}, attr::MathOptInterface.ObjectiveValue)
    @ MathOptInterface.Bridges ~/.julia/packages/MathOptInterface/864xP/src/Bridges/bridge_optimizer.jl:1065
 [25] _get_model_attribute(model::MathOptInterface.Utilities.CachingOptimizer{MathOptInterface.Bridges.LazyBridgeOptimizer{MathOptInterface.Utilities.CachingOptimizer{ECOS.Optimizer, MathOptInterface.Utilities.UniversalFallback{ECOS.OptimizerCache}}}, MathOptInterface.Utilities.UniversalFallback{MathOptInterface.Utilities.Model{Float64}}}, attr::MathOptInterface.ObjectiveValue)
    @ MathOptInterface.Utilities ~/.julia/packages/MathOptInterface/864xP/src/Utilities/cachingoptimizer.jl:828
 [26] get
    @ ~/.julia/packages/MathOptInterface/864xP/src/Utilities/cachingoptimizer.jl:876 [inlined]
 [27] _moi_get_result(model::MathOptInterface.Utilities.CachingOptimizer{MathOptInterface.Bridges.LazyBridgeOptimizer{MathOptInterface.Utilities.CachingOptimizer{ECOS.Optimizer, MathOptInterface.Utilities.UniversalFallback{ECOS.OptimizerCache}}}, MathOptInterface.Utilities.UniversalFallback{MathOptInterface.Utilities.Model{Float64}}}, args::MathOptInterface.ObjectiveValue)
    @ JuMP ~/.julia/packages/JuMP/jZvaU/src/optimizer_interface.jl:638
 [28] get(model::Model, attr::MathOptInterface.ObjectiveValue)
    @ JuMP ~/.julia/packages/JuMP/jZvaU/src/optimizer_interface.jl:658
 [29] objective_value(model::Model; result::Int64)
    @ JuMP ~/.julia/packages/JuMP/jZvaU/src/objective.jl:54
 [30] objective_value(model::Model)
    @ JuMP ~/.julia/packages/JuMP/jZvaU/src/objective.jl:50
 [31] top-level scope
    @ REPL[15]:1
@odow
Copy link
Member

odow commented Jul 29, 2023

Let me take a look. I think I know the issue.

@odow odow transferred this issue from jump-dev/JuMP.jl Jul 29, 2023
@odow
Copy link
Member

odow commented Jul 29, 2023

This is the issue

output = sum(soc[i]^2 for i in 3:bridge.dimension)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Development

Successfully merging a pull request may close this issue.

2 participants