SP_Maths Namespace Reference


Functions

void CrossProduct (const double A[3], const double B[3], double C[3])
double DotProduct (const double A[3], const double B[3])
void eigenValsAndVecsOf3by3SymMatrix (double m11, double m12, double m13, double m22, double m23, double m33, double &l1, double &l2, double &l3, double v1[3], double v2[3], double v3[3])
void eigenValsAndVecsOf3by3SymMatrixUsingQRFactor (double m11, double m12, double m13, double m22, double m23, double m33, double &l1, double &l2, double &l3, double v1[3], double v2[3], double v3[3])
double eigenValsOf3by3SymMatrix (double m11, double m12, double m13, double m22, double m23, double m33, double &lamda1, double &lamda2, double &lamda3)
double eigenValsOf3by3SymMatrixSmith1961 (double m11, double m12, double m13, double m22, double m23, double m33, double &lamda1, double &lamda2, double &lamda3)
void FindAnEigenVector (double &m11, double &m12, double &m13, double &m22, double &m23, double &m33, double l1, double v1[3])
void FindOrthogonalVectors (const double iA[3], double oB[3], double oC[3])
double RootFindingByNewtonRaphsonMethod (void(*funcd)(double x, double *fx, double *dfx), double x1, double x2, double xacc)
double rootOfCubicPolynomial (double a, double b, double c, double d, int rootNo)
double rootsOfCubicPolynomial (double a, double b, double c, double d, double &r1, double &r2, double &r3)
double rootsOfCubicPolynomial (double a, double b, double c, double d, std::complex< double > &r1, std::complex< double > &r2, std::complex< double > &r3)
void rootsOfCubicPolynomialCodeGeneratedByMaple (double a, double b, double c, double d, std::complex< double > &r1, std::complex< double > &r2, std::complex< double > &r3)

Variables

const double PI = 3.141592654


Function Documentation

void SP_Maths::CrossProduct ( const double  A[3],
const double  B[3],
double  C[3] 
)

Definition at line 21 of file sp_mathematics.cpp.

00022     {
00023         C[0] = A[1]*B[2] - A[2]*B[1];
00024         C[1] = A[2]*B[0] - A[0]*B[2];
00025         C[2] = A[0]*B[1] - A[1]*B[0];
00026     } // END FN:    CrossProduct()

double SP_Maths::DotProduct ( const double  A[3],
const double  B[3] 
)

Definition at line 31 of file sp_mathematics.cpp.

00032     {
00033         return  A[0]*B[0] + A[1]*B[1] + A[2]*B[2];
00034     } // END FN:    DotProduct()

void SP_Maths::eigenValsAndVecsOf3by3SymMatrix ( double  m11,
double  m12,
double  m13,
double  m22,
double  m23,
double  m33,
double &  l1,
double &  l2,
double &  l3,
double  v1[3],
double  v2[3],
double  v3[3] 
)

Definition at line 526 of file sp_mathematics.cpp.

