Juniper.jl
Juniper.jl copied to clipboard
Juniper integer-objective fails on specific parameters
Cut per @odow in discourse.
Simple sum-of-squares toy example, succeeds with 5 variables, stack-trace with 6 variables.
I know it’s sort of a silly example, but it feels to me like the behaviour should be consistent between problem_size = 5 and 6.
(full code as testcase.txt
attached)
optimizer = Juniper.Optimizer
nl_solver = optimizer_with_attributes(Ipopt.Optimizer,
"print_level" => 0)
mip_solver = optimizer_with_attributes(HiGHS.Optimizer,
"output_flag" => true)
model = Model(optimizer_with_attributes(
optimizer,
"nl_solver"=>nl_solver,
"mip_solver"=>mip_solver,
"log_levels"=>[:Info, :Table, :Timing, :AllOptions]))
# 6 fails. 5 works.
problem_size = 6
# x .>= 0, sum(x) >= 4
@variable(model, x[1:problem_size], integer=true)
@constraint(model, x .>= zeros(Int, problem_size))
@constraint(model, sum(x[i] for i in 1:problem_size) >= 4)
# Minimize sum(x.^2)
# Works if integer = false.
@variable(model, x_squared[1:problem_size], integer=true)
for i in 1:problem_size
@NLconstraint(model, x_squared[i] == x[i] ^ 2)
end
@NLobjective(model, Min,
x_squared[1]
+ x_squared[2]
+ x_squared[3]
+ x_squared[4]
+ x_squared[5]
+ x_squared[6])
# Also fails.
#@NLobjective(model, Min, sum(x_squared[i] for i in 1:problem_size))
optimize!(model)
causes stack-trace:
(full output in output.txt
attached)
ERROR: MethodError: no method matching operate(::typeof(-), ::Type{Int64}, ::MathOptInterface.ScalarAffineFunction{Int64}, ::MathOptInterface.ScalarAffineFunction{Float64})
Closest candidates are:
operate(::typeof(+), ::Type{T}, ::Any, ::Any, ::Any, ::Any...) where T at ~/.julia/packages/MathOptInterface/FHFUH/src/Utilities/functions.jl:1608
operate(::typeof(-), ::Type{T}, ::MathOptInterface.ScalarAffineFunction{T}) where T at ~/.julia/packages/MathOptInterface/FHFUH/src/Utilities/functions.jl:1674
operate(::Union{typeof(+), typeof(-)}, ::Type{T}, ::MathOptInterface.ScalarAffineFunction{T}, ::MathOptInterface.ScalarQuadraticFunction{T}) where T at ~/.julia/packages/MathOptInterface/FHFUH/src/Utilities/functions.jl:1691
...
Stacktrace:
[1] -(arg::MathOptInterface.ScalarAffineFunction{Int64}, args::MathOptInterface.ScalarAffineFunction{Float64})
@ MathOptInterface.Utilities ~/.julia/packages/MathOptInterface/FHFUH/src/Utilities/functions.jl:1776
[2] promote_operation_fallback(op::typeof(-), #unused#::Type{MathOptInterface.ScalarAffineFunction{Int64}}, #unused#::Type{MathOptInterface.ScalarAffineFunction{Float64}})
@ MutableArithmetics ~/.julia/packages/MutableArithmetics/BOohi/src/interface.jl:37
[3] promote_operation(::typeof(-), ::Type, ::Type)
@ MutableArithmetics ~/.julia/packages/MutableArithmetics/BOohi/src/interface.jl:99
[4] promote_operation_fallback(op::typeof(MutableArithmetics.sub_mul), #unused#::Type{MathOptInterface.ScalarAffineFunction{Int64}}, #unused#::Type{Float64}, #unused#::Type{MathOptInterface.VariableIndex})
@ MutableArithmetics ~/.julia/packages/MutableArithmetics/BOohi/src/interface.jl:69
[5] promote_operation(::typeof(MutableArithmetics.sub_mul), ::Type, ::Type, ::Type)
@ MutableArithmetics ~/.julia/packages/MutableArithmetics/BOohi/src/interface.jl:99
[6] mutability(::Type, ::Function, ::Type, ::Type, ::Type)
@ MutableArithmetics ~/.julia/packages/MutableArithmetics/BOohi/src/interface.jl:232
[7] mutability(::MathOptInterface.ScalarAffineFunction{Int64}, ::Function, ::MathOptInterface.ScalarAffineFunction{Int64}, ::Float64, ::MathOptInterface.VariableIndex)
@ MutableArithmetics ~/.julia/packages/MutableArithmetics/BOohi/src/interface.jl:240
[8] operate!!(::typeof(MutableArithmetics.sub_mul), ::MathOptInterface.ScalarAffineFunction{Int64}, ::Float64, ::MathOptInterface.VariableIndex)
@ MutableArithmetics ~/.julia/packages/MutableArithmetics/BOohi/src/rewrite.jl:88
[9] macro expansion
@ ~/.julia/packages/MutableArithmetics/BOohi/src/rewrite.jl:288 [inlined]
[10] generate_mip(optimizer::Juniper.Optimizer, m::Juniper.JuniperProblem, nlp_sol::Vector{Float64}, tabu_list::Juniper.TabuList, start_fpump::Float64)
@ Juniper ~/.julia/packages/Juniper/HEO6p/src/fpump.jl:74
[11] fpump(optimizer::Juniper.Optimizer, m::Juniper.JuniperProblem)
@ Juniper ~/.julia/packages/Juniper/HEO6p/src/fpump.jl:352
[12] optimize!(model::Juniper.Optimizer)
@ Juniper ~/.julia/packages/Juniper/HEO6p/src/MOI_wrapper/MOI_wrapper.jl:343
[13] optimize!
@ ~/.julia/packages/MathOptInterface/FHFUH/src/Bridges/bridge_optimizer.jl:348 [inlined]
[14] optimize!
@ ~/.julia/packages/MathOptInterface/FHFUH/src/MathOptInterface.jl:81 [inlined]
[15] optimize!(m::MathOptInterface.Utilities.CachingOptimizer{MathOptInterface.Bridges.LazyBridgeOptimizer{Juniper.Optimizer}, MathOptInterface.Utilities.UniversalFallback{MathOptInterface.Utilities.Model{Float6
4}}})
@ MathOptInterface.Utilities ~/.julia/packages/MathOptInterface/FHFUH/src/Utilities/cachingoptimizer.jl:313
[16] optimize!(model::Model; ignore_optimize_hook::Bool, kwargs::Base.Pairs{Symbol, Union{}, Tuple{}, NamedTuple{(), Tuple{}}})
@ JuMP ~/.julia/packages/JuMP/R2Knd/src/optimizer_interface.jl:161
[17] optimize!
@ ~/.julia/packages/JuMP/R2Knd/src/optimizer_interface.jl:143 [inlined]
[18] test()
@ Main ./REPL[510]:40
[19] top-level scope
@ ./timing.jl:220 [inlined]
[20] top-level scope
@ ./REPL[511]:0
Edit: package versions from my system:
Status `~/.julia/environments/v1.7/Project.toml`
[87dc4568] HiGHS v1.1.1
[b6b21f68] Ipopt v1.0.2
[4076af6c] JuMP v0.23.1
[2ddba703] Juniper v0.9.0
[b8f27783] MathOptInterface v1.1.0
[d8a4904e] MutableArithmetics v1.0.0
I haven't debugged, but the problem looks to be here: https://github.com/lanl-ansi/Juniper.jl/blob/7e529e98cd22482071e0f150bd6917e01ec5f94d/src/fpump.jl#L67-L83
We're producing a ScalarAffineFunction{Int}
instead of ScalarAffineFunction{Float64}
. It's probably just a matter of adding some Float64
casts in the right places.