libMesh
Public Member Functions | Private Member Functions | List of all members
DenseMatrixTest Class Reference
Inheritance diagram for DenseMatrixTest:
[legend]

Public Member Functions

void setUp ()
 
void tearDown ()
 
 CPPUNIT_TEST_SUITE (DenseMatrixTest)
 
 CPPUNIT_TEST (testOuterProduct)
 
 CPPUNIT_TEST (testSVD)
 
 CPPUNIT_TEST (testEVDreal)
 
 CPPUNIT_TEST (testEVDcomplex)
 
 CPPUNIT_TEST (testComplexSVD)
 
 CPPUNIT_TEST (testSubMatrix)
 
 CPPUNIT_TEST_SUITE_END ()
 

Private Member Functions

void testOuterProduct ()
 
void testSVD ()
 
void testEVD_helper (DenseMatrix< Real > &A, std::vector< Real > true_lambda_real, std::vector< Real > true_lambda_imag, Real tol)
 
void testEVDreal ()
 
void testEVDcomplex ()
 
void testComplexSVD ()
 
void testSubMatrix ()
 

Detailed Description

Definition at line 14 of file dense_matrix_test.C.

Member Function Documentation

◆ CPPUNIT_TEST() [1/6]

DenseMatrixTest::CPPUNIT_TEST ( testComplexSVD  )

◆ CPPUNIT_TEST() [2/6]

DenseMatrixTest::CPPUNIT_TEST ( testEVDcomplex  )

◆ CPPUNIT_TEST() [3/6]

DenseMatrixTest::CPPUNIT_TEST ( testEVDreal  )

◆ CPPUNIT_TEST() [4/6]

DenseMatrixTest::CPPUNIT_TEST ( testOuterProduct  )

◆ CPPUNIT_TEST() [5/6]

DenseMatrixTest::CPPUNIT_TEST ( testSubMatrix  )

◆ CPPUNIT_TEST() [6/6]

DenseMatrixTest::CPPUNIT_TEST ( testSVD  )

◆ CPPUNIT_TEST_SUITE()

DenseMatrixTest::CPPUNIT_TEST_SUITE ( DenseMatrixTest  )

◆ CPPUNIT_TEST_SUITE_END()

DenseMatrixTest::CPPUNIT_TEST_SUITE_END ( )

◆ setUp()

void DenseMatrixTest::setUp ( )
inline

Definition at line 17 of file dense_matrix_test.C.

17 {}

◆ tearDown()

void DenseMatrixTest::tearDown ( )
inline

Definition at line 19 of file dense_matrix_test.C.

19 {}

◆ testComplexSVD()

void DenseMatrixTest::testComplexSVD ( )
inlineprivate

Definition at line 344 of file dense_matrix_test.C.

345  {
346 #ifdef LIBMESH_USE_COMPLEX_NUMBERS
347  DenseMatrix<Complex> A(3,3);
348 
349  A(0,0) = Complex(2.18904,4.44523e-18); A(0,1) = Complex(-3.20491,-0.136699); A(0,2) = Complex(0.716316,-0.964802);
350  A(1,0) = Complex(-3.20491,0.136699); A(1,1) = Complex(4.70076,-3.25261e-18); A(1,2) = Complex(-0.98849,1.45727);
351  A(2,0) = Complex(0.716316,0.964802); A(2,1) = Complex(-0.98849,-1.45727); A(2,2) = Complex(0.659629,-4.01155e-18);
352 
353  DenseVector<Real> sigma;
354  A.svd(sigma);
355 
356  DenseVector<Real> true_sigma(3);
357  true_sigma(0) = 7.54942516052;
358  true_sigma(1) = 3.17479511368e-06;
359  true_sigma(2) = 6.64680908281e-07;
360 
361  for (unsigned i=0; i<sigma.size(); ++i)
362  LIBMESH_ASSERT_FP_EQUAL(sigma(i), true_sigma(i), 1.e-10);
363 #endif
364  }

