2525 * `G` in [`MOI.Nonnegatives`](@ref)
2626"""
2727mutable struct SplitHyperRectangleBridge{T,G,F} <: AbstractBridge
28- ci:: MOI.ConstraintIndex{G,MOI.Nonnegatives}
28+ ci:: Union{Nothing, MOI.ConstraintIndex{G,MOI.Nonnegatives} }
2929 set:: MOI.HyperRectangle{T}
3030 free_rows:: F
31+ free_primal_start:: Union{Nothing,Vector{T}}
32+ free_dual_start:: Union{Nothing,Vector{T}}
33+
34+ function SplitHyperRectangleBridge {T,G,F} (
35+ ci:: Union{Nothing,MOI.ConstraintIndex{G,MOI.Nonnegatives}} ,
36+ set:: MOI.HyperRectangle{T} ,
37+ free_rows:: F ,
38+ ) where {T,G,F}
39+ return new {T,G,F} (ci, set, free_rows, nothing , nothing )
40+ end
3141end
3242
3343const SplitHyperRectangle{T,OT<: MOI.ModelLike } =
@@ -67,6 +77,9 @@ function bridge_constraint(
6777 push! (free_rows, i)
6878 end
6979 end
80+ if length (free_rows) == N
81+ return SplitHyperRectangleBridge {T,G,F} (nothing , s, f)
82+ end
7083 g = MOI. Utilities. vectorize (g_vec[rows_to_keep])
7184 ci = MOI. add_constraint (model, g, MOI. Nonnegatives (MOI. output_dimension (g)))
7285 return SplitHyperRectangleBridge {T,G,F} (ci, s, scalars[free_rows])
@@ -106,6 +119,9 @@ function MOI.get(
106119 :: MOI.ConstraintFunction ,
107120 bridge:: SplitHyperRectangleBridge{T,G,F} ,
108121) where {T,G,F}
122+ if bridge. ci === nothing
123+ return bridge. free_rows
124+ end
109125 f = MOI. get (model, MOI. ConstraintFunction (), bridge. ci)
110126 f_s = MOI. Utilities. eachscalar (f)
111127 func = Vector {eltype(f_s)} (undef, MOI. dimension (bridge. set))
@@ -154,22 +170,28 @@ function MOI.get(
154170end
155171
156172function MOI. delete (model:: MOI.ModelLike , bridge:: SplitHyperRectangleBridge )
157- MOI. delete (model, bridge. ci)
173+ if bridge. ci != = nothing
174+ MOI. delete (model, bridge. ci)
175+ end
158176 return
159177end
160178
161179function MOI. get (
162- :: SplitHyperRectangleBridge{T,G} ,
180+ bridge :: SplitHyperRectangleBridge{T,G} ,
163181 :: MOI.NumberOfConstraints{G,MOI.Nonnegatives} ,
164182):: Int64 where {T,G}
165- return 1
183+ return ifelse (bridge . ci === nothing , 0 , 1 )
166184end
167185
168186function MOI. get (
169- bridge:: SplitHyperRectangleBridge{T,G} ,
187+ bridge:: SplitHyperRectangleBridge{T,G,F } ,
170188 :: MOI.ListOfConstraintIndices{G,MOI.Nonnegatives} ,
171- ) where {T,G}
172- return [bridge. ci]
189+ ) where {T,G,F}
190+ ret = MOI. ConstraintIndex{G,MOI. Nonnegatives}[]
191+ if bridge. ci != = nothing
192+ push! (ret, bridge. ci)
193+ end
194+ return ret
173195end
174196
175197function MOI. supports (
@@ -180,12 +202,49 @@ function MOI.supports(
180202 return MOI. supports (model, attr, MOI. ConstraintIndex{G,MOI. Nonnegatives})
181203end
182204
205+ _get_free_start (bridge, :: MOI.ConstraintDualStart ) = bridge. free_dual_start
206+
207+ function _set_free_start (bridge, :: MOI.ConstraintDualStart , value)
208+ bridge. free_dual_start = value
209+ return
210+ end
211+
212+ _get_free_start (bridge, :: MOI.ConstraintPrimalStart ) = bridge. free_primal_start
213+
214+ function _set_free_start (bridge, :: MOI.ConstraintPrimalStart , value)
215+ bridge. free_primal_start = value
216+ return
217+ end
218+
219+ # This is a punned overload. We use Union{MOI.ConstraintDual,MOI.ConstraintDualStart}
220+ # in MOI.get, so this hits the ConstraintDual branch. Since no constraints are
221+ # ever added, we just assuem that the dual is `0.0` (this is feasible because)
222+ # the set is really `f(x) in Reals()`, so the dual set is `Zeros()`
223+ function _get_free_start (
224+ bridge:: SplitHyperRectangleBridge{T} ,
225+ :: MOI.ConstraintDual ,
226+ ) where {T}
227+ return zeros (T, MOI. dimension (bridge. set))
228+ end
229+
230+ # The same cannot be said for ConstraintPrimal because we have no mechanism for
231+ # evaluating the primal of the free rows. Throw an error instead.
232+ function _get_free_start (
233+ :: SplitHyperRectangleBridge ,
234+ attr:: MOI.ConstraintPrimal ,
235+ )
236+ return throw (MOI. GetAttributeNotAllowed (attr))
237+ end
238+
183239function MOI. set (
184240 model:: MOI.ModelLike ,
185241 attr:: MOI.ConstraintPrimalStart ,
186242 bridge:: SplitHyperRectangleBridge{T} ,
187243 value:: AbstractVector{T} ,
188244) where {T}
245+ if bridge. ci === nothing
246+ return _set_free_start (bridge, attr, value)
247+ end
189248 new_values = vcat (
190249 T[v - l for (v, l) in zip (value, bridge. set. lower) if isfinite (l)],
191250 T[u - v for (v, u) in zip (value, bridge. set. upper) if isfinite (u)],
@@ -199,6 +258,9 @@ function MOI.get(
199258 attr:: Union{MOI.ConstraintPrimal,MOI.ConstraintPrimalStart} ,
200259 bridge:: SplitHyperRectangleBridge{T} ,
201260) where {T}
261+ if bridge. ci === nothing
262+ return _get_free_start (bridge, attr)
263+ end
202264 values = MOI. get (model, attr, bridge. ci)
203265 if values === nothing
204266 return nothing
@@ -226,6 +288,9 @@ function MOI.set(
226288 bridge:: SplitHyperRectangleBridge{T} ,
227289 values:: AbstractVector{T} ,
228290) where {T}
291+ if bridge. ci === nothing
292+ return _set_free_start (bridge, attr, values)
293+ end
229294 set = bridge. set
230295 new_values = vcat (
231296 T[max (T (0 ), v) for (v, l) in zip (values, set. lower) if isfinite (l)],
@@ -240,6 +305,9 @@ function MOI.get(
240305 attr:: Union{MOI.ConstraintDual,MOI.ConstraintDualStart} ,
241306 bridge:: SplitHyperRectangleBridge{T} ,
242307) where {T}
308+ if bridge. ci === nothing
309+ return _get_free_start (bridge, attr)
310+ end
243311 values = MOI. get (model, attr, bridge. ci)
244312 if values === nothing
245313 return nothing
@@ -267,6 +335,9 @@ function MOI.set(
267335 bridge:: SplitHyperRectangleBridge{T} ,
268336 :: Nothing ,
269337) where {T}
338+ if bridge. ci === nothing
339+ return _set_free_start (bridge, attr, nothing )
340+ end
270341 MOI. set (model, attr, bridge. ci, nothing )
271342 return
272343end
0 commit comments