00531     { 
00532         double errThreshold = 1E-05;    // error tolerant value
00533 
00534         double discriminant = eigenValsOf3by3SymMatrix( m11, m12, m13, m22, m23, m33, l1, l2, l3 );
00535 
00536         // Smith's Method (1961)
00537         //double discriminant = eigenValsOf3by3SymMatrixSmith1961( m11, m12, m13, m22, m23, m33, ll1, ll2, ll3 );
00538         
00539         //cout << "discriminant = " << discriminant << endl;
00540         //cout << "l1: " << l1 << "  l2: " << l2 << "  l3: " << l3 << endl;
00541 
00542         // ********************************************************************
00543         // ASSUME all eigen values are real!
00544 
00545         // If discriminant > 0, then one root is real and two complex conjugate.
00546         /*
00547         if ( discriminant > errThreshold ) {
00548             cerr << "ERR:  Discriminant > 0, i.e. one eigen value is real and two complex conjugate!" << "\n";
00549             cerr << "CONT: The function is not intended for this kind of matrix!" << endl;
00550             return;
00551         }
00552         */
00553 
00554 
00555 
00556         // If all eigen values are equal, then eigen vectors can be
00557         // any vectors that are orthogonal to one another.
00558         // Also in this case, discriminant == 0.
00559         //if ( fabs(m12) < errThreshold && fabs(m13) < errThreshold && fabs(m23) < errThreshold ) {
00560         const double ratio = 100000.0;
00561         if ( fabs(l1 - l2) < fabs(l1/ratio) ) {
00562             if ( fabs(l1 - l3) < fabs(l1/ratio) ) {         // CASE: l1 == l2 == l3
00563                 v1[0] = 1;  v1[1] = 0;  v1[2] = 0;
00564                 v2[0] = 0;  v2[1] = 1;  v2[2] = 0;
00565                 v3[0] = 0;  v3[1] = 0;  v3[2] = 1;
00566                 cout << "CASE: l1 == l2 == l3\n";
00567             }
00568             else {                                          // CASE: l1 == l2 != l3
00569                 FindAnEigenVector( m11, m12, m13, m22, m23, m33, l3, v3 );
00570                 FindOrthogonalVectors( v3, v1, v2 );
00571                 cout << "CASE: l1 == l2 != l3\n";
00572             }
00573         }
00574         else if ( fabs(l2 - l3) < fabs(l2/ratio) ) {        // CASE: l1 != l2 == l3
00575             FindAnEigenVector( m11, m12, m13, m22, m23, m33, l1, v1 );
00576             FindOrthogonalVectors( v1, v2, v3 );
00577             cout << "CASE: l1 != l2 == l3\n";
00578         }
00579         else if ( fabs(l1 - l3) < fabs(l1/ratio) ) {        // CASE: l1 == l3 != l2
00580             FindAnEigenVector( m11, m12, m13, m22, m23, m33, l2, v2 );
00581             FindOrthogonalVectors( v2, v1, v3 );
00582             cout << "CASE: l1 == l3 != l2\n";
00583         }
00584         else {                                              // CASE: l1 != l2 != l3
00585             //if ( fabs(l1) > fabs(l2) && fabs(l1) > fabs(l3) ) {}
00586             FindAnEigenVector( m11, m12, m13, m22, m23, m33, l1, v1 );
00587             //FindOrthogonalVectors( v1, v2, v3 );
00588             FindAnEigenVector( m11, m12, m13, m22, m23, m33, l2, v2 );
00589             FindAnEigenVector( m11, m12, m13, m22, m23, m33, l3, v3 );
00590             cout << "CASE: l1 != l2 != l3\n";
00591         }
00592         
00593         cout << "v1*v2 = " << DotProduct(v1,v2) << "\n";
00594         cout << "v2*v3 = " << DotProduct(v2,v3) << "\n";
00595         cout << "v1*v3 = " << DotProduct(v1,v3) << "\n";
00596     } // END FN:    eigenValsAndVecsOf3by3SymMatrix()

void SP_Maths::eigenValsAndVecsOf3by3SymMatrixUsingQRFactor ( double  m11,
double  m12,
double  m13,
double  m22,
double  m23,
double  m33,
double &  l1,
double &  l2,
double &  l3,
double  v1[3],
double  v2[3],
double  v3[3] 
)

Definition at line 603 of file sp_mathematics.cpp.