References A, and libMesh::DenseVector< T >::size().

◆ testEVD_helper()

void DenseMatrixTest::testEVD_helper ( DenseMatrix< Real > &  A,
std::vector< Real >  true_lambda_real,
std::vector< Real >  true_lambda_imag,
Real  tol 
)
inlineprivate

Definition at line 108 of file dense_matrix_test.C.

112  {
113  // Note: see bottom of this file, we only do this test if PETSc is
114  // available, but this function currently only exists if we're
115  // using real numbers.
116 #ifdef LIBMESH_USE_REAL_NUMBERS
117  // Let's compute the eigenvalues on a copy of A, so that we can
118  // use the original to check the computation.
119  DenseMatrix<Real> A_copy = A;
120 
121  DenseVector<Real> lambda_real, lambda_imag;
122  DenseMatrix<Real> VR; // right eigenvectors
123  DenseMatrix<Real> VL; // left eigenvectors
124  A_copy.evd_left_and_right(lambda_real, lambda_imag, VL, VR);
125 
126  // The matrix is square and of size N x N.
127  const unsigned N = A.m();
128 
129  // Verify left eigen-values.
130  // Test that the right eigenvalues are self-consistent by computing
131  // u_j**H * A = lambda_j * u_j**H
132  // Note that we have to handle real and complex eigenvalues
133  // differently, since complex eigenvectors share their storage.
134  for (unsigned eigenval=0; eigenval<N; ++eigenval)
135  {
136  // Only check real eigenvalues
137  if (std::abs(lambda_imag(eigenval)) < tol*tol)
138  {
139  // remove print libMesh::out << "Checking eigenvalue: " << eigenval << std::endl;
140  DenseVector<Real> lhs(N), rhs(N);
141  for (unsigned i=0; i<N; ++i)
142  {
143  rhs(i) = lambda_real(eigenval) * VL(i, eigenval);
144  for (unsigned j=0; j<N; ++j)
145  lhs(i) += A(j, i) * VL(j, eigenval); // Note: A(j,i)
146  }
147 
148  // Subtract and assert that the norm of the difference is
149  // below some tolerance.
150  lhs -= rhs;
151  LIBMESH_ASSERT_FP_EQUAL(/*expected=*/0., /*actual=*/lhs.l2_norm(), std::sqrt(tol)*tol);
152  }
153  else
154  {
155  // This is a complex eigenvalue, so:
156  // a.) It occurs in a complex-conjugate pair
157  // b.) the real part of the eigenvector is stored is VL(:,eigenval)
158  // c.) the imag part of the eigenvector is stored in VL(:,eigenval+1)
159  //
160  // Equating the real and imaginary parts of Ax=lambda*x leads to two sets
161  // of relations that must hold:
162  // 1.) A^T x_r = lambda_r*x_r + lambda_i*x_i
163  // 2.) A^T x_i = -lambda_i*x_r + lambda_r*x_i
164  // which we can verify.
165 
166  // 1.)
167  DenseVector<Real> lhs(N), rhs(N);
168  for (unsigned i=0; i<N; ++i)
169  {
170  rhs(i) = lambda_real(eigenval) * VL(i, eigenval) + lambda_imag(eigenval) * VL(i, eigenval+1);
171  for (unsigned j=0; j<N; ++j)
172  lhs(i) += A(j, i) * VL(j, eigenval); // Note: A(j,i)
173  }
174 
175  lhs -= rhs;
176  LIBMESH_ASSERT_FP_EQUAL(/*expected=*/0., /*actual=*/lhs.l2_norm(), std::sqrt(tol)*tol);
177 
178  // libMesh::out << "lhs=" << std::endl;
179  // lhs.print_scientific(libMesh::out, /*precision=*/15);
180  //
181  // libMesh::out << "rhs=" << std::endl;
182  // rhs.print_scientific(libMesh::out, /*precision=*/15);
183 
184  // 2.)
185  lhs.zero();
186  rhs.zero();
187  for (unsigned i=0; i<N; ++i)
188  {
189  rhs(i) = -lambda_imag(eigenval) * VL(i, eigenval) + lambda_real(eigenval) * VL(i, eigenval+1);
190  for (unsigned j=0; j<N; ++j)
191  lhs(i) += A(j, i) * VL(j, eigenval+1); // Note: A(j,i)
192  }
193 
194  lhs -= rhs;
195  LIBMESH_ASSERT_FP_EQUAL(/*expected=*/0., /*actual=*/lhs.l2_norm(), std::sqrt(tol)*tol);
196 
197  // libMesh::out << "lhs=" << std::endl;
198  // lhs.print_scientific(libMesh::out, /*precision=*/15);
199  //
200  // libMesh::out << "rhs=" << std::endl;
201  // rhs.print_scientific(libMesh::out, /*precision=*/15);
202 
203  // We'll skip the second member of the complex conjugate
204  // pair. If the first one worked, the second one should
205  // as well...
206  eigenval += 1;
207  }
208  }
209 
210  // Verify right eigen-values.
211  // Test that the right eigenvalues are self-consistent by computing
212  // A * v_j - lambda_j * v_j
213  // Note that we have to handle real and complex eigenvalues
214  // differently, since complex eigenvectors share their storage.
215  for (unsigned eigenval=0; eigenval<N; ++eigenval)
216  {
217  // Only check real eigenvalues
218  if (std::abs(lambda_imag(eigenval)) < tol*tol)
219  {
220  // remove print libMesh::out << "Checking eigenvalue: " << eigenval << std::endl;
221  DenseVector<Real> lhs(N), rhs(N);
222  for (unsigned i=0; i<N; ++i)
223  {
224  rhs(i) = lambda_real(eigenval) * VR(i, eigenval);
225  for (unsigned j=0; j<N; ++j)
226  lhs(i) += A(i, j) * VR(j, eigenval);
227  }
228 
229  lhs -= rhs;
230  LIBMESH_ASSERT_FP_EQUAL(/*expected=*/0., /*actual=*/lhs.l2_norm(), std::sqrt(tol)*tol);
231  }
232  else
233  {
234  // This is a complex eigenvalue, so:
235  // a.) It occurs in a complex-conjugate pair
236  // b.) the real part of the eigenvector is stored is VR(:,eigenval)
237  // c.) the imag part of the eigenvector is stored in VR(:,eigenval+1)
238  //
239  // Equating the real and imaginary parts of Ax=lambda*x leads to two sets
240  // of relations that must hold:
241  // 1.) Ax_r = lambda_r*x_r - lambda_i*x_i
242  // 2.) Ax_i = lambda_i*x_r + lambda_r*x_i
243  // which we can verify.
244 
245  // 1.)
246  DenseVector<Real> lhs(N), rhs(N);
247  for (unsigned i=0; i<N; ++i)
248  {
249  rhs(i) = lambda_real(eigenval) * VR(i, eigenval) - lambda_imag(eigenval) * VR(i, eigenval+1);
250  for (unsigned j=0; j<N; ++j)
251  lhs(i) += A(i, j) * VR(j, eigenval);
252  }
253 
254  lhs -= rhs;
255  LIBMESH_ASSERT_FP_EQUAL(/*expected=*/0., /*actual=*/lhs.l2_norm(), std::sqrt(tol)*tol);
256 
257  // 2.)
258  lhs.zero();
259  rhs.zero();
260  for (unsigned i=0; i<N; ++i)
261  {
262  rhs(i) = lambda_imag(eigenval) * VR(i, eigenval) + lambda_real(eigenval) * VR(i, eigenval+1);
263  for (unsigned j=0; j<N; ++j)
264  lhs(i) += A(i, j) * VR(j, eigenval+1);
265  }
266 
267  lhs -= rhs;
268  LIBMESH_ASSERT_FP_EQUAL(/*expected=*/0., /*actual=*/lhs.l2_norm(), std::sqrt(tol)*tol);
269 
270  // We'll skip the second member of the complex conjugate
271  // pair. If the first one worked, the second one should
272  // as well...
273  eigenval += 1;
274  }
275  }
276 
277  // Sort the results from Lapack *individually*.
278  std::sort(lambda_real.get_values().begin(), lambda_real.get_values().end());
279  std::sort(lambda_imag.get_values().begin(), lambda_imag.get_values().end());
280 
281  // Sort the true eigenvalues *individually*.
282  std::sort(true_lambda_real.begin(), true_lambda_real.end());
283  std::sort(true_lambda_imag.begin(), true_lambda_imag.end());
284 
285  // Compare the individually-sorted values.
286  for (unsigned i=0; i<lambda_real.size(); ++i)
287  {
288  // Note: I initially verified the results with TOLERANCE**2,
289  // but that turned out to be just a bit too tight for some of
290  // the test problems. I'm not sure what controls the accuracy
291  // of the eigenvalue computation in LAPACK, there is no way to
292  // set a tolerance in the LAPACKgeev_ interface.
293  LIBMESH_ASSERT_FP_EQUAL(/*expected=*/true_lambda_real[i], /*actual=*/lambda_real(i), std::sqrt(tol)*tol);
294  LIBMESH_ASSERT_FP_EQUAL(/*expected=*/true_lambda_imag[i], /*actual=*/lambda_imag(i), std::sqrt(tol)*tol);
295  }
296 #endif
297  }

