Polynomial Roots as List
roots_as_list.Rd
This helper function coerces a vector of (complex or real) roots into a list. For a complex conjugate pair of roots, only the one with a positive imaginary part is retained.
Usage
roots_as_list(roots, tol = sqrt(.Machine$double.eps))
Arguments
- roots
Vector of cplx or doubles. Obtained e.g. from a call to
zeroes
.- tol
Double. Tolerance parameter used to decide whether roots and conjugate roots "match".
Value
List of roots. For complex conjugated pairs of roots, only the ones with positive part are returned. The procedure orders the roots according to their imaginary part, and thus real roots come first.
Details
The routine assumes that complex roots appear, up to some small numerical errors, in complex conjugate pairs. Therefore the procedure tries to match the roots with their complex conjugates. If this is not possible, then an error is thrown.
Roots, which are classified as real, are replaced by their real part. Roots, which are classified as complex, are replaced by the mean of the root and the best matching conjugate root.
See also
The matching of conjugate roots is done by the internal
helper function match_vectors
.
Examples
set.seed(12345)
p = 5
a = rnorm(p+1) # coefficients of a random polynomial a(z) of degree p = 5
z = polyroot(a) # compute the roots of a(z)
z
#> [1] 0.2353419+0.9290992i -0.5313699+0.3107316i -0.5313699-0.3107316i
#> [4] 0.9253355-0.0000000i 0.2353419-0.9290992i
# try to match roots and conjugate roots
j = match_vectors(z, Conj(z))
# z is approximately equal to Conj( z[j] )
print(data.frame(z = z, j = j, `Conj(z[j])` = Conj(z[j]), d = z-Conj(z[j])))
#> z j Conj.z.j.. d
#> 1 0.2353419+0.9290992i 5 0.2353419+0.9290992i 1.221245e-15-9.992007e-16i
#> 2 -0.5313699+0.3107316i 3 -0.5313699+0.3107316i 3.108624e-15+1.887379e-15i
#> 3 -0.5313699-0.3107316i 2 -0.5313699-0.3107316i -3.108624e-15+1.887379e-15i
#> 4 0.9253355-0.0000000i 4 0.9253355+0.0000000i 0.000000e+00-1.750357e-15i
#> 5 0.2353419-0.9290992i 1 0.2353419-0.9290992i -1.221245e-15-9.992007e-16i
# z[1] and z[5] are complex conjugates (up to numerical errors)
# z[2] and z[3] are complex conjugates (up to numerical errors)
# z[4] is real (up to numerical errors)
# coerce the vector "z" to a list
(z_list = roots_as_list(z))
#> [[1]]
#> [1] 0.9253355
#>
#> [[2]]
#> [1] -0.5313699+0.3107316i
#>
#> [[3]]
#> [1] 0.2353419+0.9290992i
#>
# the first slot contains the real root (and thus is of class "numeric")
# z_list[[1]] = Re(z[4])
# the slots 2 and 3 contain the complex roots and thus are of class "complex"
# z_list[[2]] = (z[2] + Conj(z[3])/2
# z_list[[3]] = (z[1] + Conj(z[5])/2
# The routine zeroes() uses the function eigen()
# (to compute the eigenvalues of the companion matrix)
# and thus returns exact conjugate pairs:
(z = zeroes(polm(a)))
#> [1] -0.5313699-0.3107316i -0.5313699+0.3107316i 0.9253355+0.0000000i
#> [4] 0.2353419-0.9290992i 0.2353419+0.9290992i
# match roots and conjugate roots
j = match_vectors(z, Conj(z))
# z is equal to Conj(z[j])
print(j)
#> [1] 2 1 3 5 4
all.equal(z, Conj(z[j]))
#> [1] TRUE
# coerce the vector "z" to a list
(z_list = roots_as_list(z))
#> [[1]]
#> [1] 0.9253355
#>
#> [[2]]
#> [1] -0.5313699+0.3107316i
#>
#> [[3]]
#> [1] 0.2353419+0.9290992i
#>
set.seed(NULL)