Skip to content

Commit 9be3a13

Browse files
Merge branch 'master' into hb/batch_delete_test
2 parents 358d1b7 + b55cc2e commit 9be3a13

File tree

5 files changed

+88
-20
lines changed

5 files changed

+88
-20
lines changed

docs/make.jl

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,11 @@ using Documenter, MathOptInterface
22

33
makedocs(
44
sitename = "MathOptInterface",
5-
# See https://github.com/JuliaDocs/Documenter.jl/issues/868
6-
format = Documenter.HTML(prettyurls = get(ENV, "CI", nothing) == "true"),
5+
format = Documenter.HTML(
6+
# See https://github.com/JuliaDocs/Documenter.jl/issues/868
7+
prettyurls = get(ENV, "CI", nothing) == "true",
8+
mathengine = Documenter.MathJax()
9+
),
710
# See https://github.com/JuliaOpt/JuMP.jl/issues/1576
811
strict = true,
912
pages = [

docs/src/apireference.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -197,6 +197,7 @@ ConstraintIndex
197197
is_valid
198198
throw_if_not_valid
199199
delete(::ModelLike, ::Index)
200+
delete(::ModelLike, ::Vector{<:Index})
200201
```
201202

202203
### Variables

src/Bridges/Constraint/norm_to_lp.jl

Lines changed: 52 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -127,21 +127,64 @@ function MOI.get(model::MOI.ModelLike, ::MOI.ConstraintSet, c::NormOneBridge)
127127
dim = 1 + div(MOI.dimension(MOI.get(model, MOI.ConstraintSet(), c.nn_index)), 2)
128128
return MOI.NormOneCone(dim)
129129
end
130-
function MOI.get(model::MOI.ModelLike, ::MOI.ConstraintPrimal, c::NormOneBridge)
131-
ge_primal = MOI.get(model, MOI.ConstraintPrimal(), c.ge_index)
132-
nn_primal = MOI.get(model, MOI.ConstraintPrimal(), c.nn_index)
130+
131+
function MOI.supports(
132+
::MOI.ModelLike,
133+
::Union{MOI.ConstraintPrimalStart, MOI.ConstraintDualStart},
134+
::Type{<:NormOneBridge})
135+
136+
return true
137+
end
138+
function MOI.set(model::MOI.ModelLike, attr::MOI.ConstraintPrimalStart,
139+
bridge::NormOneBridge{T}, value) where T
140+
x_value = value[1 .+ (1:length(bridge.y))]
141+
y_value = abs.(x_value)
142+
for i in eachindex(bridge.y)
143+
MOI.set(model, MOI.VariablePrimalStart(), bridge.y[i], y_value[i])
144+
end
145+
MOI.set(model, attr, bridge.nn_index, [y_value - x_value; y_value + x_value])
146+
MOI.set(model, attr, bridge.ge_index, value[1] - reduce(+, y_value, init=zero(T)))
147+
return
148+
end
149+
function MOI.get(model::MOI.ModelLike,
150+
attr::Union{MOI.ConstraintPrimal, MOI.ConstraintPrimalStart},
151+
bridge::NormOneBridge)
152+
ge_primal = MOI.get(model, attr, bridge.ge_index)
153+
nn_primal = MOI.get(model, attr, bridge.nn_index)
133154
t = ge_primal + sum(nn_primal) / 2
134-
d = length(c.y)
155+
d = length(bridge.y)
135156
x = (nn_primal[(d + 1):end] - nn_primal[1:d]) / 2
136157
return vcat(t, x)
137158
end
138159
# Given a_i is dual on y_i - x_i >= 0 and b_i is dual on y_i + x_i >= 0 and c is dual on t - sum(y) >= 0,
139160
# the dual on (t, x) in NormOneCone is (u, v) in NormInfinityCone, where
140161
# v_i = -a_i + b_i and u = c.
141-
function MOI.get(model::MOI.ModelLike, ::MOI.ConstraintDual, c::NormOneBridge)
142-
t = MOI.get(model, MOI.ConstraintDual(), c.ge_index)
143-
nn_dual = MOI.get(model, MOI.ConstraintDual(), c.nn_index)
144-
d = div(length(nn_dual), 2)
145-
x = (nn_dual[(d + 1):end] - nn_dual[1:d])
162+
function MOI.get(model::MOI.ModelLike,
163+
attr::Union{MOI.ConstraintDual, MOI.ConstraintDualStart},
164+
bridge::NormOneBridge)
165+
t = MOI.get(model, attr, bridge.ge_index)
166+
nn_dual = MOI.get(model, attr, bridge.nn_index)
167+
d = length(bridge.y)
168+
x = nn_dual[(d + 1):end] - nn_dual[1:d]
146169
return vcat(t, x)
147170
end
171+
# value[1 + i] = nn_dual[d + i] - nn_dual[i]
172+
# and `nn_dual` is nonnegative. By complementarity slackness, only one of each
173+
# `nn_dual` can be nonzero (except if `x = 0`) so we can set
174+
# depending on the sense of `value[1 + i]`.
175+
function MOI.set(model::MOI.ModelLike, ::MOI.ConstraintDualStart,
176+
bridge::NormOneBridge, value)
177+
t = MOI.set(model, MOI.ConstraintDualStart(), bridge.ge_index, value[1])
178+
d = length(bridge.y)
179+
nn_dual = zeros(eltype(value), 2d)
180+
for i in eachindex(bridge.y)
181+
v = value[1 + i]
182+
if v < 0
183+
nn_dual[i] = -v
184+
else
185+
nn_dual[d + i] = v
186+
end
187+
end
188+
MOI.set(model, MOI.ConstraintDualStart(), bridge.nn_index, nn_dual)
189+
return
190+
end

src/indextypes.jl

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -116,10 +116,12 @@ The following modifications also take effect if `Index` is [`VariableIndex`](@re
116116
delete(model::ModelLike, index::Index) = throw(DeleteNotAllowed(index))
117117

118118
"""
119-
delete{R}(model::ModelLike, indices::Vector{R<:Index})
119+
delete(model::ModelLike, indices::Vector{R<:Index}) where {R}
120120
121121
Delete the referenced objects in the vector `indices` from the model.
122-
It may be assumed that `R` is a concrete type.
122+
It may be assumed that `R` is a concrete type. The default fallback sequentially
123+
deletes the individual items in `indices`, although specialized implementations
124+
may be more efficient.
123125
"""
124126
function delete(model::ModelLike, indices::Vector{<:Index})
125127
for index in indices

test/Bridges/Constraint/norm_to_lp.jl

Lines changed: 26 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -100,13 +100,17 @@ end
100100
MOIT.normone1vtest(bridged_mock, config)
101101
MOIT.normone1ftest(bridged_mock, config)
102102

103+
var_names = ["x", "y", "z"]
104+
MOI.set(bridged_mock, MOI.VariableName(), MOI.get(bridged_mock, MOI.ListOfVariableIndices()), var_names)
105+
106+
nonneg = MOI.get(mock, MOI.ListOfConstraintIndices{MOI.VectorAffineFunction{Float64}, MOI.Nonnegatives}())
107+
greater = MOI.get(mock, MOI.ListOfConstraintIndices{MOI.ScalarAffineFunction{Float64}, MOI.GreaterThan{Float64}}())
108+
u, v = MOI.get(mock, MOI.ListOfVariableIndices())[4:5]
103109
@testset "Test mock model" begin
104-
var_names = ["x", "y", "z", "u", "v"]
105-
MOI.set(mock, MOI.VariableName(), MOI.get(mock, MOI.ListOfVariableIndices()), var_names)
106-
nonneg = MOI.get(mock, MOI.ListOfConstraintIndices{MOI.VectorAffineFunction{Float64}, MOI.Nonnegatives}())
110+
MOI.set(mock, MOI.VariableName(), u, "u")
111+
MOI.set(mock, MOI.VariableName(), v, "v")
107112
@test length(nonneg) == 1
108113
MOI.set(mock, MOI.ConstraintName(), nonneg[1], "nonneg")
109-
greater = MOI.get(mock, MOI.ListOfConstraintIndices{MOI.ScalarAffineFunction{Float64}, MOI.GreaterThan{Float64}}())
110114
@test length(greater) == 1
111115
MOI.set(mock, MOI.ConstraintName(), greater[1], "greater")
112116
zeros = MOI.get(mock, MOI.ListOfConstraintIndices{MOI.VectorAffineFunction{Float64}, MOI.Zeros}())
@@ -124,12 +128,10 @@ end
124128
"""
125129
model = MOIU.Model{Float64}()
126130
MOIU.loadfromstring!(model, s)
127-
MOIU.test_models_equal(mock, model, var_names, ["nonneg", "greater", "x_eq", "y_eq"])
131+
MOIU.test_models_equal(mock, model, [var_names; "u"; "v"], ["nonneg", "greater", "x_eq", "y_eq"])
128132
end
129133

130134
@testset "Test bridged model" begin
131-
var_names = ["x", "y", "z"]
132-
MOI.set(bridged_mock, MOI.VariableName(), MOI.get(bridged_mock, MOI.ListOfVariableIndices()), var_names)
133135
normone = MOI.get(bridged_mock, MOI.ListOfConstraintIndices{MOI.VectorAffineFunction{Float64}, MOI.NormOneCone}())
134136
@test length(normone) == 1
135137
MOI.set(bridged_mock, MOI.ConstraintName(), normone[1], "normone")
@@ -151,6 +153,23 @@ end
151153
end
152154

153155
ci = first(MOI.get(bridged_mock, MOI.ListOfConstraintIndices{MOI.VectorAffineFunction{Float64}, MOI.NormOneCone}()))
156+
157+
@testset "$attr" for attr in [MOI.ConstraintPrimalStart(), MOI.ConstraintDualStart()]
158+
@test MOI.supports(bridged_mock, attr, typeof(ci))
159+
value = [4.0, 1.0, -2.0]
160+
MOI.set(bridged_mock, attr, ci, value)
161+
@test MOI.get(bridged_mock, attr, ci) value
162+
if attr isa MOI.ConstraintPrimalStart
163+
@test MOI.get(mock, MOI.VariablePrimalStart(), u) == 1
164+
@test MOI.get(mock, MOI.VariablePrimalStart(), v) == 2
165+
@test MOI.get(mock, attr, nonneg[1]) == [0.0, 4.0, 2.0, 0.0]
166+
@test MOI.get(mock, attr, greater[1]) == 1
167+
else
168+
@test MOI.get(mock, attr, nonneg[1]) == [0.0, 2.0, 1.0, 0.0]
169+
@test MOI.get(mock, attr, greater[1]) == 4
170+
end
171+
end
172+
154173
test_delete_bridge(bridged_mock, ci, 3, (
155174
(MOI.ScalarAffineFunction{Float64}, MOI.GreaterThan{Float64}, 0),
156175
(MOI.VectorAffineFunction{Float64}, MOI.Nonnegatives, 0)))

0 commit comments

Comments
 (0)