Skip to content

Commit 139fb76

Browse files
committed
Rename _div into div_multiple
1 parent d222395 commit 139fb76

File tree

6 files changed

+79
-37
lines changed

6 files changed

+79
-37
lines changed

src/division.jl

+30-18
Original file line numberDiff line numberDiff line change
@@ -44,38 +44,50 @@ _field_absorb(::UFD, ::Field) = Field()
4444
_field_absorb(::Field, ::UFD) = Field()
4545
_field_absorb(::Field, ::Field) = Field()
4646

47-
# _div(a, b) assumes that b divides a
48-
_div(::Field, a, b) = a / b
49-
_div(::UFD, a, b) = div(a, b)
50-
_div(a, b) = _div(algebraic_structure(promote_type(typeof(a), typeof(b))), a, b)
51-
_div(m1::AbstractMonomialLike, m2::AbstractMonomialLike) = mapexponents(-, m1, m2)
52-
function _div(t::AbstractTerm, m::AbstractMonomial)
53-
term(coefficient(t), _div(monomial(t), m))
47+
"""
48+
div_multiple(a, b, ma::MA.MutableTrait)
49+
50+
Return the division of `a` by `b` assuming that `a` is a multiple of `b`.
51+
If `a` is not a multiple of `b` then this function may return anything.
52+
"""
53+
div_multiple(::Field, a, b, ma::MA.MutableTrait) = a / b
54+
div_multiple(::UFD, a, b, ma::MA.IsMutable) = MA.operate!!(div, a, b)
55+
div_multiple(::UFD, a, b, ma::MA.IsNotMutable) = div(a, b)
56+
function div_multiple(a, b, ma::MA.MutableTrait=MA.IsNotMutable())
57+
return div_multiple(algebraic_structure(promote_type(typeof(a), typeof(b))), a, b, ma)
58+
end
59+
function div_multiple(m1::AbstractMonomialLike, m2::AbstractMonomialLike, ::MA.MutableTrait)
60+
return mapexponents(-, m1, m2)
61+
end
62+
function div_multiple(t::AbstractTerm, m::AbstractMonomial, mt::MA.MutableTrait=MA.IsNotMutable())
63+
term(_copy(coefficient(t), mt), div_multiple(monomial(t), m))
5464
end
55-
function _div(t1::AbstractTermLike, t2::AbstractTermLike)
56-
term(_div(coefficient(t1), coefficient(t2)), _div(monomial(t1), monomial(t2)))
65+
function div_multiple(t1::AbstractTermLike, t2::AbstractTermLike, m1::MA.MutableTrait=MA.IsNotMutable())
66+
term(div_multiple(coefficient(t1), coefficient(t2), m1), div_multiple(monomial(t1), monomial(t2)))
5767
end
58-
function _div(f::APL, g::APL)
68+
function div_multiple(f::APL, g::APL, mf=MA.IsNotMutable())
5969
lt = leadingterm(g)
60-
rf = MA.copy_if_mutable(f)
70+
rf = _copy(f, mf)
6171
rg = removeleadingterm(g)
6272
q = zero(rf)
6373
while !iszero(rf)
6474
ltf = leadingterm(rf)
6575
if !divides(lt, ltf)
6676
# In floating point arithmetics, it may happen
6777
# that `rf` is not zero even if it cannot be reduced further.
68-
# As `_div` assumes that `g` divides `f`, we know that
78+
# As `div_multiple` assumes that `g` divides `f`, we know that
6979
# `rf` is approximately zero anyway.
7080
break
7181
end
72-
qt = _div(ltf, lt)
82+
qt = div_multiple(ltf, lt)
7383
q = MA.add!!(q, qt)
7484
rf = MA.operate!!(removeleadingterm, rf)
7585
rf = MA.operate!!(MA.sub_mul, rf, qt, rg)
7686
end
7787
return q
7888
end
89+
# 2-arguments useful to be used with `Base.Fix2`
90+
_div_multiple!(a, b) = div_multiple(a, b, MA.IsMutable())
7991

