Skip to content

Commit 4050b4e

Browse files
committed
Update
1 parent ac964c4 commit 4050b4e

File tree

3 files changed

+157
-92
lines changed

3 files changed

+157
-92
lines changed

src/Bridges/Constraint/bridges/ComplementsToScalarNonlinearFunctionBridge.jl

Lines changed: 107 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -5,23 +5,24 @@
55
# in the LICENSE.md file or at https://opensource.org/licenses/MIT.
66

77
"""
8-
ComplementsToScalarNonlinearFunctionBridge{T,F} <:
8+
ComplementsToScalarNonlinearFunctionBridge{T,F,G} <:
99
Bridges.Constraint.AbstractBridge
1010
1111
`ComplementsToScalarNonlinearFunctionBridge` implements the following
1212
reformulation:
1313
1414
* ``(F, x) \\in \\textsf{Complements}()`` to
15+
``y - F = 0`` and
1516
```julia
1617
if isfinite(l)
17-
(x - l) * F <= 0.0
18+
(x - l) * y <= 0.0
1819
else
19-
1.0 * F <= 0.0
20+
y <= 0
2021
end
2122
if isfinite(u)
22-
(x - u) * F <= 0.0
23+
(x - u) * y <= 0.0
2324
else
24-
-1.0 * F <= 0.0
25+
y >= 0
2526
end
2627
```
2728
@@ -35,7 +36,9 @@ reformulation:
3536
3637
`ComplementsToScalarNonlinearFunctionBridge` creates:
3738
38-
* [`MOI.ScalarNonlinearFunction`](@ref) in [`MOI.LessThan{T}`](@ref)
39+
* `G` in [`MOI.EqualTo{T}`](@ref)
40+
* [`MOI.ScalarQuadraticFunction`](@ref) in [`MOI.LessThan{T}`](@ref)
41+
* [`MOI.VariableIndex`](@ref) in [`MOI.Interval{T}`](@ref)
3942
"""
4043
mutable struct ComplementsToScalarNonlinearFunctionBridge{
4144
T,
@@ -45,24 +48,38 @@ mutable struct ComplementsToScalarNonlinearFunctionBridge{
4548
MOI.VectorQuadraticFunction{T},
4649
MOI.VectorNonlinearFunction,
4750
},
51+
G,
4852
} <: AbstractBridge
4953
f::F
50-
ci::Vector{MOI.ConstraintIndex{MOI.ScalarNonlinearFunction,MOI.LessThan{T}}}
54+
y::Vector{MOI.VariableIndex}
55+
ci_eq::Vector{MOI.ConstraintIndex{G,MOI.EqualTo{T}}}
56+
ci_lt::Vector{
57+
MOI.ConstraintIndex{MOI.ScalarQuadraticFunction{T},MOI.LessThan{T}}
58+
}
5159
bounds::Vector{NTuple{2,T}}
52-
function ComplementsToScalarNonlinearFunctionBridge{T}(
53-
f,
60+
61+
function ComplementsToScalarNonlinearFunctionBridge{T,F,G}(
62+
f::F,
5463
::MOI.Complements,
55-
) where {T}
56-
ci = MOI.ConstraintIndex{MOI.ScalarNonlinearFunction,MOI.LessThan{T}}[]
57-
return new{T,typeof(f)}(f, ci, NTuple{2,T}[])
64+
) where {T,F,G}
65+
return new{T,F,G}(
66+
f,
67+
MOI.VariableIndex[],
68+
MOI.ConstraintIndex{G,MOI.EqualTo{T}}[],
69+
MOI.ConstraintIndex{
70+
MOI.ScalarQuadraticFunction{T},
71+
MOI.LessThan{T},
72+
}[],
73+
NTuple{2,T}[],
74+
)
5875
end
5976
end
6077

6178
const ComplementsToScalarNonlinearFunction{T,OT<:MOI.ModelLike} =
6279
SingleBridgeOptimizer{ComplementsToScalarNonlinearFunctionBridge{T},OT}
6380

