Skip to content

Commit cf60052

Browse files
authored
Merge pull request #255 from hurak/master
Modified fromroots() so that it returns real coefficients if complex poles come in conjugate pairs.
2 parents 88ce29d + 4017eb3 commit cf60052

File tree

2 files changed

+30
-21
lines changed

2 files changed

+30
-21
lines changed

src/polynomials/standard-basis.jl

Lines changed: 23 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ abstract type StandardBasisPolynomial{T} <: AbstractPolynomial{T} end
22

33

44

5-
function showterm(io::IO, ::Type{<:StandardBasisPolynomial}, pj::T, var, j, first::Bool, mimetype) where {T}
5+
function showterm(io::IO, ::Type{<:StandardBasisPolynomial}, pj::T, var, j, first::Bool, mimetype) where {T}
66
if iszero(pj) return false end
77
pj = printsign(io, pj, first, mimetype)
88
if !(pj == one(T) && !(showone(T) || j == 0))
@@ -34,6 +34,9 @@ function fromroots(P::Type{<:StandardBasisPolynomial}, r::AbstractVector{T}; var
3434
c[(i + 1)] = c[(i + 1)] - r[j] * c[i]
3535
end
3636
#return P(c, var)
37+
if sort(r[imag(r).>0], lt = (x,y) -> real(x)==real(y) ? imag(x)<imag(y) : real(x)<real(y)) == sort(conj(r[imag(r).<0]), lt = (x,y) -> real(x)==real(y) ? imag(x)<imag(y) : real(x)<real(y))
38+
c = real(c) # if complex poles come in conjugate pairs, the coeffs are real
39+
end
3740
return P(reverse(c), var)
3841
end
3942

@@ -52,7 +55,7 @@ function derivative(p::P, order::Integer = 1) where {T, P <: StandardBasisPolyno
5255
# we avoid usage like Base.promote_op(*, T, Int) here, say, as
5356
# Base.promote_op(*, Rational, Int) is Any, not Rational in analogy to
5457
# Base.promote_op(*, Complex, Int)
55-
R = eltype(one(T)*1)
58+
R = eltype(one(T)*1)
5659
order == 0 && return p
5760
hasnan(p) && return (P){R}(R[NaN], p.var)
5861
order > length(p) && return zero((P){R},p.var)
@@ -87,14 +90,14 @@ function Base.divrem(num::P, den::Q) where {T, P <: StandardBasisPolynomial{T},
8790

8891
check_same_variable(num, den) || error("Polynomials must have same variable")
8992
var = num.var
90-
91-
93+
94+
9295
n = degree(num)
9396
m = degree(den)
9497

9598
m == -1 && throw(DivideError())
9699
if m == 0 && den[0] 0 throw(DivideError()) end
97-
100+
98101
R = eltype(one(T)/one(S))
99102

100103
deg = n - m + 1
@@ -117,7 +120,7 @@ function Base.divrem(num::P, den::Q) where {T, P <: StandardBasisPolynomial{T},
117120
resize!(r_coeff, min(length(r_coeff), m))
118121

119122
return (P)(q_coeff, var), (P)(r_coeff, var)
120-
123+
121124
end
122125

123126
"""
@@ -135,7 +138,7 @@ function Base.gcd(p1::P, p2::Q, args...;
135138
method=:euclidean,
136139
kwargs...
137140
) where {T, P <: StandardBasisPolynomial{T}, Q <: StandardBasisPolynomial{T}}
138-
141+
139142
gcd(Val(method), p1, p2, args...; kwargs...)
140143
end
141144

@@ -144,15 +147,15 @@ function Base.gcd(::Val{:euclidean},
144147
atol=zero(real(T)),
145148
rtol=Base.rtoldefault(real(T)),
146149
kwargs...) where {T}
147-
148-
150+
151+
149152
iter = 1
150153
itermax = length(r₁)
151-
154+
152155
while !iszero(r₁) && iter itermax
153156
_, rtemp = divrem(r₀, r₁)
154157
r₀ = r₁
155-
r₁ = truncate(rtemp; atol=atol, rtol=rtol)
158+
r₁ = truncate(rtemp; atol=atol, rtol=rtol)
156159
iter += 1
157160
end
158161
return r₀
@@ -165,8 +168,8 @@ Base.gcd(::Val{:noda_sasaki}, p, q; kwargs...) = gcd_noda_sasaki(p,q; kwargs...)
165168
gcd_noda_sasaki(p,q; atol, rtol)
166169
167170
Greatest common divisor of two polynomials.
168-
Compute the greatest common divisor `d` of two polynomials `a` and `b` using
169-
the Euclidian Algorithm with scaling as of [1].
171+
Compute the greatest common divisor `d` of two polynomials `a` and `b` using
172+
the Euclidian Algorithm with scaling as of [1].
170173
171174
References:
172175
@@ -196,7 +199,7 @@ function _gcd_noda_sasaki(a::Vector{T}, b::Vector{S};
196199
rtol::Real=Base.rtoldefault(real(promote_type(T,S)))
197200
) where {T,S}
198201

199-
R = eltype(one(T)/one(S))
202+
R = eltype(one(T)/one(S))
200203

201204
na1 = findlast(!iszero,a) # degree(a) + 1
202205
na1 === nothing && return(ones(R, 1))
@@ -205,17 +208,17 @@ function _gcd_noda_sasaki(a::Vector{T}, b::Vector{S};
205208
nb1 === nothing && return(ones(R, 1))
206209

207210
a1 = R[a[i] for i in 1:na1]
208-
b1 = R[b[i] for i in 1:nb1]
211+
b1 = R[b[i] for i in 1:nb1]
209212
a1 ./= norm(a1)
210213
b1 ./= norm(b1)
211214

212215
tol = atol + rtol
213216

214-
# determine the degree of GCD as the nullity of the Sylvester matrix
217+
# determine the degree of GCD as the nullity of the Sylvester matrix
215218
# this computation can be replaced by simply setting nd = 1, in which case the Sylvester matrix is not formed
216219

217220
nd = na1 + nb1 - 2 - rank([NGCD.convmtx(a1,nb1-1) NGCD.convmtx(b1,na1-1)], atol = tol) # julia 1.1
218-
nd == 0 && (return [one(R)])
221+
nd == 0 && (return [one(R)])
219222

220223
sc = one(R)
221224
while na1 > nd
@@ -248,9 +251,9 @@ function companion(p::P) where {T, P <: StandardBasisPolynomial{T}}
248251
d < 1 && error("Series must have degree greater than 1")
249252
d == 1 && return diagm(0 => [-p[0] / p[1]])
250253

251-
254+
252255
R = eltype(one(T)/one(T))
253-
256+
254257
comp = diagm(-1 => ones(R, d - 1))
255258
ani = 1 / p[end]
256259
for j in 0:(degree(p)-1)
@@ -261,7 +264,7 @@ end
261264

262265
function roots(p::P; kwargs...) where {T, P <: StandardBasisPolynomial{T}}
263266

264-
R = eltype(one(T)/one(T))
267+
R = eltype(one(T)/one(T))
265268
d = degree(p)
266269
if d < 1
267270
return []
@@ -294,4 +297,3 @@ function vander(P::Type{<:StandardBasisPolynomial}, x::AbstractVector{T}, n::Int
294297
end
295298
return A
296299
end
297-

test/StandardBasis.jl

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -442,6 +442,13 @@ end
442442
x = variable()
443443
plarge = 8.362779449448982e41 - 2.510840694154672e57x + 4.2817430781178795e44x^2 - 1.6225927682921337e31x^3 + 1.0x^4 # #120
444444
@test length(roots(plarge)) == 4
445+
446+
@test begin
447+
a = P([1,1,1])*P([1,0.5,1])*P([1,1]) # two complex conjugate pole pairs and one real pole
448+
r = roots(a)
449+
b = fromroots(r)
450+
(b a) & isreal(coeffs(b)) # the coeff should be real
451+
end
445452
end
446453
end
447454

0 commit comments

Comments
 (0)