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
+
1
8
"""
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`.
3
16
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``.
5
20
"""
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)
15
32
end
16
33
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
18
44
MOIB. 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}}
21
52
end
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 }
26
57
end
27
58
28
59
# 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
33
76
34
77
# 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)
38
81
end
39
82
40
83
# Attributes, Bridge acting as a constraint
@@ -50,33 +93,45 @@ function MOI.get(model::MOI.ModelLike, attr::Union{MOI.ConstraintPrimal, MOI.Con
50
93
# lower and upper should give the same value
51
94
return MOI. get (model, attr, bridge. lower)
52
95
end
53
- function MOI. set (model:: MOI.ModelLike , a :: MOI.ConstraintPrimalStart ,
96
+ function MOI. set (model:: MOI.ModelLike , attr :: MOI.ConstraintPrimalStart ,
54
97
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.
58
107
function MOI. get (model:: MOI.ModelLike , attr:: Union{MOI.ConstraintDual, MOI.ConstraintDualStart} ,
59
108
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)
65
110
end
66
- function MOI. set (model:: MOI.ModelLike , a:: MOI.ConstraintDualStart ,
67
- bridge:: SplitIntervalBridge , value)
111
+ function _split_dual_start (value)
68
112
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
71
114
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])
74
123
end
75
124
end
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
76
131
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)
80
135
if lower_stat == MOI. NONBASIC_AT_LOWER
81
136
@warn (" GreaterThan constraints should not have basis status:" *
82
137
" NONBASIC_AT_LOWER, instead use NONBASIC." )
@@ -99,28 +154,37 @@ function MOI.get(model::MOI.ModelLike, ::MOI.ConstraintBasisStatus, c::SplitInte
99
154
end
100
155
101
156
# 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)
105
160
end
106
161
107
162
function 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)
111
166
end
112
167
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))
116
172
end
117
173
118
174
function 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)
121
186
end
122
187
function 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)
126
190
end
0 commit comments