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}}
3133end
3234
3335const SplitHyperRectangle{T,OT<: MOI.ModelLike } =
@@ -67,9 +69,18 @@ function bridge_constraint(
6769 push! (free_rows, i)
6870 end
6971 end
72+ if length (free_rows) == N
73+ return SplitHyperRectangleBridge {T,G,F} (nothing , s, f, nothing , nothing )
74+ end
7075 g = MOI. Utilities. vectorize (g_vec[rows_to_keep])
7176 ci = MOI. add_constraint (model, g, MOI. Nonnegatives (MOI. output_dimension (g)))
72- return SplitHyperRectangleBridge {T,G,F} (ci, s, scalars[free_rows])
77+ return SplitHyperRectangleBridge {T,G,F} (
78+ ci,
79+ s,
80+ scalars[free_rows],
81+ nothing ,
82+ nothing ,
83+ )
7384end
7485
7586function MOI. supports_constraint (
@@ -106,6 +117,9 @@ function MOI.get(
106117 :: MOI.ConstraintFunction ,
107118 bridge:: SplitHyperRectangleBridge{T,G,F} ,
108119) where {T,G,F}
120+ if bridge. ci === nothing
121+ return bridge. free_rows
122+ end
109123 f = MOI. get (model, MOI. ConstraintFunction (), bridge. ci)
110124 f_s = MOI. Utilities. eachscalar (f)
111125 func = Vector {eltype(f_s)} (undef, MOI. dimension (bridge. set))
@@ -154,22 +168,28 @@ function MOI.get(
154168end
155169
156170function MOI. delete (model:: MOI.ModelLike , bridge:: SplitHyperRectangleBridge )
157- MOI. delete (model, bridge. ci)
171+ if bridge. ci != = nothing
172+ MOI. delete (model, bridge. ci)
173+ end
158174 return
159175end
160176
161177function MOI. get (
162- :: SplitHyperRectangleBridge{T,G} ,
178+ bridge :: SplitHyperRectangleBridge{T,G} ,
163179 :: MOI.NumberOfConstraints{G,MOI.Nonnegatives} ,
164180):: Int64 where {T,G}
165- return 1
181+ return ifelse (bridge . ci === nothing , 0 , 1 )
166182end
167183
168184function MOI. get (
169- bridge:: SplitHyperRectangleBridge{T,G} ,
185+ bridge:: SplitHyperRectangleBridge{T,G,F } ,
170186 :: MOI.ListOfConstraintIndices{G,MOI.Nonnegatives} ,
171- ) where {T,G}
172- return [bridge. ci]
187+ ) where {T,G,F}
188+ ret = MOI. ConstraintIndex{G,MOI. Nonnegatives}[]
189+ if bridge. ci != = nothing
190+ push! (ret, bridge. ci)
191+ end
192+ return ret
173193end
174194
175195function MOI. supports (
@@ -180,12 +200,49 @@ function MOI.supports(
180200 return MOI. supports (model, attr, MOI. ConstraintIndex{G,MOI. Nonnegatives})
181201end
182202
203+ _get_free_start (bridge, :: MOI.ConstraintDualStart ) = bridge. free_dual_start
204+
205+ function _set_free_start (bridge, :: MOI.ConstraintDualStart , value)
206+ bridge. free_dual_start = value
207+ return
208+ end
209+
210+ _get_free_start (bridge, :: MOI.ConstraintPrimalStart ) = bridge. free_primal_start
211+
212+ function _set_free_start (bridge, :: MOI.ConstraintPrimalStart , value)
213+ bridge. free_primal_start = value
214+ return
215+ end
216+
217+ # This is a punned overload. We use Union{MOI.ConstraintDual,MOI.ConstraintDualStart}
218+ # in MOI.get, so this hits the ConstraintDual branch. Since no constraints are
219+ # ever added, we just assuem that the dual is `0.0` (this is feasible because)
220+ # the set is really `f(x) in Reals()`, so the dual set is `Zeros()`
221+ function _get_free_start (
222+ bridge:: SplitHyperRectangleBridge{T} ,
223+ :: MOI.ConstraintDual ,
224+ ) where {T}
225+ return zeros (T, MOI. dimension (bridge. set))
226+ end
227+
228+ # The same cannot be said for ConstraintPrimal because we have no mechanism for
229+ # evaluating the primal of the free rows. Throw an error instead.
230+ function _get_free_start (
231+ :: SplitHyperRectangleBridge ,
232+ attr:: MOI.ConstraintPrimal
233+ )
234+ return throw (MOI. GetAttributeNotAllowed (attr))
235+ end
236+
183237function MOI. set (
184238 model:: MOI.ModelLike ,
185239 attr:: MOI.ConstraintPrimalStart ,
186240 bridge:: SplitHyperRectangleBridge{T} ,
187241 value:: AbstractVector{T} ,
188242) where {T}
243+ if bridge. ci === nothing
244+ return _set_free_start (bridge, attr, value)
245+ end
189246 new_values = vcat (
190247 T[v - l for (v, l) in zip (value, bridge. set. lower) if isfinite (l)],
191248 T[u - v for (v, u) in zip (value, bridge. set. upper) if isfinite (u)],
@@ -199,6 +256,9 @@ function MOI.get(
199256 attr:: Union{MOI.ConstraintPrimal,MOI.ConstraintPrimalStart} ,
200257 bridge:: SplitHyperRectangleBridge{T} ,
201258) where {T}
259+ if bridge. ci === nothing
260+ return _get_free_start (bridge, attr)
261+ end
202262 values = MOI. get (model, attr, bridge. ci)
203263 if values === nothing
204264 return nothing
@@ -226,6 +286,9 @@ function MOI.set(
226286 bridge:: SplitHyperRectangleBridge{T} ,
227287 values:: AbstractVector{T} ,
228288) where {T}
289+ if bridge. ci === nothing
290+ return _set_free_start (bridge, attr, values)
291+ end
229292 set = bridge. set
230293 new_values = vcat (
231294 T[max (T (0 ), v) for (v, l) in zip (values, set. lower) if isfinite (l)],
@@ -240,6 +303,9 @@ function MOI.get(
240303 attr:: Union{MOI.ConstraintDual,MOI.ConstraintDualStart} ,
241304 bridge:: SplitHyperRectangleBridge{T} ,
242305) where {T}
306+ if bridge. ci === nothing
307+ return _get_free_start (bridge, attr)
308+ end
243309 values = MOI. get (model, attr, bridge. ci)
244310 if values === nothing
245311 return nothing
@@ -267,6 +333,9 @@ function MOI.set(
267333 bridge:: SplitHyperRectangleBridge{T} ,
268334 :: Nothing ,
269335) where {T}
336+ if bridge. ci === nothing
337+ return _set_free_start (bridge, attr, nothing )
338+ end
270339 MOI. set (model, attr, bridge. ci, nothing )
271340 return
272341end
0 commit comments