Skip to content

Commit dc6054b

Browse files
authored
use leja order for factored polynomial, follow up on #568 (#587)
* use leja order for factored polynomial, follow up on #568 * doctest with fix * doctest * docfix * allow test with FactoredPolynomial * remove cruft
1 parent d5a472a commit dc6054b

9 files changed

+68
-30
lines changed

Project.toml

+4-3
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,11 @@ name = "Polynomials"
22
uuid = "f27b6e38-b328-58d1-80ce-0feddd5e7a45"
33
license = "MIT"
44
author = "JuliaMath"
5-
version = "4.0.11"
5+
version = "4.0.12"
66

77
[deps]
88
LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e"
9+
OrderedCollections = "bac558e1-5e72-5ebc-8fee-abe8a469f55d"
910
RecipesBase = "3cdcf5f2-1ef4-517c-9805-6587b60abb01"
1011
Requires = "ae029012-a4dd-5104-9daa-d747884805df"
1112
Setfield = "efcf1570-3423-57d1-acb7-fd33fddbac46"
@@ -33,6 +34,7 @@ LinearAlgebra = "<0.0.1, 1"
3334
MakieCore = "0.6,0.7, 0.8"
3435
MutableArithmetics = "1"
3536
OffsetArrays = "1"
37+
OrderedCollections = "1.6.3"
3638
RecipesBase = "0.7, 0.8, 1"
3739
Requires = "1.1"
3840
Setfield = "1"
@@ -56,5 +58,4 @@ SpecialFunctions = "276daf66-3868-5448-9aa4-cd146d93841b"
5658
Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40"
5759

5860
[targets]
59-
test = ["Aqua", "ChainRulesCore", "DualNumbers", "FFTW", "LinearAlgebra",
60-
"MutableArithmetics", "SparseArrays", "OffsetArrays", "SpecialFunctions", "Test"]
61+
test = ["Aqua", "ChainRulesCore", "DualNumbers", "FFTW", "LinearAlgebra", "MutableArithmetics", "SparseArrays", "OffsetArrays", "SpecialFunctions", "Test"]

docs/src/index.md