6481
function bridge_constraint(
65-
::Type{ComplementsToScalarNonlinearFunctionBridge{T,F}},
82+
::Type{ComplementsToScalarNonlinearFunctionBridge{T,F,G}},
6683
model::MOI.ModelLike,
6784
f::F,
6885
s::MOI.Complements,
@@ -74,10 +91,11 @@ function bridge_constraint(
7491
MOI.VectorQuadraticFunction{T},
7592
MOI.VectorNonlinearFunction,
7693
},
94+
G,
7795
}
7896
# !!! info
7997
# Postpone creation until final_touch.
80-
return ComplementsToScalarNonlinearFunctionBridge{T}(f, s)
98+
return ComplementsToScalarNonlinearFunctionBridge{T,F,G}(f, s)
8199
end
82100

83101
function MOI.supports_constraint(
@@ -97,15 +115,18 @@ function MOI.supports_constraint(
97115
end
98116

99117
function MOI.Bridges.added_constrained_variable_types(
100-
::Type{<:ComplementsToScalarNonlinearFunctionBridge},
101-
)
102-
return Tuple{Type}[]
118+
::Type{ComplementsToScalarNonlinearFunctionBridge{T,F,G}},
119+
) where {T,F,G}
120+
return Tuple{Type}[(MOI.Interval{T},)]
103121
end
104122

105123
function MOI.Bridges.added_constraint_types(
106-
::Type{<:ComplementsToScalarNonlinearFunctionBridge{T}},
107-
) where {T}
108-
return Tuple{Type,Type}[(MOI.ScalarNonlinearFunction, MOI.LessThan{T})]
124+
::Type{ComplementsToScalarNonlinearFunctionBridge{T,F,G}},
125+
) where {T,F,G}
126+
return Tuple{Type,Type}[
127+
(G, MOI.EqualTo{T}),
128+
(MOI.ScalarQuadraticFunction{T}, MOI.LessThan{T}),
129+
]
109130
end
110131

111132
function concrete_bridge_type(
@@ -121,7 +142,13 @@ function concrete_bridge_type(
121142
MOI.VectorNonlinearFunction,
122143
},
123144
}
124-
return ComplementsToScalarNonlinearFunctionBridge{T,F}
145+
G = MOI.Utilities.promote_operation(
146+
-,
147+
T,
148+
MOI.Utilities.scalar_type(F),
149+
MOI.VariableIndex,
150+
)
151+
return ComplementsToScalarNonlinearFunctionBridge{T,F,G}
125152
end
126153