References A, std::abs(), libMesh::DenseMatrix< T >::evd_left_and_right(), libMesh::DenseVector< T >::get_values(), libMesh::DenseVector< T >::size(), std::sqrt(), and libMesh::DenseVector< T >::zero().

◆ testEVDcomplex()

void DenseMatrixTest::testEVDcomplex ( )
inlineprivate

Definition at line 318 of file dense_matrix_test.C.

319  {
320  // This test is also from a Matlab example, and has complex eigenvalues.
321  // http://www.mathworks.com/help/matlab/math/eigenvalues.html?s_tid=gn_loc_drop
322  DenseMatrix<Real> A(3, 3);
323  A(0,0) = 0; A(0,1) = -6; A(0,2) = -1;
324  A(1,0) = 6; A(1,1) = 2; A(1,2) = -16;
325  A(2,0) = -5; A(2,1) = 20; A(2,2) = -10;
326 
327  std::vector<Real> true_lambda_real(3);
328  true_lambda_real[0] = -3.070950351248293;
329  true_lambda_real[1] = -2.464524824375853;
330  true_lambda_real[2] = -2.464524824375853;
331  std::vector<Real> true_lambda_imag(3);
332  true_lambda_imag[0] = 0.;
333  true_lambda_imag[1] = 17.60083096447099;
334  true_lambda_imag[2] = -17.60083096447099;
335 
336  // We're good up to double precision (due to the truncated
337  // literals above) or Real precision, whichever is worse
338  const Real tol = std::max(Real(1e-6), TOLERANCE);
339 
340  // call helper function to compute and verify results
341  testEVD_helper(A, true_lambda_real, true_lambda_imag, tol);
342  }

