@@ -200,25 +200,10 @@ Springer Science & Business Media, **2013**.
200200"""
201201struct LexOrder <: AbstractMonomialOrdering end
202202
203- function compare (
204- exp1:: AbstractVector{T} ,
205- exp2:: AbstractVector{T} ,
206- :: Type{LexOrder} ,
207- ) where {T}
208- if eachindex (exp1) != eachindex (exp2)
209- throw (
210- ArgumentError (
211- " Cannot compare exponent vectors `$exp1 ` and `$exp2 ` of different indices." ,
212- ),
213- )
214- end
215- @inbounds for i in eachindex (exp1)
216- Δ = exp1[i] - exp2[i]
217- if ! iszero (Δ)
218- return Δ
219- end
220- end
221- return zero (T)
203+ const _TupleOrVector = Union{Tuple,AbstractVector}
204+
205+ function compare (exp1:: _TupleOrVector , exp2:: _TupleOrVector , :: Type{LexOrder} )
206+ return Base. cmp (exp1, exp2)
222207end
223208
224209"""
@@ -239,25 +224,16 @@ SIAM Journal on Matrix Analysis and Applications, 34(1), 102-125, *2013*.
239224"""
240225struct InverseLexOrder <: AbstractMonomialOrdering end
241226
227+ # We can't use `Iterators.Reverse` because it's not an `AbstractVector`
228+ # so not `cmp` methods is defined for it.
229+ _rev (v:: AbstractVector ) = view (v, lastindex (v): - 1 : firstindex (v))
230+ _rev (t:: Tuple ) = reverse (t)
242231function compare (
243- exp1:: AbstractVector{T} ,
244- exp2:: AbstractVector{T} ,
232+ exp1:: _TupleOrVector ,
233+ exp2:: _TupleOrVector ,
245234 :: Type{InverseLexOrder} ,
246- ) where {T}
247- if eachindex (exp1) != eachindex (exp2)
248- throw (
249- ArgumentError (
250- " Cannot compare exponent vectors `$exp1 ` and `$exp2 ` of different indices." ,
251- ),
252- )
253- end
254- @inbounds for i in Iterators. Reverse (eachindex (exp1))
255- Δ = exp1[i] - exp2[i]
256- if ! iszero (Δ)
257- return Δ
258- end
259- end
260- return zero (T)
235+ )
236+ return compare (_rev (exp1), _rev (exp2), LexOrder)
261237end
262238
263239"""
@@ -316,3 +292,199 @@ compare(a, b, ::Type{Reverse{O}}) where {O} = compare(b, a, O)
316292Returns the [`AbstractMonomialOrdering`](@ref) used for the monomials of `p`.
317293"""
318294function ordering end
295+
296+ _last_lex_index (n, :: Type{LexOrder} ) = n
297+ _prev_lex_index (i, :: Type{LexOrder} ) = i - 1
298+ _not_first_indices (n, :: Type{LexOrder} ) = n: - 1 : 2
299+ _last_lex_index (_, :: Type{InverseLexOrder} ) = 1
300+ _prev_lex_index (i, :: Type{InverseLexOrder} ) = i + 1
301+ _not_first_indices (n, :: Type{InverseLexOrder} ) = 1 : (n- 1 )
302+ _last_lex_index (n, :: Type{Graded{M}} ) where {M} = _last_lex_index (n, M)
303+ _prev_lex_index (i, :: Type{Graded{M}} ) where {M} = _prev_lex_index (i, M)
304+ _not_first_indices (n, :: Type{Graded{M}} ) where {M} = _not_first_indices (n, M)
305+
306+ """
307+ struct ExponentsIterator{M}(
308+ object;
309+ mindegree::Int = 0,
310+ maxdegree::Union{Nothing,Int} = nothing,
311+ inline::Bool = false,
312+ )
313+
314+ An iterator for generating monomial exponents for monomial
315+ ordering `M`. The type of the vector of exponents is the type of
316+ `object` and is length (i.e., the number of variables) is `length(object)`.
317+
318+ Note that `object` does not have to be zero, it just needs to implement
319+ `copy` and `setindex!` methods (except for `Tuple` which we handle with a
320+ special case).
321+
322+ See also [`monomials`](@ref).
323+
324+ ### Examples
325+
326+ The following example shows how to generate all exponents of
327+ monomials of 2 variables up to degree 2.
328+ ```jldoctest
329+ julia> collect(ExponentsIterator{Graded{LexOrder}}((0, 0), maxdegree = 2))
330+ 6-element Vector{Tuple{Int64, Int64}}:
331+ (0, 0)
332+ (0, 1)
333+ (1, 0)
334+ (0, 2)
335+ (1, 1)
336+ (2, 0)
337+ ```
338+ Note that you can easily generate the tuple of exponents
339+ of arbitrary length using `ntuple` as follows:
340+ ```jldoctest
341+ julia> collect(ExponentsIterator{Graded{LexOrder}}(ntuple(zero, 3), mindegree = 2, maxdegree = 2))
342+ 6-element Vector{Tuple{Int64, Int64, Int64}}:
343+ (0, 0, 2)
344+ (0, 1, 1)
345+ (0, 2, 0)
346+ (1, 0, 1)
347+ (1, 1, 0)
348+ (2, 0, 0)
349+ ```
350+ You can also change the monomial ordering and use `Vector` instead of `Tuple` as follows:
351+ ```jldoctest
352+ julia> collect(ExponentsIterator{LexOrder}(zeros(Int, 2), mindegree = 2, maxdegree = 3))
353+ 7-element Vector{Vector{Int64}}:
354+ [0, 2]
355+ [0, 3]
356+ [1, 1]
357+ [1, 2]
358+ [2, 0]
359+ [2, 1]
360+ [3, 0]
361+ ```
362+ """
363+ struct ExponentsIterator{M,D<: Union{Nothing,Int} ,O}
364+ object:: O # Used to get number of variables and get new zero elements
365+ mindegree:: Int
366+ maxdegree:: D
367+ inline:: Bool
368+ end
369+
370+ function ExponentsIterator {M} (
371+ object;
372+ mindegree:: Int = 0 ,
373+ maxdegree:: Union{Nothing,Int} = nothing ,
374+ inline:: Bool = false ,
375+ ) where {M}
376+ if length (object) == 0 && isnothing (maxdegree)
377+ # Otherwise, it will incorrectly think that the iterator is infinite
378+ # while it actually has zero elements
379+ maxdegree = mindegree
380+ end
381+ return ExponentsIterator {M,typeof(maxdegree),typeof(object)} (
382+ object,
383+ mindegree,
384+ maxdegree,
385+ inline,
386+ )
387+ end
388+
389+ Base. eltype (:: Type{ExponentsIterator{M,D,O}} ) where {M,D,O} = O
390+ function Base. IteratorSize (:: Type{<:ExponentsIterator{M,Nothing}} ) where {M}
391+ return Base. IsInfinite ()
392+ end
393+ function Base. IteratorSize (:: Type{<:ExponentsIterator{M,Int}} ) where {M}
394+ return Base. HasLength ()
395+ end
396+
397+ function Base. length (it:: ExponentsIterator{M,Int} ) where {M}
398+ len = binomial (nvariables (it) + it. maxdegree, nvariables (it))
399+ if it. mindegree > 0
400+ if it. maxdegree < it. mindegree
401+ return 0
402+ end
403+ len -= binomial (nvariables (it) + it. mindegree - 1 , nvariables (it))
404+ end
405+ return len
406+ end
407+
408+ nvariables (it:: ExponentsIterator ) = length (it. object)
409+
410+ _increase_degree (it:: ExponentsIterator{<:Graded,Nothing} , _) = false
411+ _increase_degree (it:: ExponentsIterator{<:Graded,Int} , _) = false
412+ _increase_degree (it:: ExponentsIterator{M,Nothing} , _) where {M} = true
413+ function _increase_degree (it:: ExponentsIterator{M,Int} , deg) where {M}
414+ return deg < it. maxdegree
415+ end
416+
417+ # We just changed the degree by removing `Δ`,
418+ # In graded ordering, we just add `Δ` to maintain the same degree
419+ _adjust_degree (:: ExponentsIterator{<:Graded} , _, Δ) = Δ
420+ # Otherwise, we just need the degree to stay above `it.mindegree`,
421+ # so we need to add `it.mindegree - deg`
422+ _adjust_degree (it:: ExponentsIterator , deg, _) = max (0 , it. mindegree - deg)
423+
424+ _setindex! (x, v, i) = Base. setindex! (x, v, i)
425+ _setindex! (x:: Tuple , v, i) = Base. setindex (x, v, i)
426+ _increment! (x, i) = _setindex! (x, x[i] + 1 , i)
427+
428+ _zero (x) = zero (x)
429+ _zero (x:: Tuple ) = zero .(x)
430+
431+ _zero! (x) = fill! (x, 0 )
432+ _zero! (x:: Tuple ) = _zero (x)
433+
434+ _copy (x) = copy (x)
435+ _copy (x:: Tuple ) = x
436+
437+ function _iterate! (it:: ExponentsIterator{M} , z, deg) where {M}
438+ if _increase_degree (it, deg)
439+ z = _increment! (z, _last_lex_index (nvariables (it), M))
440+ return z, deg + 1
441+ end
442+ I = _not_first_indices (nvariables (it), M)
443+ i = findfirst (i -> ! iszero (z[i]), I)
444+ if isnothing (i)
445+ if ! isnothing (it. maxdegree) && deg == it. maxdegree
446+ return
447+ end
448+ z = _zero! (z)
449+ z = _setindex! (z, deg + 1 , _last_lex_index (nvariables (it), M))
450+ return z, deg + 1
451+ end
452+ j = I[i]
453+ Δ = z[j] - 1
454+ z = _setindex! (z, 0 , j)
455+ j = I[i]
456+ deg -= Δ
457+ Δ = _adjust_degree (it, deg, Δ)
458+ deg += Δ
459+ z = _setindex! (z, Δ, _last_lex_index (nvariables (it), M))
460+ j = I[i]
461+ z = _increment! (z, _prev_lex_index (j, M))
462+ return z, deg
463+ end
464+
465+ function Base. iterate (it:: ExponentsIterator{M} ) where {M}
466+ z = _zero (it. object)
467+ if it. mindegree > 0
468+ if nvariables (it) == 0 ||
469+ (! isnothing (it. maxdegree) && it. maxdegree < it. mindegree)
470+ return
471+ end
472+ z = _setindex! (z, it. mindegree, _last_lex_index (nvariables (it), M))
473+ end
474+ return z, (z, it. mindegree)
475+ end
476+
477+ function Base. iterate (it:: ExponentsIterator , state)
478+ if nvariables (it) == 0
479+ return # There cannot be more than 1 element
480+ end
481+ z, deg = state
482+ if ! it. inline
483+ z = _copy (z)
484+ end
485+ state = _iterate! (it, z, deg)
486+ if isnothing (state)
487+ return
488+ end
489+ return state[1 ], state
490+ end
0 commit comments