Skip to content

Commit 91f843f

Browse files
authored
Fix monomials for LexOrder (#159)
* Fix monomials for LexOrder * Fixes * Fix * Fix
1 parent af9ccbd commit 91f843f

File tree

2 files changed

+141
-24
lines changed

2 files changed

+141
-24
lines changed

src/monomial_vector.jl

Lines changed: 79 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,6 @@ struct MonomialVector{V,M} <: AbstractVector{Monomial{V,M}}
1212
@assert !iscomm(V) || issorted(vars, rev = true)
1313
@assert all(z -> length(z) == length(vars), Z)
1414

15-
_isless = let M = M
16-
(a, b) -> MP.compare(a, b, M) < 0
17-
end
1815
return new{V,M}(vars, Z)
1916
end
2017
end
@@ -125,68 +122,126 @@ function _error_for_negative_degree(deg)
125122
end
126123
end
127124

128-
function fillZfordeg!(Z, n, deg, ::Type{Commutative}, filter::Function, ::Int)
125+
const _Lex = Union{MP.LexOrder,MP.InverseLexOrder}
126+
127+
_last_lex_index(n, ::Type{MP.LexOrder}) = n
128+
_prev_lex_index(i, ::Type{MP.LexOrder}) = i - 1
129+
_not_first_indices(n, ::Type{MP.LexOrder}) = n:-1:2
130+
_last_lex_index(_, ::Type{MP.InverseLexOrder}) = 1
131+
_prev_lex_index(i, ::Type{MP.InverseLexOrder}) = i + 1
132+
_not_first_indices(n, ::Type{MP.InverseLexOrder}) = 1:(n-1)
133+
134+
function _fill_exponents!(Z, n, degs, ::Type{Commutative}, M::Type{<:_Lex}, filter::Function)
135+
_error_for_negative_degree.(degs)
136+
maxdeg = maximum(degs, init = 0)
137+
I = _not_first_indices(n, M)
138+
z = zeros(Int, n)
139+
while true
140+
deg = sum(z)
141+
if deg in degs && filter(z)
142+
push!(Z, z)
143+
z = copy(z)
144+
end
145+
if deg == maxdeg
146+
i = findfirst(i -> !iszero(z[i]), I)
147+
if isnothing(i)
148+
break
149+
end
150+
j = I[i]
151+
z[j] = 0
152+
z[_prev_lex_index(j, M)] += 1
153+
else
154+
z[_last_lex_index(n, M)] += 1
155+
end
156+
end
157+
end
158+
159+
function _fill_exponents!(Z, n, deg, ::Type{Commutative}, M::Type{<:_Lex}, filter::Function, ::Int)
129160
_error_for_negative_degree(deg)
161+
I = _not_first_indices(n, M)
130162
z = zeros(Int, n)
131-
z[end] = deg
163+
z[_last_lex_index(n, M)] = deg
132164
while true
133165
if filter(z)
134166
push!(Z, z)
135167
z = copy(z)
136168
end
137-
if z[1] == deg
169+
i = findfirst(i -> !iszero(z[i]), I)
170+
if isnothing(i)
138171
break
139172
end
140-
i = findfirst(i -> !iszero(z[i]), n:-1:2)
141-
j = (n:-1:2)[i]
173+
j = I[i]
142174
p = z[j]
143175
z[j] = 0
144-
z[end] = p - 1
145-
z[j-1] += 1
176+
z[_last_lex_index(n, M)] = p - 1
177+
z[_prev_lex_index(j, M)] += 1
146178
end
147179
end
148-
function fillZrec!(Z, z, i, n, deg, filter::Function)
180+
181+
function _fill_noncomm_exponents_rec!(Z, z, i, n, deg, ::Type{MP.LexOrder}, filter::Function)
149182
if deg == 0
150183
if filter(z)
151184
push!(Z, copy(z))
152185
end
153186
else
154187
for i in i:i+n-1
155188
z[i] += 1
156-
fillZrec!(Z, z, i, n, deg - 1, filter)
189+
_fill_noncomm_exponents_rec!(Z, z, i, n, deg - 1, LexOrder, filter)
157190
z[i] -= 1
158191
end
159192
end
160193
end
161-
function fillZfordeg!(
194+
195+
function _fill_exponents!(
162196
Z,
163197
n,
164198
deg,
165199
::Type{NonCommutative},
200+
::Type{MP.LexOrder},
166201
filter::Function,
167202
maxdeg::Int,
168203
)
169204
_error_for_negative_degree(deg)
170205
_error_for_negative_degree(maxdeg)
171206
z = zeros(Int, maxdeg * n - maxdeg + 1)
172207
start = length(Z) + 1
173-
fillZrec!(Z, z, 1, n, deg, filter)
208+
_fill_noncomm_exponents_rec!(Z, z, 1, n, deg, MP.LexOrder, filter)
174209
return reverse!(view(Z, start:length(Z)))
175210
end
176-
# List exponents in decreasing Graded Lexicographic Order
177-
function getZfordegs(
211+
212+
function _fill_exponents!(Z, n, deg, ::Type{V}, ::Type{MP.Reverse{M}}, args...) where {V,M}
213+
prev = lastindex(Z)
214+
_fill_exponents!(Z, n, deg, V, M, args...)
215+
reverse!(view(Z, (prev + 1):lastindex(Z)))
216+
return
217+
end
218+
219+
function _fill_exponents!(
220+
Z::Vector{Vector{Int}},
178221
n,
179222
degs::AbstractVector{Int},
180223
::Type{V},
181-
::Type{M},
224+
::Type{MP.Graded{M}},
182225
filter::Function,
183226
) where {V,M}
184-
Z = Vector{Vector{Int}}()
185227
# For non-commutative, lower degree need to create a vector of exponent as large as for the highest degree
186-
maxdeg = isempty(degs) ? 0 : maximum(degs)
228+
maxdeg = maximum(degs, init = 0)
187229
for deg in sort(degs)
188-
fillZfordeg!(Z, n, deg, V, filter, maxdeg)
230+
_fill_exponents!(Z, n, deg, V, M, filter, maxdeg)
189231
end
232+
return
233+
end
234+
235+
# List exponents in decreasing Graded Lexicographic Order
236+
function _all_exponents(
237+
n,
238+
degs::AbstractVector{Int},
239+
::Type{V},
240+
::Type{M},
241+
filter::Function,
242+
) where {V,M}
243+
Z = Vector{Vector{Int}}()
244+
_fill_exponents!(Z, n, degs, V, M, filter)
190245
_isless = let M = M
191246
(a, b) -> MP.compare(a, b, M) < 0
192247
end
@@ -202,7 +257,7 @@ function MonomialVector(
202257
vars = unique!(sort(vars, rev = true))
203258
return MonomialVector(
204259
vars,
205-
getZfordegs(
260+
_all_exponents(
206261
length(vars),
207262
degs,
208263
Commutative,
@@ -222,7 +277,7 @@ function MonomialVector(
222277
filter::Function = x -> true,
223278
) where {M}
224279
vars = unique!(sort(vars, rev = true))
225-
Z = getZfordegs(
280+
Z = _all_exponents(
226281
length(vars),
227282
degs,
228283
NonCommutative,
@@ -248,11 +303,11 @@ function MP.monomials(vars::Tuple{Vararg{Variable}}, args...)
248303
end
249304

250305
#function MP.monomials(vars::TupOrVec{Variable{true}}, degs::AbstractVector{Int}, filter::Function = x->true)
251-
# Z = getZfordegs(length(vars), degs, true, z -> filter(Monomial(vars, z)))
306+
# Z = _all_exponents(length(vars), degs, true, z -> filter(Monomial(vars, z)))
252307
# [Monomial{true}(vars, z) for z in Z]
253308
#end
254309
#function MP.monomials(vars::TupOrVec{<:Variable{<:NonCommutative}}, degs::AbstractVector{Int}, filter::Function = x->true)
255-
# Z = getZfordegs(length(vars), degs, false, z -> filter(Monomial(vars, z)))
310+
# Z = _all_exponents(length(vars), degs, false, z -> filter(Monomial(vars, z)))
256311
# v = isempty(Z) ? vars : getvarsforlength(vars, length(first(Z)))
257312
# [Monomial(v, z) for z in Z]
258313
#end

test/comp.jl

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,3 +44,65 @@ end
4444
@test ordering(x[1]) == order
4545
@test issorted(monomials(x[1], 0:2))
4646
end
47+
48+
function _test_less(a, b)
49+
@test a < b
50+
@test b > a
51+
end
52+
53+
function _test_monomials(vars, degs, exp)
54+
# Without `collect`, `exp` is promoted to a `MonomialVector`
55+
# which sorts it so it doesn't test the order
56+
@test collect(monomials(vars, degs)) == exp
57+
end
58+
59+
@testset "LexOrder" begin
60+
@polyvar x y monomial_order = LexOrder
61+
_test_less(y, y^2)
62+
_test_less(x^0, y)
63+
_test_less(y^2, x)
64+
_test_less(x * y^2, x^2)
65+
_test_monomials([x, y], 3, [y^3, y^2 * x, y * x^2, x^3])
66+
_test_monomials([x, y], 1:2, [y, y^2, x, x * y, x^2])
67+
_test_monomials([x, y], [0, 1, 3], [1, y, y^3, x, y^2 * x, y * x^2, x^3])
68+
end
69+
70+
@testset "InverseLexOrder" begin
71+
@polyvar x y monomial_order = InverseLexOrder
72+
_test_less(y, y^2)
73+
_test_less(x^0, y)
74+
_test_less(x, y^2)
75+
_test_less(x^2, x * y^2)
76+
_test_monomials([x, y], 3, [x^3, x^2 * y, x * y^2, y^3])
77+
end
78+
79+
@testset "Reverse{LexOrder}" begin
80+
@polyvar x y monomial_order = Reverse{LexOrder}
81+
_test_less(y^2, y)
82+
_test_less(y, x^0)
83+
_test_less(x, y^2)
84+
_test_less(x^2, x * y^2)
85+
_test_monomials([x, y], 3, [x^3, x^2 * y, x * y^2, y^3])
86+
end
87+
88+
@testset "Reverse{InverseLexOrder}" begin
89+
@polyvar x y monomial_order = Reverse{InverseLexOrder}
90+
_test_less(y^2, y)
91+
_test_less(y, x^0)
92+
_test_less(y^2, x)
93+
_test_less(x * y^2, x^2)
94+
_test_monomials([x, y], 3, [y^3, y^2 * x, y * x^2, x^3])
95+
_test_monomials([x, y], 1:2, [y^2, x * y, y, x^2, x])
96+
_test_monomials([x, y], [0, 1, 3], [y^3, x*y^2, x^2*y, y, x^3, x, 1])
97+
end
98+
99+
@testset "Graded{Reverse{InverseLexOrder}}" begin
100+
@polyvar x y monomial_order = Graded{Reverse{InverseLexOrder}}
101+
_test_less(y, y^2)
102+
_test_less(x^0, y)
103+
_test_less(x, y^2)
104+
_test_less(x^2, x * y^2)
105+
_test_monomials([x, y], 3, [y^3, y^2 * x, y * x^2, x^3])
106+
_test_monomials([x, y], 1:2, [y, x, y^2, x * y, x^2])
107+
_test_monomials([x, y], [0, 1, 3], [1, y, x, y^3, x*y^2, x^2*y, x^3])
108+
end

0 commit comments

Comments
 (0)