00608     { 
00609         //double errThreshold = 5E-3;   // error tolerant value
00610         static const int TIMES_LIMIT = 256;
00611         int iterationTimes = 1;
00612 
00613         SPtMatrix< double > IT( 3, 3 );
00614         SPtMatrix< double > EG( 3, 3 );
00615         IT.Set( 0, 0, m11 );    IT.Set( 0, 1, m12 );    IT.Set( 0, 2, m13 );
00616         IT.Set( 1, 0, m12 );    IT.Set( 1, 1, m22 );    IT.Set( 1, 2, m23 );
00617         IT.Set( 2, 0, m13 );    IT.Set( 2, 1, m23 );    IT.Set( 2, 2, m33 );
00618         
00619         //cout << "IT is \n";
00620         //IT.DisplayElements();
00621         do {
00622             iterationTimes *= 2;
00623         
00624             MatrixOperations::EigenValsByQRFactorization( IT, iterationTimes, &EG );
00625 
00626             cout << "QR Factorization iterates " << iterationTimes << " times.\n";
00627 
00628             //cout << "IT is \n";
00629             //IT.DisplayElements();
00630             //cout << "EG is \n";
00631             //EG.DisplayElements();
00632 
00633             l1 = EG.Get( 0, 0 );
00634             l2 = EG.Get( 1, 1 );
00635             l3 = EG.Get( 2, 2 );
00636 
00637             // If all eigen values are equal, then eigen vectors can be
00638             // any vectors that are orthogonal to one another.
00639             // Also in this case, discriminant == 0.
00640             //if ( fabs(m12) < errThreshold && fabs(m13) < errThreshold && fabs(m23) < errThreshold ) {
00641             const double ratio = 10000.0;
00642             if ( fabs(l1 - l2) < fabs(l1/ratio) ) {
00643                 if ( fabs(l1 - l3) < fabs(l1/ratio) ) {         // CASE: l1 == l2 == l3
00644                     v1[0] = 1;  v1[1] = 0;  v1[2] = 0;
00645                     v2[0] = 0;  v2[1] = 1;  v2[2] = 0;
00646                     v3[0] = 0;  v3[1] = 0;  v3[2] = 1;
00647                     cout << "CASE: l1 == l2 == l3\n";
00648                 }
00649                 else {                                          // CASE: l1 == l2 != l3
00650                     FindAnEigenVector( m11, m12, m13, m22, m23, m33, l3, v3 );
00651                     FindOrthogonalVectors( v3, v1, v2 );
00652                     cout << "CASE: l1 == l2 != l3\n";
00653                 }
00654             }
00655             else if ( fabs(l2 - l3) < fabs(l2/ratio) ) {        // CASE: l1 != l2 == l3
00656                 FindAnEigenVector( m11, m12, m13, m22, m23, m33, l1, v1 );
00657                 FindOrthogonalVectors( v1, v2, v3 );
00658                 cout << "CASE: l1 != l2 == l3\n";
00659             }
00660             else if ( fabs(l1 - l3) < fabs(l1/ratio) ) {        // CASE: l1 == l3 != l2
00661                 FindAnEigenVector( m11, m12, m13, m22, m23, m33, l2, v2 );
00662                 FindOrthogonalVectors( v2, v1, v3 );
00663                 cout << "CASE: l1 == l3 != l2\n";
00664             }
00665             else {                                              // CASE: l1 != l2 != l3
00666                 //if ( fabs(l1) > fabs(l2) && fabs(l1) > fabs(l3) ) {}
00667                 FindAnEigenVector( m11, m12, m13, m22, m23, m33, l1, v1 );
00668                 //FindOrthogonalVectors( v1, v2, v3 );
00669                 FindAnEigenVector( m11, m12, m13, m22, m23, m33, l2, v2 );
00670                 FindAnEigenVector( m11, m12, m13, m22, m23, m33, l3, v3 );
00671                 cout << "CASE: l1 != l2 != l3\n";
00672             }
00673             
00674             cout << "v1*v2 = " << DotProduct(v1,v2) << "\n";
00675             cout << "v2*v3 = " << DotProduct(v2,v3) << "\n";
00676             cout << "v1*v3 = " << DotProduct(v1,v3) << "\n";
00677         } while ( fabs(DotProduct(v1,v2) + DotProduct(v2,v3) + DotProduct(v1,v3)) > 1E-06 && iterationTimes <= TIMES_LIMIT );
00678     } // END FN:    eigenValsAndVecsOf3by3SymMatrixUsingQRFactor()

double SP_Maths::eigenValsOf3by3SymMatrix ( double  m11,
double  m12,
double  m13,
double  m22,
double  m23,
double  m33,
double &  lamda1,
double &  lamda2,
double &  lamda3 
)

Definition at line 397 of file sp_mathematics.cpp.

00401     { 
00402         double errThreshold = 1E-6; // error tolerant value
00403         double b, c, d = 0;
00404         double f[5];
00405 
00406         // coefficients of the characteristic polynomial of the 3x3 symmetric matrix
00407         b = - m11 - m22 - m33;
00408         c = (m11*m22 + m22*m33 + m33*m11) - (m12*m12 + m23*m23 + m13*m13);
00409         //d = m11*m23*m23 + m22*m13*m13 + m33*m12*m12 - m11*m22*m33 - 2*m12*m23*m13;
00410         
00411         f[0] = m11*m23*m23;
00412         f[1] = m22*m13*m13;
00413         f[2] = m33*m12*m12;
00414         f[3] = -m11*m22*m33;
00415         f[4] = -2*m12*m23*m13;
00416         double dNeg = 0;
00417         for ( int i = 0; i < 5; i++ ) {
00418             if ( f[i] >= 0 )    d += f[i];
00419             else                dNeg += f[i];
00420         }
00421         d += dNeg;
00422         
00423         // the roots of the polynomial function are the eigen values of the matrix
00424         if ( fabs(m12) < errThreshold && fabs(m13) < errThreshold && fabs(m23) < errThreshold ) {
00425             double difThreshold = fabs( m11 * 1E-06 );
00426             if ( fabs(m11-m22) < difThreshold && fabs(m11-m33) < difThreshold ) {   // all roots are real and at least two are equal if discriminant = 0.
00427                 lamda1 = lamda2 = lamda3 = ( m11 + m22 + m33 ) / 3.0;
00428                 return  0;  // return zero discriminant value
00429             }
00430             else {                              // all roots are real and unequal if discriminant < 0.
00431                 lamda1 = m11;
00432                 lamda2 = m22;
00433                 lamda3 = m33;
00434                 return   -1;    // return negative discriminant value
00435             }
00436         }
00437 
00438         // Find roots using formulas from "Handbook of Mathematic"
00439         double discriminant = rootsOfCubicPolynomial( 1, b, c, d, lamda1, lamda2, lamda3 );
00440 
00441         return static_cast<double>(discriminant);
00442     } // END FN:    eigenValsOf3by3SymMatrix()

