Teuchos Package Browser (Single Doxygen Collection)  Version of the Day
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines
cxx_main_solver.cpp
Go to the documentation of this file.
00001 // @HEADER
00002 // ***********************************************************************
00003 //
00004 //                    Teuchos: Common Tools Package
00005 //                 Copyright (2004) Sandia Corporation
00006 //
00007 // Under terms of Contract DE-AC04-94AL85000, there is a non-exclusive
00008 // license for use of this work by or on behalf of the U.S. Government.
00009 //
00010 // Redistribution and use in source and binary forms, with or without
00011 // modification, are permitted provided that the following conditions are
00012 // met:
00013 //
00014 // 1. Redistributions of source code must retain the above copyright
00015 // notice, this list of conditions and the following disclaimer.
00016 //
00017 // 2. Redistributions in binary form must reproduce the above copyright
00018 // notice, this list of conditions and the following disclaimer in the
00019 // documentation and/or other materials provided with the distribution.
00020 //
00021 // 3. Neither the name of the Corporation nor the names of the
00022 // contributors may be used to endorse or promote products derived from
00023 // this software without specific prior written permission.
00024 //
00025 // THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY
00026 // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00027 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
00028 // PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE
00029 // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
00030 // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
00031 // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
00032 // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
00033 // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
00034 // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
00035 // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00036 //
00037 // Questions? Contact Michael A. Heroux (maherou@sandia.gov)
00038 //
00039 // ***********************************************************************
00040 // @HEADER
00041 
00042 #include "Teuchos_SerialDenseMatrix.hpp"
00043 #include "Teuchos_SerialDenseVector.hpp"
00044 #include "Teuchos_SerialDenseHelpers.hpp"
00045 #include "Teuchos_SerialDenseSolver.hpp"
00046 #include "Teuchos_ScalarTraits.hpp"
00047 #include "Teuchos_RCP.hpp"
00048 #include "Teuchos_Version.hpp"
00049 
00050 using Teuchos::ScalarTraits;
00051 using Teuchos::SerialDenseMatrix;
00052 using Teuchos::SerialDenseVector;
00053 
00054 #define OTYPE int
00055 #ifdef HAVE_TEUCHOS_COMPLEX
00056 #define STYPE std::complex<double>
00057 #else
00058 #define STYPE double
00059 #endif
00060 
00061 // SCALARMAX defines the maximum positive value (with a little leeway) generated for matrix and vector elements and scalars:
00062 // random numbers in [-SCALARMAX, SCALARMAX] will be generated.
00063 #ifdef HAVE_TEUCHOS_COMPLEX
00064 #define SCALARMAX  STYPE(10,0)
00065 #else
00066 #define SCALARMAX  STYPE(10)
00067 #endif
00068 
00069 template<typename TYPE>
00070 int PrintTestResults(std::string, TYPE, TYPE, bool);
00071 
00072 int ReturnCodeCheck(std::string, int, int, bool);
00073 
00074 typedef SerialDenseVector<OTYPE, STYPE> DVector;
00075 typedef SerialDenseMatrix<OTYPE, STYPE> DMatrix;
00076 
00077 // Returns ScalarTraits<TYPE>::random() (the input parameters are ignored)
00078 template<typename TYPE>
00079 TYPE GetRandom(TYPE, TYPE);
00080   
00081 // Returns a random integer between the two input parameters, inclusive
00082 template<>
00083 int GetRandom(int, int);
00084 
00085 // Returns a random double between the two input parameters, plus or minus a random number between 0 and 1
00086 template<>
00087 double GetRandom(double, double);
00088 
00089 template<typename T>
00090 std::complex<T> GetRandom( std::complex<T>, std::complex<T> );
00091 
00092 // Generates random matrices and vectors using GetRandom()
00093 Teuchos::RCP<DMatrix> GetRandomMatrix(int m, int n);
00094 Teuchos::RCP<DVector> GetRandomVector(int n);
00095 
00096 // Compares the difference between two vectors using relative euclidean norms
00097 // Returns 1 if the comparison failed, the relative difference is greater than the tolerance.
00098 int CompareVectors(const SerialDenseVector<OTYPE,STYPE>& Vector1, 
00099                    const SerialDenseVector<OTYPE,STYPE>& Vector2,
00100                    ScalarTraits<STYPE>::magnitudeType Tolerance );
00101 
00102 int main(int argc, char* argv[]) 
00103 {
00104   typedef ScalarTraits<STYPE>::magnitudeType MagnitudeType;
00105 
00106   int n=10, m=8;
00107   MagnitudeType tol = 1e-12*ScalarTraits<MagnitudeType>::one();
00108 
00109   bool verbose = 0;
00110   if (argc>1) if (argv[1][0]=='-' && argv[1][1]=='v') verbose = true;
00111 
00112   if (verbose)
00113     std::cout << Teuchos::Teuchos_Version() << std::endl << std::endl;
00114 
00115   int numberFailedTests = 0;
00116   int returnCode = 0;
00117   std::string testName = "", testType = "";
00118   
00119 #ifdef HAVE_TEUCHOS_COMPLEX
00120   testType = "COMPLEX";
00121 #else
00122   testType = "REAL";
00123 #endif
00124 
00125   if (verbose) std::cout<<std::endl<<"********** CHECKING TEUCHOS SERIAL DENSE SOLVER - " << testType << "-VALUED **********"<<std::endl<<std::endl;
00126 
00127   // Create dense matrix and vector.
00128   Teuchos::RCP<DMatrix> A1 = GetRandomMatrix(n,n);
00129   Teuchos::RCP<DVector> x1 = GetRandomVector(n);
00130   DVector xhat(n), b(n), bt(n);
00131 
00132   // Compute the right-hand side vector using multiplication.
00133   returnCode = b.multiply(Teuchos::NO_TRANS, Teuchos::NO_TRANS, ScalarTraits<STYPE>::one() , *A1, *x1, ScalarTraits<STYPE>::zero());
00134   testName = "Generating right-hand side vector using A*x, where x is a random vector:";
00135   numberFailedTests += ReturnCodeCheck(testName, returnCode, 0, verbose);
00136 
00137   returnCode = bt.multiply(Teuchos::TRANS, Teuchos::NO_TRANS, ScalarTraits<STYPE>::one() , *A1, *x1, ScalarTraits<STYPE>::zero());
00138   testName = "Generating right-hand side vector using A^T*x, where x is a random vector:";
00139   numberFailedTests += ReturnCodeCheck(testName, returnCode, 0, verbose);
00140 
00141 #ifdef HAVE_TEUCHOS_COMPLEX
00142   DVector bct(n);
00143   returnCode = bct.multiply(Teuchos::CONJ_TRANS, Teuchos::NO_TRANS, ScalarTraits<STYPE>::one() , *A1, *x1, ScalarTraits<STYPE>::zero());
00144   testName = "Generating right-hand side vector using A^H*x, where x is a random vector:";
00145   numberFailedTests += ReturnCodeCheck(testName, returnCode, 0, verbose);
00146 #endif
00147 
00148   // Fill the solution vector with zeros.
00149   xhat.putScalar( ScalarTraits<STYPE>::zero() );
00150 
00151   // Create a serial dense solver.
00152   Teuchos::SerialDenseSolver<OTYPE, STYPE> solver1;
00153  
00154   // Pass in matrix and vectors
00155   solver1.setMatrix( A1 );
00156   solver1.setVectors( Teuchos::rcp( &xhat, false ), Teuchos::rcp( &b, false ) );
00157 
00158   // Test1:  Simple factor and solve
00159   returnCode = solver1.factor();
00160   testName = "Simple solve: factor() random A:";
00161   numberFailedTests += ReturnCodeCheck(testName, returnCode, 0, verbose);
00162 
00163   // Non-transpose solve
00164   returnCode = solver1.solve();
00165   testName = "Simple solve: solve() random A (NO_TRANS):";
00166   numberFailedTests += CompareVectors( *x1, xhat, tol );
00167   numberFailedTests += ReturnCodeCheck(testName, returnCode, 0, verbose);
00168   
00169   // Tranpose solve (can be done after factorization, since factorization doesn't depend on this)
00170   xhat.putScalar( ScalarTraits<STYPE>::zero() );
00171   solver1.setVectors( Teuchos::rcp( &xhat, false ), Teuchos::rcp( &bt, false ) );
00172   solver1.solveWithTransposeFlag( Teuchos::TRANS );
00173   returnCode = solver1.solve();
00174   testName = "Simple solve: solve() random A (TRANS):";
00175   numberFailedTests += CompareVectors( *x1, xhat, tol );
00176   numberFailedTests += ReturnCodeCheck(testName, returnCode, 0, verbose);
00177  
00178 #ifdef HAVE_TEUCHOS_COMPLEX 
00179   // Conjugate tranpose solve (can be done after factorization, since factorization doesn't depend on this)
00180   xhat.putScalar( ScalarTraits<STYPE>::zero() );
00181   solver1.setVectors( Teuchos::rcp( &xhat, false ), Teuchos::rcp( &bct, false ) );
00182   solver1.solveWithTransposeFlag( Teuchos::CONJ_TRANS );
00183   returnCode = solver1.solve();
00184   testName = "Simple solve: solve() random A (CONJ_TRANS):";
00185   numberFailedTests += CompareVectors( *x1, xhat, tol );
00186   numberFailedTests += ReturnCodeCheck(testName, returnCode, 0, verbose);
00187 #endif
00188 
00189   // Test2: Invert the matrix, inverse should be in A.
00190   returnCode = solver1.invert();
00191   testName = "Simple solve: invert() random A:";
00192   numberFailedTests += ReturnCodeCheck(testName, returnCode, 0, verbose);
00193  
00194   // Compute the solution vector using multiplication and the inverse.
00195   returnCode = xhat.multiply(Teuchos::NO_TRANS, Teuchos::NO_TRANS, ScalarTraits<STYPE>::one() , *A1, b, ScalarTraits<STYPE>::zero());
00196   testName = "Computing solution using inverted random A (NO_TRANS):";
00197   numberFailedTests += CompareVectors( *x1, xhat, tol );
00198   numberFailedTests += ReturnCodeCheck(testName, returnCode, 0, verbose);
00199 
00200   returnCode = xhat.multiply(Teuchos::TRANS, Teuchos::NO_TRANS, ScalarTraits<STYPE>::one() , *A1, bt, ScalarTraits<STYPE>::zero());
00201   testName = "Computing solution using inverted random A (TRANS):";
00202   numberFailedTests += CompareVectors( *x1, xhat, tol );
00203   numberFailedTests += ReturnCodeCheck(testName, returnCode, 0, verbose);
00204 
00205 #ifdef HAVE_TEUCHOS_COMPLEX
00206   returnCode = xhat.multiply(Teuchos::CONJ_TRANS, Teuchos::NO_TRANS, ScalarTraits<STYPE>::one() , *A1, bct, ScalarTraits<STYPE>::zero());
00207   testName = "Computing solution using inverted random A (CONJ_TRANS):";
00208   numberFailedTests += CompareVectors( *x1, xhat, tol );
00209   numberFailedTests += ReturnCodeCheck(testName, returnCode, 0, verbose);
00210 #endif
00211 
00212   // Test3:  Solve with iterative refinement.
00213 
00214   // Create random linear system
00215   Teuchos::RCP<DMatrix> A2 = GetRandomMatrix(n,n);
00216   Teuchos::RCP<DVector> x2 = GetRandomVector(n);
00217 
00218   // Create LHS through multiplication with A2
00219   xhat.putScalar( ScalarTraits<STYPE>::zero() );
00220   b.multiply(Teuchos::NO_TRANS, Teuchos::NO_TRANS, ScalarTraits<STYPE>::one() , *A2, *x2, ScalarTraits<STYPE>::zero());
00221   bt.multiply(Teuchos::TRANS, Teuchos::NO_TRANS, ScalarTraits<STYPE>::one() , *A2, *x2, ScalarTraits<STYPE>::zero());
00222 #ifdef HAVE_TEUCHOS_COMPLEX
00223   bct.multiply(Teuchos::CONJ_TRANS, Teuchos::NO_TRANS, ScalarTraits<STYPE>::one() , *A2, *x2, ScalarTraits<STYPE>::zero());
00224 #endif
00225 
00226   // Create a serial dense solver.
00227   Teuchos::SerialDenseSolver<OTYPE, STYPE> solver2;
00228   solver2.solveToRefinedSolution( true );
00229  
00230   // Pass in matrix and vectors
00231   solver2.setMatrix( A2 );
00232   solver2.setVectors( Teuchos::rcp( &xhat, false ), Teuchos::rcp( &b, false ) );
00233 
00234   // Factor and solve with iterative refinement.
00235   returnCode = solver2.factor();
00236   testName = "Solve with iterative refinement: factor() random A:";
00237   numberFailedTests += ReturnCodeCheck(testName, returnCode, 0, verbose);
00238 
00239   // Non-transpose solve
00240   returnCode = solver2.solve();
00241   testName = "Solve with iterative refinement: solve() random A (NO_TRANS):";
00242   numberFailedTests += CompareVectors( *x2, xhat, tol );
00243   numberFailedTests += ReturnCodeCheck(testName, returnCode, 0, verbose);
00244   
00245   // Tranpose solve (can be done after factorization, since factorization doesn't depend on this)
00246   xhat.putScalar( ScalarTraits<STYPE>::zero() );
00247   solver2.setVectors( Teuchos::rcp( &xhat, false ), Teuchos::rcp( &bt, false ) );
00248   solver2.solveWithTransposeFlag( Teuchos::TRANS );
00249   returnCode = solver2.solve();
00250   testName = "Solve with iterative refinement: solve() random A (TRANS):";
00251   numberFailedTests += CompareVectors( *x2, xhat, tol );
00252   numberFailedTests += ReturnCodeCheck(testName, returnCode, 0, verbose);
00253  
00254 #ifdef HAVE_TEUCHOS_COMPLEX 
00255   // Conjugate tranpose solve (can be done after factorization, since factorization doesn't depend on this)
00256   xhat.putScalar( ScalarTraits<STYPE>::zero() );
00257   solver2.setVectors( Teuchos::rcp( &xhat, false ), Teuchos::rcp( &bct, false ) );
00258   solver2.solveWithTransposeFlag( Teuchos::CONJ_TRANS );
00259   returnCode = solver2.solve();
00260   testName = "Solve with iterative refinement: solve() random A (CONJ_TRANS):";
00261   numberFailedTests += CompareVectors( *x2, xhat, tol );
00262   numberFailedTests += ReturnCodeCheck(testName, returnCode, 0, verbose);
00263 #endif
00264 
00265   // Test4:  Solve with matrix equilibration.
00266  
00267   // Create random linear system
00268   Teuchos::RCP<DMatrix> A3 = GetRandomMatrix(n,n);
00269   Teuchos::RCP<DVector> x3 = GetRandomVector(n);
00270 
00271   // Create LHS through multiplication with A3
00272   xhat.putScalar( ScalarTraits<STYPE>::zero() );
00273   b.multiply(Teuchos::NO_TRANS, Teuchos::NO_TRANS, ScalarTraits<STYPE>::one() , *A3, *x3, ScalarTraits<STYPE>::zero());
00274   bt.multiply(Teuchos::TRANS, Teuchos::NO_TRANS, ScalarTraits<STYPE>::one() , *A3, *x3, ScalarTraits<STYPE>::zero());
00275 #ifdef HAVE_TEUCHOS_COMPLEX
00276   bct.multiply(Teuchos::CONJ_TRANS, Teuchos::NO_TRANS, ScalarTraits<STYPE>::one() , *A3, *x3, ScalarTraits<STYPE>::zero());
00277 #endif
00278 
00279   // Create a serial dense solver.
00280   Teuchos::SerialDenseSolver<OTYPE, STYPE> solver3;
00281   solver3.factorWithEquilibration( true );
00282  
00283   // Pass in matrix and vectors
00284   solver3.setMatrix( A3 );
00285   solver3.setVectors( Teuchos::rcp( &xhat, false ), Teuchos::rcp( &b, false ) );
00286 
00287   // Factor and solve with matrix equilibration.
00288   returnCode = solver3.factor();
00289   testName = "Solve with matrix equilibration: factor() random A:";
00290   numberFailedTests += ReturnCodeCheck(testName, returnCode, 0, verbose);
00291 
00292   // Non-transpose solve
00293   returnCode = solver3.solve();
00294   testName = "Solve with matrix equilibration: solve() random A (NO_TRANS):";
00295   numberFailedTests += CompareVectors( *x3, xhat, tol );
00296   numberFailedTests += ReturnCodeCheck(testName, returnCode, 0, verbose);
00297   
00298   // Tranpose solve (can be done after factorization, since factorization doesn't depend on this)
00299   xhat.putScalar( ScalarTraits<STYPE>::zero() );
00300   solver3.setVectors( Teuchos::rcp( &xhat, false ), Teuchos::rcp( &bt, false ) );
00301   solver3.solveWithTransposeFlag( Teuchos::TRANS );
00302   returnCode = solver3.solve();
00303   testName = "Solve with matrix equilibration: solve() random A (TRANS):";
00304   numberFailedTests += CompareVectors( *x3, xhat, tol );
00305   numberFailedTests += ReturnCodeCheck(testName, returnCode, 0, verbose);
00306  
00307 #ifdef HAVE_TEUCHOS_COMPLEX 
00308   // Conjugate tranpose solve (can be done after factorization, since factorization doesn't depend on this)
00309   xhat.putScalar( ScalarTraits<STYPE>::zero() );
00310   solver3.setVectors( Teuchos::rcp( &xhat, false ), Teuchos::rcp( &bct, false ) );
00311   solver3.solveWithTransposeFlag( Teuchos::CONJ_TRANS );
00312   returnCode = solver3.solve();
00313   testName = "Solve with matrix equilibration: solve() random A (CONJ_TRANS):";
00314   numberFailedTests += CompareVectors( *x3, xhat, tol );
00315   numberFailedTests += ReturnCodeCheck(testName, returnCode, 0, verbose);
00316 #endif
00317  
00318   //
00319   // If a test failed output the number of failed tests.
00320   //
00321   if(numberFailedTests > 0) 
00322   { 
00323       if (verbose) {
00324     std::cout << "Number of failed tests: " << numberFailedTests << std::endl;
00325                 std::cout << "End Result: TEST FAILED" << std::endl;
00326     return -1;
00327       }
00328   }
00329   if(numberFailedTests == 0)
00330     std::cout << "End Result: TEST PASSED" << std::endl;
00331 
00332   return 0;
00333 }  
00334 
00335 template<typename TYPE>
00336 int PrintTestResults(std::string testName, TYPE calculatedResult, TYPE expectedResult, bool verbose)
00337 {
00338   int result;
00339   if(calculatedResult == expectedResult)
00340     {
00341       if(verbose) std::cout << testName << " successful." << std::endl;
00342       result = 0;
00343     }
00344   else
00345     {
00346       if(verbose) std::cout << testName << " unsuccessful." << std::endl;
00347       result = 1;
00348     }
00349   return result;
00350 }
00351 
00352 int ReturnCodeCheck(std::string testName, int returnCode, int expectedResult, bool verbose)
00353 {
00354   int result;
00355   if(expectedResult == 0)
00356     {
00357       if(returnCode == 0)
00358   {
00359     if(verbose) std::cout << testName << " test successful." << std::endl;
00360     result = 0;
00361   }
00362       else
00363   {
00364     if(verbose) std::cout << testName << " test unsuccessful. Return code was " << returnCode << "." << std::endl;
00365     result = 1;
00366   }
00367     }
00368   else
00369     {
00370       if(returnCode != 0)
00371   {
00372     if(verbose) std::cout << testName << " test successful -- failed as expected." << std::endl;
00373     result = 0;
00374   }
00375       else
00376   {
00377     if(verbose) std::cout << testName << " test unsuccessful -- did not fail as expected. Return code was " << returnCode << "." << std::endl;
00378     result = 1;
00379   }
00380     }
00381   return result;
00382 }
00383 
00384 template<typename TYPE>
00385 TYPE GetRandom(TYPE Low, TYPE High)
00386 {
00387   return ((TYPE)((double)((1.0 * ScalarTraits<int>::random()) / RAND_MAX) * (High - Low + 1)) + Low);
00388 }
00389 
00390 template<typename T>
00391 std::complex<T> GetRandom( std::complex<T> Low, std::complex<T> High)
00392 {
00393   T lowMag = Low.real();
00394   T highMag = High.real();
00395   T real = (T)(((1.0 * ScalarTraits<int>::random()) / RAND_MAX) * (highMag - lowMag + ScalarTraits<T>::one())) + lowMag;
00396   T imag = (T)(((1.0 * ScalarTraits<int>::random()) / RAND_MAX) * (highMag - lowMag + ScalarTraits<T>::one())) + lowMag;
00397   return std::complex<T>( real, imag );
00398 }
00399 
00400 template<>
00401 int GetRandom(int Low, int High)
00402 {
00403   return ((int)((double)((1.0 * ScalarTraits<int>::random()) / RAND_MAX) * (High - Low + 1)) + Low);
00404 }
00405 
00406 template<>
00407 double GetRandom(double Low, double High)
00408 {
00409   return (((double)((1.0 * ScalarTraits<int>::random()) / RAND_MAX) * (High - Low + 1)) + Low + ScalarTraits<double>::random());
00410 }
00411 
00412 Teuchos::RCP<DMatrix> GetRandomMatrix(int m, int n)
00413 {
00414   Teuchos::RCP<DMatrix> newmat = Teuchos::rcp( new DMatrix(m,n) );
00415 
00416   // Fill dense matrix with random entries.
00417   for (int i=0; i<m; i++)
00418     for (int j=0; j<n; j++)
00419       (*newmat)(i,j) = GetRandom(-SCALARMAX, SCALARMAX);    
00420 
00421   return newmat;
00422 }
00423 
00424 Teuchos::RCP<DVector> GetRandomVector(int n)
00425 {
00426   Teuchos::RCP<DVector> newvec = Teuchos::rcp( new DVector( n ) );
00427 
00428   // Fill dense vector with random entries.
00429   for (int i=0; i<n; i++)
00430     (*newvec)(i) = GetRandom(-SCALARMAX, SCALARMAX);
00431   
00432   return newvec;
00433 }
00434 
00435 /*  Function:  CompareVectors
00436     Purpose:   Compares the difference between two vectors using relative euclidean-norms, i.e. ||v_1-v_2||_2/||v_2||_2
00437 */
00438 int CompareVectors(const SerialDenseVector<OTYPE,STYPE>& Vector1, 
00439                    const SerialDenseVector<OTYPE,STYPE>& Vector2,
00440                    ScalarTraits<STYPE>::magnitudeType Tolerance )
00441 {
00442   typedef ScalarTraits<STYPE>::magnitudeType MagnitudeType;
00443 
00444   SerialDenseVector<OTYPE,STYPE> diff( Vector1 );
00445   diff -= Vector2;
00446   
00447   MagnitudeType norm_diff = diff.normFrobenius();
00448   MagnitudeType norm_v2 = Vector2.normFrobenius();
00449   MagnitudeType temp = norm_diff; 
00450   if (norm_v2 != ScalarTraits<MagnitudeType>::zero())
00451     temp /= norm_v2;
00452 
00453   if (temp > Tolerance)
00454     return 1;
00455   else
00456     return 0;
00457 }
00458 
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines