libMesh
Loading...
Searching...
No Matches
dense_matrix_impl.h
Go to the documentation of this file.
1// The libMesh Finite Element Library.
2// Copyright (C) 2002-2026 Benjamin S. Kirk, John W. Peterson, Roy H. Stogner
3
4// This library is free software; you can redistribute it and/or
5// modify it under the terms of the GNU Lesser General Public
6// License as published by the Free Software Foundation; either
7// version 2.1 of the License, or (at your option) any later version.
8
9// This library is distributed in the hope that it will be useful,
10// but WITHOUT ANY WARRANTY; without even the implied warranty of
11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12// Lesser General Public License for more details.
13
14// You should have received a copy of the GNU Lesser General Public
15// License along with this library; if not, write to the Free Software
16// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17
18
19#ifndef LIBMESH_DENSE_MATRIX_IMPL_H
20#define LIBMESH_DENSE_MATRIX_IMPL_H
21
22// C++ Includes
23#include <cstdlib> // *must* precede <cmath> for proper std:abs() on PGI, Sun Studio CC
24#include <cmath> // for sqrt
25
26// Local Includes
27#include "libmesh/dense_matrix.h"
28#include "libmesh/dense_vector.h"
29#include "libmesh/int_range.h"
30#include "libmesh/libmesh.h"
31
32#ifdef LIBMESH_HAVE_METAPHYSICL
33#include "metaphysicl/dualnumber_decl.h"
34#endif
35
36namespace libMesh
37{
38
39
40
41// ------------------------------------------------------------
42// Dense Matrix member functions
43
44template<typename T>
46{
47 if (this->use_blas_lapack)
48 this->_multiply_blas(M2, LEFT_MULTIPLY);
49 else
50 {
51 // (*this) <- M2 * (*this)
52 // Where:
53 // (*this) = (m x n),
54 // M2 = (m x p),
55 // M3 = (p x n)
56
57 // M3 is a copy of *this before it gets resize()d
58 DenseMatrix<T> M3(*this);
59
60 // Resize *this so that the result can fit
61 this->resize (M2.m(), M3.n());
62
63 // Call the multiply function in the base class
64 this->multiply(*this, M2, M3);
65 }
66}
67
68
69
70template<typename T>
71template<typename T2>
73{
74 // (*this) <- M2 * (*this)
75 // Where:
76 // (*this) = (m x n),
77 // M2 = (m x p),
78 // M3 = (p x n)
79
80 // M3 is a copy of *this before it gets resize()d
81 DenseMatrix<T> M3(*this);
82
83 // Resize *this so that the result can fit
84 this->resize (M2.m(), M3.n());
85
86 // Call the multiply function in the base class
87 this->multiply(*this, M2, M3);
88}
89
90
91
92template<typename T>
94{
95 if (this->use_blas_lapack)
96 this->_multiply_blas(A, LEFT_MULTIPLY_TRANSPOSE);
97 else
98 this->_left_multiply_transpose(A);
99}
100
101
102template<typename T>
103template<typename T2>
105{
106 this->_left_multiply_transpose(A);
107}
108
109
110template<typename T>
111template<typename T2>
113{
114 //Check to see if we are doing (A^T)*A
115 if (this == &A)
116 {
117 //libmesh_here();
118 DenseMatrix<T> B(*this);
119
120 // Simple but inefficient way
121 // return this->left_multiply_transpose(B);
122
123 // More efficient, but more code way
124 // If A is mxn, the result will be a square matrix of Size n x n.
125 const unsigned int n_rows = A.m();
126 const unsigned int n_cols = A.n();
127
128 // resize() *this and also zero out all entries.
129 this->resize(n_cols,n_cols);
130
131 // Compute the lower-triangular part
132 for (unsigned int i=0; i<n_cols; ++i)
133 for (unsigned int j=0; j<=i; ++j)
134 for (unsigned int k=0; k<n_rows; ++k) // inner products are over n_rows
135 (*this)(i,j) += B(k,i)*B(k,j);
136
137 // Copy lower-triangular part into upper-triangular part
138 for (unsigned int i=0; i<n_cols; ++i)
139 for (unsigned int j=i+1; j<n_cols; ++j)
140 (*this)(i,j) = (*this)(j,i);
141 }
143 else
144 {
145 DenseMatrix<T> B(*this);
146
147 this->resize (A.n(), B.n());
149 libmesh_assert_equal_to (A.m(), B.m());
150 libmesh_assert_equal_to (this->m(), A.n());
151 libmesh_assert_equal_to (this->n(), B.n());
152
153 const unsigned int m_s = A.n();
154 const unsigned int p_s = A.m();
155 const unsigned int n_s = this->n();
156
157 // Do it this way because there is a
158 // decent chance (at least for constraint matrices)
159 // that A.transpose(i,k) = 0.
160 for (unsigned int i=0; i<m_s; i++)
161 for (unsigned int k=0; k<p_s; k++)
162 if (A.transpose(i,k) != 0.)
163 for (unsigned int j=0; j<n_s; j++)
164 (*this)(i,j) += A.transpose(i,k)*B(k,j);
165 }
166}
167
168
169
170template<typename T>
172{
173 if (this->use_blas_lapack)
174 this->_multiply_blas(M3, RIGHT_MULTIPLY);
175 else
176 {
177 // (*this) <- (*this) * M3
178 // Where:
179 // (*this) = (m x n),
180 // M2 = (m x p),
181 // M3 = (p x n)
182
183 // M2 is a copy of *this before it gets resize()d
184 DenseMatrix<T> M2(*this);
185
186 // Resize *this so that the result can fit
187 this->resize (M2.m(), M3.n());
188
189 this->multiply(*this, M2, M3);
190 }
191}
192
193
194
195template<typename T>
196template<typename T2>
198{
199 // (*this) <- M3 * (*this)
200 // Where:
201 // (*this) = (m x n),
202 // M2 = (m x p),
203 // M3 = (p x n)
204
205 // M2 is a copy of *this before it gets resize()d
206 DenseMatrix<T> M2(*this);
207
208 // Resize *this so that the result can fit
209 this->resize (M2.m(), M3.n());
210
211 this->multiply(*this, M2, M3);
212}
213
214
215
216
217template<typename T>
219{
220 if (this->use_blas_lapack)
221 this->_multiply_blas(B, RIGHT_MULTIPLY_TRANSPOSE);
222 else
223 this->_right_multiply_transpose(B);
224}
225
226
228template<typename T>
229template<typename T2>
231{
232 this->_right_multiply_transpose(B);
233}
234
235
236
237template<typename T>
238template<typename T2>
240{
241 //Check to see if we are doing B*(B^T)
242 if (this == &B)
243 {
244 //libmesh_here();
245 DenseMatrix<T> A(*this);
246
247 // Simple but inefficient way
248 // return this->right_multiply_transpose(A);
249
250 // More efficient, more code
251 // If B is mxn, the result will be a square matrix of Size m x m.
252 const unsigned int n_rows = B.m();
253 const unsigned int n_cols = B.n();
254
255 // resize() *this and also zero out all entries.
256 this->resize(n_rows,n_rows);
257
258 // Compute the lower-triangular part
259 for (unsigned int i=0; i<n_rows; ++i)
260 for (unsigned int j=0; j<=i; ++j)
261 for (unsigned int k=0; k<n_cols; ++k) // inner products are over n_cols
262 (*this)(i,j) += A(i,k)*A(j,k);
263
264 // Copy lower-triangular part into upper-triangular part
265 for (unsigned int i=0; i<n_rows; ++i)
266 for (unsigned int j=i+1; j<n_rows; ++j)
267 (*this)(i,j) = (*this)(j,i);
268 }
269
270 else
271 {
272 DenseMatrix<T> A(*this);
273
274 this->resize (A.m(), B.m());
275
276 libmesh_assert_equal_to (A.n(), B.n());
277 libmesh_assert_equal_to (this->m(), A.m());
278 libmesh_assert_equal_to (this->n(), B.m());
279
280 const unsigned int m_s = A.m();
281 const unsigned int p_s = A.n();
282 const unsigned int n_s = this->n();
283
284 // Do it this way because there is a
285 // decent chance (at least for constraint matrices)
286 // that B.transpose(k,j) = 0.
287 for (unsigned int j=0; j<n_s; j++)
288 for (unsigned int k=0; k<p_s; k++)
289 if (B.transpose(k,j) != 0.)
290 for (unsigned int i=0; i<m_s; i++)
291 (*this)(i,j) += A(i,k)*B.transpose(k,j);
292 }
293}
294
295
296
297
298template<typename T>
300 const DenseVector<T> & arg) const
301{
302 // Make sure the input sizes are compatible
303 libmesh_assert_equal_to (this->n(), arg.size());
304
305 // Resize and clear dest.
306 // Note: DenseVector::resize() also zeros the vector.
307 dest.resize(this->m());
308
309 // Short-circuit if the matrix is empty
310 if(this->m() == 0 || this->n() == 0)
311 return;
312
313 if (this->use_blas_lapack)
314 this->_matvec_blas(1., 0., dest, arg);
315 else
316 {
317 const unsigned int n_rows = this->m();
318 const unsigned int n_cols = this->n();
319
320 for (unsigned int i=0; i<n_rows; i++)
321 for (unsigned int j=0; j<n_cols; j++)
322 dest(i) += (*this)(i,j)*arg(j);
323 }
324}
325
326
327
328template<typename T>
329template<typename T2>
331 const DenseVector<T2> & arg) const
332{
333 // Make sure the input sizes are compatible
334 libmesh_assert_equal_to (this->n(), arg.size());
335
336 // Resize and clear dest.
337 // Note: DenseVector::resize() also zeros the vector.
338 dest.resize(this->m());
339
340 // Short-circuit if the matrix is empty
341 if (this->m() == 0 || this->n() == 0)
342 return;
343
344 const unsigned int n_rows = this->m();
345 const unsigned int n_cols = this->n();
346
347 for (unsigned int i=0; i<n_rows; i++)
348 for (unsigned int j=0; j<n_cols; j++)
349 dest(i) += (*this)(i,j)*arg(j);
350}
351
352
353
354template<typename T>
356 const DenseVector<T> & arg) const
357{
358 // Make sure the input sizes are compatible
359 libmesh_assert_equal_to (this->m(), arg.size());
360
361 // Resize and clear dest.
362 // Note: DenseVector::resize() also zeros the vector.
363 dest.resize(this->n());
364
365 // Short-circuit if the matrix is empty
366 if (this->m() == 0)
367 return;
368
369 if (this->use_blas_lapack)
370 {
371 this->_matvec_blas(1., 0., dest, arg, /*trans=*/true);
372 }
373 else
374 {
375 const unsigned int n_rows = this->m();
376 const unsigned int n_cols = this->n();
377
378 // WORKS
379 // for (unsigned int j=0; j<n_cols; j++)
380 // for (unsigned int i=0; i<n_rows; i++)
381 // dest(j) += (*this)(i,j)*arg(i);
382
383 // ALSO WORKS, (i,j) just swapped
384 for (unsigned int i=0; i<n_cols; i++)
385 for (unsigned int j=0; j<n_rows; j++)
386 dest(i) += (*this)(j,i)*arg(j);
387 }
388}
389
390
391
392template<typename T>
393template<typename T2>
395 const DenseVector<T2> & arg) const
396{
397 // Make sure the input sizes are compatible
398 libmesh_assert_equal_to (this->m(), arg.size());
399
400 // Resize and clear dest.
401 // Note: DenseVector::resize() also zeros the vector.
402 dest.resize(this->n());
403
404 // Short-circuit if the matrix is empty
405 if (this->m() == 0)
406 return;
407
408 const unsigned int n_rows = this->m();
409 const unsigned int n_cols = this->n();
410
411 // WORKS
412 // for (unsigned int j=0; j<n_cols; j++)
413 // for (unsigned int i=0; i<n_rows; i++)
414 // dest(j) += (*this)(i,j)*arg(i);
416 // ALSO WORKS, (i,j) just swapped
417 for (unsigned int i=0; i<n_cols; i++)
418 for (unsigned int j=0; j<n_rows; j++)
419 dest(i) += (*this)(j,i)*arg(j);
420}
421
422
423
424template<typename T>
426 const T factor,
427 const DenseVector<T> & arg) const
428{
429 // Short-circuit if the matrix is empty
430 if (this->m() == 0)
431 {
432 dest.resize(0);
433 return;
434 }
435
436 if (this->use_blas_lapack)
437 this->_matvec_blas(factor, 1., dest, arg);
438 else
439 {
440 DenseVector<T> temp(arg.size());
441 this->vector_mult(temp, arg);
442 dest.add(factor, temp);
443 }
444}
445
446
447
448template<typename T>
449template<typename T2, typename T3>
451 const T2 factor,
452 const DenseVector<T3> & arg) const
453{
454 // Short-circuit if the matrix is empty
455 if (this->m() == 0)
456 {
457 dest.resize(0);
458 return;
459 }
460
462 temp(arg.size());
463 this->vector_mult(temp, arg);
464 dest.add(factor, temp);
465}
466
467
468
469template<typename T>
471 unsigned int sub_n,
472 DenseMatrix<T> & dest) const
473{
474 libmesh_assert( (sub_m <= this->m()) && (sub_n <= this->n()) );
475
476 dest.resize(sub_m, sub_n);
477 for (unsigned int i=0; i<sub_m; i++)
478 for (unsigned int j=0; j<sub_n; j++)
479 dest(i,j) = (*this)(i,j);
480}
481
482
483
484template<typename T>
486 const DenseVector<T> & b)
487{
488 const unsigned int m = a.size();
489 const unsigned int n = b.size();
490
491 this->resize(m, n);
492 for (unsigned int i = 0; i < m; ++i)
493 for (unsigned int j = 0; j < n; ++j)
494 (*this)(i,j) = a(i) * libmesh_conj(b(j));
495}
497
498
499template<typename T>
500void DenseMatrix<T>::get_principal_submatrix (unsigned int sub_m, DenseMatrix<T> & dest) const
501{
502 get_principal_submatrix(sub_m, sub_m, dest);
503}
504
505
506
507template<typename T>
509{
510 dest.resize(this->n(), this->m());
511
512 for (auto i : make_range(dest.m()))
513 for (auto j : make_range(dest.n()))
514 dest(i,j) = (*this)(j,i);
515}
516
518
519
520template<typename T>
522 DenseVector<T> & x)
523{
524 // Check to be sure that the matrix is square before attempting
525 // an LU-solve. In general, one can compute the LU factorization of
526 // a non-square matrix, but:
527 //
528 // Overdetermined systems (m>n) have a solution only if enough of
529 // the equations are linearly-dependent.
530 //
531 // Underdetermined systems (m<n) typically have infinitely many
532 // solutions.
533 //
534 // We don't want to deal with either of these ambiguous cases here...
535 libmesh_assert_equal_to (this->m(), this->n());
536
537 switch(this->_decomposition_type)
538 {
539 case NONE:
540 {
541 if (this->use_blas_lapack)
542 this->_lu_decompose_lapack();
543 else
544 this->_lu_decompose ();
545 break;
546 }
547
548 case LU_BLAS_LAPACK:
549 {
550 // Already factored, just need to call back_substitute.
551 if (this->use_blas_lapack)
552 break;
554 libmesh_fallthrough();
555
556 case LU:
557 {
558 // Already factored, just need to call back_substitute.
559 if (!(this->use_blas_lapack))
560 break;
561 }
562 libmesh_fallthrough();
563
564 default:
565 libmesh_error_msg("Error! This matrix already has a different decomposition...");
566 }
567
568 if (this->use_blas_lapack)
569 this->_lu_back_substitute_lapack (b, x);
570 else
571 this->_lu_back_substitute (b, x);
572}
573
574
575
576
577
578
579template<typename T>
581 DenseVector<T> & x ) const
582{
583 const unsigned int
584 n_cols = this->n();
585
586 libmesh_assert_equal_to (this->m(), n_cols);
587 libmesh_assert_equal_to (this->m(), b.size());
588
589 x.resize (n_cols);
590
591 // A convenient reference to *this
592 const DenseMatrix<T> & A = *this;
593
594 // Temporary vector storage. We use this instead of
595 // modifying the RHS.
596 DenseVector<T> z = b;
597
598 // Lower-triangular "top to bottom" solve step, taking into account pivots
599 for (unsigned int i=0; i<n_cols; ++i)
600 {
601 // Swap
602 if (_pivots[i] != static_cast<pivot_index_t>(i))
603 std::swap( z(i), z(_pivots[i]) );
604
605 x(i) = z(i);
606
607 for (unsigned int j=0; j<i; ++j)
608 x(i) -= A(i,j)*x(j);
609
610 x(i) /= A(i,i);
611 }
612
613 // Upper-triangular "bottom to top" solve step
614 const unsigned int last_row = n_cols-1;
615
616 for (int i=last_row; i>=0; --i)
617 {
618 for (int j=i+1; j<static_cast<int>(n_cols); ++j)
619 x(i) -= A(i,j)*x(j);
620 }
621}
622
623
625
626
627
628
629
630template<typename T>
632{
633 using std::abs;
635 // If this function was called, there better not be any
636 // previous decomposition of the matrix.
637 libmesh_assert_equal_to (this->_decomposition_type, NONE);
638
639 // Get the matrix size and make sure it is square
640 const unsigned int
641 n_rows = this->m();
642
643 // A convenient reference to *this
644 DenseMatrix<T> & A = *this;
645
646 _pivots.resize(n_rows);
647
648 for (unsigned int i=0; i<n_rows; ++i)
649 {
650 // Find the pivot row by searching down the i'th column
651 _pivots[i] = i;
652
653 // abs(complex) must return a Real!
654 auto the_max = abs( A(i,i) );
655 for (unsigned int j=i+1; j<n_rows; ++j)
656 {
657 auto candidate_max = abs( A(j,i) );
658 if (the_max < candidate_max)
659 {
660 the_max = candidate_max;
661 _pivots[i] = j;
662 }
663 }
664
665 // libMesh::out << "the_max=" << the_max << " found at row " << _pivots[i] << std::endl;
666
667 // If the max was found in a different row, interchange rows.
668 // Here we interchange the *entire* row, in Gaussian elimination
669 // you would only interchange the subrows A(i,j) and A(p(i),j), for j>i
670 if (_pivots[i] != static_cast<pivot_index_t>(i))
671 {
672 for (unsigned int j=0; j<n_rows; ++j)
673 std::swap( A(i,j), A(_pivots[i], j) );
674 }
675
676 // If the max abs entry found is zero, the matrix is singular
677 if (A(i,i) == libMesh::zero)
678 libmesh_degenerate_mapping_msg ("Matrix A is singular!");
679
680 // Scale upper triangle entries of row i by the diagonal entry
681 // Note: don't scale the diagonal entry itself!
682 const T diag_inv = 1. / A(i,i);
683 for (unsigned int j=i+1; j<n_rows; ++j)
684 A(i,j) *= diag_inv;
685
686 // Update the remaining sub-matrix A[i+1:m][i+1:m]
687 // by subtracting off (the diagonal-scaled)
688 // upper-triangular part of row i, scaled by the
689 // i'th column entry of each row. In terms of
690 // row operations, this is:
691 // for each r > i
692 // SubRow(r) = SubRow(r) - A(r,i)*SubRow(i)
693 //
694 // If we were scaling the i'th column as well, like
695 // in Gaussian elimination, this would 'zero' the
696 // entry in the i'th column.
697 for (unsigned int row=i+1; row<n_rows; ++row)
698 for (unsigned int col=i+1; col<n_rows; ++col)
699 A(row,col) -= A(row,i) * A(i,col);
700
701 } // end i loop
702
703 // Set the flag for LU decomposition
704 this->_decomposition_type = LU;
705}
706
707
708
709template<typename T>
711{
712 // We use the LAPACK svd implementation
713 _svd_lapack(sigma);
714}
715
716
717template<typename T>
721{
722 // We use the LAPACK svd implementation
723 _svd_lapack(sigma, U, VT);
724}
725
726
727
728template<typename T>
730 DenseVector<T> & x,
731 Real rcond) const
732{
733 _svd_solve_lapack(rhs, x, rcond);
734}
735
736
737
738template<typename T>
740 DenseVector<T> & lambda_imag)
741{
742 // We use the LAPACK eigenvalue problem implementation
743 _evd_lapack(lambda_real, lambda_imag);
744}
745
746
747
748template<typename T>
750 DenseVector<T> & lambda_imag,
751 DenseMatrix<T> & VL)
752{
753 // We use the LAPACK eigenvalue problem implementation
754 _evd_lapack(lambda_real, lambda_imag, &VL, nullptr);
755}
756
757
758
759template<typename T>
761 DenseVector<T> & lambda_imag,
762 DenseMatrix<T> & VR)
763{
764 // We use the LAPACK eigenvalue problem implementation
765 _evd_lapack(lambda_real, lambda_imag, nullptr, &VR);
766}
767
768
769
770template<typename T>
772 DenseVector<T> & lambda_imag,
773 DenseMatrix<T> & VL,
774 DenseMatrix<T> & VR)
775{
776 // We use the LAPACK eigenvalue problem implementation
777 _evd_lapack(lambda_real, lambda_imag, &VL, &VR);
778}
779
780
781
782template<typename T>
784{
785 switch(this->_decomposition_type)
786 {
787 case NONE:
788 {
789 // First LU decompose the matrix.
790 // Note that the lu_decompose routine will check to see if the
791 // matrix is square so we don't worry about it.
792 if (this->use_blas_lapack)
793 this->_lu_decompose_lapack();
794 else
795 this->_lu_decompose ();
796 }
797 case LU:
798 case LU_BLAS_LAPACK:
799 {
800 // Already decomposed, don't do anything
801 break;
802 }
803 default:
804 libmesh_error_msg("Error! Can't compute the determinant under the current decomposition.");
805 }
806
807 // A variable to keep track of the running product of diagonal terms.
808 T determinant = 1.;
809
810 // Loop over diagonal terms, computing the product. In practice,
811 // be careful because this value could easily become too large to
812 // fit in a double or float. To be safe, one should keep track of
813 // the power (of 10) of the determinant in a separate variable
814 // and maintain an order 1 value for the determinant itself.
815 unsigned int n_interchanges = 0;
816 for (auto i : make_range(this->m()))
817 {
818 if (this->_decomposition_type==LU)
819 if (_pivots[i] != static_cast<pivot_index_t>(i))
820 n_interchanges++;
821
822 // Lapack pivots are 1-based!
823 if (this->_decomposition_type==LU_BLAS_LAPACK)
824 if (_pivots[i] != static_cast<pivot_index_t>(i+1))
825 n_interchanges++;
826
827 determinant *= (*this)(i,i);
828 }
829
830 // Compute sign of determinant, depends on number of row interchanges!
831 // The sign should be (-1)^{n}, where n is the number of interchanges.
832 Real sign = n_interchanges % 2 == 0 ? 1. : -1.;
833
834 return sign*determinant;
835}
836
837
838
839// The cholesky solve function first decomposes the matrix
840// with cholesky_decompose and then uses the cholesky_back_substitute
841// routine to find the solution x.
842template <typename T>
843template <typename T2>
845 DenseVector<T2> & x)
846{
847 // Check for a previous decomposition
848 switch(this->_decomposition_type)
849 {
850 case NONE:
851 {
852 this->_cholesky_decompose ();
853 break;
854 }
855
856 case CHOLESKY:
857 {
858 // Already factored, just need to call back_substitute.
859 break;
860 }
861
862 default:
863 libmesh_error_msg("Error! This matrix already has a different decomposition...");
864 }
865
866 // Perform back substitution
867 this->_cholesky_back_substitute (b, x);
868}
869
870
871
872
873// This algorithm is based on the Cholesky decomposition in
874// the Numerical Recipes in C book.
875template<typename T>
877{
878 using std::sqrt;
879
880 // If we called this function, there better not be any
881 // previous decomposition of the matrix.
882 libmesh_assert_equal_to (this->_decomposition_type, NONE);
883
884 // Shorthand notation for number of rows and columns.
885 const unsigned int
886 n_rows = this->m(),
887 n_cols = this->n();
888
889 // Just to be really sure...
890 libmesh_assert_equal_to (n_rows, n_cols);
891
892 // A convenient reference to *this
893 DenseMatrix<T> & A = *this;
894
895 for (unsigned int i=0; i<n_rows; ++i)
896 {
897 for (unsigned int j=i; j<n_cols; ++j)
898 {
899 for (unsigned int k=0; k<i; ++k)
900 A(i,j) -= A(i,k) * A(j,k);
901
902 if (i == j)
903 {
904#ifndef LIBMESH_USE_COMPLEX_NUMBERS
905 libmesh_error_msg_if(A(i,j) <= 0.0,
906 "Error! Can only use Cholesky decomposition with symmetric positive definite matrices.");
907#endif
908
909 A(i,i) = sqrt(A(i,j));
910 }
911 else
912 A(j,i) = A(i,j) / A(i,i);
913 }
914 }
915
916 // Set the flag for CHOLESKY decomposition
917 this->_decomposition_type = CHOLESKY;
918}
919
920
921
922template <typename T>
923template <typename T2>
925 DenseVector<T2> & x) const
926{
927 // Shorthand notation for number of rows and columns.
928 const unsigned int
929 n_rows = this->m(),
930 n_cols = this->n();
931
932 // Just to be really sure...
933 libmesh_assert_equal_to (n_rows, n_cols);
934
935 // A convenient reference to *this
936 const DenseMatrix<T> & A = *this;
937
938 // Now compute the solution to Ax =b using the factorization.
939 x.resize(n_rows);
940
941 // Solve for Ly=b
942 for (unsigned int i=0; i<n_cols; ++i)
943 {
944 T2 temp = b(i);
945
946 for (unsigned int k=0; k<i; ++k)
947 temp -= A(i,k)*x(k);
948
949 x(i) = temp / A(i,i);
950 }
951
952 // Solve for L^T x = y
953 for (unsigned int i=0; i<n_cols; ++i)
954 {
955 const unsigned int ib = (n_cols-1)-i;
956
957 for (unsigned int k=(ib+1); k<n_cols; ++k)
958 x(ib) -= A(k,ib) * x(k);
959
960 x(ib) /= A(ib,ib);
961 }
962}
963
964
965
966
967
968
969
970
971// This routine is commented out since it is not really a memory
972// efficient implementation. Also, you don't *need* the inverse
973// for anything, instead just use lu_solve to solve Ax=b.
974// template<typename T>
975// void DenseMatrix<T>::inverse ()
976// {
977// // First LU decompose the matrix
978// // Note that the lu_decompose routine will check to see if the
979// // matrix is square so we don't worry about it.
980// if (!this->_lu_decomposed)
981// this->_lu_decompose();
982
983// // A unit vector which will be used as a rhs
984// // to pick off a single value each time.
985// DenseVector<T> e;
986// e.resize(this->m());
987
988// // An empty vector which will be used to hold the solution
989// // to the back substitutions.
990// DenseVector<T> x;
991// x.resize(this->m());
992
993// // An empty dense matrix to store the resulting inverse
994// // temporarily until we can overwrite A.
995// DenseMatrix<T> inv;
996// inv.resize(this->m(), this->n());
997
998// // Resize the passed in matrix to hold the inverse
999// inv.resize(this->m(), this->n());
1000
1001// for (unsigned int j=0; j<this->n(); ++j)
1002// {
1003// e.zero();
1004// e(j) = 1.;
1005// this->_lu_back_substitute(e, x, false);
1006// for (unsigned int i=0; i<this->n(); ++i)
1007// inv(i,j) = x(i);
1008// }
1009
1010// // Now overwrite all the entries
1011// *this = inv;
1012// }
1013
1014
1015} // namespace libMesh
1016
1017#endif // LIBMESH_DENSE_MATRIX_IMPL_H
Defines an abstract dense matrix base class for use in Finite Element-type computations.
Defines a dense matrix for use in Finite Element-type computations.
void _cholesky_decompose()
Decomposes a symmetric positive definite matrix into a product of two lower triangular matrices accor...
void _lu_decompose()
Form the LU decomposition of the matrix.
void evd_left(DenseVector< T > &lambda_real, DenseVector< T > &lambda_imag, DenseMatrix< T > &VL)
Compute the eigenvalues (both real and imaginary parts) and left eigenvectors of a general matrix,...
void _lu_back_substitute(const DenseVector< T > &b, DenseVector< T > &x) const
Solves the system Ax=b through back substitution.
void right_multiply_transpose(const DenseMatrix< T > &A)
Right multiplies by the transpose of the matrix A.
void _left_multiply_transpose(const DenseMatrix< T2 > &A)
Left multiplies by the transpose of the matrix A which may contain a different numerical type.
void _right_multiply_transpose(const DenseMatrix< T2 > &A)
Right multiplies by the transpose of the matrix A which may contain a different numerical type.
void svd_solve(const DenseVector< T > &rhs, DenseVector< T > &x, Real rcond=std::numeric_limits< Real >::epsilon()) const
Solve the system of equations for in the least-squares sense.
void vector_mult(DenseVector< T > &dest, const DenseVector< T > &arg) const
Performs the matrix-vector multiplication, dest := (*this) * arg.
void cholesky_solve(const DenseVector< T2 > &b, DenseVector< T2 > &x)
For symmetric positive definite (SPD) matrices.
void _cholesky_back_substitute(const DenseVector< T2 > &b, DenseVector< T2 > &x) const
Solves the equation Ax=b for the unknown value x and rhs b based on the Cholesky factorization of A.
void resize(const unsigned int new_m, const unsigned int new_n)
Resizes the matrix to the specified size and calls zero().
void svd(DenseVector< Real > &sigma)
Compute the singular value decomposition of the matrix.
void lu_solve(const DenseVector< T > &b, DenseVector< T > &x)
Solve the system Ax=b given the input vector b.
virtual void right_multiply(const DenseMatrixBase< T > &M2) override final
Performs the operation: (*this) <- (*this) * M3.
void get_principal_submatrix(unsigned int sub_m, unsigned int sub_n, DenseMatrix< T > &dest) const
Put the sub_m x sub_n principal submatrix into dest.
void evd_right(DenseVector< T > &lambda_real, DenseVector< T > &lambda_imag, DenseMatrix< T > &VR)
Compute the eigenvalues (both real and imaginary parts) and right eigenvectors of a general matrix,...
void get_transpose(DenseMatrix< T > &dest) const
Put the tranposed matrix into dest.
void vector_mult_transpose(DenseVector< T > &dest, const DenseVector< T > &arg) const
Performs the matrix-vector multiplication, dest := (*this)^T * arg.
T transpose(const unsigned int i, const unsigned int j) const
virtual void left_multiply(const DenseMatrixBase< T > &M2) override final
Performs the operation: (*this) <- M2 * (*this)
void outer_product(const DenseVector< T > &a, const DenseVector< T > &b)
Computes the outer (dyadic) product of two vectors and stores in (*this).
PetscBLASInt pivot_index_t
Array used to store pivot indices.
void evd(DenseVector< T > &lambda_real, DenseVector< T > &lambda_imag)
Compute the eigenvalues (both real and imaginary parts) of a general matrix.
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...
void left_multiply_transpose(const DenseMatrix< T > &A)
Left multiplies by the transpose of the matrix A.
void vector_mult_add(DenseVector< T > &dest, const T factor, const DenseVector< T > &arg) const
Performs the scaled matrix-vector multiplication, dest += factor * (*this) * arg.
Defines a dense vector for use in Finite Element-type computations.
void resize(const unsigned int n)
Resize the vector.
std::enable_if< ScalarTraits< T2 >::value, void >::type add(const T2 factor, const DenseVector< T3 > &vec)
Adds factor times vec to this vector.
virtual unsigned int size() const override final
static const Real b
The libMesh namespace provides an interface to certain functionality in the library.
libmesh_assert(ctx)
const Number zero
.
Definition libmesh.h:297
T libmesh_conj(T a)
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real
IntRange< T > make_range(T beg, T end)
The 2-parameter make_range() helper function returns an IntRange<T> when both input parameters are of...
Definition int_range.h:176
Definition assembly.h:39