double SP_Maths::eigenValsOf3by3SymMatrixSmith1961 ( double  m11,
double  m12,
double  m13,
double  m22,
double  m23,
double  m33,
double &  lamda1,
double &  lamda2,
double &  lamda3 
)

Definition at line 449 of file sp_mathematics.cpp.

00453     { 
00454 
00455         double errThreshold = 1E-10;
00456 
00457         // 3m = trace(A)
00458         // 2q = det(A - mI)
00459         // 6p = the sum of squares of elements of (A - mI)
00460         // discriminant = p^3 - q^2
00461         // phi = 1/3*arctan( sqrt(discriminant)/q )
00462         // root1 = m + 2*sqrt(p)*cos(phi)
00463         // root2 = m - sqrt(p)*(cos(phi) + sqrt(3)*sin(phi))
00464         // root3 = m - sqrt(p)*(cos(phi) - sqrt(3)*sin(phi))
00465         double m, p, q, phi, discriminant;
00466 
00467 
00468         SPtMatrix3x3< double > IT(  m11, m12, m13,
00469                                     m12, m22, m23,
00470                                     m13, m23, m33 );
00471         SPtMatrix3x3< double > I(   1,0,0, 0,1,0, 0,0,1 );
00472         
00473         
00474         m = ( m11 + m22 + m33 ) / 3.0;
00475         
00476         SPtMatrix3x3< double > B = IT - m*I;
00477     
00478         q = (   B.Get(0,0) * ( B.Get(1,1)*B.Get(2,2) - B.Get(2,1)*B.Get(1,2) ) 
00479             -   B.Get(1,0) * ( B.Get(0,1)*B.Get(2,2) - B.Get(2,1)*B.Get(0,2) )
00480             +   B.Get(2,0) * ( B.Get(0,1)*B.Get(1,2) - B.Get(1,1)*B.Get(0,2) )
00481             ) / 2.0;
00482 
00483         p = 0;
00484         for ( int r = 0; r < 3; r++ ) {
00485             for ( int c = 0; c < 3; c++ ) {
00486                 p += B.Get(r,c)*B.Get(r,c);
00487             }
00488         }
00489         p /= 6.0;
00490 
00491         discriminant = p*p*p - q*q;
00492         if ( discriminant >= 0 ) {
00493             phi = atan( sqrt(discriminant)/q ) / 3.0;
00494 
00495             lamda1 = m + 2*sqrt(p)*cos(phi);
00496             lamda2 = m - sqrt((double)p)*(cos(phi) + sqrt((double)3)*sin(phi));
00497             lamda3 = m - sqrt((double)p)*(cos(phi) - sqrt((double)3)*sin(phi));
00498         }
00499         else {
00500             cout << "Discriminant (Smith's Method (1961) < 0: discriminant = " << discriminant << "\n";
00501         }
00502 
00503         // the roots of the polynomial function are the eigen values of the matrix
00504         if ( fabs(m12) < errThreshold && fabs(m13) < errThreshold && fabs(m23) < errThreshold ) {
00505             double difThreshold = fabs( m11 * 1E-06 );
00506             if ( fabs(m11-m22) < difThreshold && fabs(m11-m33) < difThreshold ) {   // all roots are real and at least two are equal if discriminant = 0.
00507                 lamda1 = lamda2 = lamda3 = ( m11 + m22 + m33 ) / 3.0;
00508                 return  0;  // return zero discriminant value
00509             }
00510             else {                              // all roots are real and unequal if discriminant < 0.
00511                 lamda1 = m11;
00512                 lamda2 = m22;
00513                 lamda3 = m33;
00514                 return   -1;    // return negative discriminant value
00515             }
00516         }
00517 
00518         return static_cast<double>(discriminant);
00519     } // END FN:    eigenValsOf3by3SymMatrixSmith1961()

void SP_Maths::FindAnEigenVector ( double &  m11,
double &  m12,
double &  m13,
double &  m22,
double &  m23,
double &  m33,
double  l1,
double  v1[3] 
)

Definition at line 39 of file sp_mathematics.cpp.

