|
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