|
1 |
| -export divides, pseudo_rem, rem_or_pseudo_rem |
| 1 | +export divides, div_multiple, pseudo_rem, rem_or_pseudo_rem |
2 | 2 |
|
3 | 3 | function Base.round(p::APL; args...)
|
4 | 4 | # round(0.1) is zero so we cannot use `mapcoefficientsnz`
|
@@ -44,32 +44,61 @@ _field_absorb(::UFD, ::Field) = Field()
|
44 | 44 | _field_absorb(::Field, ::UFD) = Field()
|
45 | 45 | _field_absorb(::Field, ::Field) = Field()
|
46 | 46 |
|
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) |
54 | 58 | end
|
55 |
| -function _div(t1::AbstractTermLike, t2::AbstractTermLike) |
56 |
| - term(_div(coefficient(t1), coefficient(t2)), _div(monomial(t1), monomial(t2))) |
| 59 | +function div_multiple(m1::AbstractMonomialLike, m2::AbstractMonomialLike, ::MA.MutableTrait=MA.IsNotMutable()) |
| 60 | + return mapexponents(-, m1, m2) |
57 | 61 | end
|
58 |
| -function _div(f::APL, g::APL) |
| 62 | +function div_multiple(t::AbstractTerm, m::AbstractMonomial, mt::MA.MutableTrait=MA.IsNotMutable()) |
| 63 | + term(_copy(coefficient(t), mt), div_multiple(monomial(t), m)) |
| 64 | +end |
| 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))) |
| 67 | +end |
| 68 | +function right_constant_div_multiple(f::APL, g, mf::MA.MutableTrait=MA.IsNotMutable()) |
| 69 | + if isone(g) |
| 70 | + return _copy(f, mf) |
| 71 | + end |
| 72 | + return mapcoefficients(coef -> div_multiple(coef, g, mf), f, mf; nonzero = true) |
| 73 | +end |
| 74 | +function div_multiple(f::APL, g::AbstractMonomialLike, mf::MA.MutableTrait=MA.IsNotMutable()) |
| 75 | + if isconstant(g) |
| 76 | + return _copy(f, mf) |
| 77 | + end |
| 78 | + return mapexponents(-, f, g, mf) |
| 79 | +end |
| 80 | +function div_multiple(f::APL, g::AbstractTermLike, mf::MA.MutableTrait=MA.IsNotMutable()) |
| 81 | + f = right_constant_div_multiple(f, coefficient(g), mf) |
| 82 | + return div_multiple(f, monomial(g), MA.IsMutable()) |
| 83 | +end |
| 84 | +function div_multiple(f::APL, g::APL, mf::MA.MutableTrait=MA.IsNotMutable()) |
59 | 85 | lt = leadingterm(g)
|
60 |
| - rf = MA.copy_if_mutable(f) |
| 86 | + if nterms(g) == 1 |
| 87 | + return div_multiple(f, lt, mf) |
| 88 | + end |
| 89 | + rf = _copy(f, mf) |
61 | 90 | rg = removeleadingterm(g)
|
62 | 91 | q = zero(rf)
|
63 | 92 | while !iszero(rf)
|
64 | 93 | ltf = leadingterm(rf)
|
65 | 94 | if !divides(lt, ltf)
|
66 | 95 | # In floating point arithmetics, it may happen
|
67 | 96 | # that `rf` is not zero even if it cannot be reduced further.
|
68 |
| - # As `_div` assumes that `g` divides `f`, we know that |
| 97 | + # As `div_multiple` assumes that `g` divides `f`, we know that |
69 | 98 | # `rf` is approximately zero anyway.
|
70 | 99 | break
|
71 | 100 | end
|
72 |
| - qt = _div(ltf, lt) |
| 101 | + qt = div_multiple(ltf, lt) |
73 | 102 | q = MA.add!!(q, qt)
|
74 | 103 | rf = MA.operate!!(removeleadingterm, rf)
|
75 | 104 | rf = MA.operate!!(MA.sub_mul, rf, qt, rg)
|
@@ -98,7 +127,7 @@ function _pseudo_divrem(::UFD, f::APL, g::APL, algo)
|
98 | 127 | else
|
99 | 128 | st = constantterm(coefficient(ltg), f)
|
100 | 129 | new_f = st * removeleadingterm(f)
|
101 |
| - qt = term(coefficient(ltf), _div(monomial(ltf), monomial(ltg))) |
| 130 | + qt = term(coefficient(ltf), div_multiple(monomial(ltf), monomial(ltg))) |
102 | 131 | new_g = qt * rg
|
103 | 132 | # Check with `::` that we don't have any type unstability on this variable.
|
104 | 133 | return convert(typeof(f), st), convert(typeof(f), qt), (new_f - new_g)::typeof(f)
|
@@ -136,11 +165,11 @@ end
|
136 | 165 |
|
137 | 166 | function _prepare_s_poly!(::typeof(pseudo_rem), f, ltf, ltg)
|
138 | 167 | MA.operate!(right_constant_mult, f, coefficient(ltg))
|
139 |
| - return term(coefficient(ltf), _div(monomial(ltf), monomial(ltg))) |
| 168 | + return term(coefficient(ltf), div_multiple(monomial(ltf), monomial(ltg))) |
140 | 169 | end
|
141 | 170 |
|
142 | 171 | function _prepare_s_poly!(::typeof(rem), ::APL, ltf, ltg)
|
143 |
| - return _div(ltf, ltg) |
| 172 | + return div_multiple(ltf, ltg) |
144 | 173 | end
|
145 | 174 |
|
146 | 175 | function MA.operate!(op::Union{typeof(rem), typeof(pseudo_rem)}, f::APL, g::APL, algo)
|
@@ -255,7 +284,7 @@ function Base.divrem(f::APL{T}, g::APL{S}; kwargs...) where {T, S}
|
255 | 284 | if isapproxzero(ltf; kwargs...)
|
256 | 285 | rf = MA.operate!!(removeleadingterm, rf)
|
257 | 286 | elseif divides(lm, ltf)
|
258 |
| - qt = _div(ltf, lt) |
| 287 | + qt = div_multiple(ltf, lt) |
259 | 288 | q = MA.add!!(q, qt)
|
260 | 289 | rf = MA.operate!!(removeleadingterm, rf)
|
261 | 290 | rf = MA.operate!!(MA.sub_mul, rf, qt, rg)
|
@@ -291,7 +320,7 @@ function Base.divrem(f::APL{T}, g::AbstractVector{<:APL{S}}; kwargs...) where {T
|
291 | 320 | divisionoccured = false
|
292 | 321 | for i in useful
|
293 | 322 | if divides(lm[i], ltf)
|
294 |
| - qt = _div(ltf, lt[i]) |
| 323 | + qt = div_multiple(ltf, lt[i]) |
295 | 324 | q[i] = MA.add!!(q[i], qt)
|
296 | 325 | rf = MA.operate!!(removeleadingterm, rf)
|
297 | 326 | rf = MA.operate!!(MA.sub_mul, rf, qt, rg[i])
|
|
0 commit comments