libMesh
Loading...
Searching...
No Matches
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 ()
 
 LIBMESH_CPPUNIT_TEST_SUITE (DenseMatrixTest)
 
 CPPUNIT_TEST (testClassifiers)
 
 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 testClassifiers ()
 
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 16 of file dense_matrix_test.C.

Member Function Documentation

◆ CPPUNIT_TEST() [1/7]

DenseMatrixTest::CPPUNIT_TEST ( testClassifiers  )

◆ CPPUNIT_TEST() [2/7]

DenseMatrixTest::CPPUNIT_TEST ( testComplexSVD  )

◆ CPPUNIT_TEST() [3/7]

DenseMatrixTest::CPPUNIT_TEST ( testEVDcomplex  )

◆ CPPUNIT_TEST() [4/7]

DenseMatrixTest::CPPUNIT_TEST ( testEVDreal  )

◆ CPPUNIT_TEST() [5/7]

DenseMatrixTest::CPPUNIT_TEST ( testOuterProduct  )

◆ CPPUNIT_TEST() [6/7]

DenseMatrixTest::CPPUNIT_TEST ( testSubMatrix  )

◆ CPPUNIT_TEST() [7/7]

DenseMatrixTest::CPPUNIT_TEST ( testSVD  )

◆ CPPUNIT_TEST_SUITE_END()

DenseMatrixTest::CPPUNIT_TEST_SUITE_END ( )

◆ LIBMESH_CPPUNIT_TEST_SUITE()

DenseMatrixTest::LIBMESH_CPPUNIT_TEST_SUITE ( DenseMatrixTest  )

◆ setUp()

void DenseMatrixTest::setUp ( )
inline

Definition at line 19 of file dense_matrix_test.C.

19{}

◆ tearDown()

void DenseMatrixTest::tearDown ( )
inline

Definition at line 21 of file dense_matrix_test.C.

21{}

◆ testClassifiers()

void DenseMatrixTest::testClassifiers ( )
inlineprivate

Definition at line 38 of file dense_matrix_test.C.

39 {
40 LOG_UNIT_TEST;
41
42 DenseMatrix<Real> a(2, 2, {1, 2,
43 3, 4});
44 CPPUNIT_ASSERT(isfinite(a));
45 CPPUNIT_ASSERT(!isinf(a));
46 CPPUNIT_ASSERT(!isnan(a));
47
48 DenseVector<Real> diag = a.diagonal();
49 CPPUNIT_ASSERT(isfinite(diag));
50 CPPUNIT_ASSERT(!isinf(diag));
51 CPPUNIT_ASSERT(!isnan(diag));
52
53 DenseSubMatrix suba1(a,0,0,1,1);
54 CPPUNIT_ASSERT(isfinite(suba1));
55 CPPUNIT_ASSERT(!isinf(suba1));
56 CPPUNIT_ASSERT(!isnan(suba1));
57
58 DenseSubMatrix suba2(a,1,1,1,1);
59 CPPUNIT_ASSERT(isfinite(suba2));
60 CPPUNIT_ASSERT(!isinf(suba2));
61 CPPUNIT_ASSERT(!isnan(suba2));
62
63 a(0, 0) = std::numeric_limits<Real>::infinity();
64 CPPUNIT_ASSERT(!isfinite(a));
65 CPPUNIT_ASSERT(!isfinite(suba1));
66 CPPUNIT_ASSERT(isfinite(suba2));
67 CPPUNIT_ASSERT(isinf(a));
68 CPPUNIT_ASSERT(isinf(suba1));
69 CPPUNIT_ASSERT(!isinf(suba2));
70 CPPUNIT_ASSERT(!isnan(a));
71 CPPUNIT_ASSERT(!isnan(suba1));
72 CPPUNIT_ASSERT(!isnan(suba2));
73
74 CPPUNIT_ASSERT(isfinite(diag));
75 CPPUNIT_ASSERT(!isinf(diag));
76 CPPUNIT_ASSERT(!isnan(diag));
77 diag = a.diagonal();
78 CPPUNIT_ASSERT(!isfinite(diag));
79 CPPUNIT_ASSERT(isinf(diag));
80 CPPUNIT_ASSERT(!isnan(diag));
81
82 a(0, 0) = 3;
83 a(1, 1) = std::numeric_limits<Real>::quiet_NaN();
84 CPPUNIT_ASSERT(!isfinite(a));
85 CPPUNIT_ASSERT(isfinite(suba1));
86 CPPUNIT_ASSERT(!isfinite(suba2));
87 CPPUNIT_ASSERT(!isinf(a));
88 CPPUNIT_ASSERT(!isinf(suba1));
89 CPPUNIT_ASSERT(!isinf(suba2));
90 CPPUNIT_ASSERT(isnan(a));
91 CPPUNIT_ASSERT(!isnan(suba1));
92 CPPUNIT_ASSERT(isnan(suba2));
93
94 diag = a.diagonal();
95 CPPUNIT_ASSERT(!isfinite(diag));
96 CPPUNIT_ASSERT(!isinf(diag));
97 CPPUNIT_ASSERT(isnan(diag));
98 }
Defines a dense matrix for use in Finite Element-type computations.
Defines a dense submatrix for use in Finite Element-type computations.
Defines a dense vector for use in Finite Element-type computations.
bool isfinite(std::complex< T > a)
bool isnan(std::complex< T > a)
bool isinf(std::complex< T > a)

