Skip to content

Commit 7002857

Browse files
Add hability to query duals of multiplicative parameters in parameter… (#171)
* Add hability to query duals of multiplicative parameters in parameter * parameter terms * fix condition to evaluate duals of parameter * parameter * fix formatting * update delete methods * Add a new deletion test * [no ci] remove README * [no ci] Remove revise folder * update implementation * Add missing term in quadratic parametric function * Fix formatting * Update test/jump_tests.jl * fix corner case fo quadratic parameter * remove unnecessary types --------- Co-authored-by: Joaquim <[email protected]> Co-authored-by: joaquimg <[email protected]>
1 parent ab4da45 commit 7002857

File tree

6 files changed

+90
-22
lines changed

6 files changed

+90
-22
lines changed

Project.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
name = "ParametricOptInterface"
22
uuid = "0ce4ce61-57bf-432b-a095-efac525d185e"
33
authors = ["Tomás Gutierrez <[email protected]>"]
4-
version = "0.9.0"
4+
version = "0.10.0"
55

66
[deps]
77
MathOptInterface = "b8f27783-ece8-5eb3-8dc8-9495eed66fee"

src/MOI_wrapper.jl

Lines changed: 12 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -56,12 +56,11 @@ function _cache_multiplicative_params!(
5656
f::ParametricQuadraticFunction{T},
5757
) where {T}
5858
for term in f.pv
59-
push!(model.multiplicative_parameters, term.variable_1.value)
59+
push!(model.multiplicative_parameters_pv, term.variable_1.value)
6060
end
61-
# TODO compute these duals might be feasible
6261
for term in f.pp
63-
push!(model.multiplicative_parameters, term.variable_1.value)
64-
push!(model.multiplicative_parameters, term.variable_2.value)
62+
push!(model.multiplicative_parameters_pp, term.variable_1.value)
63+
push!(model.multiplicative_parameters_pp, term.variable_2.value)
6564
end
6665
return
6766
end
@@ -97,7 +96,8 @@ function MOI.is_empty(model::Optimizer)
9796
#
9897
isempty(model.vector_affine_constraint_cache) &&
9998
#
100-
isempty(model.multiplicative_parameters) &&
99+
isempty(model.multiplicative_parameters_pv) &&
100+
isempty(model.multiplicative_parameters_pp) &&
101101
isempty(model.dual_value_of_parameters) &&
102102
model.number_of_parameters_in_model == 0 &&
103103
isempty(model.ext)
@@ -130,7 +130,8 @@ function MOI.empty!(model::Optimizer{T}) where {T}
130130
#
131131
empty!(model.vector_affine_constraint_cache)
132132
#
133-
empty!(model.multiplicative_parameters)
133+
empty!(model.multiplicative_parameters_pv)
134+
empty!(model.multiplicative_parameters_pp)
134135
empty!(model.dual_value_of_parameters)
135136
#
136137
model.number_of_parameters_in_model = 0
@@ -827,14 +828,14 @@ function MOI.delete(
827828
) where {F<:MOI.ScalarQuadraticFunction,S<:MOI.AbstractSet}
828829
if haskey(model.quadratic_outer_to_inner, c)
829830
ci_inner = model.quadratic_outer_to_inner[c]
830-
deleteat!(model.quadratic_outer_to_inner, c)
831-
deleteat!(model.quadratic_constraint_cache, c)
832-
deleteat!(model.quadratic_constraint_cache_set, c)
831+
delete!(model.quadratic_outer_to_inner, c)
832+
delete!(model.quadratic_constraint_cache, c)
833+
delete!(model.quadratic_constraint_cache_set, c)
833834
MOI.delete(model.optimizer, ci_inner)
834835
else
835836
MOI.delete(model.optimizer, c)
836837
end
837-
deleteat!(model.constraint_outer_to_inner, c)
838+
delete!(model.constraint_outer_to_inner, c)
838839
return
839840
end
840841

@@ -870,7 +871,7 @@ function MOI.delete(
870871
) where {F<:MOI.VectorAffineFunction,S<:MOI.AbstractSet}
871872
MOI.delete(model.optimizer, c)
872873
delete!(model.constraint_outer_to_inner, c)
873-
deleteat!(model.vector_affine_constraint_cache, c)
874+
delete!(model.vector_affine_constraint_cache, c)
874875
return
875876
end
876877

src/ParametricOptInterface.jl

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -158,7 +158,8 @@ mutable struct Optimizer{T,OT<:MOI.ModelLike} <: MOI.AbstractOptimizer
158158
}
159159