References A, libMesh::Real, and libMesh::TOLERANCE.

◆ testEVDreal()

void DenseMatrixTest::testEVDreal ( )
inlineprivate

Definition at line 299 of file dense_matrix_test.C.

300  {
301  // This is an example from Matlab's gallery(3) which is a
302  // non-symmetric 3x3 matrix with eigen values lambda = 1, 2, 3.
303  DenseMatrix<Real> A(3, 3);
304  A(0,0) = -149; A(0,1) = -50; A(0,2) = -154;
305  A(1,0) = 537; A(1,1) = 180; A(1,2) = 546;
306  A(2,0) = -27; A(2,1) = -9; A(2,2) = -25;
307 
308  std::vector<Real> true_lambda_real(3);
309  true_lambda_real[0] = 1.;
310  true_lambda_real[1] = 2.;
311  true_lambda_real[2] = 3.;
312  std::vector<Real> true_lambda_imag(3); // all zero
313 
314  // call helper function to compute and verify results.
315  testEVD_helper(A, true_lambda_real, true_lambda_imag, TOLERANCE);
316  }

References A, and libMesh::TOLERANCE.

◆ testOuterProduct()

void DenseMatrixTest::testOuterProduct ( )
inlineprivate

Definition at line 35 of file dense_matrix_test.C.

