View Raw SPL
/*****************************************************************************
* *
* POLYROOT.SPL Copyright (C) 2002-2003 DSP Development Corporation *
* All Rights Reserved *
* *
* Author: Randy Race *
* *
* Synopsis: Finds roots of a polynomial using the companion matrix *
* *
* Revisions: 3 Jan 2002 RRR Creation *
* 26 Sep 2003 RRR erones handles empty coeff *
* 16 Oct 2003 RRR handle leading and trailing zeros *
* *
*****************************************************************************/
#define erones(q) (if(q<=2,{},extract(diag(ones(q-2, 1)), 1, q-1)))
#define errow1(s) (ravel(extract(-rev((s)/s[length(s)]),2,-1)))
#if @HELP_POLYROOT
POLYROOT
Purpose: Finds the roots of a polynomial using the companion matrix
Syntax: POLYROOT(coef, form)
coef - A series, the polynomial coefficients
form - An optional integer, form of the polynomial coefficients,
0: ascending powers, 1: decreasing powers, defaults to 0.
Returns: A real or complex series, the roots of the polynomial.
Example:
polyroot({0, -2, 1})
returns {2, 0}, the roots of 0 - 2*x + x^2.
Example:
r = polyroot({1, -1, -1}, 1)
r == {1.618034, -0.618034}
r[1] == phi
returns 1, i.e. positive root of x^2 - x - 1 is PHI, the
Golden Mean.
Example:
a := rand
x = -10..0.01..10
W1: polyroot({a, 1, -1, -1}, 1)
W2: xy(W1, zeros(length(W1),1));points;setsym(14)
W3: a*x^3 + x^2 - x - 1;overp(W2, lred)
W3 displays a cubic of the form a*x^3 + x^2 - x - 1 over
the range -10 <= x <= 10. The roots of the cubic are
overplotted in red and displayed as solid circles.
Executing the statement a := rand creates a new polynomial that
is automatically updated in W3.
Remarks:
POLYROOT calculates the roots of a polynomial by finding the
eigenvalues of the companion matrix for the corresponding
characteristic polynomial.
POLYROOT(a) finds the roots of:
a[1] + a[2]*x + a[3]*x^2 + ... + a[n]*x^(n-1)
this is the same form as POLYFIT and POLYGRAPH.
POLYROOT(a, 1) finds the roots of:
a[1]*x^(n-1) + a[2]*x^(n-2) + ... + a[n-1]*x + a[n]
See Also:
Pfit
Poly
Polyfit
Polygraph
#endif
/* find polynomial roots using the companion matrix */
ITERATE polyroot(coef, form = 0)
{
local len, cols, r, n, idx, z = 0;
if (argc < 1) error(sprintf("%s - input series required", __FUNC__));
(len, cols) = size(coef);
if (cols > 1)
{
coef = col(yvals(coef), 1);
len = length(coef);
}
if (len < 2)
{
/* P(x) = K, no roots */
return({});
}
/* strip leading zeros */
(n, idx) = polyroot_lzeros(coef);
if (n > 0)
{
coef = extract(coef, idx, -1);
if (form == 0)
{
/* handle leading zeros as roots at zero */
z = n;
}
}
/* strip trailing zeros */
(n, idx) = polyroot_tzeros(coef);
if (n > 0)
{
coef = extract(coef, 1, idx);
if (form)
{
/* handle trailing zeros as roots at zero */
z = n;
}
}
if ((len = length(coef)) > 1)
{
/* flip coefficients */
if (form) coef = rev(coef);
/* calc roots via companion matrix */
r = eigval(ravel(errow1(coef), erones(len)));
}
else
{
r = {};
}
if (z > 0)
{
/* preprend zero roots */
r = {zeros(z, 1), r};
}
return(r);
}
/* return number and index of leading zeros */
polyroot_lzeros(b)
{
local f, idx, d;
f = {0};
d = idx = 0;
if (b[1] == 0)
{
/* find indices of non-zero elements */
f = find(b);
if (length(f) == 0)
{
/* all zeros */
d = length(b);
idx = d;
}
else
{
idx = f[1];
d = idx - 1;
}
}
return(d, idx);
}
/* return number and index of trailing zeros */
polyroot_tzeros(b)
{
local idx, d;
b = rev(b);
d = polyroot_lzeros(b);
idx = length(b) - d;
return(d, idx);
}