00041                                                                                   : 3x3 Symmetric Matrix
00042                             double l1,      // O/P: eigen value
00043                             double v1[3]    // O/P: eigen vector
00044                           )
00045     {
00046         double a1,          b1 = m12,       c1 = m13;
00047         double a2 = m12,    b2,             c2 = m23;
00048         double a3 = m13,    b3 = m23,       c3;
00049 
00050         a1 = m11 - l1;
00051         b2 = m22 - l1;
00052         c3 = m33 - l1;
00053         double divider = b2*a1 - b1*a2 - b3*a1 + b1*a3;
00054         //if ( divider != 0 ) {
00055         if ( fabs(divider) > 1E-40 ) {
00056             v1[0] = (-b2*c1 + b1*c2 + b3*c1 - b1*c3) / divider;
00057             v1[1] = (a2*c1 - a1*c2 - a3*c1 + a1*c3) /divider;
00058             v1[2] = 1;
00059 
00060         // make the vector a unit vector
00061             double vecLen = sqrt( v1[0]*v1[0] + v1[1]*v1[1] + v1[2]*v1[2] );
00062             v1[0] /= vecLen;
00063             v1[1] /= vecLen;
00064             v1[2] /= vecLen;
00065         }
00066         else {
00067             v1[0] = 0;
00068             v1[1] = 0;
00069             v1[2] = 0;
00070         }
00071     } // END FN:    FindAnEigenVector()

void SP_Maths::FindOrthogonalVectors ( const double  iA[3],
double  oB[3],
double  oC[3] 
)

Definition at line 76 of file sp_mathematics.cpp.

00077     {
00078         SPtMatrix< double > A( 3, 1 ), B( 3, 1 ), C( 3, 1 );
00079         for ( int i = 0; i < 3; i++ ) {
00080             A.Set( i, 0, iA[i] );
00081         }
00082 
00083         // alpha for x, beta for y, and zeta for z
00084         
00085         double angleZeta;
00086         if ( iA[0] != 0 )   angleZeta = atan( iA[1] / iA[0] );
00087         else                angleZeta = ( iA[1] > 0 ? 1.0 : -1.0 ) * PI / 2.0;
00088         double angleBeta = asin( iA[2] / sqrt( iA[0]*iA[0] + iA[1]*iA[1] + iA[2]*iA[2] ) );
00089         //double angleAlpha = 90.0/180.0*PI;
00090         SPtMatrix< double > Rz( 3, 3 );
00091         Rz.Set( 0, 0,  cos( angleZeta ) );  Rz.Set( 0, 1,  sin( angleZeta ) );
00092         Rz.Set( 1, 0, -sin( angleZeta ) );  Rz.Set( 1, 1,  cos( angleZeta ) );
00093         Rz.Set( 2, 2, 1 );
00094         SPtMatrix< double > Ry( 3, 3 );
00095         Ry.Set( 0, 0,  cos( angleBeta ) );  Ry.Set( 0, 2, -sin( angleBeta ) );
00096         Ry.Set( 1, 1, 1 );
00097         Ry.Set( 2, 0,  sin( angleBeta ) );  Ry.Set( 2, 2,  cos( angleBeta ) );
00098         
00099         SPtMatrix< double > Ryy( 3, 3 );
00100         Ryy.Set( 0, 0,  cos( PI/2.0 ) );    Ryy.Set( 0, 2, -sin( PI/2.0 ) );
00101         Ryy.Set( 1, 1, 1 );
00102         Ryy.Set( 2, 0,  sin( PI/2.0 ) );    Ryy.Set( 2, 2,  cos( PI/2.0 ) );
00103 
00104         /*
00105         SPtMatrix< double > Rx( 3, 3 );
00106         Rx.Set( 0, 0, 1 );
00107         Rx.Set( 1, 1,  cos( angleAlpha ) ); Rx.Set( 1, 2,  sin( angleAlpha ) );
00108         Rx.Set( 2, 1, -sin( angleAlpha ) ); Rx.Set( 2, 2,  cos( angleAlpha ) );
00109         */
00110         
00111         SPtMatrix< double > Rym( 3, 3 );
00112         Rym.Set( 0, 0,  cos( -angleBeta ) );    Rym.Set( 0, 2, -sin( -angleBeta ) );
00113         Rym.Set( 1, 1, 1 );
00114         Rym.Set( 2, 0,  sin( -angleBeta ) );    Rym.Set( 2, 2,  cos( -angleBeta ) );
00115         SPtMatrix< double > Rzm( 3, 3 );
00116         Rzm.Set( 0, 0,  cos( -angleZeta ) );    Rzm.Set( 0, 1,  sin( -angleZeta ) );
00117         Rzm.Set( 1, 0, -sin( -angleZeta ) );    Rzm.Set( 1, 1,  cos( -angleZeta ) );
00118         Rzm.Set( 2, 2, 1 );
00119 
00120         //B = Rz * Ry * Ryy * Rym * Rzm * A;
00121         B = Rzm * Rym * Ryy * Ry * Rz * A;
00122 
00123         //B.DisplayElements();
00124         //(A.GetTranspose()*B).DisplayElements();
00125 
00126         oB[0] = B.Get( 0, 0 );
00127         oB[1] = B.Get( 1, 0 );
00128         oB[2] = B.Get( 2, 0 );
00129 
00130         cout << "\niA*oB = " << ( iA[0]*oB[0] + iA[1]*oB[1] + iA[2]*oB[2] ) << "\n";
00131         CrossProduct( iA, oB, oC );
00132     } // END FN:    FindOrthogonalVectors()