36  {
37  DenseVector<Real> a(2);
38  a(0) = 1.0;
39  a(1) = 2.0;
40 
41  DenseVector<Real> b(3);
42  b(0) = 3.0;
43  b(1) = 4.0;
44  b(2) = 5.0;
45 
46  DenseMatrix<Real> a_times_b;
47  a_times_b.outer_product(a, b);
48 
49  DenseMatrix<Real> a_times_b_correct(2, 3);
50  a_times_b_correct(0, 0) = 3.0;
51  a_times_b_correct(0, 1) = 4.0;
52  a_times_b_correct(0, 2) = 5.0;
53  a_times_b_correct(1, 0) = 6.0;
54  a_times_b_correct(1, 1) = 8.0;
55  a_times_b_correct(1, 2) = 10.0;
56 
57  for (unsigned int i = 0; i < a.size(); ++i)
58  for (unsigned int j = 0; j < b.size(); ++j)
59  LIBMESH_ASSERT_FP_EQUAL(libmesh_real(a_times_b(i,j)), libmesh_real(a_times_b_correct(i,j)), TOLERANCE*TOLERANCE);
60  }

References libMesh::libmesh_real(), libMesh::DenseMatrix< T >::outer_product(), libMesh::DenseVector< T >::size(), and libMesh::TOLERANCE.

◆ testSubMatrix()

void DenseMatrixTest::testSubMatrix ( )
inlineprivate

Definition at line 366 of file dense_matrix_test.C.

367  {
368  DenseMatrix<Number> A(4, 3);
369  A(0,0) = 1.0; A(0,1) = 2.0; A(0,2) = 3.0;
370  A(1,0) = 4.0; A(1,1) = 5.0; A(1,2) = 6.0;
371  A(2,0) = 7.0; A(2,1) = 8.0; A(2,2) = 9.0;
372  A(3,0) =10.0; A(3,1) =11.0; A(3,2) =12.0;
373 
374  DenseMatrix<Number> B(2, 2);
375  B(0,0) = 7.0; B(0,1) = 8.0;
376  B(1,0) =10.0; B(1,1) =11.0;
377 
378  DenseMatrix<Number> C = A.sub_matrix(2, 2, 0, 2);
379  CPPUNIT_ASSERT(B == C);
380  }

References A.

◆ testSVD()

void DenseMatrixTest::testSVD ( )
inlineprivate

Definition at line 62 of file dense_matrix_test.C.