References libMesh::isfinite(), libMesh::isinf(), and libMesh::isnan().

◆ testComplexSVD()

void DenseMatrixTest::testComplexSVD ( )
inlineprivate

Definition at line 405 of file dense_matrix_test.C.

406 {
407#ifdef LIBMESH_USE_COMPLEX_NUMBERS
408 LOG_UNIT_TEST;
409
411
412 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);
413 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);
414 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);
415
416 DenseVector<Real> sigma;
417 A.svd(sigma);
418
419 DenseVector<Real> true_sigma(3);
420 true_sigma(0) = 7.54942516052;
421 true_sigma(1) = 3.17479511368e-06;
422 true_sigma(2) = 6.64680908281e-07;
423
424 for (unsigned i=0; i<sigma.size(); ++i)
425 LIBMESH_ASSERT_FP_EQUAL(sigma(i), true_sigma(i), 1.e-10);
426#endif
427 }
virtual unsigned int size() const override final
std::complex< Real > Complex

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

◆ 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 165 of file dense_matrix_test.C.

169 {
170 // Note: see bottom of this file, we only do this test if PETSc is
171 // available, but this function currently only exists if we're
172 // using real numbers.
173#ifdef LIBMESH_USE_REAL_NUMBERS
174 // Let's compute the eigenvalues on a copy of A, so that we can
175 // use the original to check the computation.
176 DenseMatrix<Real> A_copy = A;
177
178 DenseVector<Real> lambda_real, lambda_imag;
179 DenseMatrix<Real> VR; // right eigenvectors
180 DenseMatrix<Real> VL; // left eigenvectors
181 A_copy.evd_left_and_right(lambda_real, lambda_imag, VL, VR);
182
183 // The matrix is square and of size N x N.
184 const unsigned N = A.m();
185
186 // Verify left eigen-values.
187 // Test that the right eigenvalues are self-consistent by computing
188 // u_j**H * A = lambda_j * u_j**H
189 // Note that we have to handle real and complex eigenvalues
190 // differently, since complex eigenvectors share their storage.
191 for (unsigned eigenval=0; eigenval<N; ++eigenval)
192 {
193 // Only check real eigenvalues
194 if (std::abs(lambda_imag(eigenval)) < tol*tol)
195 {
196 // remove print libMesh::out << "Checking eigenvalue: " << eigenval << std::endl;
197 DenseVector<Real> lhs(N), rhs(N);
198 for (unsigned i=0; i<N; ++i)
199 {
200 rhs(i) = lambda_real(eigenval) * VL(i, eigenval);
201 for (unsigned j=0; j<N; ++j)
202 lhs(i) += A(j, i) * VL(j, eigenval); // Note: A(j,i)
203 }
204
205 // Subtract and assert that the norm of the difference is
206 // below some tolerance.
207 lhs -= rhs;
208 LIBMESH_ASSERT_FP_EQUAL(/*expected=*/0., /*actual=*/lhs.l2_norm(), std::sqrt(tol)*tol);
209 }
210 else
211 {
212 // This is a complex eigenvalue, so:
213 // a.) It occurs in a complex-conjugate pair
214 // b.) the real part of the eigenvector is stored is VL(:,eigenval)
215 // c.) the imag part of the eigenvector is stored in VL(:,eigenval+1)
216 //
217 // Equating the real and imaginary parts of Ax=lambda*x leads to two sets
218 // of relations that must hold:
219 // 1.) A^T x_r = lambda_r*x_r + lambda_i*x_i
220 // 2.) A^T x_i = -lambda_i*x_r + lambda_r*x_i
221 // which we can verify.
222
223 // 1.)
224 DenseVector<Real> lhs(N), rhs(N);
225 for (unsigned i=0; i<N; ++i)
226 {
227 rhs(i) = lambda_real(eigenval) * VL(i, eigenval) + lambda_imag(eigenval) * VL(i, eigenval+1);
228 for (unsigned j=0; j<N; ++j)
229 lhs(i) += A(j, i) * VL(j, eigenval); // Note: A(j,i)
230 }
231
232 lhs -= rhs;
233 LIBMESH_ASSERT_FP_EQUAL(/*expected=*/0., /*actual=*/lhs.l2_norm(), std::sqrt(tol)*tol);
234
235 // libMesh::out << "lhs=" << std::endl;
236 // lhs.print_scientific(libMesh::out, /*precision=*/15);
237 //
238 // libMesh::out << "rhs=" << std::endl;
239 // rhs.print_scientific(libMesh::out, /*precision=*/15);
240
241 // 2.)
242 lhs.zero();
243 rhs.zero();
244 for (unsigned i=0; i<N; ++i)
245 {
246 rhs(i) = -lambda_imag(eigenval) * VL(i, eigenval) + lambda_real(eigenval) * VL(i, eigenval+1);
247 for (unsigned j=0; j<N; ++j)
248 lhs(i) += A(j, i) * VL(j, eigenval+1); // Note: A(j,i)
249 }
250
251 lhs -= rhs;
252 LIBMESH_ASSERT_FP_EQUAL(/*expected=*/0., /*actual=*/lhs.l2_norm(), std::sqrt(tol)*tol);
253
254 // libMesh::out << "lhs=" << std::endl;
255 // lhs.print_scientific(libMesh::out, /*precision=*/15);
256 //
257 // libMesh::out << "rhs=" << std::endl;
258 // rhs.print_scientific(libMesh::out, /*precision=*/15);
259
260 // We'll skip the second member of the complex conjugate
261 // pair. If the first one worked, the second one should
262 // as well...
263 eigenval += 1;
264 }
265 }
266
267 // Verify right eigen-values.
268 // Test that the right eigenvalues are self-consistent by computing
269 // A * v_j - lambda_j * v_j
270 // Note that we have to handle real and complex eigenvalues
271 // differently, since complex eigenvectors share their storage.
272 for (unsigned eigenval=0; eigenval<N; ++eigenval)
273 {
274 // Only check real eigenvalues
275 if (std::abs(lambda_imag(eigenval)) < tol*tol)
276 {
277 // remove print libMesh::out << "Checking eigenvalue: " << eigenval << std::endl;
278 DenseVector<Real> lhs(N), rhs(N);
279 for (unsigned i=0; i<N; ++i)
280 {
281 rhs(i) = lambda_real(eigenval) * VR(i, eigenval);
282 for (unsigned j=0; j<N; ++j)
283 lhs(i) += A(i, j) * VR(j, eigenval);
284 }
285
286 lhs -= rhs;
287 LIBMESH_ASSERT_FP_EQUAL(/*expected=*/0., /*actual=*/lhs.l2_norm(), std::sqrt(tol)*tol);
288 }
289 else
290 {
291 // This is a complex eigenvalue, so:
292 // a.) It occurs in a complex-conjugate pair
293 // b.) the real part of the eigenvector is stored is VR(:,eigenval)
294 // c.) the imag part of the eigenvector is stored in VR(:,eigenval+1)
295 //
296 // Equating the real and imaginary parts of Ax=lambda*x leads to two sets
297 // of relations that must hold:
298 // 1.) Ax_r = lambda_r*x_r - lambda_i*x_i
299 // 2.) Ax_i = lambda_i*x_r + lambda_r*x_i
300 // which we can verify.
301
302 // 1.)
303 DenseVector<Real> lhs(N), rhs(N);
304 for (unsigned i=0; i<N; ++i)
305 {
306 rhs(i) = lambda_real(eigenval) * VR(i, eigenval) - lambda_imag(eigenval) * VR(i, eigenval+1);
307 for (unsigned j=0; j<N; ++j)
308 lhs(i) += A(i, j) * VR(j, eigenval);
309 }
310
311 lhs -= rhs;
312 LIBMESH_ASSERT_FP_EQUAL(/*expected=*/0., /*actual=*/lhs.l2_norm(), std::sqrt(tol)*tol);
313
314 // 2.)
315 lhs.zero();
316 rhs.zero();
317 for (unsigned i=0; i<N; ++i)
318 {
319 rhs(i) = lambda_imag(eigenval) * VR(i, eigenval) + lambda_real(eigenval) * VR(i, eigenval+1);
320 for (unsigned j=0; j<N; ++j)
321 lhs(i) += A(i, j) * VR(j, eigenval+1);
322 }
323
324 lhs -= rhs;
325 LIBMESH_ASSERT_FP_EQUAL(/*expected=*/0., /*actual=*/lhs.l2_norm(), std::sqrt(tol)*tol);
326
327 // We'll skip the second member of the complex conjugate
328 // pair. If the first one worked, the second one should
329 // as well...
330 eigenval += 1;
331 }
332 }
333
334 // Sort the results from Lapack *individually*.
335 std::sort(lambda_real.get_values().begin(), lambda_real.get_values().end());
336 std::sort(lambda_imag.get_values().begin(), lambda_imag.get_values().end());
337
338 // Sort the true eigenvalues *individually*.
339 std::sort(true_lambda_real.begin(), true_lambda_real.end());
340 std::sort(true_lambda_imag.begin(), true_lambda_imag.end());
341
342 // Compare the individually-sorted values.
343 for (unsigned i=0; i<lambda_real.size(); ++i)
344 {
345 // Note: I initially verified the results with TOLERANCE**2,
346 // but that turned out to be just a bit too tight for some of
347 // the test problems. I'm not sure what controls the accuracy
348 // of the eigenvalue computation in LAPACK, there is no way to
349 // set a tolerance in the LAPACKgeev_ interface.
350 LIBMESH_ASSERT_FP_EQUAL(/*expected=*/true_lambda_real[i], /*actual=*/lambda_real(i), std::sqrt(tol)*tol);
351 LIBMESH_ASSERT_FP_EQUAL(/*expected=*/true_lambda_imag[i], /*actual=*/lambda_imag(i), std::sqrt(tol)*tol);
352 }
353#endif
354 }
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...
std::vector< T > & get_values()