double SP_Maths::RootFindingByNewtonRaphsonMethod ( void(*)(double x, double *fx, double *dfx)  funcd,
double  x1,
double  x2,
double  xacc 
)

Definition at line 688 of file sp_mathematics.cpp.

00692     {
00693         const int ITERATION_LIMIT = 200;
00694         double x, fx, dx = 0, dfx;
00695 
00696         x = 0.5 * (x1 + x2);    // initial guess is the middle of the interval (x1,x2)
00697         for ( int i = 1; i < ITERATION_LIMIT; i++ ) {
00698             (*funcd)( x, &fx, &dfx );
00699             if ( fx != 0 && dfx != 0) {
00700                 dx = fx/dfx;
00701                 x -= dx;
00702             }
00703             if ( (x1-x)*(x-x2) < 0.0 ) {
00704                 cerr << "From RootFindingByNewtonRaphsonMethod():\n"
00705                      << "  The root lies outside the provided interval (x1,x2)!" << endl;
00706                 return -777;
00707             }
00708             if ( fabs(dx) < xacc )  return x;       // the convergence value is the root
00709         }
00710 
00711         cerr << "From RootFindingByNewtonRaphsonMethod():\n"
00712              << "  Maximum number of iterations exceeded!" << endl;
00713         return -777;
00714     } // END FN:    RootFindingByNewtonRaphsonMethod()

double SP_Maths::rootOfCubicPolynomial ( double  a,
double  b,
double  c,
double  d,
int  rootNo 
)

Definition at line 306 of file sp_mathematics.cpp.

00307     {
00308         double a1, a2, a3;
00309         double Q, R, D; 
00310         double S, T;    // FIX IT HERE!
00311         double zeta;
00312         double rootValue;
00313 
00314         a1 = b/a;
00315         a2 = c/a;
00316         a3 = d/a;
00317         Q = (3.0*a2 - a1*a1) / 9.0;
00318         R = (9.0*a1*a2 - 27.0*a3 - 2.0*a1*a1*a1) / 54.0;
00319         D = Q*Q*Q + R*R;
00320 
00321         // If a1, a2, a3 are real and if D = Q^3 + R^2 is the discriminant, then
00322         // (i)   one root is real and two complex conjugate if D > 0
00323         // (ii)  all roots are real and at least two are equal if D = 0
00324         // (iii) all roots are real and unequal if D < 0.
00325 
00326         if ( D >= 0 ) {
00327             double Dh = sqrt(D);
00328             S = pow(R + Dh, 1.0/3.0);   // FIX IT HERE!
00329             T = R - Dh;
00330             if ( T >= 0 )   T =  pow(  T, 1.0/3.0 );
00331             else            T = -pow( -T, 1.0/3.0 );
00332             
00333             switch ( rootNo ) {
00334                 // first root
00335                 case 1:
00336                     rootValue = S + T - a1/3.0;
00337                     return rootValue;
00338                     break;
00339 
00340                 // second root
00341                 case 2:
00342                     rootValue = -(S + T)/2.0 - a1/3.0;  // + i*sqrt(3.0)*(S - T)/2.0;
00343                     return rootValue;
00344                     break;
00345 
00346                 // third root
00347                 case 3:
00348                     rootValue = -(S + T)/2.0 - a1/3.0;  // - i*sqrt(3.0)*(S - T)/2.0;
00349                     return rootValue;
00350                     break;
00351                 
00352                 // default
00353                 default:
00354                     cerr << "ERROR:  Incorrect Root# Option!" << endl;
00355                     return -777;
00356                     break;
00357             }
00358         }
00359 
00360         // All roots are real and unequal if D < 0.
00361         //if ( D < 0 ) {
00362         else {
00363             zeta = acos( R / sqrt(-(Q*Q*Q)) );
00364             switch ( rootNo ) {
00365                 // first root
00366                 case 1:
00367                     rootValue = 2 * sqrt(-Q) * cos(zeta/3.0) - a1/3.0;
00368                     return rootValue;
00369                     break;
00370 
00371                 // second root
00372                 case 2:
00373                     rootValue = 2 * sqrt(-Q) * cos(zeta/3.0 + 2.0/3.0*PI) - a1/3.0;
00374                     return rootValue;
00375                     break;
00376 
00377                 // third root
00378                 case 3:
00379                     rootValue = 2 * sqrt(-Q) * cos(zeta/3.0 + 4.0/3.0*PI) - a1/3.0;
00380                     return rootValue;
00381                     break;
00382                 
00383                 // default
00384                 default:
00385                     cerr << "ERROR:  Incorrect Root# Option!" << endl;
00386                     return -777;
00387                     break;
00388             }
00389         }
00390     } // END FN:    rootOfCubicPolynomial()

