Skip to content

Commit 6007014

Browse files
committed
Add exponent iterator
1 parent 3c21287 commit 6007014

File tree

1 file changed

+123
-0
lines changed

1 file changed

+123
-0
lines changed

src/comparison.jl

Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -316,3 +316,126 @@ compare(a, b, ::Type{Reverse{O}}) where {O} = compare(b, a, O)
316316
Returns the [`AbstractMonomialOrdering`](@ref) used for the monomials of `p`.
317317
"""
318318
function ordering end
319+
320+
_last_lex_index(n, ::Type{LexOrder}) = n
321+
_prev_lex_index(i, ::Type{LexOrder}) = i - 1
322+
_not_first_indices(n, ::Type{LexOrder}) = n:-1:2
323+
_last_lex_index(_, ::Type{InverseLexOrder}) = 1
324+
_prev_lex_index(i, ::Type{InverseLexOrder}) = i + 1
325+
_not_first_indices(n, ::Type{InverseLexOrder}) = 1:(n-1)
326+
_last_lex_index(n, ::Type{Graded{M}}) where {M} = _last_lex_index(n, M)
327+
_prev_lex_index(i, ::Type{Graded{M}}) where {M} = _prev_lex_index(i, M)
328+
_not_first_indices(n, ::Type{Graded{M}}) where {M} = _not_first_indices(n, M)
329+
330+
"""
331+
struct ExponentsIterator{M}(
332+
object;
333+
min_deg::Int = 0,
334+
max_deg::Union{Nothing,Int} = nothing,
335+
inline::Bool = false,
336+
)
337+
338+
An iterator for generating monomial exponents for monomial
339+
ordering `M`. The type of the vector of exponents is the type of
340+
`object` and is length (i.e., the number of variables) is `length(object)`.
341+
"""
342+
struct ExponentsIterator{M,D<:Union{Nothing,Int},O}
343+
object::O # Used to get number of variables and get new zero elements
344+
min_deg::Int
345+
max_deg::D
346+
inline::Bool
347+
end
348+
349+
function ExponentsIterator{M}(object; min_deg::Int = 0, max_deg::Union{Nothing,Int} = nothing, inline::Bool = false) where {M}
350+
ExponentsIterator{M,typeof(max_deg),typeof(object)}(object, min_deg, max_deg, inline)
351+
end
352+
353+
function ExponentsIterator(args...; kws...)
354+
return ExponentsIterator{Graded{LexOrder}}(args...; kws...)
355+
end
356+
357+
Base.eltype(::Type{ExponentsIterator{M,D,O}}) where {M,D,O} = O
358+
Base.IteratorSize(::Type{<:ExponentsIterator{M,Nothing}}) where {M} = Base.IsInfinite()
359+
Base.IteratorSize(::Type{<:ExponentsIterator{M,Int}}) where {M} = Base.HasLength()
360+
361+
function Base.length(it::ExponentsIterator{M,Int}) where {M}
362+
len = binomial(nvariables(it) + it.max_deg, nvariables(it))
363+
if it.min_deg > 0
364+
len -= binomial(nvariables(it) + it.min_deg, nvariables(it))
365+
end
366+
return len
367+
end
368+
369+
nvariables(it::ExponentsIterator) = length(it.object)
370+
371+
_increase_degree(it::ExponentsIterator{<:Graded,Nothing}, _) = false
372+
_increase_degree(it::ExponentsIterator{<:Graded,Int}, _) = false
373+
_increase_degree(it::ExponentsIterator{M,Nothing}, _) where {M} = true
374+
_increase_degree(it::ExponentsIterator{M,Int}, deg) where {M} = deg < it.max_deg
375+
376+
# We just changed the degree by removing `Δ`,
377+
# In graded ordering, we just add `Δ` to maintain the same degree
378+
_adjust_degree(::ExponentsIterator{<:Graded}, _, Δ) = Δ
379+
# Otherwise, we just need the degree to stay above `it.min_deg`,
380+
# so we need to add `it.min_deg - deg`
381+
_adjust_degree(it::ExponentsIterator, deg, _) = min(0, it.min_deg - deg)
382+
383+
_setindex!(x, v, i) = Base.setindex!(x, v, i)
384+
_setindex!(x::Tuple, v, i) = Base.setindex(x, v, i)
385+
_increment!(x, i) = _setindex!(x, x[i] + 1, i)
386+
387+
_zero(x) = zero(x)
388+
_zero(x::Tuple) = zero.(x)
389+
390+
_zero!(x) = fill!(x, 0)
391+
_zero!(x::Tuple) = _zero(x)
392+
393+
_copy(x) = copy(x)
394+
_copy(x::Tuple) = x
395+
396+
function _iterate!(it::ExponentsIterator{M}, z, deg) where {M}
397+
if _increase_degree(it, deg)
398+
z = _increment!(z, _last_lex_index(nvariables(it), M))
399+
return z, deg + 1
400+
end
401+
I = _not_first_indices(nvariables(it), M)
402+
i = findfirst(i -> !iszero(z[i]), I)
403+
if isnothing(i)
404+
if !isnothing(it.max_deg) && deg == it.max_deg
405+
return
406+
end
407+
z = _zero!(z)
408+
z = _setindex!(z, deg + 1, _last_lex_index(nvariables(it), M))
409+
return z, deg + 1
410+
end
411+
j = I[i]
412+
Δ = z[j] - 1
413+
_setindex!(z, 0, j)
414+
deg -= Δ
415+
Δ = _adjust_degree(it, deg, Δ)
416+
deg += Δ
417+
z = _setindex!(z, Δ, _last_lex_index(nvariables(it), M))
418+
z = _increment!(z, _prev_lex_index(j, M))
419+
return z, deg
420+
end
421+
422+
function Base.iterate(it::ExponentsIterator{M}) where {M}
423+
if nvariables(it) == 0
424+
return
425+
end
426+
z = _zero(it.object)
427+
z = _setindex!(z, it.min_deg, _last_lex_index(nvariables(it), M))
428+
return z, (z, it.min_deg)
429+
end
430+
431+
function Base.iterate(it::ExponentsIterator, state)
432+
z, deg = state
433+
if !it.inline
434+
z = _copy(z)
435+
end
436+
state = _iterate!(it, z, deg)
437+
if isnothing(state)
438+
return
439+
end
440+
return state[1], state
441+
end

0 commit comments

Comments
 (0)