+/* === S Y N F I G ========================================================= */
+/*! \file polynomial_root.cpp
+** \brief Template File
+**
+** $Id$
+**
+** \legal
+** Copyright (c) 2002-2005 Robert B. Quattlebaum Jr., Adrian Bentley
+**
+** This package is free software; you can redistribute it and/or
+** modify it under the terms of the GNU General Public License as
+** published by the Free Software Foundation; either version 2 of
+** the License, or (at your option) any later version.
+**
+** This package is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+** General Public License for more details.
+** \endlegal
+*/
+/* ========================================================================= */
+
+/* === H E A D E R S ======================================================= */
+
+#ifdef USING_PCH
+# include "pch.h"
+#else
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include "polynomial_root.h"
+#include <complex>
+
+#endif
+
+/* === U S I N G =========================================================== */
+
+using namespace std;
+//using namespace etl;
+//using namespace synfig;
+
+/* === M A C R O S ========================================================= */
+
+/* === G L O B A L S ======================================================= */
+typedef complex<float> Complex;
+
+/* === P R O C E D U R E S ================================================= */
+
+/* === M E T H O D S ======================================================= */
+
+#define EPSS 1.0e-7
+#define MR 8
+#define MT 10
+#define MAXIT (MT*MR)
+
+/*EPSS is the estimated fractional roundoff error. We try to break (rare) limit
+cycles with MR different fractional values, once every MT steps, for MAXIT total allowed iterations.
+*/
+
+/* Explanation:
+
+ A polynomial can be represented like so:
+ Pn(x) = (x - x1)(x - x2)...(x - xn) where xi = complex roots
+
+ We can get the following:
+ ln|Pn(x)| = ln|x - x1| + ln|x - x2| + ... + ln|x - xn|
+
+ G := d ln|Pn(x)| / dx =
+ +1/(x-x1) + 1/(x-x2) + ... + 1/(x-xn)
+
+ and
+
+ H := - d2 ln|Pn(x)| / d2x =
+ +1/(x-x1)^2 + 1/(x-x2)^2 + ... + 1/(x-xn)^2
+
+ which gives
+ H = [Pn'/Pn]^2 - Pn''/Pn
+
+ Laguerre's formula guesses that the root we are seeking x1 is located
+ some distance a from our current guess x, and all the other roots are
+ located at distance b.
+
+ Using this:
+
+ 1/a + (n-1)/b = G
+
+ and
+
+ 1/a^2 + (n-1)/b^2 = H
+
+ which yields this solution for a:
+
+ a = n / G +- sqrt( (n-1)(nH - G^2) )
+
+ where +- is determined by which ever yields the largest magnitude for the denominator.
+ a can easily be complex since the factor inside the square-root can be negative.
+
+ This method iterates (x=x-a) until a is sufficiently small.
+*/
+
+/* Given the degree m and the m+1 complex coefficients a[0..m] of the polynomial sum(i=0,m){a[i]x^i},
+and given a complex value x, this routine improves x by laguerre's method until it converges,
+within the achievable roundoff limit, to a root of the given polynomial. The number of iterations taken
+is returned as `its'.
+*/
+void laguer(Complex a[], int m, Complex *x, int *its)
+{
+ int iter,j;
+ float abx, abp, abm, err;
+ Complex dx,x1,b,d,f,g,h,sq,gp,gm,g2;
+
+ //Fractions used to break a limit cycle
+ static float frac[MR+1] = {0.0,0.5,0.25,0.75,0.13,0.38,0.62,0.88,1.0};
+
+ for(iter = 1; iter <= MAXIT; ++iter)
+ {
+ *its = iter; //number of iterations so far
+
+ b = a[m]; //the highest coefficient
+ err = abs(b); //its magnitude
+
+ d = f = Complex(0,0); //clear variables for use
+ abx = abs(*x); //the magnitude of the current root
+
+ //Efficent computation of the polynomial and its first 2 derivatives
+ for(j = m-1; j >= 0; --j)
+ {
+ f = (*x)*f + d;
+ d = (*x)*d + b;
+ b = (*x)*b + a[j];
+
+ err = abs(b) + abx*err;
+ }
+
+ //Estimate the roundoff error in evaluation polynomial
+ err *= EPSS;
+
+ //Are we on the root?
+ if(abs(b) < err)
+ {
+ return;
+ }
+
+ //General case: use Laguerre's formula
+ //a = n / G +- sqrt( (n-1)(nH - G^2) )
+ //x = x - a
+
+ g = d / b; //get G
+ g2 = g * g; //for the sqrt calc
+
+ h = g2 - 2.0f * (f / b); //get H
+
+ sq = pow( (float)(m-1) * ((float)m*h - g2), 0.5f ); //get the sqrt
+
+ //get the denominator
+ gp = g + sq;
+ gm = g - sq;
+
+ abp = abs(gp);
+ abm = abs(gm);
+
+ //get the denominator with the highest magnitude
+ if(abp < abm)
+ {
+ abp = abm;
+ gp = gm;
+ }
+
+ //if the denominator is positive do one thing, otherwise do the other
+ dx = (abp > 0.0) ? (float)m / gp : polar((1+abx),(float)iter);
+ x1 = *x - dx;
+
+ //Have we converged?
+ if( *x == x1 )
+ {
+ return;
+ }
+
+ //Every so often take a fractional step, to break any limit cycle (itself a rare occurrence).
+ if( iter % MT )
+ {
+ *x = x1;
+ }else
+ {
+ *x = *x - (frac[iter/MT]*dx);
+ }
+ }
+
+ //very unusual - can occur only for complex roots. Try a different starting guess for the root.
+ //nrerror("too many iterations in laguer");
+ return;
+}
+
+#define EPS 2.0e-6
+#define MAXM 100 //a small number, and maximum anticipated value of m..
+
+/* Given the degree m and the m+1 complex coefficients a[0..m] of the polynomial a0 + a1*x +...+ an*x^n
+ the routine successively calls laguer and finds all m complex roots in roots[1..m].
+ The boolean variable polish should be input as true (1) if polishing (also by Laguerre's Method)
+ is desired, false (0) if the roots will be subsequently polished by other means.
+*/
+void RootFinder::find_all_roots(bool polish)
+{
+ int i,its,j,jj;
+ Complex x,b,c;
+ int m = coefs.size()-1;
+
+ //make sure roots is big enough
+ roots.resize(m);
+
+ if(workcoefs.size() < MAXM) workcoefs.resize(MAXM);
+
+ //Copy the coefficients for successive deflation
+ for(j = 0; j <= m; ++j)
+ {
+ workcoefs[j] = coefs[j];
+ }
+
+ //Loop over each root to be found
+ for(j = m-1; j >= 0; --j)
+ {
+ //Start at 0 to favor convergence to smallest remaining root, and find the root
+ x = Complex(0,0);
+ laguer(&workcoefs[0],j+1,&x,&its); //must add 1 to get the degree
+
+ //if it is close enough to a real root, then make it so
+ if(abs(x.imag()) <= 2.0*EPS*abs(x.real()))
+ {
+ x = Complex(x.real());
+ }
+
+ roots[j] = x;
+
+ //forward deflation
+
+ //the degree is j+1 since j(0,m-1)
+ b = workcoefs[j+1];
+ for(jj = j; jj >= 0; --jj)
+ {
+ c = workcoefs[jj];
+ workcoefs[jj] = b;
+ b = x*b + c;
+ }
+ }
+
+ //Polish the roots using the undeflated coefficients
+ if(polish)
+ {
+ for(j = 0; j < m; ++j)
+ {
+ laguer(&coefs[0],m,&roots[j],&its);
+ }
+ }
+
+ //Sort roots by their real parts by straight insertion
+ for(j = 1; j < m; ++j)
+ {
+ x = roots[j];
+ for( i = j-1; i >= 1; --i)
+ {
+ if(roots[i].real() <= x.real()) break;
+ roots[i+1] = roots[i];
+ }
+ roots[i+1] = x;
+ }
+}