double SP_Maths::rootsOfCubicPolynomial ( double  a,
double  b,
double  c,
double  d,
double &  r1,
double &  r2,
double &  r3 
)

Definition at line 284 of file sp_mathematics.cpp.

00286     {
00287         std::complex< double > cr1, cr2, cr3;
00288         double discriminant = rootsOfCubicPolynomial( a, b, c, d, cr1, cr2, cr3 );
00289         r1 = cr1.real();
00290         r2 = cr2.real();
00291         r3 = cr3.real();
00292 
00293         return discriminant;
00294     }

double SP_Maths::rootsOfCubicPolynomial ( double  a,
double  b,
double  c,
double  d,
std::complex< double > &  r1,
std::complex< double > &  r2,
std::complex< double > &  r3 
)

Definition at line 194 of file sp_mathematics.cpp.

00198     {
00199         double a1, a2, a3;
00200         double Q, R, D;
00201         std::complex<double> S, T;
00202         double zeta;
00203 
00204         a1 = b/a;
00205         a2 = c/a;
00206         a3 = d/a;
00207 
00208         //Q = (3.0*a2 - a1*a1) / 9.0;
00209         //R = (9.0*a1*a2 - 27.0*a3 - 2.0*a1*a1*a1) / 54.0;
00210         // Q^3 + R^2 can factor 9*9*9 (or 27*27) out
00211         // So  Q = 3*a2 - a1^2
00212         // and R = (f1 + f2 + f3) / 2
00213 
00214         Q = 3.0*a2 - a1*a1;
00215         double Rpos = 0, Rneg = 0;
00216         double f[3];
00217         f[0] = 9.0*a1*a2;
00218         f[1] = -27.0*a3;
00219         f[2] = -2.0*a1*a1*a1;
00220         for ( int i = 0; i < 3; i++ ) {
00221             ( f[i] >= 0 ) ? ( Rpos += f[i] ) : ( Rneg += f[i] );
00222             //if ( f[i] >= 0 )  Rpos += f[i];
00223             //else              Rneg += f[i];
00224         }
00225         R = (Rpos + Rneg) / 2.0;
00226 
00227 
00228 
00229         D = ( Q*Q*Q + R*R ) / 729.0;
00230         Q /= 9.0;
00231         R /= 27.0;
00232 
00233         // If a1, a2, a3 are real and if D = Q^3 + R^2 is the discriminant, then
00234         // (i)   one root is real and two complex conjugate if D > 0
00235         // (ii)  all roots are real and at least two are equal if D = 0
00236         // (iii) all roots are real and unequal if D < 0.
00237 
00238         if ( D >= 0 ) {
00239             std::complex<double> Dh = sqrt(D);
00240             
00241             S = pow(R + Dh, 1.0/3.0);
00242             T = pow(R - Dh, 1.0/3.0);
00243 
00244             r1 = S + T - a1/3.0;
00245             std::complex<double> pureComplex( 0, sqrt(3.0) );
00246             //r2 = -(S + T)/2.0 - a1/3.0 + i*sqrt(3.0)*(S - T)/2.0;
00247             //r3 = -(S + T)/2.0 - a1/3.0 - i*sqrt(3.0)*(S - T)/2.0;
00248             r2 = - (S + T)/2.0 - a1/3.0 + pureComplex*(S - T)/2.0;
00249             r3 = - (S + T)/2.0 - a1/3.0 - pureComplex*(S - T)/2.0;
00250         }
00251 
00252         // All roots are real and unequal if D < 0.
00253         //if ( D < 0 ) {
00254         else {
00255             //cout << "D < 0" << endl;
00256             zeta = acos( R / sqrt(-(Q*Q*Q)) );
00257             r1 = 2 * sqrt(-Q) * cos(zeta/3.0) - a1/3.0;
00258             r2 = 2 * sqrt(-Q) * cos(zeta/3.0 + 2.0/3.0*PI) - a1/3.0;
00259             r3 = 2 * sqrt(-Q) * cos(zeta/3.0 + 4.0/3.0*PI) - a1/3.0;
00260         }
00261 
00262         // DEBUG:
00263         cout.precision( 10 );
00264         cout    << "*x^3"  << (a1>0 ? " + " : " - ") << fabs(a1) << "*x^2"<< (a1>0 ? " + " : " - ") 
00265                 << fabs(a2) << "*x" << (a1>0 ? " + " : " - ") << fabs(a3) << "\n";
00266         cout << "Q = " << Q << "\n";
00267         cout << "R = " << R << "\n";
00268         cout << "Q^3 = " << Q*Q*Q << "\n";
00269         cout << "R^2 = " << R*R << "\n";
00270         cout << "D = " << D << "\n";
00271         cout << "Root#1: " << r1 << " Root#2: " << r2 << " Root#3: " << r3 << "\n";
00272         cout.precision( 6 );
00273 
00274 
00275         std::complex<double> cr1, cr2, cr3;
00276         rootsOfCubicPolynomialCodeGeneratedByMaple( a, b, c, d, cr1, cr2, cr3 );
00277 
00278 
00279         return D;   // return discriminant
00280     } // END FN:    rootsOfCubicPolynomial()