8092
Base.div(f::APL, g::Union{APL, AbstractVector{<:APL}}; kwargs...) = divrem(f, g; kwargs...)[1]
8193
Base.rem(f::APL, g::Union{APL, AbstractVector{<:APL}}; kwargs...) = divrem(f, g; kwargs...)[2]
@@ -98,7 +110,7 @@ function _pseudo_divrem(::UFD, f::APL, g::APL, algo)
98110
else
99111
st = constantterm(coefficient(ltg), f)
100112
new_f = st * removeleadingterm(f)
101-
qt = term(coefficient(ltf), _div(monomial(ltf), monomial(ltg)))
113+
qt = term(coefficient(ltf), div_multiple(monomial(ltf), monomial(ltg)))
102114
new_g = qt * rg
103115
# Check with `::` that we don't have any type unstability on this variable.
104116
return convert(typeof(f), st), convert(typeof(f), qt), (new_f - new_g)::typeof(f)
@@ -136,11 +148,11 @@ end
136148

137149
function _prepare_s_poly!(::typeof(pseudo_rem), f, ltf, ltg)
138150
MA.operate!(right_constant_mult, f, coefficient(ltg))
139-
return term(coefficient(ltf), _div(monomial(ltf), monomial(ltg)))
151+
return term(coefficient(ltf), div_multiple(monomial(ltf), monomial(ltg)))
140152
end
141153

142154
function _prepare_s_poly!(::typeof(rem), ::APL, ltf, ltg)
143-
return _div(ltf, ltg)
155+
return div_multiple(ltf, ltg)
144156
end
145157

