1+ _lower_set (set:: MOI.Interval ) = MOI. GreaterThan (set. lower)
2+ _upper_set (set:: MOI.Interval ) = MOI. LessThan (set. upper)
3+ _lower_set (set:: MOI.EqualTo ) = MOI. GreaterThan (set. value)
4+ _upper_set (set:: MOI.EqualTo ) = MOI. LessThan (set. value)
5+ _lower_set (set:: MOI.Zeros ) = MOI. Nonnegatives (set. dimension)
6+ _upper_set (set:: MOI.Zeros ) = MOI. Nonpositives (set. dimension)
7+
18"""
2- SplitIntervalBridge{T}
9+ SplitIntervalBridge{T, F, S, LS, US}
10+
11+ The `SplitIntervalBridge` splits a `F`-in-`S` constraint into a `F`-in-`LS` and
12+ a `F`-in-`US` constraint where we have either:
13+ * `F = MOI.Interval{T}`, `LS = MOI.GreaterThan{T}` and `US = MOI.LessThan{T}`,
14+ * `F = MOI.EqualTo{T}`, `LS = MOI.GreaterThan{T}` and `US = MOI.LessThan{T}`, or
15+ * `F = MOI.Zeros`, `LS = MOI.Nonnegatives` and `US = MOI.Nonpositives`.
316
4- The `SplitIntervalBridge` splits a constraint ``l ≤ ⟨a, x⟩ + α ≤ u`` into the constraints ``⟨a, x⟩ + α ≥ l`` and ``⟨a, x⟩ + α ≤ u``.
17+ For instance, if `F` is `MOI.ScalarAffineFunction` and `S` is `MOI.Interval`,
18+ it transforms the constraint ``l ≤ ⟨a, x⟩ + α ≤ u`` into the constraints
19+ ``⟨a, x⟩ + α ≥ l`` and ``⟨a, x⟩ + α ≤ u``.
520"""
6- struct SplitIntervalBridge{T, F<: MOI.AbstractScalarFunction } <: AbstractBridge
7- lower:: CI{F, MOI.GreaterThan{T}}
8- upper:: CI{F, MOI.LessThan{T}}
9- end
10- function bridge_constraint (:: Type{SplitIntervalBridge{T, F}} , model, f:: F ,
11- s:: MOI.Interval{T} ) where {T, F}
12- lower = MOI. add_constraint (model, f, MOI. GreaterThan (s. lower))
13- upper = MOI. add_constraint (model, f, MOI. LessThan (s. upper))
14- return SplitIntervalBridge {T, F} (lower, upper)
21+ struct SplitIntervalBridge{T, F<: MOI.AbstractFunction , S<: MOI.AbstractSet ,
22+ LS<: MOI.AbstractSet , US<: MOI.AbstractSet } <: AbstractBridge
23+ lower:: CI{F, LS}
24+ upper:: CI{F, US}
25+ end
26+ function bridge_constraint (
27+ :: Type{SplitIntervalBridge{T, F, S, LS, US}} , model:: MOI.ModelLike , f:: F ,
28+ set:: S ) where {T, F, S, LS, US}
29+ lower = MOI. add_constraint (model, f, _lower_set (set))
30+ upper = MOI. add_constraint (model, f, _upper_set (set))
31+ return SplitIntervalBridge {T, F, S, LS, US} (lower, upper)
1532end
1633
17- MOI. supports_constraint (:: Type{SplitIntervalBridge{T}} , :: Type{<:MOI.AbstractScalarFunction} , :: Type{MOI.Interval{T}} ) where T = true
34+ function MOI. supports_constraint (
35+ :: Type{SplitIntervalBridge{T}} , :: Type{<:MOI.AbstractScalarFunction} ,
36+ :: Type{<:Union{MOI.Interval{T}, MOI.EqualTo{T}}} ) where T
37+ return true
38+ end
39+ function MOI. supports_constraint (
40+ :: Type{SplitIntervalBridge{T}} , :: Type{<:MOI.AbstractVectorFunction} ,
41+ :: Type{MOI.Zeros} ) where T
42+ return true
43+ end
1844MOIB. added_constrained_variable_types (:: Type{<:SplitIntervalBridge} ) = Tuple{DataType}[]
19- function MOIB. added_constraint_types (:: Type{SplitIntervalBridge{T, F}} ) where {T, F}
20- return [(F, MOI. GreaterThan{T}), (F, MOI. LessThan{T})]
45+ function MOIB. added_constraint_types (:: Type{SplitIntervalBridge{T, F, S, LS, US}} ) where {T, F, S, LS, US}
46+ return [(F, LS), (F, US)]
47+ end
48+ function concrete_bridge_type (
49+ :: Type{<:SplitIntervalBridge} , F:: Type{<:MOI.AbstractScalarFunction} ,
50+ S:: Type{<:Union{MOI.Interval{T}, MOI.EqualTo{T}}} ) where T
51+ return SplitIntervalBridge{T, F, S, MOI. GreaterThan{T}, MOI. LessThan{T}}
2152end
22- function concrete_bridge_type (:: Type{<:SplitIntervalBridge} ,
23- F:: Type{<:MOI.AbstractScalarFunction } ,
24- :: Type{MOI.Interval{T} } ) where T
25- return SplitIntervalBridge{T, F}
53+ function concrete_bridge_type (
54+ :: Type{<:SplitIntervalBridge{T}} , F:: Type{<:MOI.AbstractVectorFunction } ,
55+ :: Type{MOI.Zeros } ) where T
56+ return SplitIntervalBridge{T, F, MOI . Zeros, MOI . Nonnegatives, MOI . Nonpositives }
2657end
2758
2859# Attributes, Bridge acting as a model
29- MOI. get (b:: SplitIntervalBridge{T, F} , :: MOI.NumberOfConstraints{F, MOI.LessThan{T}} ) where {T, F} = 1
30- MOI. get (b:: SplitIntervalBridge{T, F} , :: MOI.NumberOfConstraints{F, MOI.GreaterThan{T}} ) where {T, F} = 1
31- MOI. get (b:: SplitIntervalBridge{T, F} , :: MOI.ListOfConstraintIndices{F, MOI.GreaterThan{T}} ) where {T, F} = [b. lower]
32- MOI. get (b:: SplitIntervalBridge{T, F} , :: MOI.ListOfConstraintIndices{F, MOI.LessThan{T}} ) where {T, F} = [b. upper]
60+ function MOI. get (:: SplitIntervalBridge{T, F, S, LS} ,
61+ :: MOI.NumberOfConstraints{F, LS} ) where {T, F, S, LS}
62+ return 1
63+ end
64+ function MOI. get (:: SplitIntervalBridge{T, F, S, LS, US} ,
65+ :: MOI.NumberOfConstraints{F, US} ) where {T, F, S, LS, US}
66+ return 1
67+ end
68+ function MOI. get (bridge:: SplitIntervalBridge{T, F, S, LS} ,
69+ :: MOI.ListOfConstraintIndices{F, LS} ) where {T, F, S, LS}
70+ return [bridge. lower]
71+ end
72+ function MOI. get (bridge:: SplitIntervalBridge{T, F, S, LS, US} ,
73+ :: MOI.ListOfConstraintIndices{F, US} ) where {T, F, S, LS, US}
74+ return [bridge. upper]
75+ end
3376
3477# Indices
35- function MOI. delete (model:: MOI.ModelLike , c :: SplitIntervalBridge )
36- MOI. delete (model, c . lower)
37- MOI. delete (model, c . upper)
78+ function MOI. delete (model:: MOI.ModelLike , bridge :: SplitIntervalBridge )
79+ MOI. delete (model, bridge . lower)
80+ MOI. delete (model, bridge . upper)
3881end
3982
4083# Attributes, Bridge acting as a constraint
@@ -50,33 +93,45 @@ function MOI.get(model::MOI.ModelLike, attr::Union{MOI.ConstraintPrimal, MOI.Con
5093 # lower and upper should give the same value
5194 return MOI. get (model, attr, bridge. lower)
5295end
53- function MOI. set (model:: MOI.ModelLike , a :: MOI.ConstraintPrimalStart ,
96+ function MOI. set (model:: MOI.ModelLike , attr :: MOI.ConstraintPrimalStart ,
5497 bridge:: SplitIntervalBridge , value)
55- MOI. set (model, a, bridge. lower, value)
56- MOI. set (model, a, bridge. upper, value)
57- end
98+ MOI. set (model, attr, bridge. lower, value)
99+ MOI. set (model, attr, bridge. upper, value)
100+ end
101+ # The map is:
102+ # x ∈ S <=> [1 1]' * x ∈ LS × US
103+ # So the adjoint map is
104+ # [1 1] * y ∈ S* <=> y ∈ (LS × US)*
105+ # where [1 1] * y = y[1] + y[2]
106+ # so we can just sum the dual values.
58107function MOI. get (model:: MOI.ModelLike , attr:: Union{MOI.ConstraintDual, MOI.ConstraintDualStart} ,
59108 bridge:: SplitIntervalBridge )
60- # Should be nonnegative
61- lower_dual = MOI. get (model, attr, bridge. lower)
62- # Should be nonpositive
63- upper_dual = MOI. get (model, attr, bridge. upper)
64- return lower_dual > - upper_dual ? lower_dual : upper_dual
109+ return MOI. get (model, attr, bridge. lower) + MOI. get (model, attr, bridge. upper)
65110end
66- function MOI. set (model:: MOI.ModelLike , a:: MOI.ConstraintDualStart ,
67- bridge:: SplitIntervalBridge , value)
111+ function _split_dual_start (value)
68112 if value < 0
69- MOI. set (model, a, bridge. lower, 0.0 )
70- MOI. set (model, a, bridge. upper, value)
113+ return zero (value), value
71114 else
72- MOI. set (model, a, bridge. lower, value)
73- MOI. set (model, a, bridge. upper, 0.0 )
115+ return value, zero (value)
116+ end
117+ end
118+ function _split_dual_start (value:: Vector )
119+ lower = similar (value)
120+ upper = similar (value)
121+ for i in eachindex (value)
122+ lower[i], upper[i] = _split_dual_start (value[i])
74123 end
75124end
125+ function MOI. set (model:: MOI.ModelLike , attr:: MOI.ConstraintDualStart ,
126+ bridge:: SplitIntervalBridge{T} , value) where T
127+ lower, upper = _split_dual_start (value)
128+ MOI. set (model, attr, bridge. lower, lower)
129+ MOI. set (model, attr, bridge. upper, upper)
130+ end
76131
77- function MOI. get (model:: MOI.ModelLike , :: MOI.ConstraintBasisStatus , c :: SplitIntervalBridge )
78- lower_stat = MOI. get (model, MOI. ConstraintBasisStatus (), c . lower)
79- upper_stat = MOI. get (model, MOI. ConstraintBasisStatus (), c . upper)
132+ function MOI. get (model:: MOI.ModelLike , :: MOI.ConstraintBasisStatus , bridge :: SplitIntervalBridge )
133+ lower_stat = MOI. get (model, MOI. ConstraintBasisStatus (), bridge . lower)
134+ upper_stat = MOI. get (model, MOI. ConstraintBasisStatus (), bridge . upper)
80135 if lower_stat == MOI. NONBASIC_AT_LOWER
81136 @warn (" GreaterThan constraints should not have basis status:" *
82137 " NONBASIC_AT_LOWER, instead use NONBASIC." )
@@ -99,28 +154,37 @@ function MOI.get(model::MOI.ModelLike, ::MOI.ConstraintBasisStatus, c::SplitInte
99154end
100155
101156# Constraints
102- function MOI. modify (model:: MOI.ModelLike , c :: SplitIntervalBridge , change:: MOI.AbstractFunctionModification )
103- MOI. modify (model, c . lower, change)
104- MOI. modify (model, c . upper, change)
157+ function MOI. modify (model:: MOI.ModelLike , bridge :: SplitIntervalBridge , change:: MOI.AbstractFunctionModification )
158+ MOI. modify (model, bridge . lower, change)
159+ MOI. modify (model, bridge . upper, change)
105160end
106161
107162function MOI. set (model:: MOI.ModelLike , :: MOI.ConstraintFunction ,
108- c :: SplitIntervalBridge{T, F} , func:: F ) where {T, F}
109- MOI. set (model, MOI. ConstraintFunction (), c . lower, func)
110- MOI. set (model, MOI. ConstraintFunction (), c . upper, func)
163+ bridge :: SplitIntervalBridge{T, F} , func:: F ) where {T, F}
164+ MOI. set (model, MOI. ConstraintFunction (), bridge . lower, func)
165+ MOI. set (model, MOI. ConstraintFunction (), bridge . upper, func)
111166end
112167
113- function MOI. set (model:: MOI.ModelLike , :: MOI.ConstraintSet , c:: SplitIntervalBridge , change:: MOI.Interval )
114- MOI. set (model, MOI. ConstraintSet (), c. lower, MOI. GreaterThan (change. lower))
115- MOI. set (model, MOI. ConstraintSet (), c. upper, MOI. LessThan (change. upper))
168+ function MOI. set (model:: MOI.ModelLike , :: MOI.ConstraintSet ,
169+ bridge:: SplitIntervalBridge{T, F, S} , change:: S ) where {T, F, S}
170+ MOI. set (model, MOI. ConstraintSet (), bridge. lower, _lower_set (change))
171+ MOI. set (model, MOI. ConstraintSet (), bridge. upper, _upper_set (change))
116172end
117173
118174function MOI. get (model:: MOI.ModelLike , attr:: MOI.ConstraintFunction ,
119- b:: SplitIntervalBridge )
120- return MOI. get (model, attr, b. lower)
175+ bridge:: SplitIntervalBridge )
176+ return MOI. get (model, attr, bridge. lower)
177+ end
178+ function MOI. get (model:: MOI.ModelLike , attr:: MOI.ConstraintSet ,
179+ bridge:: SplitIntervalBridge{T, F, MOI.Interval{T}} ) where {T, F}
180+ return MOI. Interval (MOI. get (model, attr, bridge. lower). lower,
181+ MOI. get (model, attr, bridge. upper). upper)
182+ end
183+ function MOI. get (model:: MOI.ModelLike , attr:: MOI.ConstraintSet ,
184+ bridge:: SplitIntervalBridge{T, F, MOI.EqualTo{T}} ) where {T, F}
185+ return MOI. EqualTo (MOI. get (model, attr, bridge. lower). lower)
121186end
122187function MOI. get (model:: MOI.ModelLike , attr:: MOI.ConstraintSet ,
123- b:: SplitIntervalBridge )
124- return MOI. Interval (MOI. get (model, attr, b. lower). lower,
125- MOI. get (model, attr, b. upper). upper)
188+ bridge:: SplitIntervalBridge{T, F, MOI.Zeros} ) where {T, F}
189+ return MOI. Zeros (MOI. get (model, attr, bridge. lower). dimension)
126190end
0 commit comments