void SP_Maths::rootsOfCubicPolynomialCodeGeneratedByMaple ( double  a,
double  b,
double  c,
double  d,
std::complex< double > &  r1,
std::complex< double > &  r2,
std::complex< double > &  r3 
)

Definition at line 135 of file sp_mathematics.cpp.

00138     {
00139         std::complex<double> a1;
00140         std::complex<double> a2;
00141         std::complex<double> a3;
00142 
00143         a1 = b/a;
00144         a2 = c/a;
00145         a3 = d/a;
00146 
00147         std::complex<double> div = 1.0/3.0;
00148 
00149         // common part for all roots
00150         std::complex<double> t1 = a2*a1;
00151         std::complex<double> t4 = a1*a1;
00152         std::complex<double> t5 = t4*a1;
00153         std::complex<double> t7 = a2*a2;
00154         std::complex<double> t14 = a3*a3;
00155         std::complex<double> t19 = sqrt(12.0*t7*a2-3.0*t7*t4-54.0*t1*a3+81.0*t14+12.0*a3*t5);
00156         std::complex<double> t22 = pow(36.0*t1-108.0*a3-8.0*t5+12.0*t19,div);
00157 
00158         // Root# 1
00159         r1 = t22/6.0-6.0*(a2/3.0-t4/9.0)/t22-a1/3.0;
00160         
00161         // common part for root# 2 and 3
00162         std::complex<double> t28 = (a2/3.0-t4/9.0)/t22;
00163         std::complex<double> t31 = sqrt(3.0);
00164 
00165         // Root# 2
00166         //r2 = -t22/12.0+3.0*t28-a1/3.0+(1.0/2.0*sqrt(-1.0))*t31*(t22/6.0+6.0*t28);
00167         std::complex<double> st1 = t31*(t22/6.0+6.0*t28);
00168         std::complex<double> st2 = (sqrt(-1.0));
00169         cout << st1 << ", " << st2 << endl; 
00170         r2 = -t22/12.0+3.0*t28-a1/3.0+(1.0/2.0*sqrt(-1.0))*t31*(t22/6.0+6.0*t28);
00171 
00172         // Root# 3
00173         //r3 = -t22/12.0+3.0*t28-a1/3.0+(-1.0/2.0*sqrt(-1.0))*t31*(t22/6.0+6.0*t28);
00174         r2 = -t22/12.0+3.0*t28-a1/3.0+(1.0/2.0*sqrt(-1.0))*t31*(t22/6.0+6.0*t28);
00175 
00176 
00177         // DEBUG:
00178         cout.precision( 10 );
00179 //      cout    << "*x^3"  << (a1>0 ? " + " : " - ") << fabs(a1) << "*x^2"<< (a1>0 ? " + " : " - ") 
00180 //              << fabs(a2) << "*x" << (a1>0 ? " + " : " - ") << fabs(a3) << "\n";
00181         cout << "Root#1: " << r1 << " Root#2: " << r2 << " Root#3: " << r3 << "\n";
00182         cout.precision( 6 );
00183 
00184     } // END FN:    rootsOfCubicPolynomial()


Variable Documentation

const double SP_Maths::PI = 3.141592654

Definition at line 27 of file sp_mathematics.h.


Generated on Mon Oct 13 11:46:37 2008 for TAPs by  doxygen 1.5.6