Skip to content

Commit 5c3b572

Browse files
authored
one part of #602 (#603)
* one part of #602 * add deflation to ngcd * move where deflation happens * deflate early * bump compat * bump compat * slight cleanup
1 parent 5c8f244 commit 5c3b572

6 files changed

Lines changed: 49 additions & 19 deletions

File tree

docs/Project.toml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,4 +8,3 @@ SpecialFunctions = "276daf66-3868-5448-9aa4-cd146d93841b"
88

99
[compat]
1010
Documenter = "1"
11-
GR_jll = "< 0.58"

src/polynomials/multroot.jl

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -99,9 +99,15 @@ function multroot(p::StandardBasisPolynomial{T}; verbose=false,
9999
cs = coeffs0(p)
100100
length(cs) <= 1 && return (values=T[], multiplicities=Int[], κ=NaN, ϵ=NaN)
101101

102-
# degenerate case, all zeros
103-
if (nz = findfirst(!iszero, cs)) == length(cs)
102+
# deflate leading zeros?
103+
i = findfirst(!Polynomials.iscoeffzero,cs)
104+
if isnothing(i)
105+
# degenerate case, all zeros
106+
throw(ArgumentError("Zero polynomial has no roots defined"))
107+
elseif i == length(cs)
104108
return (values=zeros(T,1), multiplicities=[nz-1], κ=NaN, ϵ=NaN)
109+
elseif i > 1
110+
p = Polynomial(cs[i:end])
105111
end
106112

107113
# Basic algorithm is two steps
@@ -110,6 +116,11 @@ function multroot(p::StandardBasisPolynomial{T}; verbose=false,
110116
κ, ϵ = stats(p, z̃, l)
111117

112118
verbose && show_stats(κ, ϵ)
119+
if i > 1
120+
push!(z̃, zero(T))
121+
push!(l, i-1)
122+
end
123+
113124

114125
(values = z̃, multiplicities = l, κ = κ, ϵ = ϵ)
115126

src/polynomials/ngcd.jl

Lines changed: 19 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -13,26 +13,18 @@ function ngcd(p::P, q::Q,
1313
kwargs...) where {T,X,P<:StandardBasisPolynomial{T,X},
1414
S,Y,Q<:StandardBasisPolynomial{S,Y}}
1515

16+
1617
# easy cases
1718
degree(p) < 0 && return (u=q, v=p, w=one(q), θ=NaN, κ=NaN)
1819
degree(p) == 0 && return (u=one(q), v=p, w=q, θ=NaN, κ=NaN)
1920
degree(q) < 0 && return (u=one(q), v=p, w=zero(q), θ=NaN, κ=NaN)
2021
degree(q) == 0 && return (u=one(p), v=p, w=q, Θ=NaN, κ=NaN)
2122

23+
2224
if (degree(q) > degree(p))
2325
u,w,v,Θ,κ = ngcd(q,p,args...; kwargs...)
2426
return (u=u,v=v,w=w, Θ=Θ, κ=κ)
2527
end
26-
if degree(p) > 5*(1+degree(q))
27-
a,b = divrem(p,q)
28-
return ngcd(q, b, args...; λ=100, kwargs...)
29-
end
30-
31-
# other easy cases
32-
p q && return (u=p,v=one(p), w=one(p), θ=NaN, κ=NaN)
33-
Polynomials.assert_same_variable(p,q)
34-
35-
3628

3729
R = promote_type(float(T))
3830
𝑷 = Polynomials.constructorof(P){R,X}
@@ -45,14 +37,28 @@ function ngcd(p::P, q::Q,
4537
if nz == length(qs)
4638
x = variable(p)
4739
u = x^(nz-1)
48-
v,w = 𝑷(ps[nz:end]), 𝑷(qs[nz:end])
40+
ps,qs = ps[nz:end], qs[nz:end]
41+
v,w = 𝑷(ps), 𝑷(qs)
4942
return (u=u, v=v, w=w, Θ=NaN, κ=NaN)
43+
elseif 1 <= nz < length(qs)
44+
ps,qs = ps[nz:end], qs[nz:end]
45+
p,q = P(ps), Q(qs)
46+
end
47+
48+
if degree(p) > 5*(1+degree(q))
49+
a,b = divrem(p,q)
50+
return ngcd(q, b, args...; λ=100, kwargs...)
5051
end
5152

53+
# other easy cases
54+
p q && return (u=p,v=one(p), w=one(p), θ=NaN, κ=NaN)
55+
Polynomials.assert_same_variable(p,q)
56+
5257
## call ngcd
5358
P′ = PnPolynomial
54-
p′ = P′{R,X}(ps[nz:end])
55-
q′ = P′{R,X}(qs[nz:end])
59+
p′ = P′{R,X}(ps)
60+
q′ = P′{R,X}(qs)
61+
5662
out = NGCD.ngcd(p′, q′, args...; kwargs...)
5763
## convert to original polynomial type
5864
𝑷 = Polynomials.constructorof(P){R,X}

src/rational-functions/common.jl

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -458,9 +458,10 @@ function roots(pq::AbstractRationalFunction{T};
458458
multroot_method=nothing, # :direct or:iterative
459459
kwargs...) where {T}
460460
pq′ = lowest_terms(pq; method=method, kwargs...)
461-
den = numerator(pq′)
461+
num = numerator(pq′)
462+
(hasnan(num) || any(isinf, num)) && throw(ArgumentError("Reduced expression has numeric issues"))
462463
mmethod = something(multroot_method, default_multroot_method(T))
463-
mr = Multroot.multroot(den; method=mmethod)
464+
mr = Multroot.multroot(num; method=mmethod)
464465
(zs=mr.values, multiplicities = mr.multiplicities)
465466
end
466467
default_multroot_method(::Type{T}) where {T<:Union{BigFloat, Complex{BigFloat}, BigInt, Complex{BigInt}}} = :iterative

test/StandardBasis.jl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1046,6 +1046,7 @@ end
10461046
multroot_method = :direct # fails if direct
10471047
@test_throws ArgumentError poles(r; multroot_method)
10481048
@test_throws ArgumentError roots(r; multroot_method)
1049+
10491050
end
10501051

10511052
@testset "critical points" begin

test/rational-functions.jl

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,19 @@ end
124124
end
125125
@test norm(numerator(lowest_terms(d - pq)), Inf) <= sqrt(eps())
126126

127+
## Issue #602
128+
s = Polynomial([0,1],:s)
129+
r = (15s^14 + 1e-16s^15)//(1s + 14s^14)
130+
out = roots(r)
131+
@test 0 out.zs
132+
@test out.multiplicities == [1,13]
133+
134+
r = (15s^14 + 1e-16s^15)//(s)
135+
out = roots(r)
136+
@test 0 out.zs
137+
@test out.multiplicities == [1,13]
138+
139+
127140
## issue #605
128141
s = x//1
129142
X = 1//(s^4*(s+2))
@@ -145,7 +158,6 @@ end
145158
end
146159
end
147160
@test X Y
148-
149161
end
150162

151163
@testset "As matrix elements" begin

0 commit comments

Comments
 (0)