OpenWalnut  1.4.0
WPolynomialEquationSolvers_test.h
00001 //---------------------------------------------------------------------------
00002 //
00003 // Project: OpenWalnut ( http://www.openwalnut.org )
00004 //
00005 // Copyright 2009 OpenWalnut Community, BSV@Uni-Leipzig and CNCF@MPI-CBS
00006 // For more information see http://www.openwalnut.org/copying
00007 //
00008 // This file is part of OpenWalnut.
00009 //
00010 // OpenWalnut is free software: you can redistribute it and/or modify
00011 // it under the terms of the GNU Lesser General Public License as published by
00012 // the Free Software Foundation, either version 3 of the License, or
00013 // (at your option) any later version.
00014 //
00015 // OpenWalnut is distributed in the hope that it will be useful,
00016 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00017 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00018 // GNU Lesser General Public License for more details.
00019 //
00020 // You should have received a copy of the GNU Lesser General Public License
00021 // along with OpenWalnut. If not, see <http://www.gnu.org/licenses/>.
00022 //
00023 //---------------------------------------------------------------------------
00024 
00025 #ifndef WPOLYNOMIALEQUATIONSOLVERS_TEST_H
00026 #define WPOLYNOMIALEQUATIONSOLVERS_TEST_H
00027 
00028 #include <iomanip>
00029 #include <sstream>
00030 #include <string>
00031 #include <utility>
00032 
00033 #include <cxxtest/TestSuite.h>
00034 
00035 #include "../WPolynomialEquationSolvers.h"
00036 
00037 /**
00038  * Testsuite for the WPolynomialEquationSolvers functions
00039  */
00040 class WPolynomialEquationSolversTest : public CxxTest::TestSuite
00041 {
00042 public:
00043     /**
00044      * If there is no solution an exception should be thrown.
00045      */
00046     void testRealQuadraticEquationWithNoSolution( void )
00047     {
00048         TS_ASSERT_THROWS_EQUALS( solveRealQuadraticEquation( 0.0, 0.0, 1.0 ), const WEquationHasNoRoots &e,
00049                                  std::string( e.what() ), "The equation: 0x^2 + 0x + 1 = 0.0 has no solutions!" );
00050     }
00051 
00052     /**
00053      * x^2 = 0 has only one solution: 0.0.
00054      */
00055     void testRealQuadraticEquationWithOnlyOneSolution( void )
00056     {
00057         typedef std::pair< std::complex< double >, std::complex< double > > ComplexPair;
00058         ComplexPair actual = solveRealQuadraticEquation( 1.0, 0.0, 0.0 );
00059         TS_ASSERT_EQUALS( actual.first, std::complex< double >( 0.0, 0.0 ) );
00060         TS_ASSERT_EQUALS( actual.second, actual.first );
00061     }
00062 
00063     /**
00064      * x^2 - 1 = 0 has two solutions: 1.0 and -1.0.
00065      */
00066     void testRealQuadraticEquationWithTwoRealSolutions( void )
00067     {
00068         typedef std::pair< std::complex< double >, std::complex< double > > ComplexPair;
00069         ComplexPair actual = solveRealQuadraticEquation( 1.0, 0.0, -1.0 );
00070         ComplexPair expected = ComplexPair( std::complex< double >( -1.0, 0.0 ), std::complex< double >( 1.0, 0.0 ) );
00071         if(  actual.first != expected.first )
00072         {
00073             std::cout << std::endl << "We assume the order of the pair is swaped, but both solutions are right" << std::endl;
00074             TS_ASSERT_EQUALS( actual.first, expected.second );
00075             TS_ASSERT_EQUALS( actual.second, expected.first );
00076         }
00077         else
00078         {
00079             TS_ASSERT_EQUALS( actual.first, expected.first );
00080             TS_ASSERT_EQUALS( actual.second, expected.second );
00081         }
00082     }
00083 
00084     /**
00085      * x^2 + 1 = 0 has two solutions: i and -i.
00086      */
00087     void testRealQuadraticEquationWithTwoImaginarySolutions( void )
00088     {
00089         typedef std::pair< std::complex< double >, std::complex< double > > ComplexPair;
00090         ComplexPair actual = solveRealQuadraticEquation( 1.0, 0.0, 1.0 );
00091         ComplexPair expected = ComplexPair( std::complex< double >( 0.0, 1.0 ), std::complex< double >( 0.0, -1.0 ) );
00092         if(  actual.first != expected.first )
00093         {
00094             std::cout << std::endl << "We assume the order of the pair is swaped, but both solutions are right" << std::endl;
00095             TS_ASSERT_EQUALS( actual.first, expected.second );
00096             TS_ASSERT_EQUALS( actual.second, expected.first );
00097         }
00098         else
00099         {
00100             TS_ASSERT_EQUALS( actual.first, expected.first );
00101             TS_ASSERT_EQUALS( actual.second, expected.second );
00102         }
00103     }
00104 
00105     /**
00106      * This test numerical stability:
00107      * x^2 + 9999999999x -9e10 = 0, has solutions according to wolfram alpha:
00108      *    x_1 = -1.00000000079999999928x10^10
00109      *    x_2 = 8.99999999280000001224
00110      */
00111     void testRealQuadraticEquationToTestNumericalIssuesAndPrecisions( void )
00112     {
00113         typedef std::pair< std::complex< double >, std::complex< double > > ComplexPair;
00114         ComplexPair actual = solveRealQuadraticEquation( 1.0, 9999999999.0, -9.0e10 );
00115         ComplexPair expected = ComplexPair( std::complex< double >( -1.00000000079999999928e10, 0.0 ), std::complex< double >( 8.99999999280000001224, 0.0 ) ); // NOLINT line length
00116         double delta = 0.00000001; // This precision was found by trial and error
00117         if( ( ( std::abs( actual.first - expected.first ) > delta ) && ( std::abs( actual.first - expected.second ) > delta ) ) ||
00118             ( ( std::abs( actual.second - expected.second ) > delta ) && ( std::abs( actual.second - expected.first ) > delta ) ) )
00119         {
00120             std::stringstream ss;
00121             ss << std::fixed << std::setprecision( 16 ) << std::endl;
00122             ss << "Invalid solutions: " << std::endl;
00123             ss << std::real( actual.first ) << " i" << std::imag( actual.first ) << " :::: ";
00124             ss << std::real( actual.second ) << " i" << std::imag( actual.second ) << std::endl;
00125             ss << " were invalid. I expected: " << std::endl;
00126             ss << std::real( expected.first ) << " i" << std::imag( expected.first ) << " :::: ";
00127             ss << std::real( expected.second ) << " i" << std::imag( expected.second ) << std::endl;
00128             std::cout << ss.str();
00129             TS_FAIL( "Check your numerical stability and the order of the solutions found." );
00130         }
00131     }
00132 };
00133 
00134 #endif  // WPOLYNOMIALEQUATIONSOLVERS_TEST_H