References libMesh::DenseMatrix< T >::evd_left_and_right(), libMesh::DenseVector< T >::get_values(), libMesh::DenseMatrixBase< T >::m(), libMesh::DenseVector< T >::size(), and libMesh::DenseVector< T >::zero().

Referenced by testEVDcomplex(), and testEVDreal().

◆ testEVDcomplex()

void DenseMatrixTest::testEVDcomplex ( )
inlineprivate

Definition at line 377 of file dense_matrix_test.C.

378 {
379 LOG_UNIT_TEST;
380
381 // This test is also from a Matlab example, and has complex eigenvalues.
382 // http://www.mathworks.com/help/matlab/math/eigenvalues.html?s_tid=gn_loc_drop
383 DenseMatrix<Real> A(3, 3);
384 A(0,0) = 0; A(0,1) = -6; A(0,2) = -1;
385 A(1,0) = 6; A(1,1) = 2; A(1,2) = -16;
386 A(2,0) = -5; A(2,1) = 20; A(2,2) = -10;
387
388 std::vector<Real> true_lambda_real(3);
389 true_lambda_real[0] = -3.070950351248293;
390 true_lambda_real[1] = -2.464524824375853;
391 true_lambda_real[2] = -2.464524824375853;
392 std::vector<Real> true_lambda_imag(3);
393 true_lambda_imag[0] = 0.;
394 true_lambda_imag[1] = 17.60083096447099;
395 true_lambda_imag[2] = -17.60083096447099;
396
397 // We're good up to double precision (due to the truncated
398 // literals above) or Real precision, whichever is worse
399 const Real tol = std::max(Real(1e-6), TOLERANCE);
400
401 // call helper function to compute and verify results
402 testEVD_helper(A, true_lambda_real, true_lambda_imag, tol);
403 }
void testEVD_helper(DenseMatrix< Real > &A, std::vector< Real > true_lambda_real, std::vector< Real > true_lambda_imag, Real tol)
static constexpr Real TOLERANCE
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real