63  {
64  DenseMatrix<Number> U, VT;
65  DenseVector<Real> sigma;
67 
68  A.resize(3, 2);
69  A(0,0) = 1.0; A(0,1) = 2.0;
70  A(1,0) = 3.0; A(1,1) = 4.0;
71  A(2,0) = 5.0; A(2,1) = 6.0;
72 
73  A.svd(sigma, U, VT);
74 
75  // Solution for this case is (verified with numpy)
76  DenseMatrix<Number> true_U(3,2), true_VT(2,2);
77  DenseVector<Real> true_sigma(2);
78  true_U(0,0) = -2.298476964000715e-01; true_U(0,1) = 8.834610176985250e-01;
79  true_U(1,0) = -5.247448187602936e-01; true_U(1,1) = 2.407824921325463e-01;
80  true_U(2,0) = -8.196419411205157e-01; true_U(2,1) = -4.018960334334318e-01;
81 
82  true_VT(0,0) = -6.196294838293402e-01; true_VT(0,1) = -7.848944532670524e-01;
83  true_VT(1,0) = -7.848944532670524e-01; true_VT(1,1) = 6.196294838293400e-01;
84 
85  true_sigma(0) = 9.525518091565109e+00;
86  true_sigma(1) = 5.143005806586446e-01;
87 
88  // Tolerance is bounded by the double literals above and by using Real
89  const Real tol = std::max(Real(1e-12), TOLERANCE*TOLERANCE);
90 
91  for (unsigned i=0; i<U.m(); ++i)
92  for (unsigned j=0; j<U.n(); ++j)
93  LIBMESH_ASSERT_FP_EQUAL( libmesh_real(U(i,j)), libmesh_real(true_U(i,j)), tol);
94 
95  for (unsigned i=0; i<VT.m(); ++i)
96  for (unsigned j=0; j<VT.n(); ++j)
97  LIBMESH_ASSERT_FP_EQUAL( libmesh_real(VT(i,j)), libmesh_real(true_VT(i,j)), tol);
98 
99  for (unsigned i=0; i<sigma.size(); ++i)
100  LIBMESH_ASSERT_FP_EQUAL(sigma(i), true_sigma(i), tol);
101  }

References A, libMesh::libmesh_real(), libMesh::DenseMatrixBase< T >::m(), libMesh::DenseMatrixBase< T >::n(), libMesh::Real, libMesh::DenseVector< T >::size(), and libMesh::TOLERANCE.


The documentation for this class was generated from the following file:
libMesh::libmesh_real
T libmesh_real(T a)
Definition: libmesh_common.h:166
B
Definition: assembly.h:38
std::sqrt
MetaPhysicL::DualNumber< T, D > sqrt(const MetaPhysicL::DualNumber< T, D > &in)
libMesh::TOLERANCE
static const Real TOLERANCE
Definition: libmesh_common.h:128
libMesh::DenseMatrix
Defines a dense matrix for use in Finite Element-type computations.
Definition: dof_map.h:73
libMesh::DenseMatrixBase::n
unsigned int n() const
Definition: dense_matrix_base.h:109
libMesh::DenseMatrixBase::m
unsigned int m() const
Definition: dense_matrix_base.h:104
std::abs
MetaPhysicL::DualNumber< T, D > abs(const MetaPhysicL::DualNumber< T, D > &in)
libMesh::DenseMatrix::evd_left_and_right
void evd_left_and_right(DenseVector< T > &lambda_real, DenseVector< T > &lambda_imag, DenseMatrix< T > &VL, DenseMatrix< T > &VR)
Compute the eigenvalues (both real and imaginary parts) as well as the left and right eigenvectors of...
Definition: dense_matrix_impl.h:874
A
static PetscErrorCode Mat * A
Definition: petscdmlibmeshimpl.C:1026
libMesh::DenseVector::size
virtual unsigned int size() const override
Definition: dense_vector.h:92
libMesh::Complex
std::complex< Real > Complex
Definition: libmesh_common.h:160
DenseMatrixTest::testEVD_helper
void testEVD_helper(DenseMatrix< Real > &A, std::vector< Real > true_lambda_real, std::vector< Real > true_lambda_imag, Real tol)
Definition: dense_matrix_test.C:108
libMesh::DenseVector::get_values
std::vector< T > & get_values()
Definition: dense_vector.h:256
libMesh::DenseMatrix::outer_product
void outer_product(const DenseVector< T > &a, const DenseVector< T > &b)
Computes the outer (dyadic) product of two vectors and stores in (*this).
Definition: dense_matrix_impl.h:589
libMesh::Real
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real
Definition: libmesh_common.h:121
libMesh::DenseVector
Defines a dense vector for use in Finite Element-type computations.
Definition: meshless_interpolation_function.h:39