complex_quartic.h

Go to the documentation of this file.
00001 // @(#)root/mathmore:$Id: complex_quartic.h 28367 2009-04-27 16:14:36Z moneta $
00002 // Authors: L. Moneta, A. Zsenei   08/2005
00003 
00004 /* poly/zsolve_quartic.c
00005  *
00006  * Copyright (C) 2003 CERN and K.S. K\"{o}lbig
00007  *
00008  * Converted to C and implemented into the GSL Library - Sept. 2003
00009  * by Andrew W. Steiner and Andy Buckley
00010  *
00011  * This program is free software; you can redistribute it and/or modify
00012  * it under the terms of the GNU General Public License as published by
00013  * the Free Software Foundation; either version 2 of the License, or (at
00014  * your option) any later version.
00015  *
00016  * This program is distributed in the hope that it will be useful, but
00017  * WITHOUT ANY WARRANTY; without even the implied warranty of
00018  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00019  * General Public License for more details.
00020  *
00021  * You should have received a copy of the GNU General Public License
00022  * along with this program; if not, write to the Free Software
00023  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
00024  */
00025 
00026 /* zsolve_quartic.c - finds the complex roots of
00027  *  x^4 + a x^3 + b x^2 + c x + d = 0
00028  */
00029 
00030 #include <math.h>
00031 #include <gsl/gsl_math.h>
00032 #include <gsl/gsl_complex.h>
00033 #include <gsl/gsl_complex_math.h>
00034 #include <gsl/gsl_poly.h>
00035 
00036 #define SWAP(a,b) do { gsl_complex tmp = b ; b = a ; a = tmp ; } while(0)
00037 
00038 int
00039 gsl_poly_complex_solve_quartic (double a, double b, double c, double d,
00040                                 gsl_complex * z0, gsl_complex * z1,
00041                                 gsl_complex * z2, gsl_complex * z3)
00042 {
00043   gsl_complex i, zarr[4], w1, w2, w3;
00044   double r4 = 1.0 / 4.0;
00045   double q2 = 1.0 / 2.0, q4 = 1.0 / 4.0, q8 = 1.0 / 8.0;
00046   double q1 = 3.0 / 8.0, q3 = 3.0 / 16.0;
00047   double u[3], v[3], v1, v2, disc;
00048   double aa, pp, qq, rr, rc, sc, tc, q, h;
00049   int k1 = 0, k2 = 0, mt;
00050 
00051   GSL_SET_COMPLEX (&i, 0.0, 1.0);
00052   GSL_SET_COMPLEX (&zarr[0], 0.0, 0.0);
00053   GSL_SET_COMPLEX (&zarr[1], 0.0, 0.0);
00054   GSL_SET_COMPLEX (&zarr[2], 0.0, 0.0);
00055   GSL_SET_COMPLEX (&zarr[3], 0.0, 0.0);
00056   GSL_SET_COMPLEX (&w1, 0.0, 0.0);
00057   GSL_SET_COMPLEX (&w2, 0.0, 0.0);
00058   GSL_SET_COMPLEX (&w3, 0.0, 0.0);
00059 
00060   /* Deal easily with the cases where the quartic is degenerate. The
00061    * ordering of solutions is done explicitly. */
00062   if (0 == b && 0 == c)
00063     {
00064       if (0 == d)
00065         {
00066           if (a > 0)
00067             {
00068               GSL_SET_COMPLEX (z0, -a, 0.0);
00069               GSL_SET_COMPLEX (z1, 0.0, 0.0);
00070               GSL_SET_COMPLEX (z2, 0.0, 0.0);
00071               GSL_SET_COMPLEX (z3, 0.0, 0.0);
00072             }
00073           else
00074             {
00075               GSL_SET_COMPLEX (z0, 0.0, 0.0);
00076               GSL_SET_COMPLEX (z1, 0.0, 0.0);
00077               GSL_SET_COMPLEX (z2, 0.0, 0.0);
00078               GSL_SET_COMPLEX (z3, -a, 0.0);
00079             }
00080           return 4;
00081         }
00082       else if (0 == a)
00083         {
00084           if (d > 0)
00085             {
00086               double sqrt_d = sqrt (d);
00087               gsl_complex i_sqrt_d = gsl_complex_mul_real (i, sqrt_d);
00088               gsl_complex minus_i = gsl_complex_conjugate (i);
00089               *z3 = gsl_complex_sqrt (i_sqrt_d);
00090               *z2 = gsl_complex_mul (minus_i, *z3);
00091               *z1 = gsl_complex_negative (*z2);
00092               *z0 = gsl_complex_negative (*z3);
00093             }
00094           else
00095             {
00096               double sqrt_abs_d = sqrt (-d);
00097               *z3 = gsl_complex_sqrt_real (sqrt_abs_d);
00098               *z2 = gsl_complex_mul (i, *z3);
00099               *z1 = gsl_complex_negative (*z2);
00100               *z0 = gsl_complex_negative (*z3);
00101             }
00102           return 4;
00103         }
00104     }
00105 
00106   if (0.0 == c && 0.0 == d)
00107     {
00108       disc = (a * a - 4.0 * b);
00109       if (disc < 0.0)
00110         {
00111           mt = 3;
00112         }
00113       else
00114         {
00115           mt = 1;
00116         }
00117       *z0 = zarr[0];
00118       *z1 = zarr[0];
00119       gsl_poly_complex_solve_quadratic (1.0, a, b, z2, z3);
00120     }
00121   else
00122     {
00123       /* For non-degenerate solutions, proceed by constructing and
00124        * solving the resolvent cubic */
00125       aa = a * a;
00126       pp = b - q1 * aa;
00127       qq = c - q2 * a * (b - q4 * aa);
00128       rr = d - q4 * (a * c - q4 * aa * (b - q3 * aa));
00129       rc = q2 * pp;
00130       sc = q4 * (q4 * pp * pp - rr);
00131       tc = -(q8 * qq * q8 * qq);
00132 
00133       /* This code solves the resolvent cubic in a convenient fashion
00134        * for this implementation of the quartic. If there are three real
00135        * roots, then they are placed directly into u[].  If two are
00136        * complex, then the real root is put into u[0] and the real
00137        * and imaginary part of the complex roots are placed into
00138        * u[1] and u[2], respectively. Additionally, this
00139        * calculates the discriminant of the cubic and puts it into the
00140        * variable disc. */
00141       {
00142         double qcub = (rc * rc - 3 * sc);
00143         double rcub = (2 * rc * rc * rc - 9 * rc * sc + 27 * tc);
00144 
00145         double Q = qcub / 9;
00146         double R = rcub / 54;
00147 
00148         double Q3 = Q * Q * Q;
00149         double R2 = R * R;
00150 
00151         disc = R2 - Q3; 
00152 
00153 //       more numerical problems with this calculation of disc          
00154 //       double CR2 = 729 * rcub * rcub;
00155 //       double CQ3 = 2916 * qcub * qcub * qcub;
00156 //       disc = (CR2 - CQ3) / 2125764.0;       
00157 
00158 
00159         if (0 == R && 0 == Q)
00160           {
00161             u[0] = -rc / 3;
00162             u[1] = -rc / 3;
00163             u[2] = -rc / 3;
00164           }
00165         else if (R2 == Q3) 
00166           {
00167             double sqrtQ = sqrt (Q);
00168             if (R > 0)
00169               {
00170                 u[0] = -2 * sqrtQ - rc / 3;
00171                 u[1] = sqrtQ - rc / 3;
00172                 u[2] = sqrtQ - rc / 3;
00173               }
00174             else
00175               {
00176                 u[0] = -sqrtQ - rc / 3;
00177                 u[1] = -sqrtQ - rc / 3;
00178                 u[2] = 2 * sqrtQ - rc / 3;
00179               }
00180           }
00181         else if ( R2 < Q3)
00182           {
00183             double sqrtQ = sqrt (Q);
00184             double sqrtQ3 = sqrtQ * sqrtQ * sqrtQ;
00185             double ctheta = R / sqrtQ3;
00186             double theta = 0; 
00187             // protect against numerical error can make this larger than one
00188             if ( fabs(ctheta) < 1.0 )
00189                theta = acos( ctheta); 
00190             else if ( ctheta <= -1.0) 
00191                theta = M_PI; 
00192 
00193             double norm = -2 * sqrtQ;
00194 
00195             u[0] = norm * cos (theta / 3) - rc / 3;
00196             u[1] = norm * cos ((theta + 2.0 * M_PI) / 3) - rc / 3;
00197             u[2] = norm * cos ((theta - 2.0 * M_PI) / 3) - rc / 3;
00198           }
00199         else
00200           {
00201             double sgnR = (R >= 0 ? 1 : -1);
00202             double modR = fabs (R);
00203             double sqrt_disc = sqrt (disc);
00204             double A = -sgnR * pow (modR + sqrt_disc, 1.0 / 3.0);
00205             double B = Q / A;
00206 
00207             double mod_diffAB = fabs (A - B);
00208             u[0] = A + B - rc / 3;
00209             u[1] = -0.5 * (A + B) - rc / 3;
00210             u[2] = -(sqrt (3.0) / 2.0) * mod_diffAB;
00211           }
00212       }
00213       /* End of solution to resolvent cubic */
00214 
00215       /* Combine the square roots of the roots of the cubic
00216        * resolvent appropriately. Also, calculate 'mt' which
00217        * designates the nature of the roots:
00218        * mt=1 : 4 real roots
00219        * mt=2 : 0 real roots
00220        * mt=3 : 2 real roots
00221        */
00222       // when disc == 0  2 roots are identicals 
00223       if (0 >= disc)
00224         {
00225           mt = 2;
00226           v[0] = fabs (u[0]);
00227           v[1] = fabs (u[1]);
00228           v[2] = fabs (u[2]);
00229 
00230           v1 = GSL_MAX (GSL_MAX (v[0], v[1]), v[2]);
00231           if (v1 == v[0])
00232             {
00233               k1 = 0;
00234               v2 = GSL_MAX (v[1], v[2]);
00235             }
00236           else if (v1 == v[1])
00237             {
00238               k1 = 1;
00239               v2 = GSL_MAX (v[0], v[2]);
00240             }
00241           else
00242             {
00243               k1 = 2;
00244               v2 = GSL_MAX (v[0], v[1]);
00245             }
00246 
00247           if (v2 == v[0])
00248             {
00249               k2 = 0;
00250             }
00251           else if (v2 == v[1])
00252             {
00253               k2 = 1;
00254             }
00255           else
00256             {
00257               k2 = 2;
00258             }
00259           w1 = gsl_complex_sqrt_real (u[k1]);
00260           w2 = gsl_complex_sqrt_real (u[k2]);
00261         }
00262       else
00263         {
00264           mt = 3;
00265           GSL_SET_COMPLEX (&w1, u[1], u[2]);
00266           GSL_SET_COMPLEX (&w2, u[1], -u[2]);
00267           w1 = gsl_complex_sqrt (w1);
00268           w2 = gsl_complex_sqrt (w2);
00269         }
00270       /* Solve the quadratic in order to obtain the roots
00271        * to the quartic */
00272       q = qq;
00273       gsl_complex prod_w = gsl_complex_mul (w1, w2);
00274       //gsl_complex mod_prod_w = gsl_complex_abs (prod_w);
00275       /*
00276         Changed from gsl_complex to double in order to make it compile.
00277       */
00278       double mod_prod_w = gsl_complex_abs (prod_w);
00279       if (0.0 != mod_prod_w)
00280         {
00281           gsl_complex inv_prod_w = gsl_complex_inverse (prod_w);
00282           w3 = gsl_complex_mul_real (inv_prod_w, -q / 8.0);
00283         }
00284 
00285       h = r4 * a;
00286       gsl_complex sum_w12 = gsl_complex_add (w1, w2);
00287       gsl_complex neg_sum_w12 = gsl_complex_negative (sum_w12);
00288       gsl_complex sum_w123 = gsl_complex_add (sum_w12, w3);
00289       gsl_complex neg_sum_w123 = gsl_complex_add (neg_sum_w12, w3);
00290 
00291       gsl_complex diff_w12 = gsl_complex_sub (w2, w1);
00292       gsl_complex neg_diff_w12 = gsl_complex_negative (diff_w12);
00293       gsl_complex diff_w123 = gsl_complex_sub (diff_w12, w3);
00294       gsl_complex neg_diff_w123 = gsl_complex_sub (neg_diff_w12, w3);
00295 
00296       zarr[0] = gsl_complex_add_real (sum_w123, -h);
00297       zarr[1] = gsl_complex_add_real (neg_sum_w123, -h);
00298       zarr[2] = gsl_complex_add_real (diff_w123, -h);
00299       zarr[3] = gsl_complex_add_real (neg_diff_w123, -h);
00300 
00301       /* Arrange the roots into the variables z0, z1, z2, z3 */
00302       if (2 == mt)
00303         {
00304           if (u[k1] >= 0 && u[k2] >= 0)
00305             {
00306               mt = 1;
00307               GSL_SET_COMPLEX (z0, GSL_REAL (zarr[0]), 0.0);
00308               GSL_SET_COMPLEX (z1, GSL_REAL (zarr[1]), 0.0);
00309               GSL_SET_COMPLEX (z2, GSL_REAL (zarr[2]), 0.0);
00310               GSL_SET_COMPLEX (z3, GSL_REAL (zarr[3]), 0.0);
00311             }
00312           else if (u[k1] >= 0 && u[k2] < 0)
00313             {
00314               *z0 = zarr[0];
00315               *z1 = zarr[3];
00316               *z2 = zarr[2];
00317               *z3 = zarr[1];
00318             }
00319           else if (u[k1] < 0 && u[k2] >= 0)
00320             {
00321               *z0 = zarr[0];
00322               *z1 = zarr[2];
00323               *z2 = zarr[3];
00324               *z3 = zarr[1];
00325             }
00326           else if (u[k1] < 0 && u[k2] < 0)
00327             {
00328               *z0 = zarr[0];
00329               *z1 = zarr[1];
00330               *z2 = zarr[3];
00331               *z3 = zarr[2];
00332             }
00333         }
00334       else if (3 == mt)
00335         {
00336           GSL_SET_COMPLEX (z0, GSL_REAL (zarr[0]), 0.0);
00337           GSL_SET_COMPLEX (z1, GSL_REAL (zarr[1]), 0.0);
00338           *z2 = zarr[3];
00339           *z3 = zarr[2];
00340         }
00341     }
00342 
00343   /*
00344    * Sort the roots as usual: main sorting by ascending real part, secondary
00345    * sorting by ascending imaginary part
00346    */
00347 
00348   if (1 == mt)
00349     {
00350       /* Roots are all real, sort them by the real part */
00351       if (GSL_REAL (*z0) > GSL_REAL (*z1)) SWAP (*z0, *z1);
00352       if (GSL_REAL (*z0) > GSL_REAL (*z2)) SWAP (*z0, *z2);
00353       if (GSL_REAL (*z0) > GSL_REAL (*z3)) SWAP (*z0, *z3);
00354 
00355       if (GSL_REAL (*z1) > GSL_REAL (*z2)) SWAP (*z1, *z2);
00356       if (GSL_REAL (*z2) > GSL_REAL (*z3))
00357         {
00358           SWAP (*z2, *z3);
00359           if (GSL_REAL (*z1) > GSL_REAL (*z2)) SWAP (*z1, *z2);
00360         }
00361     }
00362   else if (2 == mt)
00363     {
00364       /* Roots are all complex. z0 and z1 are conjugates
00365        * and z2 and z3 are conjugates. Sort the real parts first */
00366       if (GSL_REAL (*z0) > GSL_REAL (*z2))
00367         {
00368           SWAP (*z0, *z2);
00369           SWAP (*z1, *z3);
00370         }
00371       /* Then sort by the imaginary parts */
00372       if (GSL_IMAG (*z0) > GSL_IMAG (*z1)) SWAP (*z0, *z1);
00373       if (GSL_IMAG (*z2) > GSL_IMAG (*z3)) SWAP (*z2, *z3);
00374     }
00375   else
00376     {
00377       /* 2 real roots. z2 and z3 are conjugates. */
00378 
00379       /* Swap complex roots */
00380       if (GSL_IMAG (*z2) > GSL_IMAG (*z3)) SWAP (*z2, *z3);
00381 
00382       /* Sort real parts */
00383       if (GSL_REAL (*z0) > GSL_REAL (*z1)) SWAP (*z0, *z1);
00384       if (GSL_REAL (*z1) > GSL_REAL (*z2))
00385         {
00386           if (GSL_REAL (*z0) > GSL_REAL (*z2))
00387             {
00388               SWAP (*z0, *z2);
00389               SWAP (*z1, *z3);
00390             }
00391           else
00392             {
00393               SWAP (*z1, *z2);
00394               SWAP (*z2, *z3);
00395             }
00396         }
00397     }
00398 
00399   return 4;
00400 }
00401 

Generated on Tue Jul 5 14:34:31 2011 for ROOT_528-00b_version by  doxygen 1.5.1