Skip to content

Commit

Permalink
Fix ConstraintDualStart for ScalarNonlinearFunction
Browse files Browse the repository at this point in the history
  • Loading branch information
odow committed Jul 26, 2024
1 parent 9489fc9 commit ea9fec0
Show file tree
Hide file tree
Showing 2 changed files with 53 additions and 2 deletions.
42 changes: 40 additions & 2 deletions src/MOI_wrapper.jl
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ mutable struct Optimizer <: MOI.AbstractOptimizer

nlp_data::MOI.NLPBlockData
nlp_dual_start::Union{Nothing,Vector{Float64}}

mult_g_nlp::Dict{MOI.Nonlinear.ConstraintIndex,Float64}
qp_data::QPBlockData{Float64}
nlp_model::Union{Nothing,MOI.Nonlinear.Model}
callback::Union{Nothing,Function}
Expand All @@ -62,6 +62,7 @@ mutable struct Optimizer <: MOI.AbstractOptimizer
Union{Nothing,Float64}[],
MOI.NLPBlockData([], _EmptyNLPEvaluator(), false),
nothing,
Dict{MOI.Nonlinear.ConstraintIndex,Float64}(),
QPBlockData{Float64}(),
nothing,
nothing,
Expand Down Expand Up @@ -402,7 +403,6 @@ function MOI.get(
attr::Union{
MOI.ConstraintFunction,
MOI.ConstraintSet,
MOI.ConstraintDualStart,
},
c::MOI.ConstraintIndex{F,S},
) where {F<:_FUNCTIONS,S<:_SETS}
Expand All @@ -428,6 +428,14 @@ function MOI.supports(
return true
end

function MOI.get(
model::Optimizer,
attr::MOI.ConstraintDualStart,
c::MOI.ConstraintIndex{F,S},
) where {F<:_FUNCTIONS,S<:_SETS}
return MOI.get(model.qp_data, attr, c)
end

function MOI.set(
model::Optimizer,
attr::MOI.ConstraintDualStart,
Expand All @@ -440,6 +448,33 @@ function MOI.set(
return
end

function MOI.get(
model::Optimizer,
attr::MOI.ConstraintDualStart,
ci::MOI.ConstraintIndex{MOI.ScalarNonlinearFunction,S},
) where {S<:_SETS}
MOI.throw_if_not_valid(model, ci)
index = MOI.Nonlinear.ConstraintIndex(ci.value)
return get(model.mult_g_nlp, index, nothing)
end

function MOI.set(
model::Optimizer,
attr::MOI.ConstraintDualStart,
ci::MOI.ConstraintIndex{MOI.ScalarNonlinearFunction,S},
value::Union{Real,Nothing},
) where {S<:_SETS}
MOI.throw_if_not_valid(model, ci)
index = MOI.Nonlinear.ConstraintIndex(ci.value)
if value === nothing
delete!(model.mult_g_nlp, index)
else
model.mult_g_nlp[index] = convert(Float64, value)
end
# No need to reset model.inner, because this gets handled in optimize!.
return
end

### ScalarNonlinearFunction

function MOI.is_valid(
Expand Down Expand Up @@ -940,6 +975,9 @@ function MOI.optimize!(model::Optimizer)
offset = length(model.qp_data.mult_g)
if model.nlp_dual_start === nothing
inner.mult_g[(offset+1):end] .= 0.0
for (key, val) in model.mult_g_nlp
inner.mult_g[offset + key.value] = val
end

Check warning on line 980 in src/MOI_wrapper.jl

View check run for this annotation

Codecov / codecov/patch

src/MOI_wrapper.jl#L979-L980

Added lines #L979 - L980 were not covered by tests
else
for (i, start) in enumerate(model.nlp_dual_start::Vector{Float64})
inner.mult_g[offset+i] = _dual_start(model, start, -1)
Expand Down
13 changes: 13 additions & 0 deletions test/MOI_wrapper.jl
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,19 @@ function test_ConstraintDualStart()
return
end

function test_ConstraintDualStart_ScalarNonlinearFunction()
model = Ipopt.Optimizer()
x = MOI.add_variables(model, 2)
f = MOI.ScalarNonlinearFunction(:sin, Any[1.0 * x[1] - 1.0 * x[2]])
c = MOI.add_constraint(model, f, MOI.EqualTo(0.5))
@test MOI.get(model, MOI.ConstraintDualStart(), c) === nothing
MOI.set(model, MOI.ConstraintDualStart(), c, 0.1)
@test MOI.get(model, MOI.ConstraintDualStart(), c) === 0.1
MOI.set(model, MOI.ConstraintDualStart(), c, nothing)
@test MOI.get(model, MOI.ConstraintDualStart(), c) === nothing
return
end

function test_solve_time()
model = Ipopt.Optimizer()
MOI.set(model, MOI.Silent(), true)
Expand Down

0 comments on commit ea9fec0

Please sign in to comment.