References libMesh::Real, testEVD_helper(), and libMesh::TOLERANCE.

◆ testEVDreal()

void DenseMatrixTest::testEVDreal ( )
inlineprivate

Definition at line 356 of file dense_matrix_test.C.

357 {
358 LOG_UNIT_TEST;
359
360 // This is an example from Matlab's gallery(3) which is a
361 // non-symmetric 3x3 matrix with eigen values lambda = 1, 2, 3.
362 DenseMatrix<Real> A(3, 3);
363 A(0,0) = -149; A(0,1) = -50; A(0,2) = -154;
364 A(1,0) = 537; A(1,1) = 180; A(1,2) = 546;
365 A(2,0) = -27; A(2,1) = -9; A(2,2) = -25;
366
367 std::vector<Real> true_lambda_real(3);
368 true_lambda_real[0] = 1.;
369 true_lambda_real[1] = 2.;
370 true_lambda_real[2] = 3.;
371 std::vector<Real> true_lambda_imag(3); // all zero
372
373 // call helper function to compute and verify results.
374 testEVD_helper(A, true_lambda_real, true_lambda_imag, TOLERANCE);
375 }

References testEVD_helper(), and libMesh::TOLERANCE.

◆ testOuterProduct()

void DenseMatrixTest::testOuterProduct ( )
inlineprivate