127154
function MOI.get(
@@ -145,37 +172,72 @@ function MOI.delete(
145172
model::MOI.ModelLike,
146173
bridge::ComplementsToScalarNonlinearFunctionBridge,
147174
)
148-
MOI.delete.(model, bridge.ci)
175+
MOI.delete.(model, bridge.y)
176+
MOI.delete.(model, bridge.ci_eq)
177+
MOI.delete.(model, bridge.ci_lt)
149178
empty!(bridge.bounds)
150179
return
151180
end
152181

153182
function MOI.get(
154-
::ComplementsToScalarNonlinearFunctionBridge,
183+
bridge::ComplementsToScalarNonlinearFunctionBridge,
155184
::MOI.NumberOfVariables,
156185
)::Int64
157-
return 0
186+
return length(bridge.y)
158187
end
159188

160189
function MOI.get(
161-
::ComplementsToScalarNonlinearFunctionBridge,
190+
bridge::ComplementsToScalarNonlinearFunctionBridge,
162191
::MOI.ListOfVariableIndices,
163192
)::Vector{MOI.VariableIndex}
164-
return MOI.VariableIndex[]
193+
return copy(bridge.y)
194+
end
195+
196+
function MOI.get(
197+
bridge::ComplementsToScalarNonlinearFunctionBridge{T,F,G},
198+
::MOI.NumberOfConstraints{G,MOI.EqualTo{T}},
199+
)::Int64 where {T,F,G}
200+
return length(bridge.ci_eq)
201+
end
202+
203+
function MOI.get(
204+
bridge::ComplementsToScalarNonlinearFunctionBridge{T,F,G},
205+
::MOI.ListOfConstraintIndices{G,MOI.EqualTo{T}},
206+
) where {T,F,G}
207+
return copy(bridge.ci_eq)
165208
end
166209

167210
function MOI.get(
168211
bridge::ComplementsToScalarNonlinearFunctionBridge{T},
169-
::MOI.NumberOfConstraints{MOI.ScalarNonlinearFunction,MOI.LessThan{T}},
212+
::MOI.NumberOfConstraints{MOI.ScalarQuadraticFunction{T},MOI.LessThan{T}},
170213
)::Int64 where {T}
171-
return length(bridge.ci)
214+
return length(bridge.ci_lt)
172215
end
173216

174217
function MOI.get(
175218
bridge::ComplementsToScalarNonlinearFunctionBridge{T},
176-
::MOI.ListOfConstraintIndices{MOI.ScalarNonlinearFunction,MOI.LessThan{T}},
219+
::MOI.ListOfConstraintIndices{
220+
MOI.ScalarQuadraticFunction{T},
221+
MOI.LessThan{T},
222+
},
177223
) where {T}
178-
return copy(bridge.ci)
224+
return copy(bridge.ci_lt)
225+
end
226+
227+
function MOI.get(
228+
bridge::ComplementsToScalarNonlinearFunctionBridge{T},
229+
::MOI.NumberOfConstraints{MOI.VariableIndex,MOI.Interval{T}},
230+
)::Int64 where {T}
231+
return length(bridge.y)
232+
end
233+
234+
function MOI.get(
235+
bridge::ComplementsToScalarNonlinearFunctionBridge{T},
236+
::MOI.ListOfConstraintIndices{MOI.VariableIndex,MOI.Interval{T}},
237+
) where {T}
238+
return map(bridge.y) do y
239+
return MOI.ConstraintIndex{MOI.VariableIndex,MOI.Interval{T}}(y.value)
240+
end
179241
end
180242

181243
function MOI.Bridges.needs_final_touch(
@@ -216,27 +278,23 @@ function MOI.Bridges.final_touch(
216278
end
217279
for i in 1:N
218280
(l, u), F = bridge.bounds[i], f[i]
281+
y_u = isfinite(l) ? typemax(T) : zero(T)
282+
y_l = isfinite(u) ? typemin(T) : zero(T)
283+
y, _ = MOI.add_constrained_variable(model, MOI.Interval{T}(y_l, y_u))
284+
push!(bridge.y, y)
285+
# F(x) - y = 0
286+
g = MOI.Utilities.operate(-, T, F, y)
287+
push!(bridge.ci_eq, MOI.add_constraint(model, g, MOI.EqualTo(zero(T))))
219288
x = convert(MOI.VariableIndex, f[N+i])
220-
g_l = if isfinite(l) && iszero(l)
221-
MOI.ScalarNonlinearFunction(:*, Any[x, F])
222-
elseif isfinite(l)
223-
x_l = MOI.ScalarNonlinearFunction(:-, Any[x, l])
224-
MOI.ScalarNonlinearFunction(:*, Any[x_l, F])
225-
elseif F isa MOI.ScalarNonlinearFunction
226-
F
227-
else
228-
MOI.ScalarNonlinearFunction(:+, Any[F])
229-
end
230-
push!(bridge.ci, MOI.add_constraint(model, g_l, MOI.LessThan(zero(T))))
231-
g_u = if isfinite(u) && iszero(u)
232-
MOI.ScalarNonlinearFunction(:*, Any[x, F])
233-
elseif isfinite(u)
234-
x_u = MOI.ScalarNonlinearFunction(:-, Any[x, u])
235-
MOI.ScalarNonlinearFunction(:*, Any[x_u, F])
236-
else
237-
MOI.ScalarNonlinearFunction(:*, Any[-one(T), F])
289+
# (x - b) * y <= 0
290+
for b in (l, u)
291+
if isfinite(b)
292+
x_less_b = MOI.Utilities.operate(-, T, x, b)
293+
h = MOI.Utilities.operate(*, T, x_less_b, y)
294+
ci = MOI.add_constraint(model, h, MOI.LessThan(zero(T)))
295+
push!(bridge.ci_lt, ci)
296+
end
238297
end
239-
push!(bridge.ci, MOI.add_constraint(model, g_u, MOI.LessThan(zero(T))))
240298
end
241299
return
242300
end

src/functions.jl

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -976,10 +976,7 @@ function Base.convert(
976976
return convert(VariableIndex, convert(ScalarAffineFunction{T}, f))
977977
end
978978

979-
function Base.convert(
980-
::Type{VariableIndex},
981-
f::ScalarNonlinearFunction,
982-
) where {T}
979+
function Base.convert(::Type{VariableIndex}, f::ScalarNonlinearFunction)
983980
if f.head != :+ && length(f.args) != 1
984981
throw(InexactError(:convert, VariableIndex, f))
985982
end

0 commit comments

Comments
 (0)