@@ -19,21 +19,81 @@ Base.gcd(m1::AbstractMonomialLike, m2::AbstractMonomialLike) = mapexponents(min,
19
19
Base. lcm (m1:: AbstractMonomialLike , m2:: AbstractMonomialLike ) = mapexponents (max, m1, m2)
20
20
21
21
# _div(a, b) assumes that b divides a
22
+ _div (a:: Union{Rational, AbstractFloat} , b) = a / b
23
+ _div (a, b) = div (a, b)
22
24
_div (m1:: AbstractMonomialLike , m2:: AbstractMonomialLike ) = mapexponents (- , m1, m2)
23
25
function _div (t:: AbstractTerm , m:: AbstractMonomial )
24
- coefficient (t) * _div (monomial (t), m)
26
+ term ( coefficient (t), _div (monomial (t), m) )
25
27
end
26
28
function _div (t1:: AbstractTermLike , t2:: AbstractTermLike )
27
- (coefficient (t1) / coefficient (t2)) * _div (monomial (t1), monomial (t2))
29
+ term (_div (coefficient (t1), coefficient (t2)), _div (monomial (t1), monomial (t2)))
30
+ end
31
+ function _div (f:: APL , g:: APL )
32
+ lt = leadingterm (g)
33
+ rf = MA. copy_if_mutable (f)
34
+ rg = removeleadingterm (g)
35
+ q = zero (rf)
36
+ while ! iszero (rf)
37
+ ltf = leadingterm (rf)
38
+ qt = _div (ltf, lt)
39
+ q = MA. add! (q, qt)
40
+ rf = MA. operate! (removeleadingterm, rf)
41
+ rf = MA. operate! (MA. sub_mul, rf, qt, rg)
42
+ end
43
+ return q
28
44
end
29
45
30
46
Base. div (f:: APL , g:: Union{APL, AbstractVector{<:APL}} ; kwargs... ) = divrem (f, g; kwargs... )[1 ]
31
47
Base. rem (f:: APL , g:: Union{APL, AbstractVector{<:APL}} ; kwargs... ) = divrem (f, g; kwargs... )[2 ]
32
48
33
- proddiff (x, y) = x/ y - x/ y
49
+ # FIXME What should we do for `Rational` ?
50
+ function pseudo_rem (f:: APL , g:: APL{<:Union{Rational, AbstractFloat}} , algo)
51
+ return true , rem (f, g)
52
+ end
53
+
54
+ function pseudo_rem (f:: APL , g:: APL , algo)
55
+ ltg = leadingterm (g)
56
+ rg = removeleadingterm (g)
57
+ ltf = leadingterm (f)
58
+ if ! divides (monomial (ltg), ltf)
59
+ return false , f
60
+ end
61
+ while divides (monomial (ltg), ltf)
62
+ new_f = constantterm (coefficient (ltg), f) * removeleadingterm (f)
63
+ new_g = term (coefficient (ltf), _div (monomial (ltf), monomial (ltg))) * rg
64
+ # Check with `::` that we don't have any type unstability on this variable.
65
+ f = (new_f - new_g):: typeof (f)
66
+ if algo. primitive_rem
67
+ f = primitive_part (f, algo):: typeof (f)
68
+ end
69
+ if algo. skip_last && maxdegree (f) == maxdegree (g)
70
+ break
71
+ end
72
+ ltf = leadingterm (f)
73
+ end
74
+ return true , f
75
+ end
76
+ function MA. promote_operation (
77
+ :: typeof (pseudo_rem),
78
+ :: Type{P} ,
79
+ :: Type{Q} ,
80
+ ) where {T,S<: Union{Rational, AbstractFloat} ,P<: APL{T} ,Q<: APL{S} }
81
+ return MA. promote_operation (rem, P, Q)
82
+ end
83
+ function MA. promote_operation (:: typeof (pseudo_rem), :: Type{P} , :: Type{Q} ) where {T,S,P<: APL{T} ,Q<: APL{S} }
84
+ U1 = MA. promote_operation (* , S, T)
85
+ U2 = MA. promote_operation (* , T, S)
86
+ # `promote_type(P, Q)` is needed for TypedPolynomials in case they use different variables
87
+ return polynomialtype (promote_type (P, Q), MA. promote_operation (- , U1, U2))
88
+ end
89
+
90
+ function MA. promote_operation (:: Union{typeof(div), typeof(rem)} , :: Type{P} , g:: Type{Q} ) where {T,S,P<: APL{T} ,Q<: APL{S} }
91
+ U = MA. promote_operation (/ , T, S)
92
+ # `promote_type(P, Q)` is needed for TypedPolynomials in case they use different variables
93
+ return polynomialtype (promote_type (P, Q), MA. promote_operation (- , U, U))
94
+ end
34
95
function Base. divrem (f:: APL{T} , g:: APL{S} ; kwargs... ) where {T, S}
35
- # `promote_type(typeof(f), typeof(g))` is needed for TypedPolynomials in case they use different variables
36
- rf = convert (polynomialtype (promote_type (typeof (f), typeof (g)), Base. promote_op (proddiff, T, S)), MA. copy_if_mutable (f))
96
+ rf = convert (MA. promote_operation (div, typeof (f), typeof (g)), MA. copy_if_mutable (f))
37
97
q = zero (rf)
38
98
r = zero (rf)
39
99
lt = leadingterm (g)
@@ -61,8 +121,7 @@ function Base.divrem(f::APL{T}, g::APL{S}; kwargs...) where {T, S}
61
121
q, r
62
122
end
63
123
function Base. divrem (f:: APL{T} , g:: AbstractVector{<:APL{S}} ; kwargs... ) where {T, S}
64
- # `promote_type(typeof(f), eltype(g))` is needed for TypedPolynomials in case they use different variables
65
- rf = convert (polynomialtype (promote_type (typeof (f), eltype (g)), Base. promote_op (proddiff, T, S)), MA. copy_if_mutable (f))
124
+ rf = convert (MA. promote_operation (div, typeof (f), eltype (g)), MA. copy_if_mutable (f))
66
125
r = zero (rf)
67
126
q = similar (g, typeof (rf))
68
127
for i in eachindex (q)
@@ -105,12 +164,3 @@ function Base.divrem(f::APL{T}, g::AbstractVector{<:APL{S}}; kwargs...) where {T
105
164
end
106
165
q, r
107
166
end
108
-
109
- function Base. gcd (p:: AbstractPolynomialLike{T} , q:: AbstractPolynomialLike{S} ) where {T, S}
110
- if isapproxzero (q)
111
- convert (polynomialtype (p, Base. promote_op (proddiff, T, S)), p)
112
- else
113
- gcd (q, rem (p, q))
114
- end
115
- end
116
- Base. lcm (p:: AbstractPolynomialLike , q:: AbstractPolynomialLike ) = p * div (q, gcd (p, q))
0 commit comments