@@ -88,7 +88,7 @@ MOI.dimension(sets::MixOfScalarSets) = length(sets.set_ids)
8888
8989rows (:: MixOfScalarSets , ci:: MOI.ConstraintIndex ) = ci. value
9090
91- function add_set (sets:: MixOfScalarSets , i)
91+ function add_set (sets:: MixOfScalarSets , i:: Int ) :: Int64
9292 push! (sets. set_ids, i)
9393 return length (sets. set_ids)
9494end
@@ -170,91 +170,91 @@ macro product_of_sets(name, set_types...)
170170 mutable struct $ (esc_name){$ (T)} < :
171171 $ MOI. Utilities. OrderedProductOfSets{$ (T)}
172172 """
173- During the copy, this counts the number of rows corresponding to
174- each set. At the end of copy, `final_touch` is called, which
175- converts this list into a cumulative ordering.
176- """
177- num_rows:: Vector{Int}
173+ `rows[i][j]` corresponds to constraint `j` of set type `i`.
178174
175+ The value depends on `final_touch`:
176+ * Before `final_touch`, these are `1:dimension` of the constraint
177+ * After `final_touch`, these are the 1-indexed rows of the full
178+ constraint matrix
179179 """
180- A dictionary which maps the `set_index` and `offset` of a set to the
181- dimension, that is, `dimension[(set_index,offset)] → dim`.
182- """
183- dimension:: Dict{Tuple{Int,Int},Int}
180+ rows:: Vector{Vector{UnitRange{Int}}}
184181
185182 """
186183 A sanity bit to check that we don't call functions out-of-order.
187184 """
188185 final_touch:: Bool
189186
190187 function $ (esc_name){$ (T)}() where {$ (T)}
191- return new (
192- zeros (Int, $ (length (set_types))),
193- Dict {Tuple{Int,Int},Int} (),
194- false ,
195- )
188+ n = $ (length (set_types))
189+ return new ([UnitRange{Int}[] for _ in 1 : n], false )
196190 end
197191 end
198192 )
199193 return _sets_code (esc_name, T, type_def, set_types... )
200194end
201195
202- MOI. is_empty (sets:: OrderedProductOfSets ) = all (iszero , sets. num_rows )
196+ MOI. is_empty (sets:: OrderedProductOfSets ) = all (isempty , sets. rows )
203197
204198function MOI. empty! (sets:: OrderedProductOfSets )
205- fill! (sets. num_rows, 0 )
206- empty! (sets. dimension)
199+ map (empty!, sets. rows)
207200 sets. final_touch = false
208201 return
209202end
210203
211- function MOI. dimension (sets:: OrderedProductOfSets )
204+ function MOI. dimension (sets:: OrderedProductOfSets ):: Int
212205 @assert sets. final_touch
213- if isempty (sets. num_rows)
214- # There is no set type
215- return 0
216- else
217- return sets. num_rows[end ]
206+ for i in reverse (eachindex (sets. rows))
207+ if ! isempty (sets. rows[i])
208+ return last (sets. rows[i][end ])
209+ end
218210 end
211+ return 0 # All rows were empty.
212+ end
213+
214+ # A backwards-compatible method to ensure callers of `sets.num_rows` still
215+ # works.
216+ function Base. getproperty (sets:: OrderedProductOfSets , key:: Symbol )
217+ if key == :num_rows
218+ if sets. final_touch
219+ return cumsum (num_rows (sets, S) for S in set_types (sets))
220+ end
221+ return Int[num_rows (sets, S) for S in set_types (sets)]
222+ end
223+ return getfield (sets, key)
219224end
220225
221226function rows (
222227 sets:: OrderedProductOfSets{T} ,
223228 ci:: MOI.ConstraintIndex{MOI.ScalarAffineFunction{T},S} ,
224- ) where {T,S}
229+ ):: Int where {T,S}
225230 @assert sets. final_touch
226231 i = set_index (sets, S):: Int
227- return (i == 1 ? 0 : sets. num_rows[i - 1 ]) + ci. value
232+ return only ( sets. rows[i][ ci. value])
228233end
229234
230235function rows (
231236 sets:: OrderedProductOfSets{T} ,
232237 ci:: MOI.ConstraintIndex{MOI.VectorAffineFunction{T},S} ,
233- ) where {T,S}
238+ ):: UnitRange{Int} where {T,S}
234239 @assert sets. final_touch
235240 i = set_index (sets, S):: Int
236- offset = i == 1 ? 0 : sets. num_rows[i- 1 ]
237- return (offset + ci. value - 1 ) .+ (1 : sets. dimension[(i, ci. value)])
238- end
239-
240- function add_set (sets:: OrderedProductOfSets , i)
241- @assert ! sets. final_touch
242- sets. num_rows[i] += 1
243- return sets. num_rows[i]
241+ return sets. rows[i][ci. value]
244242end
245243
246- function add_set (sets:: OrderedProductOfSets , i, dim)
244+ function add_set (sets:: OrderedProductOfSets , i:: Int , dim:: Int = 1 ) :: Int64
247245 @assert ! sets. final_touch
248- ci = sets. num_rows[i] + 1
249- sets. dimension[(i, ci)] = dim
250- sets. num_rows[i] += dim
251- return ci
246+ push! (sets. rows[i], 1 : dim)
247+ return length (sets. rows[i])
252248end
253249
254- function final_touch (sets:: OrderedProductOfSets )
250+ function final_touch (sets:: OrderedProductOfSets ):: Nothing
255251 @assert ! sets. final_touch
256- for i in 2 : length (sets. num_rows)
257- sets. num_rows[i] += sets. num_rows[i- 1 ]
252+ offset = 0
253+ for (i, rows) in enumerate (sets. rows)
254+ for (j, row) in enumerate (rows)
255+ rows[j] = offset .+ row
256+ offset += length (row)
257+ end
258258 end
259259 sets. final_touch = true
260260 return
@@ -266,103 +266,57 @@ end
266266Return the number of rows corresponding to a set of type `S`. That is, it is
267267the sum of the dimensions of the sets of type `S`.
268268"""
269- function num_rows (sets:: OrderedProductOfSets , :: Type{S} ) where {S}
269+ function num_rows (sets:: OrderedProductOfSets , :: Type{S} ):: Int where {S}
270270 i = set_index (sets, S):: Int
271- if ! sets. final_touch || i == 1
272- return sets. num_rows[i]
271+ rows = sets. rows[i]
272+ if isempty (rows)
273+ return 0
274+ elseif sets. final_touch
275+ return max (0 , last (rows[end ]) - first (rows[1 ]) + 1 )
276+ else
277+ return mapreduce (length, + , rows)
273278 end
274- return sets. num_rows[i] - sets. num_rows[i- 1 ]
275279end
276280
277281function MOI. get (
278282 sets:: OrderedProductOfSets{T} ,
279283 :: MOI.ListOfConstraintTypesPresent ,
280- ) where {T}
284+ ):: Vector{Tuple{Type,Type}} where {T}
281285 return Tuple{Type,Type}[
282286 (_affine_function_type (T, S), S) for
283- S in set_types (sets) if num_rows (sets, S) > 0
287+ (i, S) in enumerate ( set_types (sets)) if ! isempty (sets. rows[i])
284288 ]
285289end
286290
287- struct _UnevenIterator
288- i:: Int
289- start:: Int
290- stop:: Int
291- dimension:: Dict{Tuple{Int,Int},Int}
292- end
293-
294- Base. IteratorSize (:: _UnevenIterator ) = Base. SizeUnknown ()
295-
296- function Base. iterate (it:: _UnevenIterator , cur = it. start)
297- if cur > it. stop
298- return nothing
299- end
300- return (cur, cur + it. dimension[(it. i, cur)])
301- end
302-
303- function Base. in (x:: Int64 , it:: _UnevenIterator )
304- return it. start <= x <= it. stop && haskey (it. dimension, (it. i, x))
305- end
306-
307- function _range_iterator (
308- :: OrderedProductOfSets{T} ,
309- :: Int ,
310- start:: Int ,
311- stop:: Int ,
312- :: Type{MOI.ScalarAffineFunction{T}} ,
313- ) where {T}
314- return start: stop
315- end
316-
317- function _range_iterator (
318- sets:: OrderedProductOfSets{T} ,
319- i:: Int ,
320- start:: Int ,
321- stop:: Int ,
322- :: Type{MOI.VectorAffineFunction{T}} ,
323- ) where {T}
324- return _UnevenIterator (i, start, stop, sets. dimension)
325- end
326-
327- function _range_iterator (
328- sets:: OrderedProductOfSets{T} ,
329- :: Type{F} ,
330- :: Type{S} ,
331- ) where {T,F,S}
332- i = set_index (sets, S)
333- if i === nothing || F != _affine_function_type (T, S)
334- return
335- end
336- return _range_iterator (sets, i, 1 , num_rows (sets, S), F)
337- end
338-
339- _length (:: Nothing ) = 0
340- _length (r:: UnitRange ) = length (r)
341- _length (r:: _UnevenIterator ) = count (_ -> true , r)
342-
343291function MOI. get (
344292 sets:: OrderedProductOfSets ,
345293 :: MOI.NumberOfConstraints{F,S} ,
346- ) where {F,S}
347- r = _range_iterator (sets, F, S)
348- return _length (r)
294+ ):: Int64 where {F,S}
295+ i = set_index (sets, S):: Union{Nothing,Int}
296+ if i == nothing
297+ return 0
298+ end
299+ return length (sets. rows[i])
349300end
350301
351302function MOI. get (
352303 sets:: OrderedProductOfSets ,
353304 :: MOI.ListOfConstraintIndices{F,S} ,
354- ) where {F,S}
355- rows = _range_iterator (sets, F, S)
356- if rows = == nothing
305+ ):: Vector{MOI.ConstraintIndex{F,S}} where {F,S}
306+ i = set_index (sets, S) :: Union{Nothing,Int}
307+ if i == nothing
357308 return MOI. ConstraintIndex{F,S}[]
358309 end
359- return MOI. ConstraintIndex {F,S} .(rows)
310+ return MOI. ConstraintIndex {F,S} .(1 : length (sets . rows[i]) )
360311end
361312
362313function MOI. is_valid (
363314 sets:: OrderedProductOfSets ,
364315 ci:: MOI.ConstraintIndex{F,S} ,
365- ) where {F,S}
366- r = _range_iterator (sets, F, S)
367- return r != = nothing && ci. value in r
316+ ):: Bool where {F,S}
317+ i = set_index (sets, S):: Union{Nothing,Int}
318+ if i == nothing
319+ return false
320+ end
321+ return 1 <= ci. value <= length (sets. rows[i])
368322end
0 commit comments