LCOV - code coverage report
Current view: top level - include/numerics - dense_matrix.h (source / functions) Hit Total Coverage
Test: libMesh/libmesh: #4523 (33cf8b) with base 9e965b Lines: 74 139 53.2 %
Date: 2026-08-16 16:35:36 Functions: 29 65 44.6 %
Legend: Lines: hit not hit

          Line data    Source code
       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             : 
      20             : #ifndef LIBMESH_DENSE_MATRIX_H
      21             : #define LIBMESH_DENSE_MATRIX_H
      22             : 
      23             : // Local Includes
      24             : #include "libmesh/libmesh_common.h"
      25             : #include "libmesh/dense_matrix_base.h"
      26             : #include "libmesh/int_range.h"
      27             : #include "libmesh/parallel_algorithms.h"
      28             : 
      29             : // For the definition of PetscBLASInt.
      30             : #if (LIBMESH_HAVE_PETSC)
      31             : # include "libmesh/petsc_macro.h"
      32             : # ifdef I
      33             : #  define LIBMESH_SAW_I
      34             : # endif
      35             : 
      36             : #include "libmesh/ignore_warnings.h"
      37             : # include <petscsys.h>
      38             : #include "libmesh/restore_warnings.h"
      39             : 
      40             : # ifndef LIBMESH_SAW_I
      41             : #  undef I // Avoid complex.h contamination
      42             : # endif
      43             : #endif
      44             : 
      45             : // C++ includes
      46             : #include <algorithm>
      47             : #include <initializer_list>
      48             : #include <vector>
      49             : 
      50             : #ifdef LIBMESH_HAVE_METAPHYSICL
      51             : #include "metaphysicl/dualnumber_decl.h"
      52             : #include "metaphysicl/raw_type.h"
      53             : #endif
      54             : 
      55             : namespace libMesh
      56             : {
      57             : 
      58             : // Forward Declarations
      59             : template <typename T> class DenseVector;
      60             : 
      61             : /**
      62             :  * Defines a dense matrix for use in Finite Element-type computations.
      63             :  * Useful for storing element stiffness matrices before summation into
      64             :  * a global matrix.  All overridden virtual functions are documented
      65             :  * in dense_matrix_base.h.
      66             :  *
      67             :  * \author Benjamin S. Kirk
      68             :  * \date 2002
      69             :  * \brief A matrix object used for finite element assembly and numerics.
      70             :  */
      71             : template<typename T>
      72      315200 : class DenseMatrix : public DenseMatrixBase<T>
      73             : {
      74             : public:
      75             : 
      76             :   /**
      77             :    * Constructor.  Creates a dense matrix of dimension \p m by \p n.
      78             :    */
      79             :   DenseMatrix(const unsigned int new_m=0,
      80             :               const unsigned int new_n=0);
      81             : 
      82             :   /**
      83             :    * Constructor taking the number of rows, columns, and an
      84             :    * initializer_list, which must be of length nrow * ncol, of
      85             :    * row-major values to initialize the DenseMatrix with.
      86             :    */
      87             :   template <typename T2>
      88             :   DenseMatrix(unsigned int nrow,
      89             :               unsigned int ncol,
      90             :               std::initializer_list<T2> init_list);
      91             : 
      92             :   /**
      93             :    * The 5 special functions can be defaulted for this class, as it
      94             :    * does not manage any memory itself.
      95             :    */
      96           0 :   DenseMatrix (DenseMatrix &&) = default;
      97      881148 :   DenseMatrix (const DenseMatrix &) = default;
      98      262326 :   DenseMatrix & operator= (const DenseMatrix &) = default;
      99             :   DenseMatrix & operator= (DenseMatrix &&) = default;
     100   104461424 :   virtual ~DenseMatrix() = default;
     101             : 
     102             :   /**
     103             :    * Sets all elements of the matrix to 0 and resets any decomposition
     104             :    * flag which may have been previously set.  This allows e.g. a new
     105             :    * LU decomposition to be computed while reusing the same storage.
     106             :    */
     107             :   virtual void zero() override final;
     108             : 
     109             :   /**
     110             :    * Get submatrix with the smallest row and column indices and the submatrix size.
     111             :    */
     112             :   DenseMatrix sub_matrix(unsigned int row_id, unsigned int row_size,
     113             :                          unsigned int col_id, unsigned int col_size) const;
     114             : 
     115             :   /**
     116             :    * \returns The \p (i,j) element of the matrix.
     117             :    */
     118             :   T operator() (const unsigned int i,
     119             :                 const unsigned int j) const;
     120             : 
     121             :   /**
     122             :    * \returns The \p (i,j) element of the matrix as a writable reference.
     123             :    */
     124             :   T & operator() (const unsigned int i,
     125             :                   const unsigned int j);
     126             : 
     127    54989648 :   virtual T el(const unsigned int i,
     128             :                const unsigned int j) const override final
     129    54989648 :   { return (*this)(i,j); }
     130             : 
     131    22183512 :   virtual T & el(const unsigned int i,
     132             :                  const unsigned int j) override final
     133    22183512 :   { return (*this)(i,j); }
     134             : 
     135             :   virtual void left_multiply (const DenseMatrixBase<T> & M2) override final;
     136             : 
     137             :   /**
     138             :    * Left multiplies by the matrix \p M2 of different type
     139             :    */
     140             :   template <typename T2>
     141             :   void left_multiply (const DenseMatrixBase<T2> & M2);
     142             : 
     143             :   virtual void right_multiply (const DenseMatrixBase<T> & M2) override final;
     144             : 
     145             :   /**
     146             :    * Right multiplies by the matrix \p M2 of different type
     147             :    */
     148             :   template <typename T2>
     149             :   void right_multiply (const DenseMatrixBase<T2> & M2);
     150             : 
     151             :   /**
     152             :    * Performs the matrix-vector multiplication,
     153             :    * \p dest := (*this) * \p arg.
     154             :    */
     155             :   void vector_mult (DenseVector<T> & dest,
     156             :                     const DenseVector<T> & arg) const;
     157             : 
     158             :   /**
     159             :    * Performs the matrix-vector multiplication,
     160             :    * \p dest := (*this) * \p arg
     161             :    * on mixed types
     162             :    */
     163             :   template <typename T2>
     164             :   void vector_mult (DenseVector<typename CompareTypes<T,T2>::supertype> & dest,
     165             :                     const DenseVector<T2> & arg) const;
     166             : 
     167             :   /**
     168             :    * Performs the matrix-vector multiplication,
     169             :    * \p dest := (*this)^T * \p arg.
     170             :    */
     171             :   void vector_mult_transpose (DenseVector<T> & dest,
     172             :                               const DenseVector<T> & arg) const;
     173             : 
     174             :   /**
     175             :    * Performs the matrix-vector multiplication,
     176             :    * \p dest := (*this)^T * \p arg.
     177             :    * on mixed types
     178             :    */
     179             :   template <typename T2>
     180             :   void vector_mult_transpose (DenseVector<typename CompareTypes<T,T2>::supertype> & dest,
     181             :                               const DenseVector<T2> & arg) const;
     182             : 
     183             :   /**
     184             :    * Performs the scaled matrix-vector multiplication,
     185             :    * \p dest += \p factor * (*this) * \p arg.
     186             :    */
     187             :   void vector_mult_add (DenseVector<T> & dest,
     188             :                         const T factor,
     189             :                         const DenseVector<T> & arg) const;
     190             : 
     191             :   /**
     192             :    * Performs the scaled matrix-vector multiplication,
     193             :    * \p dest += \p factor * (*this) * \p arg.
     194             :    * on mixed types
     195             :    */
     196             :   template <typename T2, typename T3>
     197             :   void vector_mult_add (DenseVector<typename CompareTypes<T, typename CompareTypes<T2,T3>::supertype>::supertype> & dest,
     198             :                         const T2 factor,
     199             :                         const DenseVector<T3> & arg) const;
     200             : 
     201             :   /**
     202             :    * Put the \p sub_m x \p sub_n principal submatrix into \p dest.
     203             :    */
     204             :   void get_principal_submatrix (unsigned int sub_m, unsigned int sub_n, DenseMatrix<T> & dest) const;
     205             : 
     206             :   /**
     207             :    * Put the \p sub_m x \p sub_m principal submatrix into \p dest.
     208             :    */
     209             :   void get_principal_submatrix (unsigned int sub_m, DenseMatrix<T> & dest) const;
     210             : 
     211             :   /**
     212             :    * Computes the outer (dyadic) product of two vectors and stores in (*this).
     213             :    *
     214             :    * The outer product of two real-valued vectors \f$\mathbf{a}\f$ and \f$\mathbf{b}\f$ is
     215             :    * \f[
     216             :    *   (\mathbf{a}\mathbf{b}^T)_{i,j} = \mathbf{a}_i \mathbf{b}_j .
     217             :    * \f]
     218             :    * The outer product of two complex-valued vectors \f$\mathbf{a}\f$ and \f$\mathbf{b}\f$ is
     219             :    * \f[
     220             :    *   (\mathbf{a}\mathbf{b}^H)_{i,j} = \mathbf{a}_i \mathbf{b}^*_j ,
     221             :    * \f]
     222             :    * where \f$H\f$ denotes the conjugate transpose of the vector and \f$*\f$
     223             :    * denotes the complex conjugate.
     224             :    *
     225             :    * \param[in] a   Vector whose entries correspond to rows in the product matrix.
     226             :    * \param[in] b   Vector whose entries correspond to columns in the product matrix.
     227             :    */
     228             :   void outer_product(const DenseVector<T> & a, const DenseVector<T> & b);
     229             : 
     230             :   /**
     231             :    * Assignment-from-other-matrix-type operator.
     232             :    *
     233             :    * Copies the dense matrix of type T2 into the present matrix.  This
     234             :    * is useful for copying real matrices into complex ones for further
     235             :    * operations.
     236             :    *
     237             :    * \returns A reference to *this.
     238             :    */
     239             :   template <typename T2>
     240             :   DenseMatrix<T> & operator = (const DenseMatrix<T2> & other_matrix);
     241             : 
     242             :   /**
     243             :    * STL-like swap method
     244             :    */
     245             :   void swap(DenseMatrix<T> & other_matrix);
     246             : 
     247             :   /**
     248             :    * Resizes the matrix to the specified size and calls zero().  Will
     249             :    * never free memory, but may allocate more. Note: when the matrix
     250             :    * is zero()'d, any decomposition (LU, Cholesky, etc.) is also
     251             :    * cleared, forcing a new decomposition to be computed the next time
     252             :    * e.g. lu_solve() is called.
     253             :    */
     254             :   void resize(const unsigned int new_m,
     255             :               const unsigned int new_n);
     256             : 
     257             :   /**
     258             :    * Multiplies every element in the matrix by \p factor.
     259             :    */
     260             :   void scale (const T factor);
     261             : 
     262             :   /**
     263             :    * Multiplies every element in the column \p col matrix by \p factor.
     264             :    */
     265             :   void scale_column (const unsigned int col, const T factor);
     266             : 
     267             :   /**
     268             :    * Multiplies every element in the matrix by \p factor.
     269             :    *
     270             :    * \returns A reference to *this.
     271             :    */
     272             :   DenseMatrix<T> & operator *= (const T factor);
     273             : 
     274             :   /**
     275             :    * Adds \p factor times \p mat to this matrix.
     276             :    *
     277             :    * \returns A reference to *this.
     278             :    */
     279             :   template<typename T2, typename T3>
     280             :   typename std::enable_if<
     281             :     ScalarTraits<T2>::value, void >::type add (const T2 factor,
     282             :                                                const DenseMatrix<T3> & mat);
     283             : 
     284             :   /**
     285             :    * \returns \p true if \p mat is exactly equal to this matrix, \p false otherwise.
     286             :    */
     287             :   bool operator== (const DenseMatrix<T> & mat) const;
     288             : 
     289             :   /**
     290             :    * \returns \p true if \p mat is not exactly equal to this matrix, false otherwise.
     291             :    */
     292             :   bool operator!= (const DenseMatrix<T> & mat) const;
     293             : 
     294             :   /**
     295             :    * Adds \p mat to this matrix.
     296             :    *
     297             :    * \returns A reference to *this.
     298             :    */
     299             :   DenseMatrix<T> & operator+= (const DenseMatrix<T> & mat);
     300             : 
     301             :   /**
     302             :    * Subtracts \p mat from this matrix.
     303             :    *
     304             :    * \returns A reference to *this.
     305             :    */
     306             :   DenseMatrix<T> & operator-= (const DenseMatrix<T> & mat);
     307             : 
     308             :   /**
     309             :    * \returns The minimum entry in the matrix, or the minimum real
     310             :    * part in the case of complex numbers.
     311             :    */
     312             :   auto min () const -> decltype(libmesh_real(T(0)));
     313             : 
     314             :   /**
     315             :    * \returns The maximum entry in the matrix, or the maximum real
     316             :    * part in the case of complex numbers.
     317             :    */
     318             :   auto max () const -> decltype(libmesh_real(T(0)));
     319             : 
     320             :   /**
     321             :    * \returns The l1-norm of the matrix, that is, the max column sum:
     322             :    *
     323             :    * \f$ |M|_1 = max_{all columns j} \sum_{all rows i} |M_ij| \f$,
     324             :    *
     325             :    * This is the natural matrix norm that is compatible to the l1-norm
     326             :    * for vectors, i.e. \f$ |Mv|_1 \leq |M|_1 |v|_1 \f$.
     327             :    */
     328             :   auto l1_norm () const;
     329             : 
     330             :   /**
     331             :    * \returns The linfty-norm of the matrix, that is, the max row sum:
     332             :    *
     333             :    * \f$ |M|_\infty = max_{all rows i} \sum_{all columns j} |M_ij| \f$,
     334             :    *
     335             :    * This is the natural matrix norm that is compatible to the
     336             :    * linfty-norm of vectors, i.e. \f$ |Mv|_\infty \leq |M|_\infty |v|_\infty \f$.
     337             :    */
     338             :   auto linfty_norm () const;
     339             : 
     340             :   /**
     341             :    * Left multiplies by the transpose of the matrix \p A.
     342             :    */
     343             :   void left_multiply_transpose (const DenseMatrix<T> & A);
     344             : 
     345             :   /**
     346             :    * Left multiplies by the transpose of the matrix \p A which
     347             :    * contains a different numerical type.
     348             :    */
     349             :   template <typename T2>
     350             :   void left_multiply_transpose (const DenseMatrix<T2> & A);
     351             : 
     352             : 
     353             :   /**
     354             :    * Right multiplies by the transpose of the matrix \p A
     355             :    */
     356             :   void right_multiply_transpose (const DenseMatrix<T> & A);
     357             : 
     358             :   /**
     359             :    * Right multiplies by the transpose of the matrix \p A which
     360             :    * contains a different numerical type.
     361             :    */
     362             :   template <typename T2>
     363             :   void right_multiply_transpose (const DenseMatrix<T2> & A);
     364             : 
     365             :   /**
     366             :    * \returns The \p (i,j) element of the transposed matrix.
     367             :    */
     368             :   T transpose (const unsigned int i,
     369             :                const unsigned int j) const;
     370             : 
     371             :   /**
     372             :    * Put the tranposed matrix into \p dest.
     373             :    */
     374             :   void get_transpose(DenseMatrix<T> & dest) const;
     375             : 
     376             :   /**
     377             :    * \returns A reference to the underlying data storage vector.
     378             :    *
     379             :    * This should be used with caution (i.e. one should not change the
     380             :    * size of the vector, etc.) but is useful for interoperating with
     381             :    * low level BLAS routines which expect a simple array.
     382             :    */
     383     2326073 :   std::vector<T> & get_values() { return _val; }
     384             : 
     385             :   /**
     386             :    * \returns A constant reference to the underlying data storage vector.
     387             :    */
     388     3300132 :   const std::vector<T> & get_values() const { return _val; }
     389             : 
     390             :   /**
     391             :    * Condense-out the \p (i,j) entry of the matrix, forcing
     392             :    * it to take on the value \p val.  This is useful in numerical
     393             :    * simulations for applying boundary conditions.  Preserves the
     394             :    * symmetry of the matrix.
     395             :    */
     396           0 :   void condense(const unsigned int i,
     397             :                 const unsigned int j,
     398             :                 const T val,
     399             :                 DenseVector<T> & rhs)
     400           0 :   { DenseMatrixBase<T>::condense (i, j, val, rhs); }
     401             : 
     402             :   /**
     403             :    * Solve the system Ax=b given the input vector b.  Partial pivoting
     404             :    * is performed by default in order to keep the algorithm stable to
     405             :    * the effects of round-off error.
     406             :    *
     407             :    * Important note: once you call lu_solve(), you must _not_ modify
     408             :    * the entries of the matrix via calls to operator(i,j) and call
     409             :    * lu_solve() again without first calling either zero() or resize(),
     410             :    * otherwise the code will skip computing the decomposition of the
     411             :    * matrix and go directly to the back substitution step. This is
     412             :    * done on purpose for efficiency, so that the same LU decomposition
     413             :    * can be used with multiple right-hand sides, but it does also make
     414             :    * it possible to "shoot yourself in the foot", so be careful!
     415             :    */
     416             :   void lu_solve (const DenseVector<T> & b,
     417             :                  DenseVector<T> & x);
     418             : 
     419             :   /**
     420             :    * For symmetric positive definite (SPD) matrices. A Cholesky factorization
     421             :    * of A such that A = L L^T is about twice as fast as a standard LU
     422             :    * factorization.  Therefore you can use this method if you know a-priori
     423             :    * that the matrix is SPD.  If the matrix is not SPD, an error is generated.
     424             :    * One nice property of Cholesky decompositions is that they do not require
     425             :    * pivoting for stability.
     426             :    *
     427             :    * Important note: once you call cholesky_solve(), you must _not_
     428             :    * modify the entries of the matrix via calls to operator(i,j) and
     429             :    * call cholesky_solve() again without first calling either zero()
     430             :    * or resize(), otherwise the code will skip computing the
     431             :    * decomposition of the matrix and go directly to the back
     432             :    * substitution step. This is done on purpose for efficiency, so
     433             :    * that the same decomposition can be used with multiple right-hand
     434             :    * sides, but it does also make it possible to "shoot yourself in
     435             :    * the foot", so be careful!
     436             :    *
     437             :    * \note This method may also be used when A is real-valued and x
     438             :    * and b are complex-valued.
     439             :    */
     440             :   template <typename T2>
     441             :   void cholesky_solve(const DenseVector<T2> & b,
     442             :                       DenseVector<T2> & x);
     443             : 
     444             :   /**
     445             :    * Compute the singular value decomposition of the matrix.
     446             :    * On exit, sigma holds all of the singular values (in
     447             :    * descending order).
     448             :    *
     449             :    * The implementation uses PETSc's interface to BLAS/LAPACK.
     450             :    * If this is not available, this function throws an error.
     451             :    */
     452             :   void svd(DenseVector<Real> & sigma);
     453             : 
     454             :   /**
     455             :    * Compute the "reduced" singular value decomposition of the matrix.
     456             :    * On exit, sigma holds all of the singular values (in
     457             :    * descending order), U holds the left singular vectors,
     458             :    * and VT holds the transpose of the right singular vectors.
     459             :    * In the reduced SVD, U has min(m,n) columns and VT has
     460             :    * min(m,n) rows. (In the "full" SVD, U and VT would be square.)
     461             :    *
     462             :    * The implementation uses PETSc's interface to BLAS/LAPACK.
     463             :    * If this is not available, this function throws an error.
     464             :    */
     465             :   void svd(DenseVector<Real> & sigma,
     466             :            DenseMatrix<Number> & U,
     467             :            DenseMatrix<Number> & VT);
     468             : 
     469             :   /**
     470             :    * Solve the system of equations \f$ A x = rhs \f$ for \f$ x \f$ in the
     471             :    * least-squares sense. \f$ A \f$ may be non-square and/or rank-deficient.
     472             :    * You can control which singular values are treated as zero by
     473             :    * changing the "rcond" parameter.  Singular values S(i) for which
     474             :    * S(i) <= rcond*S(1) are treated as zero for purposes of the solve.
     475             :    * Passing a negative number for rcond forces a "machine precision"
     476             :    * value to be used instead.
     477             :    *
     478             :    * This function is marked const, since due to various
     479             :    * implementation details, we do not need to modify the contents of
     480             :    * A in order to compute the SVD (a copy is made internally
     481             :    * instead).
     482             :    *
     483             :    * Requires PETSc >= 3.1 since this was the first version to provide
     484             :    * the LAPACKgelss_ wrapper.
     485             :    */
     486             :   void svd_solve(const DenseVector<T> & rhs,
     487             :                  DenseVector<T> & x,
     488             :                  Real rcond=std::numeric_limits<Real>::epsilon()) const;
     489             : 
     490             :   /**
     491             :    * Compute the eigenvalues (both real and imaginary parts) of a general matrix.
     492             :    *
     493             :    * Warning: the contents of \p *this are overwritten by this function!
     494             :    *
     495             :    * The implementation requires the LAPACKgeev_ function which is wrapped by PETSc.
     496             :    */
     497             :   void evd(DenseVector<T> & lambda_real,
     498             :            DenseVector<T> & lambda_imag);
     499             : 
     500             :   /**
     501             :    * Compute the eigenvalues (both real and imaginary parts) and left
     502             :    * eigenvectors of a general matrix, \f$ A \f$.
     503             :    *
     504             :    * Warning: the contents of \p *this are overwritten by this function!
     505             :    *
     506             :    * The left eigenvector \f$ u_j \f$ of \f$ A \f$ satisfies:
     507             :    * \f$ u_j^H A = lambda_j u_j^H \f$
     508             :    * where \f$ u_j^H \f$ denotes the conjugate-transpose of \f$ u_j \f$.
     509             :    *
     510             :    * If the j-th and (j+1)-st eigenvalues form a complex conjugate
     511             :    * pair, then the j-th and (j+1)-st columns of VL "share" their
     512             :    * real-valued storage in the following way:
     513             :    * u_j     = VL(:,j) + i*VL(:,j+1) and
     514             :    * u_{j+1} = VL(:,j) - i*VL(:,j+1).
     515             :    *
     516             :    * The implementation requires the LAPACKgeev_ routine which is provided by PETSc.
     517             :    */
     518             :   void evd_left(DenseVector<T> & lambda_real,
     519             :                 DenseVector<T> & lambda_imag,
     520             :                 DenseMatrix<T> & VL);
     521             : 
     522             :   /**
     523             :    * Compute the eigenvalues (both real and imaginary parts) and right
     524             :    * eigenvectors of a general matrix, \f$ A \f$.
     525             :    *
     526             :    * Warning: the contents of \p *this are overwritten by this function!
     527             :    *
     528             :    * The right eigenvector \f$ v_j \f$ of \f$ A \f$ satisfies:
     529             :    * \f$ A v_j = lambda_j v_j \f$
     530             :    * where \f$ lambda_j \f$ is its corresponding eigenvalue.
     531             :    *
     532             :    * \note If the j-th and (j+1)-st eigenvalues form a complex
     533             :    * conjugate pair, then the j-th and (j+1)-st columns of VR "share"
     534             :    * their real-valued storage in the following way:
     535             :    * v_j     = VR(:,j) + i*VR(:,j+1) and
     536             :    * v_{j+1} = VR(:,j) - i*VR(:,j+1).
     537             :    *
     538             :    * The implementation requires the LAPACKgeev_ routine which is provided by PETSc.
     539             :    */
     540             :   void evd_right(DenseVector<T> & lambda_real,
     541             :                  DenseVector<T> & lambda_imag,
     542             :                  DenseMatrix<T> & VR);
     543             : 
     544             :   /**
     545             :    * Compute the eigenvalues (both real and imaginary parts) as well as the left
     546             :    * and right eigenvectors of a general matrix.
     547             :    *
     548             :    * Warning: the contents of \p *this are overwritten by this function!
     549             :    *
     550             :    * See the documentation of the \p evd_left() and \p evd_right()
     551             :    * functions for more information.  The implementation requires the
     552             :    * LAPACKgeev_ routine which is provided by PETSc.
     553             :    */
     554             :   void evd_left_and_right(DenseVector<T> & lambda_real,
     555             :                           DenseVector<T> & lambda_imag,
     556             :                           DenseMatrix<T> & VL,
     557             :                           DenseMatrix<T> & VR);
     558             : 
     559             :   /**
     560             :    * \returns The determinant of the matrix.
     561             :    *
     562             :    * \note Implemented by computing an LU decomposition and then
     563             :    * taking the product of the diagonal terms.  Therefore this is a
     564             :    * non-const method which modifies the entries of the matrix.
     565             :    */
     566             :   T det();
     567             : 
     568             :   /**
     569             :    * Returns true iff every entry is finite.
     570             :    */
     571             :   friend bool isfinite (const DenseMatrix<T> & var)
     572             :   {
     573             :     using std::isfinite;
     574             :     using libMesh::isfinite; // for T==complex
     575             :     for (const T & v : var._val)
     576             :       if (!isfinite(v))
     577             :         return false;
     578             :     return true;
     579             :   }
     580             : 
     581             :   /**
     582             :    * Returns true iff no entry is NaN and any entry is infinite.
     583             :    *
     584             :    * This is arguably inconsistent with our std::complex overload (and
     585             :    * the C99 Annex G recommendations for _Complex, and C++
     586             :    * std::complex arithmetic), which treats mixed (inf,NaN) pairs as
     587             :    * infinite, but this is probably safer for users.
     588             :    */
     589             :   friend bool isinf (const DenseMatrix<T> & var)
     590             :   {
     591             :     using std::isinf;
     592             :     using libMesh::isinf; // for T==complex
     593             :     using std::isnan;
     594             :     using libMesh::isnan;
     595             :     bool has_inf = false;
     596             :     for (const T & v : var._val)
     597             :       {
     598             :         // NaN anywhere makes us NaN, not inf
     599             :         if (isnan(v))
     600             :           return false;
     601             :         has_inf = has_inf || isinf(v);
     602             :       }
     603             :     return has_inf;
     604             :   }
     605             : 
     606             :   /**
     607             :    * Returns true iff any entry is NaN.
     608             :    *
     609             :    * This is arguably inconsistent with our std::complex overload (and
     610             :    * the C99 Annex G recommendations for _Complex, and C++
     611             :    * std::complex arithmetic), which treats mixed (inf,NaN) pairs as
     612             :    * infinite, but this is probably safer for users.
     613             :    */
     614             :   friend bool isnan (const DenseMatrix<T> & var)
     615             :   {
     616             :     using std::isnan;
     617             :     using libMesh::isnan; // for T==complex
     618             :     for (const T & v : var._val)
     619             :       if (isnan(v))
     620             :         return true;
     621             :     return false;
     622             :   }
     623             : 
     624             :   /**
     625             :    * Computes the inverse of the dense matrix (assuming it is invertible)
     626             :    * by first computing the LU decomposition and then performing multiple
     627             :    * back substitution steps.  Follows the algorithm from Numerical Recipes
     628             :    * in C that is available on the web.
     629             :    *
     630             :    * This routine is commented out since it is not really a memory- or
     631             :    * computationally- efficient implementation.  Also, you typically
     632             :    * don't need the actual inverse for anything, and can use something
     633             :    * like lu_solve() instead.
     634             :    */
     635             :   // void inverse();
     636             : 
     637             :   /**
     638             :    * Run-time selectable option to turn on/off BLAS support.
     639             :    * This was primarily used for testing purposes, and could be
     640             :    * removed...
     641             :    */
     642             :   bool use_blas_lapack;
     643             : 
     644             :   /**
     645             :    * Helper structure for determining whether to use blas_lapack
     646             :    */
     647             :   struct UseBlasLapack
     648             :   {
     649             :     static const bool value = false;
     650             :   };
     651             : 
     652             : private:
     653             : 
     654             :   /**
     655             :    * The actual data values, stored as a 1D array.
     656             :    */
     657             :   std::vector<T> _val;
     658             : 
     659             :   /**
     660             :    * Form the LU decomposition of the matrix.  This function
     661             :    * is private since it is only called as part of the implementation
     662             :    * of the lu_solve(...) function.
     663             :    */
     664             :   void _lu_decompose ();
     665             : 
     666             :   /**
     667             :    * Solves the system Ax=b through back substitution.  This function
     668             :    * is private since it is only called as part of the implementation
     669             :    * of the lu_solve(...) function.
     670             :    */
     671             :   void _lu_back_substitute (const DenseVector<T> & b,
     672             :                             DenseVector<T> & x) const;
     673             : 
     674             :   /**
     675             :    * Decomposes a symmetric positive definite matrix into a
     676             :    * product of two lower triangular matrices according to
     677             :    * A = LL^T.
     678             :    *
     679             :    * \note This program generates an error if the matrix is not SPD.
     680             :    */
     681             :   void _cholesky_decompose();
     682             : 
     683             :   /**
     684             :    * Solves the equation Ax=b for the unknown value x and rhs
     685             :    * b based on the Cholesky factorization of A.
     686             :    *
     687             :    * \note This method may be used when A is real-valued and b and x
     688             :    * are complex-valued.
     689             :    */
     690             :   template <typename T2>
     691             :   void _cholesky_back_substitute(const DenseVector<T2> & b,
     692             :                                  DenseVector<T2> & x) const;
     693             : 
     694             :   /**
     695             :    * The decomposition schemes above change the entries of the matrix
     696             :    * A.  It is therefore an error to call A.lu_solve() and subsequently
     697             :    * call A.cholesky_solve() since the result will probably not match
     698             :    * any desired outcome.  This typedef keeps track of which decomposition
     699             :    * has been called for this matrix.
     700             :    */
     701             :   enum DecompositionType {LU=0, CHOLESKY=1, LU_BLAS_LAPACK, NONE};
     702             : 
     703             :   /**
     704             :    * This flag keeps track of which type of decomposition has been
     705             :    * performed on the matrix.
     706             :    */
     707             :   DecompositionType _decomposition_type;
     708             : 
     709             :   /**
     710             :    * Enumeration used to determine the behavior of the _multiply_blas
     711             :    * function.
     712             :    */
     713             :   enum _BLAS_Multiply_Flag {
     714             :     LEFT_MULTIPLY = 0,
     715             :     RIGHT_MULTIPLY,
     716             :     LEFT_MULTIPLY_TRANSPOSE,
     717             :     RIGHT_MULTIPLY_TRANSPOSE
     718             :   };
     719             : 
     720             :   /**
     721             :    * The _multiply_blas function computes A <- op(A) * op(B) using
     722             :    * BLAS gemm function.  Used in the right_multiply(),
     723             :    * left_multiply(), right_multiply_transpose(), and
     724             :    * left_multiply_transpose() routines.
     725             :    * [ Implementation in dense_matrix_blas_lapack.C ]
     726             :    */
     727             :   void _multiply_blas(const DenseMatrixBase<T> & other,
     728             :                       _BLAS_Multiply_Flag flag);
     729             : 
     730             :   /**
     731             :    * Computes an LU factorization of the matrix using the
     732             :    * Lapack routine "getrf".  This routine should only be
     733             :    * used by the "use_blas_lapack" branch of the lu_solve()
     734             :    * function.  After the call to this function, the matrix
     735             :    * is replaced by its factorized version, and the
     736             :    * DecompositionType is set to LU_BLAS_LAPACK.
     737             :    * [ Implementation in dense_matrix_blas_lapack.C ]
     738             :    */
     739             :   void _lu_decompose_lapack();
     740             : 
     741             :   /**
     742             :    * Computes an SVD of the matrix using the
     743             :    * Lapack routine "getsvd".
     744             :    * [ Implementation in dense_matrix_blas_lapack.C ]
     745             :    */
     746             :   void _svd_lapack(DenseVector<Real> & sigma);
     747             : 
     748             :   /**
     749             :    * Computes a "reduced" SVD of the matrix using the
     750             :    * Lapack routine "getsvd".
     751             :    * [ Implementation in dense_matrix_blas_lapack.C ]
     752             :    */
     753             :   void _svd_lapack(DenseVector<Real> & sigma,
     754             :                    DenseMatrix<Number> & U,
     755             :                    DenseMatrix<Number> & VT);
     756             : 
     757             :   /**
     758             :    * Called by svd_solve(rhs).
     759             :    */
     760             :   void _svd_solve_lapack(const DenseVector<T> & rhs,
     761             :                          DenseVector<T> & x,
     762             :                          Real rcond) const;
     763             : 
     764             :   /**
     765             :    * Helper function that actually performs the SVD.
     766             :    * [ Implementation in dense_matrix_blas_lapack.C ]
     767             :    */
     768             :   void _svd_helper (char JOBU,
     769             :                     char JOBVT,
     770             :                     std::vector<Real> & sigma_val,
     771             :                     std::vector<Number> & U_val,
     772             :                     std::vector<Number> & VT_val);
     773             : 
     774             :   /**
     775             :    * Computes the eigenvalues of the matrix using the Lapack routine
     776             :    * "DGEEV".  If VR and/or VL are not nullptr, then the matrix of right
     777             :    * and/or left eigenvectors is also computed and returned by this
     778             :    * function.
     779             :    *
     780             :    * [ Implementation in dense_matrix_blas_lapack.C ]
     781             :    */
     782             :   void _evd_lapack(DenseVector<T> & lambda_real,
     783             :                    DenseVector<T> & lambda_imag,
     784             :                    DenseMatrix<T> * VL = nullptr,
     785             :                    DenseMatrix<T> * VR = nullptr);
     786             : 
     787             :   /**
     788             :    * Array used to store pivot indices.  May be used by whatever
     789             :    * factorization is currently active, clients of the class should
     790             :    * not rely on it for any reason.
     791             :    */
     792             : #if (LIBMESH_HAVE_PETSC && LIBMESH_USE_REAL_NUMBERS)
     793             :   typedef PetscBLASInt pivot_index_t;
     794             : #else
     795             :   typedef int pivot_index_t;
     796             : #endif
     797             :   std::vector<pivot_index_t> _pivots;
     798             : 
     799             :   /**
     800             :    * Companion function to _lu_decompose_lapack().  Do not use
     801             :    * directly, called through the public lu_solve() interface.
     802             :    * This function is logically const in that it does not modify
     803             :    * the matrix, but since we are just calling LAPACK routines,
     804             :    * it's less const_cast hassle to just declare the function
     805             :    * non-const.
     806             :    * [ Implementation in dense_matrix_blas_lapack.C ]
     807             :    */
     808             :   void _lu_back_substitute_lapack (const DenseVector<T> & b,
     809             :                                    DenseVector<T> & x);
     810             : 
     811             :   /**
     812             :    * Uses the BLAS GEMV function (through PETSc) to compute
     813             :    *
     814             :    * dest := alpha*A*arg + beta*dest
     815             :    *
     816             :    * where alpha and beta are scalars, A is this matrix, and
     817             :    * arg and dest are input vectors of appropriate size.  If
     818             :    * trans is true, the transpose matvec is computed instead.
     819             :    * By default, trans==false.
     820             :    *
     821             :    * [ Implementation in dense_matrix_blas_lapack.C ]
     822             :    */
     823             :   void _matvec_blas(T alpha, T beta,
     824             :                     DenseVector<T> & dest,
     825             :                     const DenseVector<T> & arg,
     826             :                     bool trans=false) const;
     827             : 
     828             :   /**
     829             :    * Left multiplies by the transpose of the matrix \p A which
     830             :    * may contain a different numerical type.
     831             :    */
     832             :   template <typename T2>
     833             :   void _left_multiply_transpose (const DenseMatrix<T2> & A);
     834             : 
     835             :   /**
     836             :    * Right multiplies by the transpose of the matrix \p A which
     837             :    * may contain a different numerical type.
     838             :    */
     839             :   template <typename T2>
     840             :   void _right_multiply_transpose (const DenseMatrix<T2> & A);
     841             : };
     842             : 
     843             : 
     844             : 
     845             : 
     846             : 
     847             : // ------------------------------------------------------------
     848             : /**
     849             :  * Provide Typedefs for dense matrices
     850             :  */
     851             : namespace DenseMatrices
     852             : {
     853             : 
     854             : /**
     855             :  * Convenient definition of a real-only
     856             :  * dense matrix.
     857             :  */
     858             : typedef DenseMatrix<Real> RealDenseMatrix;
     859             : 
     860             : /**
     861             :  * This typedef may be either a real-only matrix, or a truly complex
     862             :  * matrix, depending on how \p Number was defined in \p
     863             :  * libmesh_common.h.  Also, be aware of the fact that \p
     864             :  * DenseMatrix<T> is likely to be more efficient for real than for
     865             :  * complex data.
     866             :  */
     867             : typedef DenseMatrix<Complex> ComplexDenseMatrix;
     868             : 
     869             : }
     870             : 
     871             : 
     872             : 
     873             : using namespace DenseMatrices;
     874             : 
     875             : // The PETSc Lapack wrappers are only for PetscScalar, therefore we
     876             : // can't e.g. get a Lapack version of DenseMatrix<Real>::lu_solve()
     877             : // when libmesh/PETSc are compiled with complex numbers.
     878             : #if defined(LIBMESH_HAVE_PETSC) && \
     879             :   defined(LIBMESH_USE_REAL_NUMBERS) && \
     880             :   defined(LIBMESH_DEFAULT_DOUBLE_PRECISION)
     881             : template <>
     882             : struct DenseMatrix<double>::UseBlasLapack
     883             : {
     884             :   static const bool value = true;
     885             : };
     886             : #endif
     887             : 
     888             : 
     889             : // ------------------------------------------------------------
     890             : // Dense Matrix member functions
     891             : template<typename T>
     892             : inline
     893   108454285 : DenseMatrix<T>::DenseMatrix(const unsigned int new_m,
     894             :                             const unsigned int new_n) :
     895             :   DenseMatrixBase<T>(new_m,new_n),
     896    92818226 :   use_blas_lapack(DenseMatrix<T>::UseBlasLapack::value),
     897             :   _val(),
     898   119191868 :   _decomposition_type(NONE)
     899             : {
     900    97716702 :   this->resize(new_m,new_n);
     901   108454285 : }
     902             : 
     903             : template <typename T>
     904             : template <typename T2>
     905             : DenseMatrix<T>::DenseMatrix(unsigned int nrow,
     906             :                             unsigned int ncol,
     907             :                             std::initializer_list<T2> init_list) :
     908             :   DenseMatrixBase<T>(nrow, ncol),
     909             :   use_blas_lapack(DenseMatrix<T>::UseBlasLapack::value),
     910             :   _val(init_list.begin(), init_list.end()),
     911             :   _decomposition_type(NONE)
     912             : {
     913             :   // Make sure the user passed us an amount of data which is
     914             :   // consistent with the size of the matrix.
     915             :   libmesh_assert_equal_to(nrow * ncol, init_list.size());
     916             : }
     917             : 
     918             : 
     919             : 
     920             : template<typename T>
     921             : inline
     922     5991596 : void DenseMatrix<T>::swap(DenseMatrix<T> & other_matrix)
     923             : {
     924             :   using std::swap;
     925      594836 :   swap(this->_m, other_matrix._m);
     926      594836 :   swap(this->_n, other_matrix._n);
     927      594836 :   _val.swap(other_matrix._val);
     928     6586432 :   DecompositionType _temp = _decomposition_type;
     929     6586432 :   _decomposition_type = other_matrix._decomposition_type;
     930     6586432 :   other_matrix._decomposition_type = _temp;
     931     5991596 : }
     932             : 
     933             : 
     934             : template <typename T>
     935             : template <typename T2>
     936             : inline
     937             : DenseMatrix<T> &
     938             : DenseMatrix<T>::operator=(const DenseMatrix<T2> & mat)
     939             : {
     940             :   unsigned int mat_m = mat.m(), mat_n = mat.n();
     941             :   this->resize(mat_m, mat_n);
     942             :   for (unsigned int i=0; i<mat_m; i++)
     943             :     for (unsigned int j=0; j<mat_n; j++)
     944             :       (*this)(i,j) = mat(i,j);
     945             : 
     946             :   return *this;
     947             : }
     948             : 
     949             : 
     950             : 
     951             : template<typename T>
     952             : inline
     953   138896310 : void DenseMatrix<T>::resize(const unsigned int new_m,
     954             :                             const unsigned int new_n)
     955             : {
     956   153650441 :   _val.resize(new_m*new_n);
     957             : 
     958   153650441 :   this->_m = new_m;
     959   153650441 :   this->_n = new_n;
     960             : 
     961             :   // zero and set decomposition_type to NONE
     962     8458623 :   this->zero();
     963   138896310 : }
     964             : 
     965             : 
     966             : 
     967             : template<typename T>
     968             : inline
     969     8672739 : void DenseMatrix<T>::zero()
     970             : {
     971   154332520 :   _decomposition_type = NONE;
     972             : 
     973     8672739 :   std::fill (_val.begin(), _val.end(), static_cast<T>(0));
     974     8672739 : }
     975             : 
     976             : 
     977             : 
     978             : template<typename T>
     979             : inline
     980           0 : DenseMatrix<T> DenseMatrix<T>::sub_matrix(unsigned int row_id, unsigned int row_size,
     981             :                                           unsigned int col_id, unsigned int col_size) const
     982             : {
     983           0 :   libmesh_assert_less (row_id + row_size - 1, this->_m);
     984           0 :   libmesh_assert_less (col_id + col_size - 1, this->_n);
     985             : 
     986           0 :   DenseMatrix<T> sub;
     987           0 :   sub._m = row_size;
     988           0 :   sub._n = col_size;
     989           0 :   sub._val.resize(row_size * col_size);
     990             : 
     991           0 :   unsigned int end_col = this->_n - col_size - col_id;
     992           0 :   unsigned int p = row_id * this->_n;
     993           0 :   unsigned int q = 0;
     994           0 :   for (unsigned int i=0; i<row_size; i++)
     995             :   {
     996             :     // skip the beginning columns
     997           0 :     p += col_id;
     998           0 :     for (unsigned int j=0; j<col_size; j++)
     999           0 :       sub._val[q++] = _val[p++];
    1000             :     // skip the rest columns
    1001           0 :     p += end_col;
    1002             :   }
    1003             : 
    1004           0 :   return sub;
    1005           0 : }
    1006             : 
    1007             : 
    1008             : 
    1009             : template<typename T>
    1010             : inline
    1011     7902664 : T DenseMatrix<T>::operator () (const unsigned int i,
    1012             :                                const unsigned int j) const
    1013             : {
    1014     7902664 :   libmesh_assert_less (i*j, _val.size());
    1015     7902664 :   libmesh_assert_less (i, this->_m);
    1016     7902664 :   libmesh_assert_less (j, this->_n);
    1017             : 
    1018             : 
    1019             :   //  return _val[(i) + (this->_m)*(j)]; // col-major
    1020   884595700 :   return _val[(i)*(this->_n) + (j)]; // row-major
    1021             : }
    1022             : 
    1023             : 
    1024             : 
    1025             : template<typename T>
    1026             : inline
    1027           0 : T & DenseMatrix<T>::operator () (const unsigned int i,
    1028             :                                  const unsigned int j)
    1029             : {
    1030           0 :   libmesh_assert_less (i*j, _val.size());
    1031           0 :   libmesh_assert_less (i, this->_m);
    1032           0 :   libmesh_assert_less (j, this->_n);
    1033             : 
    1034             :   //return _val[(i) + (this->_m)*(j)]; // col-major
    1035  8563029181 :   return _val[(i)*(this->_n) + (j)]; // row-major
    1036             : }
    1037             : 
    1038             : 
    1039             : 
    1040             : 
    1041             : 
    1042             : template<typename T>
    1043             : inline
    1044      122111 : void DenseMatrix<T>::scale (const T factor)
    1045             : {
    1046  2005351276 :   for (auto & v : _val)
    1047  1904676072 :     v *= factor;
    1048      122111 : }
    1049             : 
    1050             : 
    1051             : template<typename T>
    1052             : inline
    1053           0 : void DenseMatrix<T>::scale_column (const unsigned int col, const T factor)
    1054             : {
    1055           0 :   for (auto i : make_range(this->m()))
    1056           0 :     (*this)(i, col) *= factor;
    1057           0 : }
    1058             : 
    1059             : 
    1060             : 
    1061             : template<typename T>
    1062             : inline
    1063      128111 : DenseMatrix<T> & DenseMatrix<T>::operator *= (const T factor)
    1064             : {
    1065      128111 :   this->scale(factor);
    1066      128111 :   return *this;
    1067             : }
    1068             : 
    1069             : 
    1070             : 
    1071             : template<typename T>
    1072             : template<typename T2, typename T3>
    1073             : inline
    1074             : typename std::enable_if<
    1075             :   ScalarTraits<T2>::value, void >::type
    1076     1353372 : DenseMatrix<T>::add (const T2 factor,
    1077             :                      const DenseMatrix<T3> & mat)
    1078             : {
    1079      114036 :   libmesh_assert_equal_to (this->m(), mat.m());
    1080      114036 :   libmesh_assert_equal_to (this->n(), mat.n());
    1081             : 
    1082    11507940 :   for (auto i : make_range(this->m()))
    1083   117040026 :     for (auto j : make_range(this->n()))
    1084   109118208 :       (*this)(i,j) += factor * mat(i,j);
    1085     1353372 : }
    1086             : 
    1087             : 
    1088             : 
    1089             : template<typename T>
    1090             : inline
    1091      547008 : bool DenseMatrix<T>::operator == (const DenseMatrix<T> & mat) const
    1092             : {
    1093    91652784 :   for (auto i : index_range(_val))
    1094    91105776 :     if (_val[i] != mat._val[i])
    1095           0 :       return false;
    1096             : 
    1097      547008 :   return true;
    1098             : }
    1099             : 
    1100             : 
    1101             : 
    1102             : template<typename T>
    1103             : inline
    1104           0 : bool DenseMatrix<T>::operator != (const DenseMatrix<T> & mat) const
    1105             : {
    1106           0 :   for (auto i : index_range(_val))
    1107           0 :     if (_val[i] != mat._val[i])
    1108           0 :       return true;
    1109             : 
    1110           0 :   return false;
    1111             : }
    1112             : 
    1113             : 
    1114             : 
    1115             : template<typename T>
    1116             : inline
    1117     6263411 : DenseMatrix<T> & DenseMatrix<T>::operator += (const DenseMatrix<T> & mat)
    1118             : {
    1119  1899817523 :   for (auto i : index_range(_val))
    1120  2119545086 :     _val[i] += mat._val[i];
    1121             : 
    1122     6263411 :   return *this;
    1123             : }
    1124             : 
    1125             : 
    1126             : 
    1127             : template<typename T>
    1128             : inline
    1129           0 : DenseMatrix<T> & DenseMatrix<T>::operator -= (const DenseMatrix<T> & mat)
    1130             : {
    1131           0 :   for (auto i : index_range(_val))
    1132           0 :     _val[i] -= mat._val[i];
    1133             : 
    1134           0 :   return *this;
    1135             : }
    1136             : 
    1137             : 
    1138             : 
    1139             : template<typename T>
    1140             : inline
    1141           0 : auto DenseMatrix<T>::min () const -> decltype(libmesh_real(T(0)))
    1142             : {
    1143           0 :   libmesh_assert (this->_m);
    1144           0 :   libmesh_assert (this->_n);
    1145             :   typedef decltype(libmesh_real(T(0))) realfromT;
    1146             :   return libmesh_transform_reduce
    1147           0 :     (_val.begin(), _val.end(), std::numeric_limits<realfromT>::max(),
    1148           0 :      [](const auto & a, const auto & b){using std::min; return min(a,b);},
    1149           0 :      [](const T & v){return libmesh_real(v);});
    1150             : }
    1151             : 
    1152             : 
    1153             : 
    1154             : template<typename T>
    1155             : inline
    1156           0 : auto DenseMatrix<T>::max () const -> decltype(libmesh_real(T(0)))
    1157             : {
    1158           0 :   libmesh_assert (this->_m);
    1159           0 :   libmesh_assert (this->_n);
    1160             :   typedef decltype(libmesh_real(T(0))) realfromT;
    1161             :   return libmesh_transform_reduce
    1162           0 :     (_val.begin(), _val.end(), std::numeric_limits<realfromT>::lowest(),
    1163           0 :      [](const auto & a, const auto & b){using std::max; return max(a,b);},
    1164           0 :      [](const T & v){return libmesh_real(v);});
    1165             : }
    1166             : 
    1167             : 
    1168             : 
    1169             : template<typename T>
    1170             : inline
    1171       27228 : auto DenseMatrix<T>::l1_norm () const
    1172             : {
    1173       27228 :   libmesh_assert (this->_m);
    1174       27228 :   libmesh_assert (this->_n);
    1175             : 
    1176             :   using std::abs;
    1177       27228 :   auto columnsum = abs(T(0));
    1178      300732 :   for (unsigned int i=0; i!=this->_m; i++)
    1179             :     {
    1180      273504 :       columnsum += abs((*this)(i,0));
    1181             :     }
    1182       27228 :   auto my_max = columnsum;
    1183      273504 :   for (unsigned int j=1; j!=this->_n; j++)
    1184             :     {
    1185      246276 :       columnsum = 0.;
    1186     3149772 :       for (unsigned int i=0; i!=this->_m; i++)
    1187             :         {
    1188     2903496 :           columnsum += abs((*this)(i,j));
    1189             :         }
    1190      246276 :       my_max = (my_max > columnsum? my_max : columnsum);
    1191             :     }
    1192       27228 :   return my_max;
    1193             : }
    1194             : 
    1195             : 
    1196             : 
    1197             : template<typename T>
    1198             : inline
    1199           0 : auto DenseMatrix<T>::linfty_norm () const
    1200             : {
    1201           0 :   libmesh_assert (this->_m);
    1202           0 :   libmesh_assert (this->_n);
    1203             :   using std::abs;
    1204             : 
    1205           0 :   auto rowsum = abs(T(0));
    1206           0 :   for (unsigned int j=0; j!=this->_n; j++)
    1207             :     {
    1208           0 :       rowsum += abs((*this)(0,j));
    1209             :     }
    1210           0 :   auto my_max = rowsum;
    1211           0 :   for (unsigned int i=1; i!=this->_m; i++)
    1212             :     {
    1213           0 :       rowsum = 0.;
    1214           0 :       for (unsigned int j=0; j!=this->_n; j++)
    1215             :         {
    1216           0 :           rowsum += abs((*this)(i,j));
    1217             :         }
    1218           0 :       my_max = (my_max > rowsum? my_max : rowsum);
    1219             :     }
    1220           0 :   return my_max;
    1221             : }
    1222             : 
    1223             : 
    1224             : 
    1225             : template<typename T>
    1226             : inline
    1227           0 : T DenseMatrix<T>::transpose (const unsigned int i,
    1228             :                              const unsigned int j) const
    1229             : {
    1230             :   // Implement in terms of operator()
    1231           0 :   return (*this)(j,i);
    1232             : }
    1233             : 
    1234             : 
    1235             : 
    1236             : 
    1237             : 
    1238             : // template<typename T>
    1239             : // inline
    1240             : // void DenseMatrix<T>::condense(const unsigned int iv,
    1241             : //       const unsigned int jv,
    1242             : //       const T val,
    1243             : //       DenseVector<T> & rhs)
    1244             : // {
    1245             : //   libmesh_assert_equal_to (this->_m, rhs.size());
    1246             : //   libmesh_assert_equal_to (iv, jv);
    1247             : 
    1248             : 
    1249             : //   // move the known value into the RHS
    1250             : //   // and zero the column
    1251             : //   for (auto i : make_range(this->m()))
    1252             : //     {
    1253             : //       rhs(i) -= ((*this)(i,jv))*val;
    1254             : //       (*this)(i,jv) = 0.;
    1255             : //     }
    1256             : 
    1257             : //   // zero the row
    1258             : //   for (auto j : make_range(this->n()))
    1259             : //     (*this)(iv,j) = 0.;
    1260             : 
    1261             : //   (*this)(iv,jv) = 1.;
    1262             : //   rhs(iv) = val;
    1263             : 
    1264             : // }
    1265             : 
    1266             : 
    1267             : } // namespace libMesh
    1268             : 
    1269             : #ifdef LIBMESH_HAVE_METAPHYSICL
    1270             : namespace MetaPhysicL
    1271             : {
    1272             : template <typename T>
    1273             : struct RawType<libMesh::DenseMatrix<T>>
    1274             : {
    1275             :   typedef libMesh::DenseMatrix<typename RawType<T>::value_type> value_type;
    1276             : 
    1277             :   static value_type value (const libMesh::DenseMatrix<T> & in)
    1278             :     {
    1279             :       const auto m = in.m(), n = in.n();
    1280             :       value_type ret(m, n);
    1281             :       for (unsigned int i = 0; i < m; ++i)
    1282             :         for (unsigned int j = 0; j < n; ++j)
    1283             :           ret(i,j) = raw_value(in(i,j));
    1284             : 
    1285             :       return ret;
    1286             :     }
    1287             : };
    1288             : }
    1289             : #endif
    1290             : 
    1291             : 
    1292             : #endif // LIBMESH_DENSE_MATRIX_H

Generated by: LCOV version 1.14