146158
function MA.operate!(op::Union{typeof(rem), typeof(pseudo_rem)}, f::APL, g::APL, algo)
@@ -255,7 +267,7 @@ function Base.divrem(f::APL{T}, g::APL{S}; kwargs...) where {T, S}
255267
if isapproxzero(ltf; kwargs...)
256268
rf = MA.operate!!(removeleadingterm, rf)
257269
elseif divides(lm, ltf)
258-
qt = _div(ltf, lt)
270+
qt = div_multiple(ltf, lt)
259271
q = MA.add!!(q, qt)
260272
rf = MA.operate!!(removeleadingterm, rf)
261273
rf = MA.operate!!(MA.sub_mul, rf, qt, rg)
@@ -291,7 +303,7 @@ function Base.divrem(f::APL{T}, g::AbstractVector{<:APL{S}}; kwargs...) where {T
291303
divisionoccured = false
292304
for i in useful
293305
if divides(lm[i], ltf)
294-
qt = _div(ltf, lt[i])
306+
qt = div_multiple(ltf, lt[i])
295307
q[i] = MA.add!!(q[i], qt)
296308
rf = MA.operate!!(removeleadingterm, rf)
297309
rf = MA.operate!!(MA.sub_mul, rf, qt, rg[i])

src/gcd.jl

+36-13
Original file line numberDiff line numberDiff line change
@@ -397,7 +397,7 @@ _polynomial(ts, state, ::MA.IsNotMutable) = polynomial(ts, state)
397397
_polynomial(ts, state, ::MA.IsMutable) = polynomial!(ts, state)
398398

399399
"""
400-
primitive_univariate_gcd!(p::APL, q::APL, algo::AbstractUnivariateGCDAlgorithm)
400+
primitive_univariate_gcd!(p::APL, q::APL, algo::AbstractUnivariateGCDAlgorithm, buffer=nothing)
401401
402402
Returns the `gcd` of primitive polynomials `p` and `q` using algorithm `algo`
403403
which is a subtype of [`AbstractUnivariateGCDAlgorithm`](@ref).
@@ -419,11 +419,19 @@ end
419419

420420
# If `p` and `q` do not have the same type then the local variables `p` and `q`
421421
# won't be type stable so we create `u` and `v`.
422-
function primitive_univariate_gcd!(p::APL, q::APL, algo::GeneralizedEuclideanAlgorithm)
422+
function primitive_univariate_gcd!(
423+
p::APL,
424+
q::APL,
425+
algo::GeneralizedEuclideanAlgorithm,
426+
buffer=nothing,
427+
)
423428
if maxdegree(p) < maxdegree(q)
424-
return primitive_univariate_gcd!(q, p, algo)
429+
return primitive_univariate_gcd!(q, p, algo, buffer)
425430
end
426431
R = MA.promote_operation(gcd, typeof(p), typeof(q))
432+
if isnothing(buffer)
433+
buffer = MA.buffer_for(rem_or_pseudo_rem, R, R, typeof(algo))
434+
end
427435
u = convert(R, p)
428436
v = convert(R, q)
429437
while true
@@ -436,7 +444,7 @@ function primitive_univariate_gcd!(p::APL, q::APL, algo::GeneralizedEuclideanAlg
436444
end
437445

438446
d_before = degree(leadingmonomial(u))
439-
r = MA.operate!!(rem_or_pseudo_rem, u, v, algo)
447+
r = MA.buffered_operate!!(buffer, rem_or_pseudo_rem, u, v, algo)
440448
d_after = degree(leadingmonomial(r))
441449
if d_after == d_before
442450
not_divided_error(u, v)
@@ -485,7 +493,7 @@ function primitive_univariate_gcdx(u0::APL, v0::APL, algo::GeneralizedEuclideanA
485493
end
486494

487495

488-
function primitive_univariate_gcd!(p::APL, q::APL, ::SubresultantAlgorithm)
496+
function primitive_univariate_gcd!(p::APL, q::APL, ::SubresultantAlgorithm, buffer=nothing)
489497
error("Not implemented yet")
490498
end
491499

@@ -512,20 +520,35 @@ If the coefficients are not `AbstractFloat`, this
512520
*Art of computer programming, volume 2: Seminumerical algorithms.*
513521
Addison-Wesley Professional. Third edition.
514522
"""
515-
function univariate_gcd(p1::APL{S}, p2::APL{T}, algo::AbstractUnivariateGCDAlgorithm, m1::MA.MutableTrait, m2::MA.MutableTrait) where {S,T}
516-
return univariate_gcd(_field_absorb(algebraic_structure(S), algebraic_structure(T)), p1, p2, algo, m1, m2)
517-
end
518-
function univariate_gcd(::UFD, p1::APL, p2::APL, algo::AbstractUnivariateGCDAlgorithm, m1::MA.MutableTrait, m2::MA.MutableTrait)
523+
function univariate_gcd(
524+
p1::APL{S},
525+
p2::APL{T},
526+
algo::AbstractUnivariateGCDAlgorithm,
527+
m1::MA.MutableTrait,
528+
m2::MA.MutableTrait,
529+
buffer=nothing
530+
) where {S,T}
531+
return univariate_gcd(_field_absorb(algebraic_structure(S), algebraic_structure(T)), p1, p2, algo, m1, m2, buffer)
532+
end
533+
function univariate_gcd(
534+
::UFD,
535+
p1::APL,
536+
p2::APL,
537+
algo::AbstractUnivariateGCDAlgorithm,
538+
m1::MA.MutableTrait,
539+
m2::MA.MutableTrait,
540+
buffer=nothing,
541+
)
519542
f1, g1 = primitive_part_content(p1, algo, m1)
520543
f2, g2 = primitive_part_content(p2, algo, m2)
521-
pp = primitive_univariate_gcd!(f1, f2, algo)
544+
pp = primitive_univariate_gcd!(f1, f2, algo, buffer)
522545
gg = _gcd(g1, g2, algo, MA.IsMutable(), MA.IsMutable())#::MA.promote_operation(gcd, typeof(g1), typeof(g2))
523546
# Multiply each coefficient by the gcd of the contents.
524-
return mapcoefficients!(Base.Fix1(*, gg), pp, nonzero = true)
547+
return mapcoefficients!(Base.Fix2(MA.mul!!, gg), pp, nonzero = true)
525548
end
526549

527550
function univariate_gcd(::Field, p1::APL, p2::APL, algo::AbstractUnivariateGCDAlgorithm, m1::MA.MutableTrait, m2::MA.MutableTrait)
528-
return primitive_univariate_gcd!(_copy(p1, m1), _copy(p2, m2), algo)
551+
return primitive_univariate_gcd!(_copy(p1, m1), _copy(p2, m2), algo, buffer)
529552
end
530553

531554
function univariate_gcdx(p1::APL{S}, p2::APL{T}, algo::AbstractUnivariateGCDAlgorithm) where {S,T}
@@ -652,5 +675,5 @@ Addison-Wesley Professional. Third edition.
652675
"""
653676
function primitive_part_content(p, algo::AbstractUnivariateGCDAlgorithm, mutability::MA.MutableTrait)
654677
g = content(p, algo, MA.IsNotMutable())
655-
return mapcoefficients(Base.Fix2(_div, g), p, mutability; nonzero = true), g
678+
return mapcoefficients(Base.Fix2(_div_multiple!, g), p, mutability; nonzero = true), g
656679
end

src/monomial.jl

+1-1
Original file line numberDiff line numberDiff line change
@@ -130,7 +130,7 @@ If ``m_1 = \\prod x^{\\alpha_i}`` and ``m_2 = \\prod x^{\\beta_i}`` then it retu
130130
131131
### Examples
132132
133-
The multiplication `m1 * m2` is equivalent to `mapexponents(+, m1, m2)`, the unsafe division `_div(m1, m2)` is equivalent to `mapexponents(-, m1, m2)`, `gcd(m1, m2)` is equivalent to `mapexponents(min, m1, m2)`, `lcm(m1, m2)` is equivalent to `mapexponents(max, m1, m2)`.
133+
The multiplication `m1 * m2` is equivalent to `mapexponents(+, m1, m2)`, the unsafe division `div_multiple(m1, m2)` is equivalent to `mapexponents(-, m1, m2)`, `gcd(m1, m2)` is equivalent to `mapexponents(min, m1, m2)`, `lcm(m1, m2)` is equivalent to `mapexponents(max, m1, m2)`.
134134
"""
135135
mapexponents(f, m1::AbstractMonomialLike, m2::AbstractMonomialLike) = mapexponents(f, monomial(m1), monomial(m2))
136136

src/term.jl

+1-1
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,7 @@ function coefficient(f::APL, m::AbstractMonomialLike, vars)
102102
end
103103
match || continue
104104

105-
coeff += term(coefficient(t), _div(monomial(t), m))
105+
coeff += term(coefficient(t), div_multiple(monomial(t), m))
106106
end
107107
coeff
108108
end

test/allocations.jl

+10-3
Original file line numberDiff line numberDiff line change
@@ -151,15 +151,22 @@ function _test_univ_gcd(T, algo)
151151
@polyvar x
152152
p1 = o * x^2 + 2o * x + o
153153
p2 = o * x + o
154+
buffer = buffer_for(MP.rem_or_pseudo_rem, typeof(p1), typeof(p2), typeof(algo))
154155
mutable_alloc_test(mutable_copy(p1), 0) do p1
155-
MP.univariate_gcd(p1, p2, algo, IsMutable(), IsMutable())
156+
MP.primitive_univariate_gcd!(p1, p2, algo, buffer)
157+
end
158+
if T === Int
159+
mutable_alloc_test(mutable_copy(p1), 0) do p1
160+
MP.gcd(p1, p2, algo, IsMutable(), IsMutable())
161+
end
156162
end
157163
end
158164

159165
function test_univ_gcd()
160166
algo = GeneralizedEuclideanAlgorithm()
161-
_test_univ_gcd(Int, algo)
162-
#_test_univ_gcd(BigInt, algo) # TODO
167+
@testset "$T" for T in [Int, BigInt]
168+
_test_univ_gcd(T, algo)
169+
end
163170
end
164171

165172
end

test/monomial.jl

+1-1
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,7 @@ end
8181

8282
@test monic(x^2) == x^2
8383

84-
@test MP._div(2x^2*y[1]^3, x*y[1]^2) == 2x*y[1]
84+
@test MP.div_multiple(2x^2*y[1]^3, x*y[1]^2) == 2x*y[1]
8585

8686
@test transpose(x) == x
8787
@test adjoint(x) == x

0 commit comments

Comments
 (0)