libMesh
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 
36 namespace libMesh
37 {
38 
39 
40 
41 // ------------------------------------------------------------
42 // Dense Matrix member functions
43 
44 template<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 
70 template<typename T>
71 template<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 
92 template<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 
102 template<typename T>
103 template<typename T2>
105 {
106  this->_left_multiply_transpose(A);
107 }
108 
109 
110 template<typename T>
111 template<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  }
142 
143  else
144  {
145  DenseMatrix<T> B(*this);
146 
147  this->resize (A.n(), B.n());
148 
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 
170 template<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 
195 template<typename T>
196 template<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 
217 template<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 
227 
228 template<typename T>
229 template<typename T2>
231 {
232  this->_right_multiply_transpose(B);
233 }
234 
235 
236 
237 template<typename T>
238 template<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 
298 template<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 
328 template<typename T>
329 template<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 
354 template<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 
392 template<typename T>
393 template<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);
415 
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 
424 template<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 
448 template<typename T>
449 template<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 
469 template<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 
484 template<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 }
496 
497 
498 
499 template<typename T>
500 void 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 
507 template<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 
517 
518 
519 
520 template<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;
553  }
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 
579 template<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 
624 
625 
626 
627 
628 
629 
630 template<typename T>
632 {
633  using std::abs;
634 
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 
709 template<typename T>
711 {
712  // We use the LAPACK svd implementation
713  _svd_lapack(sigma);
714 }
715 
716 
717 template<typename T>
720  DenseMatrix<Number> & VT)
721 {
722  // We use the LAPACK svd implementation
723  _svd_lapack(sigma, U, VT);
724 }
725 
726 
727 
728 template<typename T>
730  DenseVector<T> & x,
731  Real rcond) const
732 {
733  _svd_solve_lapack(rhs, x, rcond);
734 }
735 
736 
737 
738 template<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 
748 template<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 
759 template<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 
770 template<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 
782 template<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.
842 template <typename T>
843 template <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.
875 template<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 
922 template <typename T>
923 template <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
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 _lu_back_substitute(const DenseVector< T > &b, DenseVector< T > &x) const
Solves the system Ax=b through back substitution.
T transpose(const unsigned int i, const unsigned int j) const
T libmesh_conj(T a)
void resize(const unsigned int n)
Resize the vector.
Definition: dense_vector.h:396
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 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...
unsigned int m() const
The libMesh namespace provides an interface to certain functionality in the library.
const Number zero
.
Definition: libmesh.h:297
void outer_product(const DenseVector< T > &a, const DenseVector< T > &b)
Computes the outer (dyadic) product of two vectors and stores in (*this).
void vector_mult_transpose(DenseVector< T > &dest, const DenseVector< T > &arg) const
Performs the matrix-vector multiplication, dest := (*this)^T * arg.
Definition: assembly.h:38
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. ...
void svd(DenseVector< Real > &sigma)
Compute the singular value decomposition of the matrix.
void _lu_decompose()
Form the LU decomposition of the matrix.
void get_transpose(DenseMatrix< T > &dest) const
Put the tranposed matrix 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...
libmesh_assert(ctx)
void _cholesky_decompose()
Decomposes a symmetric positive definite matrix into a product of two lower triangular matrices accor...
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.
std::enable_if< ScalarTraits< T2 >::value, void >::type add(const T2 factor, const DenseVector< T3 > &vec)
Adds factor times vec to this vector.
Definition: dense_vector.h:477
void right_multiply_transpose(const DenseMatrix< T > &A)
Right multiplies by the transpose of the matrix A.
void lu_solve(const DenseVector< T > &b, DenseVector< T > &x)
Solve the system Ax=b given the input vector b.
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real
void evd(DenseVector< T > &lambda_real, DenseVector< T > &lambda_imag)
Compute the eigenvalues (both real and imaginary parts) of a general matrix.
void left_multiply_transpose(const DenseMatrix< T > &A)
Left multiplies by the transpose of the matrix A.
static const Real b
virtual void right_multiply(const DenseMatrixBase< T > &M2) override final
Performs the operation: (*this) <- (*this) * M3.
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 resize(const unsigned int new_m, const unsigned int new_n)
Resizes the matrix to the specified size and calls zero().
Definition: dense_matrix.h:895
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
virtual unsigned int size() const override final
Definition: dense_vector.h:104
Defines a dense vector for use in Finite Element-type computations.
Definition: dof_map.h:74
void cholesky_solve(const DenseVector< T2 > &b, DenseVector< T2 > &x)
For symmetric positive definite (SPD) matrices.
void _right_multiply_transpose(const DenseMatrix< T2 > &A)
Right multiplies by the transpose of the matrix A which may contain a different numerical type...
Defines an abstract dense matrix base class for use in Finite Element-type computations.
unsigned int n() const
Defines a dense matrix for use in Finite Element-type computations.
Definition: dof_map.h:75
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.
virtual void left_multiply(const DenseMatrixBase< T > &M2) override final
Performs the operation: (*this) <- M2 * (*this)
void vector_mult(DenseVector< T > &dest, const DenseVector< T > &arg) const
Performs the matrix-vector multiplication, dest := (*this) * arg.