160160
#
161-
multiplicative_parameters::Set{Int64}
161+
multiplicative_parameters_pv::Set{Int64}
162+
multiplicative_parameters_pp::Set{Int64}
162163
dual_value_of_parameters::Vector{T}
163164

164165
# params
@@ -221,6 +222,7 @@ mutable struct Optimizer{T,OT<:MOI.ModelLike} <: MOI.AbstractOptimizer
221222
DoubleDict{ParametricVectorAffineFunction{T}}(),
222223
# other
223224
Set{Int64}(),
225+
Set{Int64}(),
224226
Vector{T}(),
225227
evaluate_duals,
226228
0,

src/duals.jl

Lines changed: 31 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -48,9 +48,9 @@ function _update_duals_from_quadratic_constraints!(model::Optimizer)
4848
end
4949

5050
function _compute_parameters_in_ci!(
51-
model::OT,
51+
model::Optimizer,
5252
constraint_cache_inner::DoubleDictInner{F,S,V},
53-
) where {OT,F,S,V}
53+
) where {F,S,V}
5454
for (inner_ci, pf) in constraint_cache_inner
5555
_compute_parameters_in_ci!(model, pf, inner_ci)
5656
end
@@ -59,9 +59,9 @@ end
5959

6060
function _compute_parameters_in_ci!(
6161
model::Optimizer{T},
62-
pf,
62+
pf::ParametricAffineFunction{T},
6363
ci::MOI.ConstraintIndex{F,S},
64-
) where {F,S} where {T}
64+
) where {F,S,T}
6565
cons_dual = MOI.get(model.optimizer, MOI.ConstraintDual(), ci)
6666
for term in pf.p
6767
model.dual_value_of_parameters[p_val(term.variable)] -=
@@ -70,6 +70,32 @@ function _compute_parameters_in_ci!(
7070
return
7171
end
7272

73+
function _compute_parameters_in_ci!(
74+
model::Optimizer{T},
75+
pf::ParametricQuadraticFunction{T},
76+
ci::MOI.ConstraintIndex{F,S},
77+
) where {F,S,T}
78+
cons_dual = MOI.get(model.optimizer, MOI.ConstraintDual(), ci)
79+
for term in pf.p
80+
model.dual_value_of_parameters[p_val(term.variable)] -=
81+
cons_dual * term.coefficient
82+
end
83+
for term in pf.pp
84+
coef = ifelse(term.variable_1 == term.variable_2, T(1 // 2), T(1))
85+
model.dual_value_of_parameters[p_val(term.variable_1)] -=
86+
coef *
87+
cons_dual *
88+
term.coefficient *
89+
MOI.get(model, ParameterValue(), term.variable_2)
90+
model.dual_value_of_parameters[p_val(term.variable_2)] -=
91+
coef *
92+
cons_dual *
93+
term.coefficient *
94+
MOI.get(model, ParameterValue(), term.variable_1)
95+
end
96+
return
97+
end
98+
7399
function _compute_parameters_in_ci!(
74100
model::Optimizer{T},
75101
pf::ParametricVectorAffineFunction{T},
@@ -143,7 +169,7 @@ function MOI.get(
143169
end
144170

145171
function _is_additive(model::Optimizer, cp::MOI.ConstraintIndex)
146-
if cp.value in model.multiplicative_parameters
172+
if cp.value in model.multiplicative_parameters_pv
147173
return false
148174
end
149175
return true

test/jump_tests.jl

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1089,3 +1089,43 @@ function test_get_quadratic_constraint()
10891089
@test value(c) 2.0 * value(x)
10901090
return
10911091
end
1092+
1093+
function test_get_duals_from_multiplicative_parameters_1()
1094+
model = Model(() -> POI.Optimizer(GLPK.Optimizer()))
1095+
@variable(model, x)
1096+
@variable(model, p1 in Parameter(2.0))
1097+
@variable(model, p2 in Parameter(2.0))
1098+
@constraint(model, c, 3 * x >= p1 * p2)
1099+
@objective(model, Min, sum(x))
1100+
optimize!(model)
1101+
@test dual(c) 1.0 / 3.0
1102+
@test MOI.get.(model, POI.ParameterDual(), p1) 2.0 / 3
1103+
@test MOI.get.(model, POI.ParameterDual(), p2) 2.0 / 3
1104+
return
1105+
end
1106+
1107+
function test_get_duals_from_multiplicative_parameters_2()
1108+
model = Model(() -> POI.Optimizer(GLPK.Optimizer()))
1109+
@variable(model, x)
1110+
@variable(model, p1 in Parameter(40.0))
1111+
@variable(model, p2 in Parameter(2.0))
1112+
@constraint(model, c, 3 * x >= p1 * p2)
1113+
@objective(model, Min, sum(x))
1114+
optimize!(model)
1115+
@test dual(c) 1.0 / 3.0
1116+
@test MOI.get.(model, POI.ParameterDual(), p1) 2.0 / 3
1117+
@test MOI.get.(model, POI.ParameterDual(), p2) 40.0 / 3
1118+
return
1119+
end
1120+
1121+
function test_get_duals_from_multiplicative_parameters_3()
1122+
model = Model(() -> POI.Optimizer(GLPK.Optimizer()))
1123+
@variable(model, x)
1124+
@variable(model, p in Parameter(4.0))
1125+
@constraint(model, c, 3 * x >= p * p)
1126+
@objective(model, Min, sum(x))
1127+
optimize!(model)
1128+
@test dual(c) 1.0 / 3.0
1129+
@test MOI.get.(model, POI.ParameterDual(), p) 2 * 4.0 / 3
1130+
return
1131+
end

test/moi_tests.jl

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -150,6 +150,7 @@ function test_basic_special_cases_of_getters()
150150
@test MOI.get(optimizer, MOI.ObjectiveFunctionType()) ==
151151
MOI.ScalarQuadraticFunction{Float64}
152152
@test MOI.get(optimizer, MOI.NumberOfVariables()) == 3
153+
MOI.delete(optimizer, cons_index)
153154
return
154155
end
155156

@@ -1383,10 +1384,8 @@ function test_qp_objective_parameter_times_parameter()
13831384
0.0,
13841385
atol = ATOL,
13851386
)
1386-
err =
1387-
ErrorException("Cannot compute the dual of a multiplicative parameter")
1388-
@test_throws err MOI.get(optimizer, MOI.ConstraintDual(), cy)
1389-
@test_throws err MOI.get(optimizer, MOI.ConstraintDual(), cz)
1387+
@test MOI.get(optimizer, MOI.ConstraintDual(), cy) == 0.0
1388+
@test MOI.get(optimizer, MOI.ConstraintDual(), cz) == 0.0
13901389
MOI.set(optimizer, MOI.ConstraintSet(), cy, MOI.Parameter(2.0))
13911390
MOI.optimize!(optimizer)
13921391
@test isapprox(MOI.get(optimizer, MOI.ObjectiveValue()), 2.0, atol = ATOL)

0 commit comments

Comments
 (0)