Skip to content

Commit a58b33f

Browse files
authored
Zero allocation univariate gcd with Int (#237)
1 parent 3beca78 commit a58b33f

File tree

2 files changed

+51
-33
lines changed

2 files changed

+51
-33
lines changed

src/gcd.jl

Lines changed: 31 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -141,41 +141,42 @@ function Base.gcd(t1::AbstractTermLike{T}, t2::AbstractTermLike{S}, algo::Abstra
141141
return term(_coefficient_gcd(coefficient(t1), coefficient(t2)), gcd(monomial(t1), monomial(t2)))
142142
end
143143

144+
function shift_deflation(p::AbstractPolynomialLike, v::AbstractVariable)
145+
shift = -1
146+
defl = 0
147+
for mono in monomials(p)
148+
exp = degree(mono, v)
149+
if shift == -1
150+
shift = exp
151+
elseif exp < shift
152+
# There are two cases:
153+
# 1) If `defl[i]` is zero then it means all previous monomials
154+
# had degree `shift[i]` so we just set `defl[i]` to
155+
# `shift[i] - exp` or equivalently `gcd(0, shift[i] - exp)`.
156+
# 2) If `defl[i]` is positive then we have some monomials with
157+
# degree `shift[i]` and some with degree
158+
# `shift[i] + k * defl[i]` for some `k > 0`. We have
159+
# `gcd(shift[i] - exp, shift[i] + k1 * defl[i] - exp, shift[i] + k2 * defl[i] - exp, ...) =`
160+
# `gcd(shift[i] - exp, k1 * defl[i], k2 * defl[i], ...)`
161+
# Since `gcd(k1, k2, ...) = 1`, this is equal to
162+
# `gcd(shift[i] - exp, defl[i])`
163+
defl = gcd(defl, shift - exp)
164+
shift = exp
165+
else
166+
defl = gcd(defl, exp - shift)
167+
end
168+
end
169+
return shift, defl
170+
end
171+
144172
# Inspired from to `AbstractAlgebra.deflation`
145173
function deflation(p::AbstractPolynomialLike)
146174
if iszero(p)
147175
return constantmonomial(p), constantmonomial(p)
148176
end
149-
shift = fill(-1, nvariables(p))
150-
defl = zeros(Int, nvariables(p))
151-
for mono in monomials(p)
152-
exps = exponents(mono)
153-
for i in eachindex(exps)
154-
exp = exps[i]
155-
@assert exp >= 0
156-
if shift[i] == -1
157-
shift[i] = exp
158-
elseif exp < shift[i]
159-
# There are two cases:
160-
# 1) If `defl[i]` is zero then it means all previous monomials
161-
# had degree `shift[i]` so we just set `defl[i]` to
162-
# `shift[i] - exp` or equivalently `gcd(0, shift[i] - exp)`.
163-
# 2) If `defl[i]` is positive then we have some monomials with
164-
# degree `shift[i]` and some with degree
165-
# `shift[i] + k * defl[i]` for some `k > 0`. We have
166-
# `gcd(shift[i] - exp, shift[i] + k1 * defl[i] - exp, shift[i] + k2 * defl[i] - exp, ...) =`
167-
# `gcd(shift[i] - exp, k1 * defl[i], k2 * defl[i], ...)`
168-
# Since `gcd(k1, k2, ...) = 1`, this is equal to
169-
# `gcd(shift[i] - exp, defl[i])`
170-
defl[i] = gcd(defl[i], shift[i] - exp)
171-
shift[i] = exp
172-
else
173-
defl[i] = gcd(defl[i], exp - shift[i])
174-
end
175-
end
176-
end
177-
@assert all(d -> d >= 0, shift)
178-
@assert all(d -> d >= 0, defl)
177+
shift_defl = shift_deflation.(p, variables(p))
178+
shift = getindex.(shift_defl, 1)
179+
defl = getindex.(shift_defl, 2)
179180
s = prod(variables(p).^shift; init = constantmonomial(p))::monomialtype(p)
180181
d = prod(variables(p).^defl; init = constantmonomial(p))::monomialtype(p)
181182
return s, d

test/allocations.jl

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,7 @@ function test_isapproxzero()
9393
end
9494
end
9595

96-
function _test_gcd(T)
96+
function _test_term_gcd(T)
9797
o = one(T)
9898
@polyvar x y
9999
t1 = o * x * y
@@ -103,8 +103,8 @@ function _test_gcd(T)
103103
end
104104
end
105105

106-
function test_gcd()
107-
_test_gcd(Int)
106+
function test_term_gcd()
107+
_test_term_gcd(Int)
108108
end
109109

110110
function _pseudo_rem_test(p1, p2, algo)
@@ -146,5 +146,22 @@ function test_div()
146146
end
147147
end
148148

149+
function _test_univ_gcd(T, algo)
150+
o = one(T)
151+
@polyvar x
152+
p1 = o * x^2 + 2o * x + o
153+
p2 = o * x + o
154+
mutable_alloc_test(mutable_copy(p1), 0) do p1
155+
MP.univariate_gcd(p1, p2, algo, IsMutable(), IsMutable())
156+
end
157+
end
158+
159+
function test_univ_gcd()
160+
algo = GeneralizedEuclideanAlgorithm()
161+
_test_univ_gcd(Int, algo)
162+
#_test_univ_gcd(BigInt, algo) # TODO
163+
end
164+
149165
end
166+
150167
TestAllocations.runtests()

0 commit comments

Comments
 (0)