Wm4PolynomialRoots.cpp

Go to the documentation of this file.
00001 // Wild Magic Source Code
00002 // David Eberly
00003 // http://www.geometrictools.com
00004 // Copyright (c) 1998-2007
00005 //
00006 // This library is free software; you can redistribute it and/or modify it
00007 // under the terms of the GNU Lesser General Public License as published by
00008 // the Free Software Foundation; either version 2.1 of the License, or (at
00009 // your option) any later version.  The license is available for reading at
00010 // either of the locations:
00011 //     http://www.gnu.org/copyleft/lgpl.html
00012 //     http://www.geometrictools.com/License/WildMagicLicense.pdf
00013 // The license applies to versions 0 through 4 of Wild Magic.
00014 //
00015 // Version: 4.0.0 (2006/06/28)
00016 
00017 #include "Wm4FoundationPCH.h"
00018 #include "Wm4PolynomialRoots.h"
00019 
00020 namespace Wm4
00021 {
00022 //----------------------------------------------------------------------------
00023 template <class Real>
00024 PolynomialRoots<Real>::PolynomialRoots (Real fEpsilon)
00025 {
00026     assert(fEpsilon >= (Real)0.0);
00027     m_fEpsilon = fEpsilon;
00028     m_iMaxIterations = 128;
00029     m_iCount = 0;
00030     m_iMaxRoot = 4;  // default support for degree <= 4
00031     m_afRoot = WM4_NEW Real[m_iMaxRoot];
00032 }
00033 //----------------------------------------------------------------------------
00034 template <class Real>
00035 PolynomialRoots<Real>::~PolynomialRoots ()
00036 {
00037     WM4_DELETE[] m_afRoot;
00038 }
00039 //----------------------------------------------------------------------------
00040 template <class Real>
00041 int PolynomialRoots<Real>::GetCount () const
00042 {
00043     return m_iCount;
00044 }
00045 //----------------------------------------------------------------------------
00046 template <class Real>
00047 const Real* PolynomialRoots<Real>::GetRoots () const
00048 {
00049     return m_afRoot;
00050 }
00051 //----------------------------------------------------------------------------
00052 template <class Real>
00053 Real PolynomialRoots<Real>::GetRoot (int i) const
00054 {
00055     assert(0 <= i && i < m_iCount);
00056     if (0 <= i && i < m_iCount)
00057     {
00058         return m_afRoot[i];
00059     }
00060 
00061     return Math<Real>::MAX_REAL;
00062 }
00063 //----------------------------------------------------------------------------
00064 template <class Real>
00065 Real& PolynomialRoots<Real>::Epsilon ()
00066 {
00067     return m_fEpsilon;
00068 }
00069 //----------------------------------------------------------------------------
00070 template <class Real>
00071 Real PolynomialRoots<Real>::Epsilon () const
00072 {
00073     return m_fEpsilon;
00074 }
00075 //----------------------------------------------------------------------------
00076 template <class Real>
00077 int& PolynomialRoots<Real>::MaxIterations ()
00078 {
00079     return m_iMaxIterations;
00080 }
00081 //----------------------------------------------------------------------------
00082 template <class Real>
00083 int PolynomialRoots<Real>::MaxIterations () const
00084 {
00085     return m_iMaxIterations;
00086 }
00087 //----------------------------------------------------------------------------
00088 
00089 //----------------------------------------------------------------------------
00090 // degree 1
00091 //----------------------------------------------------------------------------
00092 template <class Real>
00093 bool PolynomialRoots<Real>::FindA (Real fC0, Real fC1)
00094 {
00095     if (Math<Real>::FAbs(fC1) >= m_fEpsilon)
00096     {
00097         m_afRoot[0] = -fC0/fC1;
00098         m_iCount = 1;
00099         return true;
00100     }
00101 
00102     m_iCount = 0;
00103     return false;
00104 }
00105 //----------------------------------------------------------------------------
00106 template <class Real>
00107 Real PolynomialRoots<Real>::GetBound (Real fC0, Real fC1)
00108 {
00109     if (Math<Real>::FAbs(fC1) <= m_fEpsilon)
00110     {
00111         // polynomial is constant, return invalid bound
00112         return -(Real)1.0;
00113     }
00114 
00115     Real fInvC1 = ((Real)1.0)/fC1;
00116     Real fMax = Math<Real>::FAbs(fC0)*fInvC1;
00117     return (Real)1.0 + fMax;
00118 }
00119 //----------------------------------------------------------------------------
00120 
00121 //----------------------------------------------------------------------------
00122 // degree 2
00123 //----------------------------------------------------------------------------
00124 template <class Real>
00125 bool PolynomialRoots<Real>::FindA (Real fC0, Real fC1, Real fC2)
00126 {
00127     if (Math<Real>::FAbs(fC2) <= m_fEpsilon)
00128     {
00129         // polynomial is linear
00130         return FindA(fC0,fC1);
00131     }
00132 
00133     Real fDiscr = fC1*fC1 - 4.0f*fC0*fC2;
00134     if (Math<Real>::FAbs(fDiscr) <= m_fEpsilon)
00135     {
00136         fDiscr = (Real)0.0;
00137     }
00138 
00139     if (fDiscr < (Real)0.0)
00140     {
00141         m_iCount = 0;
00142         return false;
00143     }
00144 
00145     Real fTmp = ((Real)0.5)/fC2;
00146 
00147     if (fDiscr > (Real)0.0)
00148     {
00149         fDiscr = Math<Real>::Sqrt(fDiscr);
00150         m_afRoot[0] = fTmp*(-fC1 - fDiscr);
00151         m_afRoot[1] = fTmp*(-fC1 + fDiscr);
00152         m_iCount = 2;
00153     }
00154     else
00155     {
00156         m_afRoot[0] = -fTmp*fC1;
00157         m_iCount = 1;
00158     }
00159 
00160     return true;
00161 }
00162 //----------------------------------------------------------------------------
00163 template <class Real>
00164 Real PolynomialRoots<Real>::GetBound (Real fC0, Real fC1, Real fC2)
00165 {
00166     if (Math<Real>::FAbs(fC2) <= m_fEpsilon)
00167     {
00168         // polynomial is linear
00169         return (FindA(fC0,fC1) ? m_afRoot[0] : Math<Real>::MAX_REAL);
00170     }
00171 
00172     Real fInvC2 = ((Real)1.0)/fC2;
00173     Real fTmp0 = Math<Real>::FAbs(fC0)*fInvC2;
00174     Real fTmp1 = Math<Real>::FAbs(fC1)*fInvC2;
00175     Real fMax = ( fTmp0 >= fTmp1 ? fTmp0 : fTmp1 );
00176     return (Real)1.0 + fMax;
00177 }
00178 //----------------------------------------------------------------------------
00179 
00180 //----------------------------------------------------------------------------
00181 // degree 3
00182 //----------------------------------------------------------------------------
00183 template <class Real>
00184 bool PolynomialRoots<Real>::FindA (Real fC0, Real fC1, Real fC2, Real fC3)
00185 {
00186     if (Math<Real>::FAbs(fC3) <= m_fEpsilon)
00187     {
00188         // polynomial is quadratic
00189         return FindA(fC0,fC1,fC2);
00190     }
00191 
00192     // make polynomial monic, x^3+c2*x^2+c1*x+c0
00193     Real fInvC3 = ((Real)1.0)/fC3;
00194     fC0 *= fInvC3;
00195     fC1 *= fInvC3;
00196     fC2 *= fInvC3;
00197 
00198     // convert to y^3+a*y+b = 0 by x = y-c2/3
00199     const Real fThird = (Real)1.0/(Real)3.0;
00200     const Real fTwentySeventh = (Real)1.0/(Real)27.0;
00201     Real fOffset = fThird*fC2;
00202     Real fA = fC1 - fC2*fOffset;
00203     Real fB = fC0+fC2*(((Real)2.0)*fC2*fC2-((Real)9.0)*fC1)*fTwentySeventh;
00204     Real fHalfB = ((Real)0.5)*fB;
00205 
00206     Real fDiscr = fHalfB*fHalfB + fA*fA*fA*fTwentySeventh;
00207     if (Math<Real>::FAbs(fDiscr) <= m_fEpsilon)
00208     {
00209         fDiscr = (Real)0.0;
00210     }
00211 
00212     if (fDiscr > (Real)0.0)  // 1 real, 2 complex roots
00213     {
00214         fDiscr = Math<Real>::Sqrt(fDiscr);
00215         Real fTemp = -fHalfB + fDiscr;
00216         if (fTemp >= (Real)0.0)
00217         {
00218             m_afRoot[0] = Math<Real>::Pow(fTemp,fThird);
00219         }
00220         else
00221         {
00222             m_afRoot[0] = -Math<Real>::Pow(-fTemp,fThird);
00223         }
00224         fTemp = -fHalfB - fDiscr;
00225         if ( fTemp >= (Real)0.0 )
00226         {
00227             m_afRoot[0] += Math<Real>::Pow(fTemp,fThird);
00228         }
00229         else
00230         {
00231             m_afRoot[0] -= Math<Real>::Pow(-fTemp,fThird);
00232         }
00233         m_afRoot[0] -= fOffset;
00234         m_iCount = 1;
00235     }
00236     else if (fDiscr < (Real)0.0) 
00237     {
00238         const Real fSqrt3 = Math<Real>::Sqrt((Real)3.0);
00239         Real fDist = Math<Real>::Sqrt(-fThird*fA);
00240         Real fAngle = fThird*Math<Real>::ATan2(Math<Real>::Sqrt(-fDiscr),
00241             -fHalfB);
00242         Real fCos = Math<Real>::Cos(fAngle);
00243         Real fSin = Math<Real>::Sin(fAngle);
00244         m_afRoot[0] = ((Real)2.0)*fDist*fCos-fOffset;
00245         m_afRoot[1] = -fDist*(fCos+fSqrt3*fSin)-fOffset;
00246         m_afRoot[2] = -fDist*(fCos-fSqrt3*fSin)-fOffset;
00247         m_iCount = 3;
00248     }
00249     else 
00250     {
00251         Real fTemp;
00252         if (fHalfB >= (Real)0.0)
00253         {
00254             fTemp = -Math<Real>::Pow(fHalfB,fThird);
00255         }
00256         else
00257         {
00258             fTemp = Math<Real>::Pow(-fHalfB,fThird);
00259         }
00260         m_afRoot[0] = ((Real)2.0)*fTemp-fOffset;
00261         m_afRoot[1] = -fTemp-fOffset;
00262         m_afRoot[2] = m_afRoot[1];
00263         m_iCount = 3;
00264     }
00265 
00266     return true;
00267 }
00268 //----------------------------------------------------------------------------
00269 template <class Real>
00270 bool PolynomialRoots<Real>::FindE (Real fC0, Real fC1, Real fC2, Real fC3,
00271     bool bDoBalancing)
00272 {
00273     if (Math<Real>::FAbs(fC3) <= m_fEpsilon)
00274     {
00275         // polynomial is quadratic
00276         return FindA(fC0,fC1,fC2);
00277     }
00278 
00279     // make polynomial monic, x^3+c2*x^2+c1*x+c0
00280     Real fInvC3 = ((Real)1.0)/fC3;
00281     fC0 *= fInvC3;
00282     fC1 *= fInvC3;
00283     fC2 *= fInvC3;
00284 
00285     // construct the 3-by-3 companion matrix
00286     GMatrix<Real> kMat(3,3);  // initialized to zero
00287     kMat[1][0] = (Real)1.0;
00288     kMat[2][1] = (Real)1.0;
00289     kMat[0][2] = -fC0;
00290     kMat[1][2] = -fC1;
00291     kMat[2][2] = -fC2;
00292 
00293     if (bDoBalancing)
00294     {
00295         BalanceCompanion3(kMat);
00296     }
00297 
00298     return QRIteration3(kMat);
00299 }
00300 //----------------------------------------------------------------------------
00301 template <class Real>
00302 Real PolynomialRoots<Real>::GetBound (Real fC0, Real fC1, Real fC2, Real fC3)
00303 {
00304     if (Math<Real>::FAbs(fC3) <= m_fEpsilon)
00305     {
00306         // polynomial is quadratic
00307         return GetBound(fC0,fC1,fC2);
00308     }
00309 
00310     Real fInvC3 = ((Real)1.0)/fC3;
00311     Real fMax = Math<Real>::FAbs(fC0)*fInvC3;
00312 
00313     Real fTmp = Math<Real>::FAbs(fC1)*fInvC3;
00314     if (fTmp > fMax)
00315     {
00316         fMax = fTmp;
00317     }
00318 
00319     fTmp = Math<Real>::FAbs(fC2)*fInvC3;
00320     if (fTmp > fMax)
00321     {
00322         fMax = fTmp;
00323     }
00324 
00325     return (Real)1.0 + fMax;
00326 }
00327 //----------------------------------------------------------------------------
00328 template <class Real>
00329 Real PolynomialRoots<Real>::SpecialCubic (Real fA, Real fB, Real fC)
00330 {
00331     // Solve A*r^3 + B*r = C where A > 0 and B > 0.
00332     //
00333     // Let r = D*sinh(u) where D = sqrt(4*B/(3*A)).  Then
00334     // sinh(3*u) = 4*[sinh(u)]^3+3*sinh(u) = E where E = 4*C/(A*D^3).
00335     // sinh(3*u) = E has solution u = (1/3)*log(E+sqrt(E^2+1)).  This
00336     // leads to sinh(u) = ((E+sqrt(E^2+1))^{1/3}-(E+sqrt(E^2+1))^{-1/3})/2.
00337     // Therefore,  r = D*((E+sqrt(E^2+1))^{1/3}-(E+sqrt(E^2+1))^{-1/3})/2.
00338 
00339     const Real fThird = (Real)1.0/(Real)3.0;
00340     Real fD = Math<Real>::Sqrt(((Real)4.0)*fThird*fB/fA);
00341     Real fE = ((Real)4.0)*fC/(fA*fD*fD*fD);
00342     Real fF = Math<Real>::Pow(fE+Math<Real>::Sqrt(fE*fE+(Real)1.0),fThird);
00343     Real fRoot = ((Real)0.5)*fD*(fF-((Real)1.0)/fF);
00344     return fRoot;
00345 }
00346 //----------------------------------------------------------------------------
00347 template <class Real>
00348 Real PolynomialRoots<Real>::GetRowNorm (int iRow, GMatrix<Real>& rkMat)
00349 {
00350     Real fNorm = Math<Real>::FAbs(rkMat[iRow][0]);
00351     for (int iCol = 1; iCol < rkMat.GetColumns(); iCol++)
00352     {
00353         Real fAbs = Math<Real>::FAbs(rkMat[iRow][iCol]);
00354         if (fAbs > fNorm)
00355         {
00356             fNorm = fAbs;
00357         }
00358     }
00359     return fNorm;
00360 }
00361 //----------------------------------------------------------------------------
00362 template <class Real>
00363 Real PolynomialRoots<Real>::GetColNorm (int iCol, GMatrix<Real>& rkMat)
00364 {
00365     Real fNorm = Math<Real>::FAbs(rkMat[0][iCol]);
00366     for (int iRow = 1; iRow < rkMat.GetRows(); iRow++)
00367     {
00368         Real fAbs = Math<Real>::FAbs(rkMat[iRow][iCol]);
00369         if (fAbs > fNorm)
00370         {
00371             fNorm = fAbs;
00372         }
00373     }
00374     return fNorm;
00375 }
00376 //----------------------------------------------------------------------------
00377 template <class Real>
00378 void PolynomialRoots<Real>::ScaleRow (int iRow, Real fScale,
00379     GMatrix<Real>& rkMat)
00380 {
00381     for (int iCol = 0; iCol < rkMat.GetColumns(); iCol++)
00382     {
00383         rkMat[iRow][iCol] *= fScale;
00384     }
00385 }
00386 //----------------------------------------------------------------------------
00387 template <class Real>
00388 void PolynomialRoots<Real>::ScaleCol (int iCol, Real fScale,
00389     GMatrix<Real>& rkMat)
00390 {
00391     for (int iRow = 0; iRow < rkMat.GetRows(); iRow++)
00392     {
00393         rkMat[iRow][iCol] *= fScale;
00394     }
00395 }
00396 //----------------------------------------------------------------------------
00397 template <class Real>
00398 bool PolynomialRoots<Real>::IsBalanced3 (GMatrix<Real>& rkMat)
00399 {
00400     const Real fTolerance = (Real)0.001;
00401     for (int i = 0; i < 3; i++)
00402     {
00403         Real fRowNorm = GetRowNorm(i,rkMat);
00404         Real fColNorm = GetColNorm(i,rkMat);
00405         Real fTest = Math<Real>::FAbs((Real)1.0 - fColNorm/fRowNorm);
00406         if (fTest > fTolerance)
00407         {
00408             return false;
00409         }
00410     }
00411     return true;
00412 }
00413 //----------------------------------------------------------------------------
00414 template <class Real>
00415 void PolynomialRoots<Real>::Balance3 (GMatrix<Real>& rkMat)
00416 {
00417     const int iMax = 16;
00418     int i;
00419     for (i = 0; i < iMax; i++)
00420     {
00421         for (int j = 0; j < 3; j++)
00422         {
00423             Real fRowNorm = GetRowNorm(j,rkMat);
00424             Real fColNorm = GetColNorm(j,rkMat);
00425             Real fScale = Math<Real>::Sqrt(fColNorm/fRowNorm);
00426             Real fInvScale = ((Real)1.0)/fScale;
00427             ScaleRow(j,fScale,rkMat);
00428             ScaleCol(j,fInvScale,rkMat);
00429         }
00430 
00431         if (IsBalanced3(rkMat))
00432         {
00433             break;
00434         }
00435     }
00436     assert(i < iMax);
00437 }
00438 //----------------------------------------------------------------------------
00439 template <class Real>
00440 bool PolynomialRoots<Real>::IsBalancedCompanion3 (Real fA10, Real fA21,
00441     Real fA02, Real fA12, Real fA22)
00442 {
00443     const Real fTolerance = (Real)0.001;
00444 
00445     // row/col 0
00446     Real fRowNorm = fA02;
00447     Real fColNorm = fA10;
00448     Real fTest = Math<Real>::FAbs((Real)1.0 - fColNorm/fRowNorm);
00449     if (fTest > fTolerance)
00450     {
00451         return false;
00452     }
00453 
00454     // row/col 1
00455     fRowNorm = (fA10 >= fA12 ? fA10 : fA12);
00456     fColNorm = fA21;
00457     fTest = Math<Real>::FAbs((Real)1.0 - fColNorm/fRowNorm);
00458     if (fTest > fTolerance)
00459     {
00460         return false;
00461     }
00462 
00463     // row/col 2
00464     fRowNorm = (fA21 >= fA22 ? fA21 : fA22);
00465     fColNorm = (fA02 >= fA12 ? fA02 : fA12);
00466     if (fA22 > fColNorm)
00467     {
00468         fColNorm = fA22;
00469     }
00470     fTest = Math<Real>::FAbs((Real)1.0 - fColNorm/fRowNorm);
00471     return fTest <= fTolerance;
00472 }
00473 //----------------------------------------------------------------------------
00474 template <class Real>
00475 void PolynomialRoots<Real>::BalanceCompanion3 (GMatrix<Real>& rkMat)
00476 {
00477     Real fA10 = Math<Real>::FAbs(rkMat[1][0]);
00478     Real fA21 = Math<Real>::FAbs(rkMat[2][1]);
00479     Real fA02 = Math<Real>::FAbs(rkMat[0][2]);
00480     Real fA12 = Math<Real>::FAbs(rkMat[1][2]);
00481     Real fA22 = Math<Real>::FAbs(rkMat[2][2]);
00482     Real fRowNorm, fColNorm, fScale, fInvScale;
00483 
00484     const int iMax = 16;
00485     int i;
00486     for (i = 0; i < iMax; i++)
00487     {
00488         // balance row/col 0
00489         fRowNorm = fA02;
00490         fColNorm = fA10;
00491         fScale = Math<Real>::Sqrt(fColNorm/fRowNorm);
00492         fA02 *= fScale;
00493         fA10 = fA02;
00494 
00495         // balance row/col 1
00496         fRowNorm = (fA10 >= fA12 ? fA10 : fA12);
00497         fColNorm = fA21;
00498         fScale = Math<Real>::Sqrt(fColNorm/fRowNorm);
00499         fInvScale = ((Real)1.0)/fScale;
00500         fA10 *= fScale;
00501         fA12 *= fScale;
00502         fA21 *= fInvScale;
00503 
00504         // balance row/col 2
00505         fRowNorm = (fA21 >= fA22 ? fA21 : fA22);
00506         fColNorm = (fA02 >= fA12 ? fA02 : fA12);
00507         if (fA22 > fColNorm)
00508         {
00509             fColNorm = fA22;
00510         }
00511         fScale = Math<Real>::Sqrt(fColNorm/fRowNorm);
00512         fInvScale = ((Real)1.0)/fScale;
00513         fA21 *= fScale;
00514         fA02 *= fInvScale;
00515         fA12 *= fInvScale;
00516 
00517         if (IsBalancedCompanion3(fA10,fA21,fA02,fA12,fA22))
00518         {
00519             break;
00520         }
00521     }
00522     assert(i < iMax);
00523 
00524     rkMat[1][0] = (rkMat[1][0] >= (Real)0.0 ? fA10 : -fA10);
00525     rkMat[2][1] = (rkMat[2][1] >= (Real)0.0 ? fA21 : -fA21);
00526     rkMat[0][2] = (rkMat[0][2] >= (Real)0.0 ? fA02 : -fA02);
00527     rkMat[1][2] = (rkMat[1][2] >= (Real)0.0 ? fA12 : -fA12);
00528     rkMat[2][2] = (rkMat[2][2] >= (Real)0.0 ? fA22 : -fA22);
00529 }
00530 //----------------------------------------------------------------------------
00531 template <class Real>
00532 bool PolynomialRoots<Real>::QRIteration3 (GMatrix<Real>& rkMat)
00533 {
00534     GVector<Real> kW(3);
00535     Real fRHS, fTrace, fDet;
00536     for (int i = 0; i < m_iMaxIterations; i++)
00537     {
00538         fRHS = m_fEpsilon*(Math<Real>::FAbs(rkMat[0][0]) +
00539             Math<Real>::FAbs(rkMat[1][1]));
00540 
00541         if (Math<Real>::FAbs(rkMat[1][0]) <= fRHS)
00542         {
00543             // mat[0][0] is a root, solve the quadratic for the submatrix
00544             fTrace = rkMat[1][1] + rkMat[2][2];
00545             fDet = rkMat[1][1]*rkMat[2][2] - rkMat[1][2]*rkMat[2][1];
00546             FindA(fDet,-fTrace,(Real)1.0);
00547             m_afRoot[m_iCount++] = rkMat[0][0];
00548             return true;
00549         }
00550 
00551         fRHS = m_fEpsilon*(Math<Real>::FAbs(rkMat[1][1]) +
00552             Math<Real>::FAbs(rkMat[2][2]));
00553 
00554         if (Math<Real>::FAbs(rkMat[2][1]) <= fRHS)
00555         {
00556             // mat[2][2] is a root, solve the quadratic for the submatrix
00557             fTrace = rkMat[0][0] + rkMat[1][1];
00558             fDet = rkMat[0][0]*rkMat[1][1] - rkMat[0][1]*rkMat[1][0];
00559             FindA(fDet,-fTrace,(Real)1.0);
00560             m_afRoot[m_iCount++] = rkMat[2][2];
00561             return true;
00562         }
00563 
00564         FrancisQRStep(rkMat,kW);
00565     }
00566 
00567     // TO DO: In theory, cubic polynomials always have one real-valued root,
00568     // but if the maximum iterations were exceeded, what to do?  Some
00569     // experiments show that when the polynomial nearly has a double root,
00570     // the convergence of the algorithm is slow.  Maybe a random perturbation
00571     // to "kick" the system a bit might work?
00572     //
00573     // If you want to trap exceeding the maximum iterations, uncomment the
00574     // 'assert' line of code.
00575     //
00576     // assert( false );
00577 
00578     // For now, zero out the smallest subdiagonal entry to decouple the
00579     // matrix.
00580     if (Math<Real>::FAbs(rkMat[1][0]) <= Math<Real>::FAbs(rkMat[2][1]))
00581     {
00582         // mat[0][0] is a root, solve the quadratic for the submatrix
00583         fTrace = rkMat[1][1] + rkMat[2][2];
00584         fDet = rkMat[1][1]*rkMat[2][2] - rkMat[1][2]*rkMat[2][1];
00585         FindA(fDet,-fTrace,(Real)1.0);
00586         m_afRoot[m_iCount++] = rkMat[0][0];
00587     }
00588     else
00589     {
00590         // mat[2][2] is a root, solve the quadratic for the submatrix
00591         fTrace = rkMat[0][0] + rkMat[1][1];
00592         fDet = rkMat[0][0]*rkMat[1][1] - rkMat[0][1]*rkMat[1][0];
00593         FindA(fDet,-fTrace,(Real)1.0);
00594         m_afRoot[m_iCount++] = rkMat[2][2];
00595     }
00596 
00597     return true;
00598 }
00599 //----------------------------------------------------------------------------
00600 
00601 //----------------------------------------------------------------------------
00602 // degree 4
00603 //----------------------------------------------------------------------------
00604 template <class Real>
00605 bool PolynomialRoots<Real>::FindA (Real fC0, Real fC1, Real fC2, Real fC3,
00606     Real fC4)
00607 {
00608     if (Math<Real>::FAbs(fC4) <= m_fEpsilon)
00609     {
00610         // polynomial is cubic
00611         return FindA(fC0,fC1,fC2,fC3);
00612     }
00613 
00614     // make polynomial monic, x^4+c3*x^3+c2*x^2+c1*x+c0
00615     Real fInvC4 = ((Real)1.0)/fC4;
00616     fC0 *= fInvC4;
00617     fC1 *= fInvC4;
00618     fC2 *= fInvC4;
00619     fC3 *= fInvC4;
00620 
00621     // reduction to resolvent cubic polynomial y^3+r2*y^2+r1*y+r0 = 0
00622     Real fR0 = -fC3*fC3*fC0 + ((Real)4.0)*fC2*fC0 - fC1*fC1;
00623     Real fR1 = fC3*fC1 - ((Real)4.0)*fC0;
00624     Real fR2 = -fC2;
00625     FindA(fR0,fR1,fR2,(Real)1.0);  // always produces at least one root
00626     Real fY = m_afRoot[0];
00627 
00628     m_iCount = 0;
00629     Real fDiscr = ((Real)0.25)*fC3*fC3 - fC2 + fY;
00630     if (Math<Real>::FAbs(fDiscr) <= m_fEpsilon)
00631     {
00632         fDiscr = (Real)0.0;
00633     }
00634 
00635     if (fDiscr > (Real)0.0) 
00636     {
00637         Real fR = Math<Real>::Sqrt(fDiscr);
00638         Real fT1 = ((Real)0.75)*fC3*fC3 - fR*fR - ((Real)2.0)*fC2;
00639         Real fT2 = (((Real)4.0)*fC3*fC2 - ((Real)8.0)*fC1 - fC3*fC3*fC3) /
00640             (((Real)4.0)*fR);
00641 
00642         Real fTplus = fT1+fT2;
00643         Real fTminus = fT1-fT2;
00644         if (Math<Real>::FAbs(fTplus) <= m_fEpsilon) 
00645         {
00646             fTplus = (Real)0.0;
00647         }
00648         if (Math<Real>::FAbs(fTminus) <= m_fEpsilon) 
00649         {
00650             fTminus = (Real)0.0;
00651         }
00652 
00653         if (fTplus >= (Real)0.0)
00654         {
00655             Real fD = Math<Real>::Sqrt(fTplus);
00656             m_afRoot[0] = -((Real)0.25)*fC3+((Real)0.5)*(fR+fD);
00657             m_afRoot[1] = -((Real)0.25)*fC3+((Real)0.5)*(fR-fD);
00658             m_iCount += 2;
00659         }
00660         if (fTminus >= (Real)0.0)
00661         {
00662             Real fE = Math<Real>::Sqrt(fTminus);
00663             m_afRoot[m_iCount++] = -((Real)0.25)*fC3+((Real)0.5)*(fE-fR);
00664             m_afRoot[m_iCount++] = -((Real)0.25)*fC3-((Real)0.5)*(fE+fR);
00665         }
00666     }
00667     else if (fDiscr < (Real)0.0)
00668     {
00669         m_iCount = 0;
00670     }
00671     else
00672     {
00673         Real fT2 = fY*fY-((Real)4.0)*fC0;
00674         if (fT2 >= -m_fEpsilon) 
00675         {
00676             if (fT2 < (Real)0.0) // round to zero
00677             {
00678                 fT2 = (Real)0.0;
00679             }
00680             fT2 = ((Real)2.0)*Math<Real>::Sqrt(fT2);
00681             Real fT1 = ((Real)0.75)*fC3*fC3 - ((Real)2.0)*fC2;
00682             if (fT1+fT2 >= m_fEpsilon) 
00683             {
00684                 Real fD = Math<Real>::Sqrt(fT1+fT2);
00685                 m_afRoot[0] = -((Real)0.25)*fC3+((Real)0.5)*fD;
00686                 m_afRoot[1] = -((Real)0.25)*fC3-((Real)0.5)*fD;
00687                 m_iCount += 2;
00688             }
00689             if (fT1-fT2 >= m_fEpsilon) 
00690             {
00691                 Real fE = Math<Real>::Sqrt(fT1-fT2);
00692                 m_afRoot[m_iCount++] = -((Real)0.25)*fC3+((Real)0.5)*fE;
00693                 m_afRoot[m_iCount++] = -((Real)0.25)*fC3-((Real)0.5)*fE;
00694             }
00695         }
00696     }
00697 
00698     return m_iCount > 0;
00699 }
00700 //----------------------------------------------------------------------------
00701 template <class Real>
00702 bool PolynomialRoots<Real>::FindE (Real fC0, Real fC1, Real fC2, Real fC3,
00703     Real fC4, bool bDoBalancing)
00704 {
00705     if (Math<Real>::FAbs(fC4) <= m_fEpsilon)
00706     {
00707         // polynomial is cubic
00708         return FindA(fC0,fC1,fC2,fC3);
00709     }
00710 
00711     // make polynomial monic, x^4+c3*x^3+c2*x^2+c1*x+c0
00712     Real fInvC4 = ((Real)1.0)/fC4;
00713     fC0 *= fInvC4;
00714     fC1 *= fInvC4;
00715     fC2 *= fInvC4;
00716     fC3 *= fInvC4;
00717 
00718     // construct the 4-by-4 companion matrix
00719     GMatrix<Real> kMat(4,4);  // initialized to zero
00720     kMat[1][0] = (Real)1.0;
00721     kMat[2][1] = (Real)1.0;
00722     kMat[3][2] = (Real)1.0;
00723     kMat[0][3] = -fC0;
00724     kMat[1][3] = -fC1;
00725     kMat[2][3] = -fC2;
00726     kMat[3][3] = -fC3;
00727 
00728     if (bDoBalancing)
00729     {
00730         BalanceCompanion4(kMat);
00731     }
00732 
00733     return QRIteration4(kMat);
00734 }
00735 //----------------------------------------------------------------------------
00736 template <class Real>
00737 Real PolynomialRoots<Real>::GetBound (Real fC0, Real fC1, Real fC2, Real fC3,
00738     Real fC4)
00739 {
00740     if (Math<Real>::FAbs(fC4) <= m_fEpsilon)
00741     {
00742         // polynomial is cubic
00743         return GetBound(fC0,fC1,fC2,fC3);
00744     }
00745 
00746     Real fInvC4 = ((Real)1.0)/fC4;
00747     Real fMax = Math<Real>::FAbs(fC0)*fInvC4;
00748 
00749     Real fTmp = Math<Real>::FAbs(fC1)*fInvC4;
00750     if (fTmp > fMax)
00751     {
00752         fMax = fTmp;
00753     }
00754 
00755     fTmp = Math<Real>::FAbs(fC2)*fInvC4;
00756     if (fTmp > fMax)
00757     {
00758         fMax = fTmp;
00759     }
00760 
00761     fTmp = Math<Real>::FAbs(fC3)*fInvC4;
00762     if (fTmp > fMax)
00763     {
00764         fMax = fTmp;
00765     }
00766 
00767     return (Real)1.0 + fMax;
00768 }
00769 //----------------------------------------------------------------------------
00770 template <class Real>
00771 bool PolynomialRoots<Real>::IsBalancedCompanion4 (Real fA10, Real fA21,
00772     Real fA32, Real fA03, Real fA13, Real fA23, Real fA33)
00773 {
00774     const Real fTolerance = (Real)0.001;
00775 
00776     // row/col 0
00777     Real fRowNorm = fA03;
00778     Real fColNorm = fA10;
00779     Real fTest = Math<Real>::FAbs(1.0f - fColNorm/fRowNorm);
00780     if (fTest > fTolerance)
00781     {
00782         return false;
00783     }
00784 
00785     // row/col 1
00786     fRowNorm = (fA10 >= fA13 ? fA10 : fA13);
00787     fColNorm = fA21;
00788     fTest = Math<Real>::FAbs(1.0f - fColNorm/fRowNorm);
00789     if (fTest > fTolerance)
00790     {
00791         return false;
00792     }
00793 
00794     // row/col 2
00795     fRowNorm = (fA21 >= fA23 ? fA21 : fA23);
00796     fColNorm = fA32;
00797     fTest = Math<Real>::FAbs(1.0f - fColNorm/fRowNorm);
00798     if (fTest > fTolerance)
00799     {
00800         return false;
00801     }
00802 
00803     // row/col 3
00804     fRowNorm = (fA32 >= fA33 ? fA32 : fA33);
00805     fColNorm = (fA03 >= fA13 ? fA03 : fA13);
00806     if (fA23 > fColNorm)
00807     {
00808         fColNorm = fA23;
00809     }
00810     if (fA33 > fColNorm)
00811     {
00812         fColNorm = fA33;
00813     }
00814     fTest = Math<Real>::FAbs(1.0f - fColNorm/fRowNorm);
00815     return fTest <= fTolerance;
00816 }
00817 //----------------------------------------------------------------------------
00818 template <class Real>
00819 void PolynomialRoots<Real>::BalanceCompanion4 (GMatrix<Real>& rkMat)
00820 {
00821     Real fA10 = Math<Real>::FAbs(rkMat[1][0]);
00822     Real fA21 = Math<Real>::FAbs(rkMat[2][1]);
00823     Real fA32 = Math<Real>::FAbs(rkMat[3][2]);
00824     Real fA03 = Math<Real>::FAbs(rkMat[0][3]);
00825     Real fA13 = Math<Real>::FAbs(rkMat[1][3]);
00826     Real fA23 = Math<Real>::FAbs(rkMat[2][3]);
00827     Real fA33 = Math<Real>::FAbs(rkMat[3][3]);
00828     Real fRowNorm, fColNorm, fScale, fInvScale;
00829 
00830     const int iMax = 16;
00831     int i;
00832     for (i = 0; i < iMax; i++)
00833     {
00834         // balance row/col 0
00835         fRowNorm = fA03;
00836         fColNorm = fA10;
00837         fScale = Math<Real>::Sqrt(fColNorm/fRowNorm);
00838         fA03 *= fScale;
00839         fA10 = fA03;
00840 
00841         // balance row/col 1
00842         fRowNorm = (fA10 >= fA13 ? fA10 : fA13);
00843         fColNorm = fA21;
00844         fScale = Math<Real>::Sqrt(fColNorm/fRowNorm);
00845         fInvScale = ((Real)1.0)/fScale;
00846         fA10 *= fScale;
00847         fA13 *= fScale;
00848         fA21 *= fInvScale;
00849 
00850         // balance row/col 2
00851         fRowNorm = (fA21 >= fA23 ? fA21 : fA23);
00852         fColNorm = fA32;
00853         fScale = Math<Real>::Sqrt(fColNorm/fRowNorm);
00854         fInvScale = ((Real)1.0)/fScale;
00855         fA21 *= fScale;
00856         fA23 *= fScale;
00857         fA32 *= fInvScale;
00858 
00859         // balance row/col 3
00860         fRowNorm = (fA32 >= fA33 ? fA32 : fA33);
00861         fColNorm = (fA03 >= fA13 ? fA03 : fA13);
00862         if (fA23 > fColNorm)
00863         {
00864             fColNorm = fA23;
00865         }
00866         if (fA33 > fColNorm)
00867         {
00868             fColNorm = fA33;
00869         }
00870         fScale = Math<Real>::Sqrt(fColNorm/fRowNorm);
00871         fInvScale = ((Real)1.0)/fScale;
00872         fA32 *= fScale;
00873         fA03 *= fInvScale;
00874         fA13 *= fInvScale;
00875         fA23 *= fInvScale;
00876 
00877         if (IsBalancedCompanion4(fA10,fA21,fA32,fA03,fA13,fA23,fA33))
00878         {
00879             break;
00880         }
00881     }
00882     assert(i < iMax);
00883 
00884     rkMat[1][0] = (rkMat[1][0] >= (Real)0.0 ? fA10 : -fA10);
00885     rkMat[2][1] = (rkMat[2][1] >= (Real)0.0 ? fA21 : -fA21);
00886     rkMat[3][2] = (rkMat[3][2] >= (Real)0.0 ? fA32 : -fA32);
00887     rkMat[0][3] = (rkMat[0][3] >= (Real)0.0 ? fA03 : -fA03);
00888     rkMat[1][3] = (rkMat[1][3] >= (Real)0.0 ? fA13 : -fA13);
00889     rkMat[2][3] = (rkMat[2][3] >= (Real)0.0 ? fA23 : -fA23);
00890     rkMat[3][3] = (rkMat[3][3] >= (Real)0.0 ? fA33 : -fA33);
00891 }
00892 //----------------------------------------------------------------------------
00893 template <class Real>
00894 bool PolynomialRoots<Real>::QRIteration4 (GMatrix<Real>& rkMat)
00895 {
00896     GVector<Real> kW(4);
00897     GMatrix<Real> kMS(3,3);
00898     Real fRHS, fTrace, fDet, afSaveRoot[2];
00899     int i, j, iSaveCount;
00900     for (i = 0; i < m_iMaxIterations; i++)
00901     {
00902         fRHS = m_fEpsilon*(Math<Real>::FAbs(rkMat[0][0]) +
00903             Math<Real>::FAbs(rkMat[1][1]));
00904 
00905         if (Math<Real>::FAbs(rkMat[1][0]) <= fRHS)
00906         {
00907             // mat[0][0] is a root, reduce the 3-by-3 submatrix
00908             // TO DO:  Avoid the copy and pass row/column offsets to the
00909             // FrancisQR method.
00910             kMS[0][0] = rkMat[1][1];
00911             kMS[0][1] = rkMat[1][2];
00912             kMS[0][2] = rkMat[1][3];
00913             kMS[1][0] = rkMat[2][1];
00914             kMS[1][1] = rkMat[2][2];
00915             kMS[1][2] = rkMat[2][3];
00916             kMS[2][0] = rkMat[3][1];
00917             kMS[2][1] = rkMat[3][2];
00918             kMS[2][2] = rkMat[3][3];
00919             QRIteration3(kMS);
00920             m_afRoot[m_iCount++] = rkMat[0][0];
00921             return true;
00922         }
00923 
00924         fRHS = m_fEpsilon*(Math<Real>::FAbs(rkMat[1][1]) +
00925             Math<Real>::FAbs(rkMat[2][2]));
00926 
00927         if (Math<Real>::FAbs(rkMat[2][1]) <= fRHS)
00928         {
00929             // The matrix is decoupled into two 2-by-2 blocks.  Solve the
00930             // quadratics for the blocks.
00931             fTrace = rkMat[0][0] + rkMat[1][1];
00932             fDet = rkMat[0][0]*rkMat[1][1] - rkMat[0][1]*rkMat[1][0];
00933             FindA(fDet,-fTrace,(Real)1.0);
00934             iSaveCount = m_iCount;
00935             for (j = 0; j < iSaveCount; j++)
00936             {
00937                 afSaveRoot[j] = m_afRoot[j];
00938             }
00939 
00940             fTrace = rkMat[2][2] + rkMat[3][3];
00941             fDet = rkMat[2][2]*rkMat[3][3] - rkMat[2][3]*rkMat[3][2];
00942             FindA(fDet,-fTrace,(Real)1.0);
00943             for (j = 0; j < iSaveCount; j++)
00944             {
00945                 m_afRoot[m_iCount++] = afSaveRoot[j];
00946             }
00947             return m_iCount > 0;
00948         }
00949 
00950         fRHS = m_fEpsilon*(Math<Real>::FAbs(rkMat[2][2]) +
00951             Math<Real>::FAbs(rkMat[3][3]));
00952 
00953         if (Math<Real>::FAbs(rkMat[3][2]) <= fRHS)
00954         {
00955             // mat[3][3] is a root, reduce the 3-by-3 submatrix
00956             // TO DO:  Avoid the copy and pass row/column offsets to the
00957             // FrancisQR method.
00958             kMS[0][0] = rkMat[0][0];
00959             kMS[0][1] = rkMat[0][1];
00960             kMS[0][2] = rkMat[0][2];
00961             kMS[1][0] = rkMat[1][0];
00962             kMS[1][1] = rkMat[1][1];
00963             kMS[1][2] = rkMat[1][2];
00964             kMS[2][0] = rkMat[2][0];
00965             kMS[2][1] = rkMat[2][1];
00966             kMS[2][2] = rkMat[2][2];
00967             QRIteration3(kMS);
00968             m_afRoot[m_iCount++] = rkMat[3][3];
00969             return true;
00970         }
00971 
00972         FrancisQRStep(rkMat,kW);
00973     }
00974 
00975     // TO DO:  What to do if the maximum iterations were exceeded?  Maybe a
00976     // random perturbation to "kick" the system a bit might work?
00977     //
00978     // If you want to trap exceeding the maximum iterations, uncomment the
00979     // 'assert' line of code.
00980     //
00981     // assert( false );
00982 
00983     // For now, decouple the matrix using the smallest subdiagonal entry.
00984     i = 0;
00985     Real fMin = Math<Real>::FAbs(rkMat[1][0]);
00986     Real fAbs = Math<Real>::FAbs(rkMat[2][1]);
00987     if (fAbs < fMin)
00988     {
00989         fMin = fAbs;
00990         i = 1;
00991     }
00992     fAbs = Math<Real>::FAbs(rkMat[3][2]);
00993     if (fAbs < fMin)
00994     {
00995         fMin = fAbs;
00996         i = 2;
00997     }
00998 
00999     if (i == 0)
01000     {
01001         // mat[0][0] is a root, reduce the 3-by-3 submatrix
01002         // TO DO:  Avoid the copy and pass row/column offsets to the
01003         // FrancisQR method.
01004         kMS[0][0] = rkMat[1][1];
01005         kMS[0][1] = rkMat[1][2];
01006         kMS[0][2] = rkMat[1][3];
01007         kMS[1][0] = rkMat[2][1];
01008         kMS[1][1] = rkMat[2][2];
01009         kMS[1][2] = rkMat[2][3];
01010         kMS[2][0] = rkMat[3][1];
01011         kMS[2][1] = rkMat[3][2];
01012         kMS[2][2] = rkMat[3][3];
01013         QRIteration3(kMS);
01014         m_afRoot[m_iCount++] = rkMat[0][0];
01015     }
01016     else if (i == 1)
01017     {
01018         // The matrix is decoupled into two 2-by-2 blocks.  Solve the
01019         // quadratics for the blocks.
01020         fTrace = rkMat[0][0] + rkMat[1][1];
01021         fDet = rkMat[0][0]*rkMat[1][1] - rkMat[0][1]*rkMat[1][0];
01022         FindA(fDet,-fTrace,(Real)1.0);
01023         iSaveCount = m_iCount;
01024         for (j = 0; j < iSaveCount; j++)
01025         {
01026             afSaveRoot[j] = m_afRoot[j];
01027         }
01028 
01029         fTrace = rkMat[2][2] + rkMat[3][3];
01030         fDet = rkMat[2][2]*rkMat[3][3] - rkMat[2][3]*rkMat[3][2];
01031         FindA(fDet,-fTrace,(Real)1.0);
01032         for (j = 0; j < iSaveCount; j++)
01033         {
01034             m_afRoot[m_iCount++] = afSaveRoot[j];
01035         }
01036     }
01037     else  // i == 2
01038     {
01039         // mat[3][3] is a root, reduce the 3-by-3 submatrix
01040         // TO DO:  Avoid the copy and pass row/column offsets to the
01041         // FrancisQR method.
01042         kMS[0][0] = rkMat[0][0];
01043         kMS[0][1] = rkMat[0][1];
01044         kMS[0][2] = rkMat[0][2];
01045         kMS[1][0] = rkMat[1][0];
01046         kMS[1][1] = rkMat[1][1];
01047         kMS[1][2] = rkMat[1][2];
01048         kMS[2][0] = rkMat[2][0];
01049         kMS[2][1] = rkMat[2][1];
01050         kMS[2][2] = rkMat[2][2];
01051         QRIteration3(kMS);
01052         m_afRoot[m_iCount++] = rkMat[3][3];
01053     }
01054 
01055     return m_iCount > 0;
01056 }
01057 //----------------------------------------------------------------------------
01058 
01059 //----------------------------------------------------------------------------
01060 // degree N
01061 //----------------------------------------------------------------------------
01062 template <class Real>
01063 bool PolynomialRoots<Real>::FindB (const Polynomial1<Real>& rkPoly,
01064     int iDigits)
01065 {
01066     Real fBound = GetBound(rkPoly);
01067     return FindB(rkPoly,-fBound,fBound,iDigits);
01068 }
01069 //----------------------------------------------------------------------------
01070 template <class Real>
01071 bool PolynomialRoots<Real>::FindN (const Polynomial1<Real>&, int)
01072 {
01073     // TO DO:  Implement this.
01074     assert(false);
01075     return false;
01076 }
01077 //----------------------------------------------------------------------------
01078 template <class Real>
01079 bool PolynomialRoots<Real>::FindE (const Polynomial1<Real>&, bool)
01080 {
01081     // TO DO:  Implement this.
01082     assert(false);
01083     return false;
01084 }
01085 //----------------------------------------------------------------------------
01086 template <class Real>
01087 Real PolynomialRoots<Real>::GetBound (const Polynomial1<Real>& rkPoly)
01088 {
01089     Polynomial1<Real> kCPoly = rkPoly;
01090     kCPoly.Compress(m_fEpsilon);
01091     int iDegree = kCPoly.GetDegree();
01092     if (iDegree < 1)
01093     {
01094         // polynomial is constant, return invalid bound
01095         return -(Real)1.0;
01096     }
01097 
01098     Real fInvCDeg = ((Real)1.0)/kCPoly[iDegree];
01099     Real fMax = (Real)0.0;
01100     for (int i = 0; i < iDegree; i++)
01101     {
01102         Real fTmp = Math<Real>::FAbs(kCPoly[i])*fInvCDeg;
01103         if (fTmp > fMax)
01104         {
01105             fMax = fTmp;
01106         }
01107     }
01108 
01109     return (Real)1.0 + fMax;
01110 }
01111 //----------------------------------------------------------------------------
01112 template <class Real>
01113 bool PolynomialRoots<Real>::FindB (const Polynomial1<Real>& rkPoly,
01114     Real fXMin, Real fXMax, int iDigits)
01115 {
01116     // reallocate root array if necessary
01117     if (rkPoly.GetDegree() > m_iMaxRoot)
01118     {
01119         m_iMaxRoot = rkPoly.GetDegree();
01120         WM4_DELETE[] m_afRoot;
01121         m_afRoot = WM4_NEW Real[m_iMaxRoot];
01122     }
01123 
01124     Real fRoot;
01125     if (rkPoly.GetDegree() == 1)
01126     {
01127         if (Bisection(rkPoly,fXMin,fXMax,iDigits,fRoot))
01128         {
01129             m_iCount = 1;
01130             m_afRoot[0] = fRoot;
01131             return true;
01132         }
01133         m_iCount = 0;
01134         return false;
01135     }
01136 
01137     // get roots of derivative polynomial
01138     Polynomial1<Real> kDeriv = rkPoly.GetDerivative();
01139     FindB(kDeriv,fXMin,fXMax,iDigits);
01140 
01141     int i, iNewCount = 0;
01142     Real* afNewRoot = WM4_NEW Real[m_iCount+1];
01143 
01144     if ( m_iCount > 0 )
01145     {
01146         // find root on [xmin,root[0]]
01147         if (Bisection(rkPoly,fXMin,m_afRoot[0],iDigits,fRoot))
01148         {
01149             afNewRoot[iNewCount++] = fRoot;
01150         }
01151 
01152         // find root on [root[i],root[i+1]] for 0 <= i <= count-2
01153         for (i = 0; i <= m_iCount-2; i++)
01154         {
01155             if (Bisection(rkPoly,m_afRoot[i],m_afRoot[i+1],iDigits,fRoot))
01156             {
01157                 afNewRoot[iNewCount++] = fRoot;
01158             }
01159         }
01160 
01161         // find root on [root[count-1],xmax]
01162         if (Bisection(rkPoly,m_afRoot[m_iCount-1],fXMax,iDigits,fRoot))
01163         {
01164             afNewRoot[iNewCount++] = fRoot;
01165         }
01166     }
01167     else
01168     {
01169         // polynomial is monotone on [xmin,xmax], has at most one root
01170         if (Bisection(rkPoly,fXMin,fXMax,iDigits,fRoot))
01171         {
01172             afNewRoot[iNewCount++] = fRoot;
01173         }
01174     }
01175 
01176     // copy to old buffer
01177     if (iNewCount > 0)
01178     {
01179         m_iCount = 1;
01180         m_afRoot[0] = afNewRoot[0];
01181         for (i = 1; i < iNewCount; i++)
01182         {
01183             Real fRootDiff = afNewRoot[i]-afNewRoot[i-1];
01184             if (Math<Real>::FAbs(fRootDiff) > m_fEpsilon)
01185             {
01186                 m_afRoot[m_iCount++] = afNewRoot[i];
01187             }
01188         }
01189     }
01190     else
01191     {
01192         m_iCount = 0;
01193     }
01194 
01195     WM4_DELETE[] afNewRoot;
01196     return m_iCount > 0;
01197 }
01198 //----------------------------------------------------------------------------
01199 template <class Real>
01200 bool PolynomialRoots<Real>::FindN (const Polynomial1<Real>&, Real, Real, int)
01201 {
01202     // TO DO:  Implement this.
01203     assert(false);
01204     return false;
01205 }
01206 //----------------------------------------------------------------------------
01207 template <class Real>
01208 bool PolynomialRoots<Real>::AllRealPartsNegative (
01209     const Polynomial1<Real>& rkPoly)
01210 {
01211     // make a copy of coefficients, later calls will change the copy
01212     int iDegree = rkPoly.GetDegree();
01213     const Real* afPolyCoeff = (const Real*)rkPoly;
01214     Real* afCoeff = WM4_NEW Real[iDegree+1];
01215     size_t uiSize = (iDegree+1)*sizeof(Real);
01216     System::Memcpy(afCoeff,uiSize,afPolyCoeff,uiSize);
01217 
01218     // make polynomial monic
01219     if (afCoeff[iDegree] != (Real)1.0)
01220     {
01221         Real fInv = ((Real)1.0)/afCoeff[iDegree];
01222         for (int i = 0; i < iDegree; i++)
01223         {
01224             afCoeff[i] *= fInv;
01225         }
01226         afCoeff[iDegree] = (Real)1.0;
01227     }
01228 
01229     return AllRealPartsNegative(iDegree,afCoeff);
01230 }
01231 //----------------------------------------------------------------------------
01232 template <class Real>
01233 bool PolynomialRoots<Real>::AllRealPartsPositive (
01234     const Polynomial1<Real>& rkPoly)
01235 {
01236     // make a copy of coefficients, later calls will change the copy
01237     int iDegree = rkPoly.GetDegree();
01238     const Real* afPolyCoeff = (const Real*)rkPoly;
01239     Real* afCoeff = WM4_NEW Real[iDegree+1];
01240     size_t uiSize = (iDegree+1)*sizeof(Real);
01241     System::Memcpy(afCoeff,uiSize,afPolyCoeff,uiSize);
01242 
01243     // make polynomial monic
01244     int i;
01245     if (afCoeff[iDegree] != (Real)1.0)
01246     {
01247         Real fInv = ((Real)1.0)/afCoeff[iDegree];
01248         for (i = 0; i < iDegree; i++)
01249         {
01250             afCoeff[i] *= fInv;
01251         }
01252         afCoeff[iDegree] = (Real)1.0;
01253     }
01254 
01255     // reflect z -> -z
01256     int iSign = -1;
01257     for (i = iDegree-1; i >= 0; i--, iSign = -iSign)
01258     {
01259         afCoeff[i] *= iSign;
01260     }
01261 
01262     return AllRealPartsNegative(iDegree,afCoeff);
01263 }
01264 //----------------------------------------------------------------------------
01265 template <class Real>
01266 bool PolynomialRoots<Real>::AllRealPartsNegative (int iDegree, Real* afCoeff)
01267 {
01268     // assert:  afCoeff[iDegree] = 1
01269 
01270     if (afCoeff[iDegree-1] <= (Real)0.0)
01271     {
01272         return false;
01273     }
01274     if (iDegree == 1)
01275     {
01276         return true;
01277     }
01278 
01279     Real* afTmpCoeff = WM4_NEW Real[iDegree];
01280     afTmpCoeff[0] = ((Real)2.0)*afCoeff[0]*afCoeff[iDegree-1];
01281     int i;
01282     for (i = 1; i <= iDegree-2; i++) 
01283     {
01284         afTmpCoeff[i] = afCoeff[iDegree-1]*afCoeff[i];
01285         if (((iDegree-i) % 2) == 0)
01286         {
01287             afTmpCoeff[i] -= afCoeff[i-1];
01288         }
01289         afTmpCoeff[i] *= (Real)2.0;
01290     }
01291     afTmpCoeff[iDegree-1] =
01292         ((Real)2.0)*afCoeff[iDegree-1]*afCoeff[iDegree-1];
01293 
01294     int iNextDegree;
01295     for (iNextDegree = iDegree-1; iNextDegree >= 0; iNextDegree--)
01296     {
01297         if (afTmpCoeff[iNextDegree] != (Real)0.0)
01298         {
01299             break;
01300         }
01301     }
01302     for (i = 0; i <= iNextDegree-1; i++)
01303     {
01304         afCoeff[i] = afTmpCoeff[i]/afTmpCoeff[iNextDegree];
01305     }
01306     WM4_DELETE[] afTmpCoeff;
01307 
01308     return AllRealPartsNegative(iNextDegree,afCoeff);
01309 }
01310 //----------------------------------------------------------------------------
01311 template <class Real>
01312 int PolynomialRoots<Real>::GetRootCount (const Polynomial1<Real>& rkPoly,
01313     Real fT0, Real fT1)
01314 {
01315     int iDegree = rkPoly.GetDegree();
01316     const Real* afCoeff = (const Real*)rkPoly;
01317 
01318     if (iDegree == 0)
01319     {
01320         // polynomial is constant on the interval
01321         if (afCoeff[0] != (Real)0.0)
01322         {
01323             return 0;
01324         }
01325         else
01326         {
01327             return -1;  // to indicate "infinitely many"
01328         }
01329     }
01330 
01331     // generate the Sturm sequence
01332     std::vector<Polynomial1<Real>*> kSturm;
01333     Polynomial1<Real>* pkF0 = WM4_NEW Polynomial1<Real>(rkPoly);
01334     Polynomial1<Real>* pkF1 = WM4_NEW Polynomial1<Real>(
01335         pkF0->GetDerivative());
01336     kSturm.push_back(pkF0);
01337     kSturm.push_back(pkF1);
01338 
01339     while (pkF1->GetDegree() > 0)
01340     {
01341         Polynomial1<Real>* pkF2 = WM4_NEW Polynomial1<Real>(-1);
01342         Polynomial1<Real> kQuot;
01343         pkF0->Divide(*pkF1,kQuot,*pkF2,Math<Real>::ZERO_TOLERANCE);
01344         *pkF2 = -(*pkF2);
01345         kSturm.push_back(pkF2);
01346         pkF0 = pkF1;
01347         pkF1 = pkF2;
01348     }
01349 
01350     int i;
01351     Real fValue0, fValue1;
01352 
01353     // count the sign changes at t0
01354     int iSignChanges0 = 0;
01355     if (fT0 == -Math<Real>::MAX_REAL)
01356     {
01357         pkF0 = kSturm[0];
01358         if (pkF0->GetDegree() & 1)
01359         {
01360             fValue0 = -(*pkF0)[pkF0->GetDegree()];
01361         }
01362         else
01363         {
01364             fValue0 = (*pkF0)[pkF0->GetDegree()];
01365         }
01366 
01367         if (Math<Real>::FAbs(fValue0) < m_fEpsilon)
01368         {
01369             fValue0 = (Real)0.0;
01370         }
01371 
01372         for (i = 1; i < (int)kSturm.size(); i++)
01373         {
01374             pkF1 = kSturm[i];
01375 
01376             if (pkF1->GetDegree() & 1)
01377             {
01378                 fValue1 = -(*pkF1)[pkF1->GetDegree()];
01379             }
01380             else
01381             {
01382                 fValue1 = (*pkF1)[pkF1->GetDegree()];
01383             }
01384 
01385             if (Math<Real>::FAbs(fValue1) < m_fEpsilon)
01386             {
01387                 fValue1 = (Real)0.0;
01388             }
01389 
01390             if (fValue0*fValue1 < (Real)0.0 || fValue0 == (Real)0.0)
01391             {
01392                 iSignChanges0++;
01393             }
01394 
01395             fValue0 = fValue1;
01396             pkF0 = pkF1;
01397         }
01398     }
01399     else
01400     {
01401         pkF0 = kSturm[0];
01402         fValue0 = (*pkF0)(fT0);
01403         if (Math<Real>::FAbs(fValue0) < m_fEpsilon)
01404         {
01405             fValue0 = (Real)0.0;
01406         }
01407 
01408         for (i = 1; i < (int)kSturm.size(); i++)
01409         {
01410             pkF1 = kSturm[i];
01411             fValue1 = (*pkF1)(fT0);
01412             if (Math<Real>::FAbs(fValue1) < m_fEpsilon)
01413             {
01414                 fValue1 = (Real)0.0;
01415             }
01416 
01417             if (fValue0*fValue1 < (Real)0.0 || fValue0 == (Real)0.0)
01418             {
01419                 iSignChanges0++;
01420             }
01421 
01422             fValue0 = fValue1;
01423             pkF0 = pkF1;
01424         }
01425     }
01426 
01427     // count the sign changes at t1
01428     int iSignChanges1 = 0;
01429     if (fT1 == Math<Real>::MAX_REAL)
01430     {
01431         pkF0 = kSturm[0];
01432         fValue0 = (*pkF0)[pkF0->GetDegree()];
01433         if (Math<Real>::FAbs(fValue0) < m_fEpsilon)
01434         {
01435             fValue0 = (Real)0.0;
01436         }
01437 
01438         for (i = 1; i < (int)kSturm.size(); i++)
01439         {
01440             pkF1 = kSturm[i];
01441             fValue1 = (*pkF1)[pkF1->GetDegree()];
01442             if (Math<Real>::FAbs(fValue1) < m_fEpsilon)
01443             {
01444                 fValue1 = (Real)0.0;
01445             }
01446 
01447             if (fValue0*fValue1 < (Real)0.0 || fValue0 == (Real)0.0)
01448             {
01449                 iSignChanges1++;
01450             }
01451 
01452             fValue0 = fValue1;
01453             pkF0 = pkF1;
01454         }
01455     }
01456     else
01457     {
01458         pkF0 = kSturm[0];
01459         fValue0 = (*pkF0)(fT1);
01460         if (Math<Real>::FAbs(fValue0) < m_fEpsilon)
01461         {
01462             fValue0 = (Real)0.0;
01463         }
01464 
01465         for (i = 1; i < (int)kSturm.size(); i++)
01466         {
01467             pkF1 = kSturm[i];
01468             fValue1 = (*pkF1)(fT1);
01469             if (Math<Real>::FAbs(fValue1) < m_fEpsilon)
01470             {
01471                 fValue1 = (Real)0.0;
01472             }
01473 
01474             if (fValue0*fValue1 < (Real)0.0 || fValue0 == (Real)0.0 )
01475             {
01476                 iSignChanges1++;
01477             }
01478 
01479             fValue0 = fValue1;
01480             pkF0 = pkF1;
01481         }
01482     }
01483 
01484     // clean up
01485     for (i = 0; i < (int)kSturm.size(); i++)
01486     {
01487         WM4_DELETE kSturm[i];
01488     }
01489 
01490     if (iSignChanges0 >= iSignChanges1)
01491     {
01492         return iSignChanges0 - iSignChanges1;
01493     }
01494 
01495     // theoretically we should not get here
01496     assert(false);
01497     return 0;
01498 }
01499 //----------------------------------------------------------------------------
01500 template <class Real>
01501 bool PolynomialRoots<Real>::Bisection (const Polynomial1<Real>& rkPoly,
01502     Real fXMin, Real fXMax, int iDigits, Real& rfRoot)
01503 {
01504     Real fP0 = rkPoly(fXMin);
01505     if (Math<Real>::FAbs(fP0) <= Math<Real>::ZERO_TOLERANCE)
01506     {
01507         rfRoot = fXMin;
01508         return true;
01509     }
01510     Real fP1 = rkPoly(fXMax);
01511     if (Math<Real>::FAbs(fP1) <= Math<Real>::ZERO_TOLERANCE)
01512     {
01513         rfRoot = fXMax;
01514         return true;
01515     }
01516     if (fP0*fP1 > (Real)0.0)
01517         return false;
01518 
01519     // determine number of iterations to get 'digits' accuracy.
01520     Real fTmp0 = Math<Real>::Log(fXMax-fXMin);
01521     Real fTmp1 = ((Real)iDigits)*Math<Real>::Log((Real)10.0);
01522     Real fArg = (fTmp0 + fTmp1)/Math<Real>::Log((Real)2.0);
01523     int iMaxIter = (int)(fArg + (Real)0.5);
01524 
01525     for (int i = 0; i < iMaxIter; i++)
01526     {
01527         rfRoot = ((Real)0.5)*(fXMin + fXMax);
01528         Real fP = rkPoly(rfRoot);
01529         Real fProduct = fP*fP0;
01530         if (fProduct < (Real)0.0)
01531         {
01532             fXMax = rfRoot;
01533             fP1 = fP;
01534         }
01535         else if (fProduct > (Real)0.0)
01536         {
01537             fXMin = rfRoot;
01538             fP0 = fP;
01539         }
01540         else
01541         {
01542             break;
01543         }
01544     }
01545 
01546     return true;
01547 }
01548 //----------------------------------------------------------------------------
01549 
01550 //----------------------------------------------------------------------------
01551 // FindE support
01552 //----------------------------------------------------------------------------
01553 template <class Real>
01554 void PolynomialRoots<Real>::GetHouseholderVector (int iSize,
01555     const Vector3<Real>& rkU, Vector3<Real>& rkV)
01556 {
01557     // Householder vector V:
01558     // Given a vector U, compute a vector V such that V[0] = 1 and
01559     // (I-2*V*V^T/|V|^2)*U is zero in all but the first component.  The
01560     // matrix P = I-2*V*V^T/|V|^2 is a Householder transformation, a
01561     // reflection matrix.
01562 
01563     Real fLength = rkU[0]*rkU[0];
01564     int i;
01565     for (i = 1; i < iSize; i++)
01566     {
01567         fLength += rkU[i]*rkU[i];
01568     }
01569     fLength = Math<Real>::Sqrt(fLength);
01570 
01571     if (fLength > m_fEpsilon)
01572     {
01573         Real fInv = ((Real)1.0)/(rkU[0]+Math<Real>::Sign(rkU[0])*fLength);
01574         rkV[0] = (Real)1.0;
01575         for (i = 1; i < iSize; i++)
01576         {
01577             rkV[i] = fInv*rkU[i];
01578         }
01579     }
01580     else
01581     {
01582         // U is the zero vector, any vector will do
01583         rkV[0] = (Real)1.0;
01584         for (i = 1; i < iSize; i++)
01585         {
01586             rkV[i] = (Real)0.0;
01587         }
01588     }
01589 }
01590 //----------------------------------------------------------------------------
01591 template <class Real>
01592 void PolynomialRoots<Real>::PremultiplyHouseholder (GMatrix<Real>& rkMat,
01593     GVector<Real>& rkW, int iRMin, int iRMax, int iCMin, int iCMax,
01594     int iVSize, const Vector3<Real>& rkV)
01595 {
01596     // Householder premultiplication:
01597     // Given a matrix A and an m-by-1 vector V with V[0] = 1, let S be the
01598     // submatrix of A with m rows rmin <= r <= m+rmin-1 and columns
01599     // cmin <= c <= cmax.  Overwrite S with P*S where P = I-2*V*V^T/|V|^2.
01600 
01601     int iSubRows = iRMax - iRMin + 1, iSubCols = iCMax - iCMin + 1;
01602     int iRow, iCol;
01603 
01604     Real fSqrLen = rkV[0]*rkV[0];
01605     for (int i = 1; i < iVSize; i++)
01606     {
01607         fSqrLen += rkV[i]*rkV[i];
01608     }
01609 
01610     Real fBeta = -((Real)2.0)/fSqrLen;
01611     for (iCol = 0; iCol < iSubCols; iCol++)
01612     {
01613         rkW[iCol] = (Real)0.0;
01614         for (iRow = 0; iRow < iSubRows; iRow++)
01615         {
01616             rkW[iCol] += rkV[iRow]*rkMat[iRMin+iRow][iCMin+iCol];
01617         }
01618         rkW[iCol] *= fBeta;
01619     }
01620 
01621     for (iRow = 0; iRow < iSubRows; iRow++)
01622     {
01623         for (iCol = 0; iCol < iSubCols; iCol++)
01624         {
01625             rkMat[iRMin+iRow][iCMin+iCol] += rkV[iRow]*rkW[iCol];
01626         }
01627     }
01628 }
01629 //----------------------------------------------------------------------------
01630 template <class Real>
01631 void PolynomialRoots<Real>::PostmultiplyHouseholder (GMatrix<Real>& rkMat,
01632     GVector<Real>& rkW, int iRMin, int iRMax, int iCMin, int iCMax,
01633     int iVSize, const Vector3<Real>& rkV)
01634 {
01635     // Householder postmultiplication:
01636     // Given a matrix A and an n-by-1 vector V with V[0] = 1, let S be the
01637     // submatrix of A with n columns cmin <= c <= n+cmin-1 and rows
01638     // rmin <= r <= rmax.  Overwrite S with S*P where P = I-2*V*V^T/|V|^2.
01639 
01640     int iSubRows = iRMax - iRMin + 1, iSubCols = iCMax - iCMin + 1;
01641     int iRow, iCol;
01642 
01643     Real fSqrLen = rkV[0]*rkV[0];
01644     for (int i = 1; i < iVSize; i++)
01645     {
01646         fSqrLen += rkV[i]*rkV[i];
01647     }
01648 
01649     Real fBeta = -((Real)2.0)/fSqrLen;
01650     for (iRow = 0; iRow < iSubRows; iRow++)
01651     {
01652         rkW[iRow] = (Real)0.0;
01653         for (iCol = 0; iCol < iSubCols; iCol++)
01654         {
01655             rkW[iRow] += rkMat[iRMin+iRow][iCMin+iCol]*rkV[iCol];
01656         }
01657         rkW[iRow] *= fBeta;
01658     }
01659 
01660     for (iRow = 0; iRow < iSubRows; iRow++)
01661     {
01662         for (iCol = 0; iCol < iSubCols; iCol++)
01663         {
01664             rkMat[iRMin+iRow][iCMin+iCol] += rkW[iRow]*rkV[iCol];
01665         }
01666     }
01667 }
01668 //----------------------------------------------------------------------------
01669 template <class Real>
01670 void PolynomialRoots<Real>::FrancisQRStep (GMatrix<Real>& rkH,
01671     GVector<Real>& rkW)
01672 {
01673     // Given an n-by-n unreduced upper Hessenberg matrix H whose trailing
01674     // 2-by-2 principal submatrix has eigenvalues a1 and a2, overwrite H
01675     // with Z^T*H*Z where Z = P(1)*...*P(n-2) is a product of Householder
01676     // matrices and Z^T*(H-a1*I)*(H-a2*I) is upper triangular.
01677 
01678     // assert:  H is unreduced upper Hessenberg and n >= 3
01679 
01680     // compute first column of (H-a1*I)*(H-a2*I)
01681     int iN = rkH.GetRows();
01682     Real fTrace = rkH[iN-2][iN-2] + rkH[iN-1][iN-1];
01683     Real fDet = rkH[iN-2][iN-2]*rkH[iN-1][iN-1] -
01684         rkH[iN-2][iN-1]*rkH[iN-1][iN-2];
01685     Vector3<Real> kU;
01686     kU[0] = rkH[0][0]*rkH[1][1]+rkH[0][1]*rkH[1][0]-fTrace*rkH[0][0]+fDet;
01687     kU[1] = rkH[1][0]*(rkH[0][0]+rkH[1][1]-fTrace);
01688     kU[2] = rkH[1][0]*rkH[2][1];
01689 
01690     // overwrite H with P(0)*H*P(0)^T
01691     Vector3<Real> kV;
01692     GetHouseholderVector(3,kU,kV);
01693     PremultiplyHouseholder(rkH,rkW,0,2,0,iN-1,3,kV);
01694     PostmultiplyHouseholder(rkH,rkW,0,iN-1,0,2,3,kV);
01695 
01696     for (int i = 1; i <= iN-3; i++)
01697     {
01698         // overwrite H with P(i)*H*P(i)^T
01699         kU[0] = rkH[i  ][i-1];
01700         kU[1] = rkH[i+1][i-1];
01701         kU[2] = rkH[i+2][i-1];
01702         GetHouseholderVector(3,kU,kV);
01703 
01704         // The column range does not need to be 0 to iN-1 because of the
01705         // pattern of zeros that occur in matrix H.
01706         PremultiplyHouseholder(rkH,rkW,i,i+2,i-1,iN-1,3,kV);
01707 
01708         // The row range does not need to be 0 to iN-1 because of the pattern
01709         // of zeros that occur in matrix H.
01710         int iRMax = i+3;
01711         if (iRMax >= iN)
01712         {
01713             iRMax = iN-1;
01714         }
01715         PostmultiplyHouseholder(rkH,rkW,0,iRMax,i,i+2,3,kV);
01716     }
01717 
01718     // overwrite H with P(n-2)*H*P(n-2)^T
01719     kU[0] = rkH[iN-2][iN-3];
01720     kU[1] = rkH[iN-1][iN-3];
01721     GetHouseholderVector(2,kU,kV);
01722 
01723     // The column range does not need to be 0 to iN-1 because of the pattern
01724     // of zeros that occur in matrix H.
01725     PremultiplyHouseholder(rkH,rkW,iN-2,iN-1,iN-3,iN-1,2,kV);
01726 
01727     PostmultiplyHouseholder(rkH,rkW,0,iN-1,iN-2,iN-1,2,kV);
01728 }
01729 //----------------------------------------------------------------------------
01730 
01731 //----------------------------------------------------------------------------
01732 // explicit instantiation
01733 //----------------------------------------------------------------------------
01734 template WM4_FOUNDATION_ITEM
01735 class PolynomialRoots<float>;
01736 
01737 template WM4_FOUNDATION_ITEM
01738 class PolynomialRoots<double>;
01739 //----------------------------------------------------------------------------
01740 }

Generated on Wed Nov 23 19:01:06 2011 for FreeCAD by  doxygen 1.6.1