libMesh
dense_matrix_impl.h
Go to the documentation of this file.
1 // The libMesh Finite Element Library.
2 // Copyright (C) 2002-2025 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  // If this function was called, there better not be any
634  // previous decomposition of the matrix.
635  libmesh_assert_equal_to (this->_decomposition_type, NONE);
636 
637  // Get the matrix size and make sure it is square
638  const unsigned int
639  n_rows = this->m();
640 
641  // A convenient reference to *this
642  DenseMatrix<T> & A = *this;
643 
644  _pivots.resize(n_rows);
645 
646  for (unsigned int i=0; i<n_rows; ++i)
647  {
648  // Find the pivot row by searching down the i'th column
649  _pivots[i] = i;
650 
651  // std::abs(complex) must return a Real!
652  auto the_max = std::abs( A(i,i) );
653  for (unsigned int j=i+1; j<n_rows; ++j)
654  {
655  auto candidate_max = std::abs( A(j,i) );
656  if (the_max < candidate_max)
657  {
658  the_max = candidate_max;
659  _pivots[i] = j;
660  }
661  }
662 
663  // libMesh::out << "the_max=" << the_max << " found at row " << _pivots[i] << std::endl;
664 
665  // If the max was found in a different row, interchange rows.
666  // Here we interchange the *entire* row, in Gaussian elimination
667  // you would only interchange the subrows A(i,j) and A(p(i),j), for j>i
668  if (_pivots[i] != static_cast<pivot_index_t>(i))
669  {
670  for (unsigned int j=0; j<n_rows; ++j)
671  std::swap( A(i,j), A(_pivots[i], j) );
672  }
673 
674  // If the max abs entry found is zero, the matrix is singular
675  libmesh_error_msg_if(A(i,i) == libMesh::zero, "Matrix A is singular!");
676 
677  // Scale upper triangle entries of row i by the diagonal entry
678  // Note: don't scale the diagonal entry itself!
679  const T diag_inv = 1. / A(i,i);
680  for (unsigned int j=i+1; j<n_rows; ++j)
681  A(i,j) *= diag_inv;
682 
683  // Update the remaining sub-matrix A[i+1:m][i+1:m]
684  // by subtracting off (the diagonal-scaled)
685  // upper-triangular part of row i, scaled by the
686  // i'th column entry of each row. In terms of
687  // row operations, this is:
688  // for each r > i
689  // SubRow(r) = SubRow(r) - A(r,i)*SubRow(i)
690  //
691  // If we were scaling the i'th column as well, like
692  // in Gaussian elimination, this would 'zero' the
693  // entry in the i'th column.
694  for (unsigned int row=i+1; row<n_rows; ++row)
695  for (unsigned int col=i+1; col<n_rows; ++col)
696  A(row,col) -= A(row,i) * A(i,col);
697 
698  } // end i loop
699 
700  // Set the flag for LU decomposition
701  this->_decomposition_type = LU;
702 }
703 
704 
705 
706 template<typename T>
708 {
709  // We use the LAPACK svd implementation
710  _svd_lapack(sigma);
711 }
712 
713 
714 template<typename T>
717  DenseMatrix<Number> & VT)
718 {
719  // We use the LAPACK svd implementation
720  _svd_lapack(sigma, U, VT);
721 }
722 
723 
724 
725 template<typename T>
727  DenseVector<T> & x,
728  Real rcond) const
729 {
730  _svd_solve_lapack(rhs, x, rcond);
731 }
732 
733 
734 
735 template<typename T>
737  DenseVector<T> & lambda_imag)
738 {
739  // We use the LAPACK eigenvalue problem implementation
740  _evd_lapack(lambda_real, lambda_imag);
741 }
742 
743 
744 
745 template<typename T>
747  DenseVector<T> & lambda_imag,
748  DenseMatrix<T> & VL)
749 {
750  // We use the LAPACK eigenvalue problem implementation
751  _evd_lapack(lambda_real, lambda_imag, &VL, nullptr);
752 }
753 
754 
755 
756 template<typename T>
758  DenseVector<T> & lambda_imag,
759  DenseMatrix<T> & VR)
760 {
761  // We use the LAPACK eigenvalue problem implementation
762  _evd_lapack(lambda_real, lambda_imag, nullptr, &VR);
763 }
764 
765 
766 
767 template<typename T>
769  DenseVector<T> & lambda_imag,
770  DenseMatrix<T> & VL,
771  DenseMatrix<T> & VR)
772 {
773  // We use the LAPACK eigenvalue problem implementation
774  _evd_lapack(lambda_real, lambda_imag, &VL, &VR);
775 }
776 
777 
778 
779 template<typename T>
781 {
782  switch(this->_decomposition_type)
783  {
784  case NONE:
785  {
786  // First LU decompose the matrix.
787  // Note that the lu_decompose routine will check to see if the
788  // matrix is square so we don't worry about it.
789  if (this->use_blas_lapack)
790  this->_lu_decompose_lapack();
791  else
792  this->_lu_decompose ();
793  }
794  case LU:
795  case LU_BLAS_LAPACK:
796  {
797  // Already decomposed, don't do anything
798  break;
799  }
800  default:
801  libmesh_error_msg("Error! Can't compute the determinant under the current decomposition.");
802  }
803 
804  // A variable to keep track of the running product of diagonal terms.
805  T determinant = 1.;
806 
807  // Loop over diagonal terms, computing the product. In practice,
808  // be careful because this value could easily become too large to
809  // fit in a double or float. To be safe, one should keep track of
810  // the power (of 10) of the determinant in a separate variable
811  // and maintain an order 1 value for the determinant itself.
812  unsigned int n_interchanges = 0;
813  for (auto i : make_range(this->m()))
814  {
815  if (this->_decomposition_type==LU)
816  if (_pivots[i] != static_cast<pivot_index_t>(i))
817  n_interchanges++;
818 
819  // Lapack pivots are 1-based!
820  if (this->_decomposition_type==LU_BLAS_LAPACK)
821  if (_pivots[i] != static_cast<pivot_index_t>(i+1))
822  n_interchanges++;
823 
824  determinant *= (*this)(i,i);
825  }
826 
827  // Compute sign of determinant, depends on number of row interchanges!
828  // The sign should be (-1)^{n}, where n is the number of interchanges.
829  Real sign = n_interchanges % 2 == 0 ? 1. : -1.;
830 
831  return sign*determinant;
832 }
833 
834 
835 
836 // The cholesky solve function first decomposes the matrix
837 // with cholesky_decompose and then uses the cholesky_back_substitute
838 // routine to find the solution x.
839 template <typename T>
840 template <typename T2>
842  DenseVector<T2> & x)
843 {
844  // Check for a previous decomposition
845  switch(this->_decomposition_type)
846  {
847  case NONE:
848  {
849  this->_cholesky_decompose ();
850  break;
851  }
852 
853  case CHOLESKY:
854  {
855  // Already factored, just need to call back_substitute.
856  break;
857  }
858 
859  default:
860  libmesh_error_msg("Error! This matrix already has a different decomposition...");
861  }
862 
863  // Perform back substitution
864  this->_cholesky_back_substitute (b, x);
865 }
866 
867 
868 
869 
870 // This algorithm is based on the Cholesky decomposition in
871 // the Numerical Recipes in C book.
872 template<typename T>
874 {
875  // If we called this function, there better not be any
876  // previous decomposition of the matrix.
877  libmesh_assert_equal_to (this->_decomposition_type, NONE);
878 
879  // Shorthand notation for number of rows and columns.
880  const unsigned int
881  n_rows = this->m(),
882  n_cols = this->n();
883 
884  // Just to be really sure...
885  libmesh_assert_equal_to (n_rows, n_cols);
886 
887  // A convenient reference to *this
888  DenseMatrix<T> & A = *this;
889 
890  for (unsigned int i=0; i<n_rows; ++i)
891  {
892  for (unsigned int j=i; j<n_cols; ++j)
893  {
894  for (unsigned int k=0; k<i; ++k)
895  A(i,j) -= A(i,k) * A(j,k);
896 
897  if (i == j)
898  {
899 #ifndef LIBMESH_USE_COMPLEX_NUMBERS
900  libmesh_error_msg_if(A(i,j) <= 0.0,
901  "Error! Can only use Cholesky decomposition with symmetric positive definite matrices.");
902 #endif
903 
904  A(i,i) = std::sqrt(A(i,j));
905  }
906  else
907  A(j,i) = A(i,j) / A(i,i);
908  }
909  }
910 
911  // Set the flag for CHOLESKY decomposition
912  this->_decomposition_type = CHOLESKY;
913 }
914 
915 
916 
917 template <typename T>
918 template <typename T2>
920  DenseVector<T2> & x) const
921 {
922  // Shorthand notation for number of rows and columns.
923  const unsigned int
924  n_rows = this->m(),
925  n_cols = this->n();
926 
927  // Just to be really sure...
928  libmesh_assert_equal_to (n_rows, n_cols);
929 
930  // A convenient reference to *this
931  const DenseMatrix<T> & A = *this;
932 
933  // Now compute the solution to Ax =b using the factorization.
934  x.resize(n_rows);
935 
936  // Solve for Ly=b
937  for (unsigned int i=0; i<n_cols; ++i)
938  {
939  T2 temp = b(i);
940 
941  for (unsigned int k=0; k<i; ++k)
942  temp -= A(i,k)*x(k);
943 
944  x(i) = temp / A(i,i);
945  }
946 
947  // Solve for L^T x = y
948  for (unsigned int i=0; i<n_cols; ++i)
949  {
950  const unsigned int ib = (n_cols-1)-i;
951 
952  for (unsigned int k=(ib+1); k<n_cols; ++k)
953  x(ib) -= A(k,ib) * x(k);
954 
955  x(ib) /= A(ib,ib);
956  }
957 }
958 
959 
960 
961 
962 
963 
964 
965 
966 // This routine is commented out since it is not really a memory
967 // efficient implementation. Also, you don't *need* the inverse
968 // for anything, instead just use lu_solve to solve Ax=b.
969 // template<typename T>
970 // void DenseMatrix<T>::inverse ()
971 // {
972 // // First LU decompose the matrix
973 // // Note that the lu_decompose routine will check to see if the
974 // // matrix is square so we don't worry about it.
975 // if (!this->_lu_decomposed)
976 // this->_lu_decompose();
977 
978 // // A unit vector which will be used as a rhs
979 // // to pick off a single value each time.
980 // DenseVector<T> e;
981 // e.resize(this->m());
982 
983 // // An empty vector which will be used to hold the solution
984 // // to the back substitutions.
985 // DenseVector<T> x;
986 // x.resize(this->m());
987 
988 // // An empty dense matrix to store the resulting inverse
989 // // temporarily until we can overwrite A.
990 // DenseMatrix<T> inv;
991 // inv.resize(this->m(), this->n());
992 
993 // // Resize the passed in matrix to hold the inverse
994 // inv.resize(this->m(), this->n());
995 
996 // for (unsigned int j=0; j<this->n(); ++j)
997 // {
998 // e.zero();
999 // e(j) = 1.;
1000 // this->_lu_back_substitute(e, x, false);
1001 // for (unsigned int i=0; i<this->n(); ++i)
1002 // inv(i,j) = x(i);
1003 // }
1004 
1005 // // Now overwrite all the entries
1006 // *this = inv;
1007 // }
1008 
1009 
1010 } // namespace libMesh
1011 
1012 #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
boostcopy::enable_if_c< 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
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:304
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.
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.
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:140
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.