Teuchos Package Browser (Single Doxygen Collection)  Version of the Day
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
cxx_main_solver.cpp
Go to the documentation of this file.
1 // @HEADER
2 // *****************************************************************************
3 // Teuchos: Common Tools Package
4 //
5 // Copyright 2004 NTESS and the Teuchos contributors.
6 // SPDX-License-Identifier: BSD-3-Clause
7 // *****************************************************************************
8 // @HEADER
9 
14 #include "Teuchos_ScalarTraits.hpp"
15 #include "Teuchos_RCP.hpp"
16 #include "Teuchos_Version.hpp"
17 
21 
22 #define OTYPE int
23 #ifdef HAVE_TEUCHOS_COMPLEX
24 #define STYPE std::complex<double>
25 #else
26 #define STYPE double
27 #endif
28 
29 // SCALARMAX defines the maximum positive value (with a little leeway) generated for matrix and vector elements and scalars:
30 // random numbers in [-SCALARMAX, SCALARMAX] will be generated.
31 #ifdef HAVE_TEUCHOS_COMPLEX
32 #define SCALARMAX STYPE(10,0)
33 #else
34 #define SCALARMAX STYPE(10)
35 #endif
36 
37 template<typename TYPE>
38 int PrintTestResults(std::string, TYPE, TYPE, bool);
39 
40 int ReturnCodeCheck(std::string, int, int, bool);
41 
44 
45 // Returns ScalarTraits<TYPE>::random() (the input parameters are ignored)
46 template<typename TYPE>
47 TYPE GetRandom(TYPE, TYPE);
48 
49 // Returns a random integer between the two input parameters, inclusive
50 template<>
51 int GetRandom(int, int);
52 
53 // Returns a random double between the two input parameters, plus or minus a random number between 0 and 1
54 template<>
55 double GetRandom(double, double);
56 
57 template<typename T>
58 std::complex<T> GetRandom( std::complex<T>, std::complex<T> );
59 
60 // Generates random matrices and vectors using GetRandom()
63 
64 // Compares the difference between two vectors using relative euclidean norms
65 // Returns 1 if the comparison failed, the relative difference is greater than the tolerance.
67  const SerialDenseVector<OTYPE,STYPE>& Vector2,
69  bool verbose);
70 
71 int main(int argc, char* argv[])
72 {
73  typedef ScalarTraits<STYPE>::magnitudeType MagnitudeType;
74 
75  int n=10, m=8;
76  (void) m; // forestall "unused variable" compiler warning
77  MagnitudeType tol = 1e-12*ScalarTraits<MagnitudeType>::one();
78 
79  bool verbose = 0;
80  if (argc>1) if (argv[1][0]=='-' && argv[1][1]=='v') verbose = true;
81 
82  if (verbose)
83  std::cout << Teuchos::Teuchos_Version() << std::endl << std::endl;
84 
85  int numberFailedTests = 0;
86  int returnCode = 0;
87  std::string testName = "", testType = "";
88 
89 #ifdef HAVE_TEUCHOS_COMPLEX
90  testType = "COMPLEX";
91 #else
92  testType = "REAL";
93 #endif
94 
95  if (verbose) std::cout<<std::endl<<"********** CHECKING TEUCHOS SERIAL DENSE SOLVER - " << testType << "-VALUED **********"<<std::endl<<std::endl;
96 
97  // Create dense matrix and vector.
100  DVector xhat(n), b(n), bt(n);
101 
102  // Compute the right-hand side vector using multiplication.
104  testName = "Generating right-hand side vector using A*x, where x is a random vector:";
105  numberFailedTests += ReturnCodeCheck(testName, returnCode, 0, verbose);
106 
108  testName = "Generating right-hand side vector using A^T*x, where x is a random vector:";
109  numberFailedTests += ReturnCodeCheck(testName, returnCode, 0, verbose);
110 
111 #ifdef HAVE_TEUCHOS_COMPLEX
112  DVector bct(n);
114  testName = "Generating right-hand side vector using A^H*x, where x is a random vector:";
115  numberFailedTests += ReturnCodeCheck(testName, returnCode, 0, verbose);
116 #endif
117 
118  // Fill the solution vector with zeros.
119  xhat.putScalar( ScalarTraits<STYPE>::zero() );
120 
121  // Create a serial dense solver.
123 
124  // Pass in matrix and vectors
125  solver1.setMatrix( A1 );
126  solver1.setVectors( Teuchos::rcp( &xhat, false ), Teuchos::rcp( &b, false ) );
127 
128  // Test1: Simple factor and solve
129  returnCode = solver1.factor();
130  testName = "Simple solve: factor() random A:";
131  numberFailedTests += ReturnCodeCheck(testName, returnCode, 0, verbose);
132 
133  // Non-transpose solve
134  returnCode = solver1.solve();
135  testName = "Simple solve: solve() random A (NO_TRANS):";
136  numberFailedTests += CompareVectors( *x1, xhat, tol, verbose );
137  numberFailedTests += ReturnCodeCheck(testName, returnCode, 0, verbose);
138 
139  // Tranpose solve (can be done after factorization, since factorization doesn't depend on this)
140  xhat.putScalar( ScalarTraits<STYPE>::zero() );
141  solver1.setVectors( Teuchos::rcp( &xhat, false ), Teuchos::rcp( &bt, false ) );
143  returnCode = solver1.solve();
144  testName = "Simple solve: solve() random A (TRANS):";
145  numberFailedTests += CompareVectors( *x1, xhat, tol, verbose );
146  numberFailedTests += ReturnCodeCheck(testName, returnCode, 0, verbose);
147 
148 #ifdef HAVE_TEUCHOS_COMPLEX
149  // Conjugate tranpose solve (can be done after factorization, since factorization doesn't depend on this)
150  xhat.putScalar( ScalarTraits<STYPE>::zero() );
151  solver1.setVectors( Teuchos::rcp( &xhat, false ), Teuchos::rcp( &bct, false ) );
153  returnCode = solver1.solve();
154  testName = "Simple solve: solve() random A (CONJ_TRANS):";
155  numberFailedTests += CompareVectors( *x1, xhat, tol, verbose );
156  numberFailedTests += ReturnCodeCheck(testName, returnCode, 0, verbose);
157 #endif
158 
159  // Test2: Invert the matrix, inverse should be in A.
160  returnCode = solver1.invert();
161  testName = "Simple solve: invert() random A:";
162  numberFailedTests += ReturnCodeCheck(testName, returnCode, 0, verbose);
163 
164  // Compute the solution vector using multiplication and the inverse.
166  testName = "Computing solution using inverted random A (NO_TRANS):";
167  numberFailedTests += CompareVectors( *x1, xhat, tol, verbose );
168  numberFailedTests += ReturnCodeCheck(testName, returnCode, 0, verbose);
169 
170  returnCode = xhat.multiply(Teuchos::TRANS, Teuchos::NO_TRANS, ScalarTraits<STYPE>::one() , *A1, bt, ScalarTraits<STYPE>::zero());
171  testName = "Computing solution using inverted random A (TRANS):";
172  numberFailedTests += CompareVectors( *x1, xhat, tol, verbose );
173  numberFailedTests += ReturnCodeCheck(testName, returnCode, 0, verbose);
174 
175 #ifdef HAVE_TEUCHOS_COMPLEX
176  returnCode = xhat.multiply(Teuchos::CONJ_TRANS, Teuchos::NO_TRANS, ScalarTraits<STYPE>::one() , *A1, bct, ScalarTraits<STYPE>::zero());
177  testName = "Computing solution using inverted random A (CONJ_TRANS):";
178  numberFailedTests += CompareVectors( *x1, xhat, tol, verbose );
179  numberFailedTests += ReturnCodeCheck(testName, returnCode, 0, verbose);
180 #endif
181 
182  // Test3: Solve with iterative refinement.
183 #ifdef HAVE_TEUCHOSNUMERICS_EIGEN
184  // Iterative refinement not implemented in Eigen
185 #else
186  // Create random linear system
189 
190  // Create LHS through multiplication with A2
191  xhat.putScalar( ScalarTraits<STYPE>::zero() );
194 #ifdef HAVE_TEUCHOS_COMPLEX
196 #endif
197 
198  // Create a serial dense solver.
200  solver2.solveToRefinedSolution( true );
201 
202  // Pass in matrix and vectors
203  solver2.setMatrix( A2 );
204  solver2.setVectors( Teuchos::rcp( &xhat, false ), Teuchos::rcp( &b, false ) );
205 
206  // Factor and solve with iterative refinement.
207  returnCode = solver2.factor();
208  testName = "Solve with iterative refinement: factor() random A:";
209  numberFailedTests += ReturnCodeCheck(testName, returnCode, 0, verbose);
210 
211  // Non-transpose solve
212  returnCode = solver2.solve();
213  testName = "Solve with iterative refinement: solve() random A (NO_TRANS):";
214  numberFailedTests += CompareVectors( *x2, xhat, tol, verbose );
215  numberFailedTests += ReturnCodeCheck(testName, returnCode, 0, verbose);
216 
217  // Tranpose solve (can be done after factorization, since factorization doesn't depend on this)
218  xhat.putScalar( ScalarTraits<STYPE>::zero() );
219  solver2.setVectors( Teuchos::rcp( &xhat, false ), Teuchos::rcp( &bt, false ) );
221  returnCode = solver2.solve();
222  testName = "Solve with iterative refinement: solve() random A (TRANS):";
223  numberFailedTests += CompareVectors( *x2, xhat, tol, verbose );
224  numberFailedTests += ReturnCodeCheck(testName, returnCode, 0, verbose);
225 
226 #ifdef HAVE_TEUCHOS_COMPLEX
227  // Conjugate tranpose solve (can be done after factorization, since factorization doesn't depend on this)
228  xhat.putScalar( ScalarTraits<STYPE>::zero() );
229  solver2.setVectors( Teuchos::rcp( &xhat, false ), Teuchos::rcp( &bct, false ) );
231  returnCode = solver2.solve();
232  testName = "Solve with iterative refinement: solve() random A (CONJ_TRANS):";
233  numberFailedTests += CompareVectors( *x2, xhat, tol, verbose );
234  numberFailedTests += ReturnCodeCheck(testName, returnCode, 0, verbose);
235 #endif
236 #endif
237 
238  // Test4: Solve with matrix equilibration.
239 
240  // Create random linear system
243 
244  // Create LHS through multiplication with A3
245  xhat.putScalar( ScalarTraits<STYPE>::zero() );
248 #ifdef HAVE_TEUCHOS_COMPLEX
250 #endif
251 
252  // Save backups for multiple solves.
255 
256  // Create a serial dense solver.
258  solver3.factorWithEquilibration( true );
259 
260  // Pass in matrix and vectors
261  solver3.setMatrix( A3 );
262  solver3.setVectors( Teuchos::rcp( &xhat, false ), Teuchos::rcp( &b, false ) );
263 
264  // Factor and solve with matrix equilibration.
265  returnCode = solver3.factor();
266  testName = "Solve with matrix equilibration: factor() random A:";
267  numberFailedTests += ReturnCodeCheck(testName, returnCode, 0, verbose);
268 
269  // Non-transpose solve
270  returnCode = solver3.solve();
271  testName = "Solve with matrix equilibration: solve() random A (NO_TRANS):";
272  numberFailedTests += CompareVectors( *x3, xhat, tol, verbose );
273  numberFailedTests += ReturnCodeCheck(testName, returnCode, 0, verbose);
274 
275  // Tranpose solve (can be done after factorization, since factorization doesn't depend on this)
276  xhat.putScalar( ScalarTraits<STYPE>::zero() );
277  solver3.setVectors( Teuchos::rcp( &xhat, false ), Teuchos::rcp( &bt, false ) );
279  returnCode = solver3.solve();
280  testName = "Solve with matrix equilibration: solve() random A (TRANS):";
281  numberFailedTests += CompareVectors( *x3, xhat, tol, verbose );
282  numberFailedTests += ReturnCodeCheck(testName, returnCode, 0, verbose);
283 
284 #ifdef HAVE_TEUCHOS_COMPLEX
285  // Conjugate tranpose solve (can be done after factorization, since factorization doesn't depend on this)
286  xhat.putScalar( ScalarTraits<STYPE>::zero() );
287  solver3.setVectors( Teuchos::rcp( &xhat, false ), Teuchos::rcp( &bct, false ) );
289  returnCode = solver3.solve();
290  testName = "Solve with matrix equilibration: solve() random A (CONJ_TRANS):";
291  numberFailedTests += CompareVectors( *x3, xhat, tol, verbose );
292  numberFailedTests += ReturnCodeCheck(testName, returnCode, 0, verbose);
293 #endif
294 
295  // Factor and solve with matrix equilibration, only call solve not factor.
296  // Use copy of A3 and b, they were overwritten in last factor() call.
297  xhat.putScalar( ScalarTraits<STYPE>::zero() );
298  solver3.setMatrix( A3bak );
299  solver3.setVectors( Teuchos::rcp( &xhat, false ), b3bak );
301  returnCode = solver3.solve();
302  testName = "Solve with matrix equilibration: solve() without factor() random A (NO_TRANS):";
303  numberFailedTests += CompareVectors( *x3, xhat, tol, verbose );
304  numberFailedTests += ReturnCodeCheck(testName, returnCode, 0, verbose);
305 
306  //
307  // If a test failed output the number of failed tests.
308  //
309  if(numberFailedTests > 0)
310  {
311  if (verbose) {
312  std::cout << "Number of failed tests: " << numberFailedTests << std::endl;
313  std::cout << "End Result: TEST FAILED" << std::endl;
314  return -1;
315  }
316  }
317  if(numberFailedTests == 0)
318  std::cout << "End Result: TEST PASSED" << std::endl;
319 
320  return 0;
321 }
322 
323 template<typename TYPE>
324 int PrintTestResults(std::string testName, TYPE calculatedResult, TYPE expectedResult, bool verbose)
325 {
326  int result;
327  if(calculatedResult == expectedResult)
328  {
329  if(verbose) std::cout << testName << " successful." << std::endl;
330  result = 0;
331  }
332  else
333  {
334  if(verbose) std::cout << testName << " unsuccessful." << std::endl;
335  result = 1;
336  }
337  return result;
338 }
339 
340 int ReturnCodeCheck(std::string testName, int returnCode, int expectedResult, bool verbose)
341 {
342  int result;
343  if(expectedResult == 0)
344  {
345  if(returnCode == 0)
346  {
347  if(verbose) std::cout << testName << " test successful." << std::endl;
348  result = 0;
349  }
350  else
351  {
352  if(verbose) std::cout << testName << " test unsuccessful. Return code was " << returnCode << "." << std::endl;
353  result = 1;
354  }
355  }
356  else
357  {
358  if(returnCode != 0)
359  {
360  if(verbose) std::cout << testName << " test successful -- failed as expected." << std::endl;
361  result = 0;
362  }
363  else
364  {
365  if(verbose) std::cout << testName << " test unsuccessful -- did not fail as expected. Return code was " << returnCode << "." << std::endl;
366  result = 1;
367  }
368  }
369  return result;
370 }
371 
372 template<typename TYPE>
373 TYPE GetRandom(TYPE Low, TYPE High)
374 {
375  return ((TYPE)((double)((1.0 * ScalarTraits<int>::random()) / RAND_MAX) * (High - Low + 1)) + Low);
376 }
377 
378 template<typename T>
379 std::complex<T> GetRandom( std::complex<T> Low, std::complex<T> High)
380 {
381  T lowMag = Low.real();
382  T highMag = High.real();
383  T real = (T)(((1.0 * ScalarTraits<int>::random()) / RAND_MAX) * (highMag - lowMag + ScalarTraits<T>::one())) + lowMag;
384  T imag = (T)(((1.0 * ScalarTraits<int>::random()) / RAND_MAX) * (highMag - lowMag + ScalarTraits<T>::one())) + lowMag;
385  return std::complex<T>( real, imag );
386 }
387 
388 template<>
389 int GetRandom(int Low, int High)
390 {
391  return ((int)((double)((1.0 * ScalarTraits<int>::random()) / RAND_MAX) * (High - Low + 1)) + Low);
392 }
393 
394 template<>
395 double GetRandom(double Low, double High)
396 {
397  return (((double)((1.0 * ScalarTraits<int>::random()) / RAND_MAX) * (High - Low + 1)) + Low + ScalarTraits<double>::random());
398 }
399 
401 {
402  Teuchos::RCP<DMatrix> newmat = Teuchos::rcp( new DMatrix(m,n) );
403 
404  // Fill dense matrix with random entries.
405  for (int i=0; i<m; i++)
406  for (int j=0; j<n; j++)
407  (*newmat)(i,j) = GetRandom(-SCALARMAX, SCALARMAX);
408 
409  return newmat;
410 }
411 
413 {
414  Teuchos::RCP<DVector> newvec = Teuchos::rcp( new DVector( n ) );
415 
416  // Fill dense vector with random entries.
417  for (int i=0; i<n; i++)
418  (*newvec)(i) = GetRandom(-SCALARMAX, SCALARMAX);
419 
420  return newvec;
421 }
422 
423 /* Function: CompareVectors
424  Purpose: Compares the difference between two vectors using relative euclidean-norms, i.e. ||v_1-v_2||_2/||v_2||_2
425 */
427  const SerialDenseVector<OTYPE,STYPE>& Vector2,
429  bool verbose)
430 {
431  typedef ScalarTraits<STYPE>::magnitudeType MagnitudeType;
432 
433  SerialDenseVector<OTYPE,STYPE> diff( Vector1 );
434  diff -= Vector2;
435 
436  MagnitudeType norm_diff = diff.normFrobenius();
437  MagnitudeType norm_v2 = Vector2.normFrobenius();
438  MagnitudeType temp = norm_diff;
439  if (norm_v2 != ScalarTraits<MagnitudeType>::zero())
440  temp /= norm_v2;
441 
442  if (temp > Tolerance)
443  {
444  if (verbose)
445  std::cout << "COMPARISON FAILED : ";
446  return 1;
447  }
448  else
449  return 0;
450 }
int PrintTestResults(std::string, TYPE, TYPE, bool)
Non-member helper functions on the templated serial, dense matrix/vector classes. ...
Templated serial dense matrix class.
Teuchos::SerialDenseVector< int, std::complex< Real > > DVector
int solve()
Computes the solution X to AX = B for the this matrix and the B provided to SetVectors()..
int multiply(ETransp transa, ETransp transb, ScalarType alpha, const SerialDenseMatrix< OrdinalType, ScalarType > &A, const SerialDenseMatrix< OrdinalType, ScalarType > &B, ScalarType beta)
Multiply A * B and add them to this; this = beta * this + alpha*A*B.
This class creates and provides basic support for dense vectors of templated type as a specialization...
ScalarTraits< ScalarType >::magnitudeType normFrobenius() const
Returns the Frobenius-norm of the matrix.
This structure defines some basic traits for a scalar field type.
void solveToRefinedSolution(bool flag)
Causes all solves to compute solution to best ability using iterative refinement. ...
Templated class for solving dense linear problems.
TEUCHOS_DEPRECATED RCP< T > rcp(T *p, Dealloc_T dealloc, bool owns_mem)
Deprecated.
TYPE GetRandom(TYPE, TYPE)
void factorWithEquilibration(bool flag)
Causes equilibration to be called just before the matrix factorization as part of the call to factor...
void solveWithTransposeFlag(Teuchos::ETransp trans)
All subsequent function calls will work with the transpose-type set by this method (Teuchos::NO_TRANS...
int invert()
Inverts the this matrix.
Teuchos::RCP< DMatrix > GetRandomMatrix(int m, int n)
bool CompareVectors(TYPE1 *Vector1, TYPE2 *Vector2, OType Size, TYPE2 Tolerance)
Teuchos::SerialDenseMatrix< int, std::complex< Real > > DMatrix
std::string Teuchos_Version()
int ReturnCodeCheck(std::string, int, int, bool)
int main(int argc, char *argv[])
int setVectors(const RCP< SerialDenseMatrix< OrdinalType, ScalarType > > &X, const RCP< SerialDenseMatrix< OrdinalType, ScalarType > > &B)
Sets the pointers for left and right hand side vector(s).
Templated serial dense vector class.
Defines basic traits for the scalar field type.
Teuchos::RCP< DVector > GetRandomVector(int n)
Smart reference counting pointer class for automatic garbage collection.
int factor()
Computes the in-place LU factorization of the matrix using the LAPACK routine _GETRF.
#define SCALARMAX
Reference-counted pointer class and non-member templated function implementations.
A class for solving dense linear problems.
int setMatrix(const RCP< SerialDenseMatrix< OrdinalType, ScalarType > > &A)
Sets the pointers for coefficient matrix.
This class creates and provides basic support for dense rectangular matrix of templated type...