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_qr_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 
19 using Teuchos::LAPACK;
22 
23 #define OTYPE int
24 #ifdef HAVE_TEUCHOS_COMPLEX
25 #define STYPE std::complex<double>
26 #else
27 #define STYPE double
28 #endif
29 
30 // SCALARMAX defines the maximum positive value (with a little leeway) generated for matrix and vector elements and scalars:
31 // random numbers in [-SCALARMAX, SCALARMAX] will be generated.
32 #ifdef HAVE_TEUCHOS_COMPLEX
33 #define SCALARMAX STYPE(10,0)
34 #else
35 #define SCALARMAX STYPE(10)
36 #endif
37 
38 template<typename TYPE>
39 int PrintTestResults(std::string, TYPE, TYPE, bool);
40 
41 int ReturnCodeCheck(std::string, int, int, bool);
42 
45 
46 // Returns ScalarTraits<TYPE>::random() (the input parameters are ignored)
47 template<typename TYPE>
48 TYPE GetRandom(TYPE, TYPE);
49 
50 // Returns a random integer between the two input parameters, inclusive
51 template<>
52 int GetRandom(int, int);
53 
54 // Returns a random double between the two input parameters, plus or minus a random number between 0 and 1
55 template<>
56 double GetRandom(double, double);
57 
58 template<typename T>
59 std::complex<T> GetRandom( std::complex<T>, std::complex<T> );
60 
61 // Generates random matrices and vectors using GetRandom()
64 
65 // Compares the difference between two vectors using relative euclidean norms
66 // Returns 1 if the comparison failed, the relative difference is greater than the tolerance.
68  const SerialDenseVector<OTYPE,STYPE>& Vector2,
70 
71 int main(int argc, char* argv[])
72 {
73  typedef ScalarTraits<STYPE>::magnitudeType MagnitudeType;
74 
76 
77  int n=8, m=12;
78  MagnitudeType tol = 1e-12*ScalarTraits<MagnitudeType>::one();
79 
80  bool verbose = 0;
81  if (argc>1) if (argv[1][0]=='-' && argv[1][1]=='v') verbose = true;
82 
83  if (verbose)
84  std::cout << Teuchos::Teuchos_Version() << std::endl << std::endl;
85 
86  int numberFailedTests = 0;
87  int returnCode = 0;
88  std::string testName = "", testType = "";
89 
90 #ifdef HAVE_TEUCHOS_COMPLEX
91  testType = "COMPLEX";
92 #else
93  testType = "REAL";
94 #endif
95 
96  if (verbose) std::cout<<std::endl<<"********** CHECKING TEUCHOS SERIAL QR SOLVER - " << testType << "-VALUED **********"<<std::endl<<std::endl;
97 
98  // Create dense matrix and vector.
102  DVector xhat(n), b(m), xhatt(m);
103 
104  // Compute the right-hand side vector using multiplication.
106  testName = "Generating right-hand side vector using A*x, where x is a random vector:";
107  numberFailedTests += ReturnCodeCheck(testName, returnCode, 0, verbose);
108 
109 #ifdef HAVE_TEUCHOS_COMPLEX
110  DVector bct(n);
112  testName = "Generating right-hand side vector using A^H*x, where x is a random vector:";
113  numberFailedTests += ReturnCodeCheck(testName, returnCode, 0, verbose);
114 #else
115  DVector bt(n);
117  testName = "Generating right-hand side vector using A^T*x, where x is a random vector:";
118  numberFailedTests += ReturnCodeCheck(testName, returnCode, 0, verbose);
119 #endif
120  DVector bp, bp2;
122  DVector tmp(n), tmp2(m);
123 
124  // Fill the solution vector with zeros.
125  xhat.putScalar( ScalarTraits<STYPE>::zero() );
127 
128  // Create a serial dense solver.
130 
131  // Pass in matrix and vectors
132  solver1.setMatrix( A1 );
133  solver1.setVectors( Teuchos::rcp( &xhat, false ), Teuchos::rcp( &b, false ) );
134 
135  // Test1: Simple factor and solve
136  returnCode = solver1.factor();
137  testName = "Simple solve: factor() random A:";
138  numberFailedTests += ReturnCodeCheck(testName, returnCode, 0, verbose);
139  returnCode = solver1.formQ();
140  testName = "Simple solve: formQ() random A:";
141  numberFailedTests += ReturnCodeCheck(testName, returnCode, 0, verbose);
142 
143  // Non-transpose solve
144  returnCode = solver1.solve();
145  testName = "Simple solve: solve() random A (NO_TRANS):";
146  numberFailedTests += CompareVectors( *x1, xhat, tol );
147  numberFailedTests += ReturnCodeCheck(testName, returnCode, 0, verbose);
148  testName = "Simple solve: multiplyQ(TRANS) solveR (NO_TRANS) random A (NO_TRANS):";
149  bp = b;
150  returnCode = solver1.multiplyQ( Teuchos::TRANS, bp );
151  numberFailedTests += ReturnCodeCheck(testName, returnCode, 0, verbose);
152  for (OTYPE i=0; i<n; i++) {tmp(i) = bp(i);}
153  returnCode = solver1.solveR( Teuchos::NO_TRANS, tmp );
154  numberFailedTests += ReturnCodeCheck(testName, returnCode, 0, verbose);
155  numberFailedTests += CompareVectors( tmp, xhat, tol );
156 
157 #ifdef HAVE_TEUCHOS_COMPLEX
158  testName = "Simple solve: formQ() solve with explicit Q implicit R random A (NO_TRANS):";
159  Q = solver1.getQ();
160  bp.multiply(Teuchos::CONJ_TRANS, Teuchos::NO_TRANS, 1.0, *Q, b, 0.0);
161  for (OTYPE i=0; i<n; i++) {tmp(i) = bp(i);}
162  returnCode = solver1.solveR( Teuchos::NO_TRANS, tmp );
163  numberFailedTests += ReturnCodeCheck(testName, returnCode, 0, verbose);
164  numberFailedTests += CompareVectors( tmp, xhat, tol );
165  testName = "Simple solve: formQ() solve with explicit Q explicit R random A (NO_TRANS):";
166  Q = solver1.getQ();
167  returnCode = solver1.formR();
168  numberFailedTests += ReturnCodeCheck(testName, returnCode, 0, verbose);
169  bp.multiply(Teuchos::CONJ_TRANS, Teuchos::NO_TRANS, 1.0, *Q, b, 0.0);
170  for (OTYPE i=0; i<n; i++) {tmp(i) = bp(i);}
171  returnCode = solver1.solveR( Teuchos::NO_TRANS, tmp );
172  numberFailedTests += ReturnCodeCheck(testName, returnCode, 0, verbose);
173  numberFailedTests += CompareVectors( tmp, xhat, tol );
174 #else
175  testName = "Simple solve: formQ() solve with explicit Q random A (NO_TRANS):";
176  Q = solver1.getQ();
177  bp.multiply(Teuchos::TRANS, Teuchos::NO_TRANS, 1.0, *Q, b, 0.0);
178  for (OTYPE i=0; i<n; i++) {tmp(i) = bp(i);}
179  returnCode = solver1.solveR( Teuchos::NO_TRANS, tmp );
180  numberFailedTests += ReturnCodeCheck(testName, returnCode, 0, verbose);
181  numberFailedTests += CompareVectors( tmp, xhat, tol );
182  testName = "Simple solve: formQ() solve with explicit Q explicit R random A (NO_TRANS):";
183  Q = solver1.getQ();
184  returnCode = solver1.formR();
185  numberFailedTests += ReturnCodeCheck(testName, returnCode, 0, verbose);
186  bp.multiply(Teuchos::TRANS, Teuchos::NO_TRANS, 1.0, *Q, b, 0.0);
187  for (OTYPE i=0; i<n; i++) {tmp(i) = bp(i);}
188  returnCode = solver1.solveR( Teuchos::NO_TRANS, tmp );
189  numberFailedTests += ReturnCodeCheck(testName, returnCode, 0, verbose);
190  numberFailedTests += CompareVectors( tmp, xhat, tol );
191 #endif
192 
193 #ifdef HAVE_TEUCHOS_COMPLEX
194  // Conjugate tranpose solve (can be done after factorization, since factorization doesn't depend on this)
196  solver1.setVectors( Teuchos::rcp( &xhatt, false ), Teuchos::rcp( &bct, false ) );
198  returnCode = solver1.solve();
199  testName = "Simple solve: solve() random A (CONJ_TRANS):";
200  if (m == n)
201  numberFailedTests += CompareVectors( *x1t, xhatt, tol );
202  numberFailedTests += ReturnCodeCheck(testName, returnCode, 0, verbose);
203  testName = "Simple solve: solveR (NO_TRANS) multiplyQ(TRANS) random A (CONJ_TRANS):";
204  bp = bct;
205  returnCode = solver1.solveR( Teuchos::TRANS, bp );
206  numberFailedTests += ReturnCodeCheck(testName, returnCode, 0, verbose);
207  for (OTYPE i=0; i<n; i++) {tmp2(i) = bp(i);}
208  returnCode = solver1.multiplyQ( Teuchos::NO_TRANS, tmp2 );
209  numberFailedTests += ReturnCodeCheck(testName, returnCode, 0, verbose);
210  if (m == n)
211  numberFailedTests += CompareVectors(*x1t, tmp2, tol );
212  numberFailedTests += CompareVectors( tmp2, xhatt, tol );
213  testName = "Simple solve: formQ() solve with explicit Q random A (CONJ_TRANS):";
214  bp = bct;
215  Q = solver1.getQ();
216  returnCode = solver1.solveR( Teuchos::TRANS, bp );
217  numberFailedTests += ReturnCodeCheck(testName, returnCode, 0, verbose);
218  tmp2.multiply(Teuchos::NO_TRANS, Teuchos::NO_TRANS, 1.0, *Q, bp, 0.0);
219  if (m == n)
220  numberFailedTests += CompareVectors(*x1t, tmp2, tol );
221  numberFailedTests += CompareVectors( tmp2, xhatt, tol );
222 
223 #else
224  // Tranpose solve (can be done after factorization, since factorization doesn't depend on this)
226  solver1.setVectors( Teuchos::rcp( &xhatt, false ), Teuchos::rcp( &bt, false ) );
228  returnCode = solver1.solve();
229  testName = "Simple solve: solve() random A (TRANS):";
230  if (m == n)
231  numberFailedTests += CompareVectors( *x1t, xhatt, tol );
232  numberFailedTests += ReturnCodeCheck(testName, returnCode, 0, verbose);
233  bp = bt;
234  testName = "Simple solve: solveR multiplyQ(TRANS) (NO_TRANS) random A (TRANS):";
235  returnCode = solver1.solveR( Teuchos::TRANS, bp );
236  numberFailedTests += ReturnCodeCheck(testName, returnCode, 0, verbose);
237  for (OTYPE i=0; i<n; i++) {tmp2(i) = bp(i);}
238  returnCode = solver1.multiplyQ( Teuchos::NO_TRANS, tmp2 );
239  numberFailedTests += ReturnCodeCheck(testName, returnCode, 0, verbose);
240  if (m == n)
241  numberFailedTests += CompareVectors(*x1t, tmp2, tol );
242  numberFailedTests += CompareVectors( tmp2, xhatt, tol );
243  testName = "Simple solve: formQ() solve with explicit Q random A (CONJ_TRANS):";
244  bp = bt;
245  Q = solver1.getQ();
246  returnCode = solver1.solveR( Teuchos::TRANS, bp );
247  numberFailedTests += ReturnCodeCheck(testName, returnCode, 0, verbose);
248  tmp2.multiply(Teuchos::NO_TRANS, Teuchos::NO_TRANS, 1.0, *Q, bp, 0.0);
249  if (m == n)
250  numberFailedTests += CompareVectors(*x1t, tmp2, tol );
251  numberFailedTests += CompareVectors( tmp2, xhatt, tol );
252 
253 #endif
254 
255  // Test2: Solve with matrix equilibration.
256 
257  // Create random linear system
261 
262  // Create LHS through multiplication with A2
263  xhat.putScalar( ScalarTraits<STYPE>::zero() );
266 #ifdef HAVE_TEUCHOS_COMPLEX
268 #else
270 #endif
271 
272  // Create a serial dense solver.
274  solver2.factorWithEquilibration( true );
275 
276  // Pass in matrix and vectors
277  MagnitudeType safeMin = ScalarTraits<STYPE>::sfmin();
278  MagnitudeType prec = ScalarTraits<STYPE>::prec();
280  MagnitudeType smlnum = ScalarTraits<STYPE>::magnitude(safeMin/prec);
281  MagnitudeType bignum = ScalarTraits<STYPE>::magnitude(sOne/smlnum);
282  (void) bignum; // Silence "unused variable" compiler warning.
283  MagnitudeType smlnum2 = smlnum/2;
284  (void) smlnum2; // Silence "unused variable" compiler warning.
286  for (OTYPE j = 0; j < A2->numCols(); j++) {
287  for (OTYPE i = 0; i < A2->numRows(); i++) {
288  anorm = TEUCHOS_MAX( anorm, ScalarTraits<STYPE>::magnitude((*A2)(i,j)) );
289  }
290  }
291  OTYPE BW = 0;
292  (void) BW; // Silence "unused variable" compiler warning.
293  OTYPE info = 0;
294  (void) info; // Silence "unused variable" compiler warning.
295  // TODO: fix scaling test
296  // L.LASCL(Teuchos::ETypeChar[Teuchos::FULL], BW, BW, anorm, smlnum2, A2->numRows(), A2->numCols(), A2->values(), A2->stride(), &info);
297  solver2.setMatrix( A2 );
298  solver2.setVectors( Teuchos::rcp( &xhat, false ), Teuchos::rcp( &b, false ) );
299 
302 
303  // Factor and solve with matrix equilibration.
304  returnCode = solver2.factor();
305  testName = "Solve with matrix equilibration: factor() random A:";
306  numberFailedTests += ReturnCodeCheck(testName, returnCode, 0, verbose);
307 
308  // Non-transpose solve
309  returnCode = solver2.solve();
310  testName = "Solve with matrix equilibration: solve() random A (NO_TRANS):";
311  numberFailedTests += CompareVectors( *x2, xhat, tol );
312  numberFailedTests += ReturnCodeCheck(testName, returnCode, 0, verbose);
313 
314 #ifdef HAVE_TEUCHOS_COMPLEX
315  // Conjugate tranpose solve (can be done after factorization, since factorization doesn't depend on this)
317  solver2.setVectors( Teuchos::rcp( &xhatt, false ), Teuchos::rcp( &bct, false ) );
319  returnCode = solver2.solve();
320  testName = "Solve with matrix equilibration: solve() random A (CONJ_TRANS):";
321  if (m == n)
322  numberFailedTests += CompareVectors( *x2t, xhatt, tol );
323  numberFailedTests += ReturnCodeCheck(testName, returnCode, 0, verbose);
324 
325 #else
326  // Tranpose solve (can be done after factorization, since factorization doesn't depend on this)
328  solver2.setVectors( Teuchos::rcp( &xhatt, false ), Teuchos::rcp( &bt, false ) );
330  returnCode = solver2.solve();
331  testName = "Solve with matrix equilibration: solve() random A (TRANS):";
332  if (m == n)
333  numberFailedTests += CompareVectors( *x2t, xhatt, tol );
334  numberFailedTests += ReturnCodeCheck(testName, returnCode, 0, verbose);
335 #endif
336 
337  // Non-transpose solve without call to factor.
338  xhat.putScalar( ScalarTraits<STYPE>::zero() );
339  solver2.setMatrix( A2bak );
340  solver2.setVectors( Teuchos::rcp( &xhat, false ), b2bak );
342  returnCode = solver2.solve();
343  testName = "Solve with matrix equilibration: solve() without factor() random A (NO_TRANS):";
344  numberFailedTests += CompareVectors( *x2, xhat, tol );
345  numberFailedTests += ReturnCodeCheck(testName, returnCode, 0, verbose);
346 
347  //
348  // If a test failed output the number of failed tests.
349  //
350  if(numberFailedTests > 0)
351  {
352  if (verbose) {
353  std::cout << "Number of failed tests: " << numberFailedTests << std::endl;
354  std::cout << "End Result: TEST FAILED" << std::endl;
355  return -1;
356  }
357  }
358  if(numberFailedTests == 0)
359  std::cout << "End Result: TEST PASSED" << std::endl;
360 
361  return 0;
362 }
363 
364 template<typename TYPE>
365 int PrintTestResults(std::string testName, TYPE calculatedResult, TYPE expectedResult, bool verbose)
366 {
367  int result;
368  if(calculatedResult == expectedResult)
369  {
370  if(verbose) std::cout << testName << " successful." << std::endl;
371  result = 0;
372  }
373  else
374  {
375  if(verbose) std::cout << testName << " unsuccessful." << std::endl;
376  result = 1;
377  }
378  return result;
379 }
380 
381 int ReturnCodeCheck(std::string testName, int returnCode, int expectedResult, bool verbose)
382 {
383  int result;
384  if(expectedResult == 0)
385  {
386  if(returnCode == 0)
387  {
388  if(verbose) std::cout << testName << " test successful." << std::endl;
389  result = 0;
390  }
391  else
392  {
393  if(verbose) std::cout << testName << " test unsuccessful. Return code was " << returnCode << "." << std::endl;
394  result = 1;
395  }
396  }
397  else
398  {
399  if(returnCode != 0)
400  {
401  if(verbose) std::cout << testName << " test successful -- failed as expected." << std::endl;
402  result = 0;
403  }
404  else
405  {
406  if(verbose) std::cout << testName << " test unsuccessful -- did not fail as expected. Return code was " << returnCode << "." << std::endl;
407  result = 1;
408  }
409  }
410  return result;
411 }
412 
413 template<typename TYPE>
414 TYPE GetRandom(TYPE Low, TYPE High)
415 {
416  return ((TYPE)((double)((1.0 * ScalarTraits<int>::random()) / RAND_MAX) * (High - Low + 1)) + Low);
417 }
418 
419 template<typename T>
420 std::complex<T> GetRandom( std::complex<T> Low, std::complex<T> High)
421 {
422  T lowMag = Low.real();
423  T highMag = High.real();
424  T real = (T)(((1.0 * ScalarTraits<int>::random()) / RAND_MAX) * (highMag - lowMag + ScalarTraits<T>::one())) + lowMag;
425  T imag = (T)(((1.0 * ScalarTraits<int>::random()) / RAND_MAX) * (highMag - lowMag + ScalarTraits<T>::one())) + lowMag;
426  return std::complex<T>( real, imag );
427 }
428 
429 template<>
430 int GetRandom(int Low, int High)
431 {
432  return ((int)((double)((1.0 * ScalarTraits<int>::random()) / RAND_MAX) * (High - Low + 1)) + Low);
433 }
434 
435 template<>
436 double GetRandom(double Low, double High)
437 {
438  return (((double)((1.0 * ScalarTraits<int>::random()) / RAND_MAX) * (High - Low + 1)) + Low + ScalarTraits<double>::random());
439 }
440 
442 {
443  Teuchos::RCP<DMatrix> newmat = Teuchos::rcp( new DMatrix(m,n) );
444 
445  // Fill dense matrix with random entries.
446  for (int i=0; i<m; i++)
447  for (int j=0; j<n; j++) {
448  (*newmat)(i,j) = GetRandom(-SCALARMAX, SCALARMAX);
449  }
450  return newmat;
451 }
452 
454 {
455  Teuchos::RCP<DVector> newvec = Teuchos::rcp( new DVector( n ) );
456 
457  // Fill dense vector with random entries.
458  for (int i=0; i<n; i++) {
459  (*newvec)(i) = GetRandom(-SCALARMAX, SCALARMAX);
460  }
461 
462  return newvec;
463 }
464 
465 /* Function: CompareVectors
466  Purpose: Compares the difference between two vectors using relative euclidean-norms, i.e. ||v_1-v_2||_2/||v_2||_2
467 */
469  const SerialDenseVector<OTYPE,STYPE>& Vector2,
471 {
472  typedef ScalarTraits<STYPE>::magnitudeType MagnitudeType;
473 
474  SerialDenseVector<OTYPE,STYPE> diff( Vector1 );
475  diff -= Vector2;
476 
477  MagnitudeType norm_diff = diff.normFrobenius();
478  MagnitudeType norm_v2 = Vector2.normFrobenius();
479  MagnitudeType temp = norm_diff;
480  if (norm_v2 != ScalarTraits<MagnitudeType>::zero())
481  temp /= norm_v2;
482 
483  if (temp > Tolerance)
484  return 1;
485  else
486  return 0;
487 }
int PrintTestResults(std::string, TYPE, TYPE, bool)
Non-member helper functions on the templated serial, dense matrix/vector classes. ...
int setMatrix(const RCP< SerialDenseMatrix< OrdinalType, ScalarType > > &A)
Sets the pointers for coefficient matrix.
Templated serial dense matrix class.
int multiplyQ(ETransp transq, SerialDenseMatrix< OrdinalType, ScalarType > &C)
Left multiply the input matrix by the unitary matrix Q or its adjoint.
int solveR(ETransp transr, SerialDenseMatrix< OrdinalType, ScalarType > &C)
Solve input matrix on the left with the upper triangular matrix R or its adjoint. ...
int formQ()
Explicitly forms the unitary matrix Q.
Teuchos::SerialDenseVector< int, std::complex< Real > > DVector
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.
Templated class for solving dense linear problems.
#define STYPE
This class creates and provides basic support for dense vectors of templated type as a specialization...
#define SCALARMAX
int solve()
Computes the solution X to AX = B for the this matrix and the B provided to SetVectors()..
ScalarTraits< ScalarType >::magnitudeType normFrobenius() const
Returns the Frobenius-norm of the matrix.
This structure defines some basic traits for a scalar field type.
A class for solving dense linear problems.
void solveWithTransposeFlag(Teuchos::ETransp trans)
All subsequent function calls will work with the transpose-type set by this method (Teuchos::NO_TRANS...
TEUCHOS_DEPRECATED RCP< T > rcp(T *p, Dealloc_T dealloc, bool owns_mem)
Deprecated.
TYPE GetRandom(TYPE, TYPE)
int putScalar(const ScalarType value=Teuchos::ScalarTraits< ScalarType >::zero())
Set all values in the matrix to a constant value.
#define OTYPE
Teuchos::RCP< DMatrix > GetRandomMatrix(int m, int n)
The Templated LAPACK Wrapper Class.
bool CompareVectors(TYPE1 *Vector1, TYPE2 *Vector2, OType Size, TYPE2 Tolerance)
#define TEUCHOS_MAX(x, y)
Teuchos::SerialDenseMatrix< int, std::complex< Real > > DMatrix
std::string Teuchos_Version()
int ReturnCodeCheck(std::string, int, int, bool)
int main(int argc, char *argv[])
OrdinalType numCols() const
Returns the column dimension of this matrix.
void factorWithEquilibration(bool flag)
Causes equilibration to be called just before the matrix factorization as part of the call to factor...
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 formR()
Explicitly forms the upper triangular matrix R.
RCP< SerialDenseMatrix< OrdinalType, ScalarType > > getQ() const
Returns pointer to Q (assuming factorization has been performed).
int factor()
Computes the in-place QR factorization of the matrix using the LAPACK routine _GETRF or the Eigen cla...
Reference-counted pointer class and non-member templated function implementations.
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).
OrdinalType numRows() const
Returns the row dimension of this matrix.
This class creates and provides basic support for dense rectangular matrix of templated type...