+4-4
Original file line numberDiff line numberDiff line change
@@ -576,7 +576,7 @@ julia> p = Polynomial([24, -50, 35, -10, 1])
576576
Polynomial(24 - 50*x + 35*x^2 - 10*x^3 + x^4)
577577
578578
julia> q = convert(FactoredPolynomial, p) # noisy form of `factor`:
579-
FactoredPolynomial((x - 4.0000000000000036) * (x - 2.9999999999999942) * (x - 1.0000000000000002) * (x - 2.0000000000000018))
579+
FactoredPolynomial((x - 4.0000000000000036) * (x - 1.0000000000000002) * (x - 2.9999999999999942) * (x - 2.0000000000000018))
580580
581581
julia> map(x -> round(x, digits=10), q)
582582
FactoredPolynomial((x - 4.0) * (x - 2.0) * (x - 3.0) * (x - 1.0))
@@ -792,10 +792,10 @@ julia> P = FactoredPolynomial
792792
FactoredPolynomial
793793
794794
julia> p,q = fromroots(P, [1,2,3,4]), fromroots(P, [2,2,3,5])
795-
(FactoredPolynomial((x - 4) * (x - 2) * (x - 3) * (x - 1)), FactoredPolynomial((x - 5) * (x - 2)² * (x - 3)))
795+
(FactoredPolynomial((x - 4) * (x - 1) * (x - 3) * (x - 2)), FactoredPolynomial((x - 5) * (x - 2)² * (x - 3)))
796796
797797
julia> pq = p // q
798-
((x - 4) * (x - 2) * (x - 3) * (x - 1)) // ((x - 5) * (x - 2)² * (x - 3))
798+
((x - 4) * (x - 1) * (x - 3) * (x - 2)) // ((x - 5) * (x - 2)² * (x - 3))
799799
800800
julia> lowest_terms(pq)
801801
((x - 4.0) * (x - 1.0)) // ((x - 5.0) * (x - 2.0))
@@ -814,7 +814,7 @@ julia> for (λ, rs) ∈ r # reconstruct p/q from output of `residues`
814814
end
815815
816816
julia> d
817-
((x - 4.0) * (x - 1.0000000000000002)) // ((x - 5.0) * (x - 2.0))
817+
((x - 1.0000000000000002) * (x - 4.0)) // ((x - 5.0) * (x - 2.0))
818818
```
819819

820820
A basic plot recipe is provided.

src/Polynomials.jl

+1
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ using LinearAlgebra
1010
import Base: evalpoly
1111
using Setfield
1212
using SparseArrays
13+
using OrderedCollections
1314

1415
include("abstract.jl")
1516
include("show.jl")

src/common.jl

+11-1
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,8 @@ Construct a polynomial of the given type given the roots. If no type is given, d
6060
6161
# Examples
6262
```jldoctest
63+
julia> using Polynomials
64+
6365
julia> r = [3, 2]; # (x - 3)(x - 2)
6466
6567
julia> fromroots(r)
@@ -83,6 +85,8 @@ Construct a polynomial of the given type using the eigenvalues of the given matr
8385
8486
# Examples
8587
```jldoctest
88+
julia> using Polynomials
89+
8690
julia> A = [1 2; 3 4]; # (x - 5.37228)(x + 0.37228)
8791
8892
julia> fromroots(A)
@@ -754,6 +758,8 @@ Given values of x that are assumed to be unbounded (-∞, ∞), return values re
754758
755759
# Examples
756760
```jldoctest
761+
julia> using Polynomials
762+
757763
julia> x = -10:10
758764
-10:10
759765
@@ -976,6 +982,8 @@ Return the monomial `x` in the indicated polynomial basis. If no type is give,
976982
977983
# Examples
978984
```jldoctest
985+
julia> using Polynomials
986+
979987
julia> x = variable()
980988
Polynomial(x)
981989
@@ -1237,6 +1245,8 @@ Find the greatest common denominator of two polynomials recursively using
12371245
# Examples
12381246
12391247
```jldoctest
1248+
julia> using Polynomials
1249+
12401250
julia> gcd(fromroots([1, 1, 2]), fromroots([1, 2, 3]))
12411251
Polynomial(4.0 - 6.0*x + 2.0*x^2)
12421252
```
@@ -1326,7 +1336,7 @@ function Base.isapprox(p1::AbstractPolynomial{T,X},
13261336
atol::Real = 0,) where {T,S,X}
13271337
(hasnan(p1) || hasnan(p2)) && return false # NaN poisons comparisons
13281338
# copy over from abstractarray.jl
1329-
Δ = norm(p1-p2)
1339+
Δ = norm(p1-p2) # p1 - p2 does conversion to common type
13301340
if isfinite(Δ)
13311341
return Δ <= max(atol, rtol*max(norm(p1), norm(p2)))
13321342
else

src/polynomials/factored_polynomial.jl

+36-19
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,10 @@ julia> p = FactoredPolynomial(Dict([0=>1, 1=>2, 3=>4]))
1616
FactoredPolynomial(x * (x - 3)⁴ * (x - 1)²)
1717
1818
julia> q = fromroots(FactoredPolynomial, [0,1,2,3])
19-
FactoredPolynomial(x * (x - 2) * (x - 3) * (x - 1))
19+
FactoredPolynomial((x - 3) * x * (x - 2) * (x - 1))
2020
2121
julia> p*q
22-
FactoredPolynomial(x² * (x - 2) * (x - 3)⁵ * (x - 1)³)
22+
FactoredPolynomial(x² * (x - 3)⁵ * (x - 1)³ * (x - 2))
2323
2424
julia> p^1000
2525
FactoredPolynomial(x¹⁰⁰⁰ * (x - 3)⁴⁰⁰⁰ * (x - 1)²⁰⁰⁰)
@@ -31,29 +31,29 @@ julia> p = Polynomial([24, -50, 35, -10, 1])
3131
Polynomial(24 - 50*x + 35*x^2 - 10*x^3 + x^4)
3232
3333
julia> q = convert(FactoredPolynomial, p) # noisy form of `factor`:
34-
FactoredPolynomial((x - 4.0000000000000036) * (x - 2.9999999999999942) * (x - 1.0000000000000002) * (x - 2.0000000000000018))
34+
FactoredPolynomial((x - 4.0000000000000036) * (x - 1.0000000000000002) * (x - 2.9999999999999942) * (x - 2.0000000000000018))
3535
3636
julia> map(x->round(x, digits=12), q) # map works over factors and leading coefficient -- not coefficients in the standard basis
3737
FactoredPolynomial((x - 4.0) * (x - 2.0) * (x - 3.0) * (x - 1.0))
3838
```
3939
"""
4040
struct FactoredPolynomial{T <: Number, X} <: AbstractPolynomial{T, X}
41-
coeffs::Dict{T,Int}
41+
coeffs::OrderedDict{T,Int}
4242
c::T
43-
function FactoredPolynomial{T, X}(checked::Val{false}, cs::Dict{T,Int}, c::T) where {T, X}
44-
new{T,X}(cs,T(c))
43+
function FactoredPolynomial{T, X}(checked::Val{false}, cs::AbstractDict{T,Int}, c::T) where {T, X}
44+
new{T,X}(convert(OrderedDict,cs),T(c))
4545
end
46-
function FactoredPolynomial{T, X}(cs::Dict{T,Int}, c=one(T)) where {T, X}
47-
D = Dict{T,Int}()
46+
function FactoredPolynomial{T, X}(cs::AbstractDict{T,Int}, c=one(T)) where {T, X}
47+
D = OrderedDict{T,Int}()
4848
for (k,v) cs
4949
v > 0 && (D[k] = v)
5050
end
5151
FactoredPolynomial{T,X}(Val(false), D,T(c))
5252
end
53-
function FactoredPolynomial(cs::Dict{T,Int}, c::S=1, var::SymbolLike=:x) where {T,S}
53+
function FactoredPolynomial(cs::AbstractDict{T,Int}, c::S=1, var::SymbolLike=:x) where {T,S}
5454
X = Symbol(var)
5555
R = promote_type(T,S)
56-
D = convert(Dict{R,Int}, cs)
56+
D = convert(OrderedDict{R,Int}, cs)
5757
FactoredPolynomial{R,X}(D, R(c))
5858
end
5959
end
@@ -72,8 +72,14 @@ function FactoredPolynomial{T,X}(coeffs::AbstractVector{S}) where {T,S,X}
7272

7373
zs = Multroot.multroot(p)
7474
c = p[end]
75-
D = Dict(zip(zs.values, zs.multiplicities))
76-
FactoredPolynomial(D, c, X)
75+
76+
D = LittleDict(k=>v for (k,v) zip(zs.values, zs.multiplicities))
77+
D′ = OrderedDict{eltype(zs.values), Int}()
78+
for z lejaorder(zs.values)
79+
D′[z] = D[z]
80+
end
81+
82+
FactoredPolynomial(D′, c, X)
7783
end
7884

7985
function FactoredPolynomial{T}(coeffs::AbstractVector{S}, var::SymbolLike=:x) where {T,S}
@@ -100,22 +106,31 @@ function Base.convert(P::Type{<:FactoredPolynomial}, p::FactoredPolynomial{T,X})
100106
copy!(d, p.coeffs)
101107
FactoredPolynomial{𝑻,𝑿}(d, p.c)
102108
end
109+
103110
Base.promote(p::P,q::Q) where {X,T,P<:FactoredPolynomial{T,X},Q<:FactoredPolynomial{T,X}} = p,q
111+
104112
Base.promote_rule(::Type{<:FactoredPolynomial{T,X}}, ::Type{<:FactoredPolynomial{S,X}}) where {T,S,X} =
105113
FactoredPolynomial{promote_type(T,S), X}
114+
106115
Base.promote_rule(::Type{<:FactoredPolynomial{T,X}}, ::Type{S}) where {T,S<:Number,X} =
107116
FactoredPolynomial{promote_type(T,S), X}
117+
108118
FactoredPolynomial{T,X}(n::S) where {T,X,S<:Number} = T(n) * one(FactoredPolynomial{T,X})
119+
109120
FactoredPolynomial{T}(n::S, var::SymbolLike=:x) where {T,S<:Number} = T(n) * one(FactoredPolynomial{T,Symbol(var)})
121+
110122
FactoredPolynomial(n::S, var::SymbolLike=:x) where {S<:Number} = n * one(FactoredPolynomial{S,Symbol(var)})
123+
111124
FactoredPolynomial(var::SymbolLike=:x) = variable(FactoredPolynomial, Symbol(var))
125+
112126
(p::FactoredPolynomial)(x) = evalpoly(x, p)
113127

114128
function Base.convert(::Type{<:Polynomial}, p::FactoredPolynomial{T,X}) where {T,X}
115129
x = variable(Polynomial{T,X})
116130
isconstant(p) && return Polynomial{T,X}(p.c)
117131
p(x)
118132
end
133+
119134
function Base.convert(P::Type{<:FactoredPolynomial}, p::Polynomial{T,X}) where {T,X}
120135
isconstant(p) && return (P)(constantterm(p), X)
121136
(P)(coeffs(p), X)
@@ -239,8 +254,8 @@ end
239254

240255
function fromroots(::Type{P}, r::AbstractVector{T}; var::SymbolLike=:x) where {T <: Number, P<:FactoredPolynomial}
241256
X = Symbol(var)
242-
d = Dict{T,Int}()
243-
for rᵢ r
257+
d = OrderedDict{T,Int}()
258+
for rᵢ lejaorder(r)
244259
d[rᵢ] = get(d, rᵢ, 0) + 1
245260
end
246261
FactoredPolynomial{T, X}(d)
@@ -291,8 +306,10 @@ end
291306
# scalar mult
292307
function scalar_mult(p::P, c::S) where {S<:Number, T, X, P <: FactoredPolynomial{T, X}}
293308
R = promote_type(T,S)
294-
d = Dict{R, Int}() # wident
295-
copy!(d, p.coeffs)
309+
d = OrderedDict{R, Int}() # wident
310+
for (k,v) p.coeffs
311+
d[k] = v
312+
end
296313
FactoredPolynomial{R,X}(d, c * p.c)
297314
end
298315
scalar_mult(c::S, p::P) where {S<:Number, T, X, P <: FactoredPolynomial{T, X}} = scalar_mult(p, c) # assume commutative, as we have S <: Number
@@ -304,7 +321,7 @@ end
304321

305322
function Base.:^(p::P, n::Integer) where {T,X, P<:FactoredPolynomial{T,X}}
306323
n >= 0 || throw(ArgumentError("n must be non-negative"))
307-
d = Dict{T,Int}()
324+
d = OrderedDict{T,Int}()
308325
for (k,v) p.coeffs
309326
d[k] = v*n
310327
end
@@ -316,7 +333,7 @@ end
316333
function Base.gcd(p::P, q::P) where {T, X, P<:FactoredPolynomial{T,X}}
317334
iszero(p) && return q
318335
iszero(q) && return p
319-
d = Dict{T,Int}()
336+
d = OrderedDict{T,Int}()
320337

321338
for k intersect(keys(p.coeffs), keys(q.coeffs))
322339
d[k] = min(p.coeffs[k], q.coeffs[k])
@@ -327,7 +344,7 @@ end
327344

328345
# return u,v,w with p = u*v , q = u*w
329346
function uvw(p::P, q::P; kwargs...) where {T, X, P<:FactoredPolynomial{T,X}}
330-
du, dv, dw = Dict{T,Int}(), Dict{T,Int}(), Dict{T,Int}()
347+
du, dv, dw = OrderedDict{T,Int}(), OrderedDict{T,Int}(), OrderedDict{T,Int}()
331348
dp,dq = p.coeffs, q.coeffs
332349
kp,kq = keys(dp), keys(dq)
333350

src/polynomials/standard-basis/immutable-polynomial.jl

+2
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,8 @@ are precluded from use in rational functions.
3535
# Examples
3636
3737
```jldoctest
38+
julia> using Polynomials
39+
3840
julia> ImmutablePolynomial((1, 0, 3, 4))
3941
ImmutablePolynomial(1 + 3*x^2 + 4*x^3)
4042

src/polynomials/standard-basis/laurent-polynomial.jl

+7
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@ Integration will fail if there is a `x⁻¹` term in the polynomial.
1717
1818
# Examples:
1919
```jldoctest
20+
julia> using Polynomials
21+
2022
julia> P = LaurentPolynomial;
2123
2224
julia> p = P([1,1,1], -1)
@@ -48,6 +50,7 @@ LaurentPolynomial(1.0*x + 0.5*x² + 0.3333333333333333*x³)
4850
4951
julia> integrate(p) # x⁻¹ term is an issue
5052
ERROR: ArgumentError: Can't integrate Laurent polynomial with `x⁻¹` term
53+
[...]
5154
5255
julia> integrate(P([1,1,1], -5))
5356
LaurentPolynomial(-0.25*x⁻⁴ - 0.3333333333333333*x⁻³ - 0.5*x⁻²)
@@ -184,6 +187,8 @@ Call `p̂ = paraconj(p)` and `p̄` = conj(p)`, then this satisfies
184187
Examples:
185188
186189
```jldoctest
190+
julia> using Polynomials
191+
187192
julia> z = variable(LaurentPolynomial, :z)
188193
LaurentPolynomial(z)
189194
@@ -223,6 +228,8 @@ This satisfies for *imaginary* `s`: `conj(p(s)) = p̃(s) = (conj ∘ p)(s) = cco
223228
224229
Examples:
225230
```jldoctest
231+
julia> using Polynomials
232+
226233
julia> s = 2im
227234
0 + 2im
228235

src/polynomials/standard-basis/sparse-polynomial.jl

+2
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ advantageous.
1010
# Examples:
1111
1212
```jldoctest
13+
julia> using Polynomials
14+
1315
julia> P = SparsePolynomial;
1416
1517
julia> p, q = P([1,2,3]), P([4,3,2,1])

test/StandardBasis.jl

+1-3
Original file line numberDiff line numberDiff line change
@@ -985,9 +985,7 @@ end
985985
(b a) & isreal(coeffs(b)) # the coeff should be real
986986
end
987987
p = Polynomial([1; zeros(99); -1])
988-
if P !== FactoredPolynomial
989-
@test fromroots(P, roots(p)) * p[end] p
990-
end
988+
@test fromroots(P, roots(p)) * p[end] p
991989
end
992990
end
993991

0 commit comments

Comments
 (0)