Definition at line 100 of file dense_matrix_test.C.

101 {
102 LOG_UNIT_TEST;
103
104 DenseVector<Real> a = {1.0, 2.0};
105 DenseVector<Real> b = {3.0, 4.0, 5.0};
106
107 DenseMatrix<Real> a_times_b;
108 a_times_b.outer_product(a, b);
109
110 DenseMatrix<Real> a_times_b_correct(2, 3,
111 {3., 4., 5.,
112 6., 8., 10.});
113
114 for (unsigned int i = 0; i < a.size(); ++i)
115 for (unsigned int j = 0; j < b.size(); ++j)
116 LIBMESH_ASSERT_NUMBERS_EQUAL
117 (a_times_b(i,j), a_times_b_correct(i,j), TOLERANCE*TOLERANCE);
118 }
void outer_product(const DenseVector< T > &a, const DenseVector< T > &b)
Computes the outer (dyadic) product of two vectors and stores in (*this).
static const Real b

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

◆ testSubMatrix()

void DenseMatrixTest::testSubMatrix ( )
inlineprivate

Definition at line 429 of file dense_matrix_test.C.

430 {
431 LOG_UNIT_TEST;
432
433 DenseMatrix<Number> A(4, 3);
434 A(0,0) = 1.0; A(0,1) = 2.0; A(0,2) = 3.0;
435 A(1,0) = 4.0; A(1,1) = 5.0; A(1,2) = 6.0;
436 A(2,0) = 7.0; A(2,1) = 8.0; A(2,2) = 9.0;
437 A(3,0) =10.0; A(3,1) =11.0; A(3,2) =12.0;
438
440 B(0,0) = 7.0; B(0,1) = 8.0;
441 B(1,0) =10.0; B(1,1) =11.0;
442
443 DenseMatrix<Number> C = A.sub_matrix(2, 2, 0, 2);
444 CPPUNIT_ASSERT(B == C);
445 }
DenseMatrix sub_matrix(unsigned int row_id, unsigned int row_size, unsigned int col_id, unsigned int col_size) const
Get submatrix with the smallest row and column indices and the submatrix size.
Definition assembly.h:39

References libMesh::DenseMatrix< T >::sub_matrix().

◆ testSVD()

void DenseMatrixTest::testSVD ( )
inlineprivate

Definition at line 120 of file dense_matrix_test.C.

121 {
122 LOG_UNIT_TEST;
123
125 DenseVector<Real> sigma;
126 DenseMatrix<Number> A(3, 2, {
127 1.0, 2.0,
128 3.0, 4.0,
129 5.0, 6.0});
130
131 A.svd(sigma, U, VT);
132
133 // Solution for this case is (verified with numpy)
134 DenseMatrix<Number> true_U(3, 2, {
135 -2.298476964000715e-01, 8.834610176985250e-01,
136 -5.247448187602936e-01, 2.407824921325463e-01,
137 -8.196419411205157e-01, -4.018960334334318e-01});
138
139 DenseMatrix<Number> true_VT(2, 2, {
140 -6.196294838293402e-01, -7.848944532670524e-01,
141 -7.848944532670524e-01, 6.196294838293400e-01});
142
143 DenseVector<Real> true_sigma = {9.525518091565109e+00, 5.143005806586446e-01};
144
145 // Tolerance is bounded by the double literals above and by using Real
146 const Real tol = std::max(Real(1e-12), TOLERANCE*TOLERANCE);
147
148 for (unsigned i=0; i<U.m(); ++i)
149 for (unsigned j=0; j<U.n(); ++j)
150 LIBMESH_ASSERT_NUMBERS_EQUAL( U(i,j), true_U(i,j), tol);
151
152 for (unsigned i=0; i<VT.m(); ++i)
153 for (unsigned j=0; j<VT.n(); ++j)
154 LIBMESH_ASSERT_NUMBERS_EQUAL( VT(i,j), true_VT(i,j), tol);
155
156 for (unsigned i=0; i<sigma.size(); ++i)
157 LIBMESH_ASSERT_FP_EQUAL(sigma(i), true_sigma(i), tol);
158 }
void svd(DenseVector< Real > &sigma)
Compute the singular value decomposition of the matrix.

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


The documentation for this class was generated from the following file: