SpECTRE Documentation Coverage Report
Current view: top level - NumericalAlgorithms/LinearAlgebra - FindRealEigensystem.hpp Coverage Total Hit
Commit: a37d7b3c1803b88b537d2aef1c27ca5e6b499398 Lines: 100.0 % 2 2
Test Date: 2026-11-12 04:47:19
Legend: Lines:     hit not hit

            Line data    Source code
       1            1 : // Distributed under the MIT License.
       2              : // See LICENSE.txt for details.
       3              : 
       4              : /// \file
       5              : /// Defines function find_real_eigensystem.
       6              : 
       7              : #pragma once
       8              : 
       9              : #include <cstddef>
      10              : 
      11              : #include "DataStructures/Tensor/TypeAliases.hpp"
      12              : 
      13              : /// \cond
      14              : class DataVector;
      15              : namespace gsl {
      16              : template <typename T>
      17              : class not_null;
      18              : }  // namespace gsl
      19              : /// \endcond
      20              : 
      21              : /*!
      22              :  * \ingroup NumericalAlgorithmsGroup
      23              :  * \brief Find the eigensystem of a diagonalizable matrix whose eigenvalues are
      24              :  * all real, with a complete set of eigenvectors even when degeneracies are
      25              :  * present.
      26              :  *
      27              :  * We label the matrix $A_{m}{}^{n}$ such that the index $m$ labels rows and the
      28              :  * index $n$ labels columns.
      29              :  *
      30              :  * With this choice of indices, the $i$th left eigensystem is given by
      31              :  * \begin{equation}
      32              :  *   \sum_m L^{im} A_{m}{}^{n} = \lambda_{(i)} L^{in},
      33              :  * \end{equation}
      34              :  * where $\lambda_{(i)}$ is the $i$th eigenvalue.
      35              :  * Similarly, the $i$th right eigensystem is given by
      36              :  * \begin{equation}
      37              :  *   \sum_n R_{in} A_{m}{}^{n} = \lambda_{(i)} R_{im}.
      38              :  * \end{equation}
      39              :  *
      40              :  * We take the matrix and provide the eigensystem in the following types:
      41              :  * - %Matrix $A_{m}{}^{n}$: `tnsr::iJ<DataVector, MatrixSize> matrix`
      42              :  * - Eigenvalues $\lambda_{(i)}$: `tnsr::i<DataVector, MatrixSize> eigenvalues`
      43              :  * - Right eigenvectors $R_{in}$: `tnsr::ij<DataVector, MatrixSize>
      44              :  *   right_eigenvectors`
      45              :  * - Left eigenvectors $L^{im}$: `tnsr::IJ<DataVector, MatrixSize>
      46              :  *   left_eigenvectors`
      47              :  *
      48              :  * Note that the indices $i$, $m$, and $n$ are not tensorial. They simply label
      49              :  * the eigensystem, rows of the matrix, and columns of the matrix, respectively.
      50              :  * We make the conventions (raised or lowered) presented above to clearly
      51              :  * distinguish which indices (first or second) of the matrix get contracted
      52              :  * with which eigenvectors (left or right).
      53              :  *
      54              :  * Each grid point holds an independent matrix. Repeated (degenerate)
      55              :  * eigenvalues are allowed, as long as the matrix is diagonalizable. The
      56              :  * eigenvalues are in increasing order, with degenerate eigenvalues grouped
      57              :  * together.
      58              :  *
      59              :  * To compute such an eigensystem, we follow the procedure outlined below, each
      60              :  * step using a LAPACK routine.
      61              :  *
      62              :  * 1. Balance the matrix (`dgebal`), $A' = D^{-1} A D$, where $D$ is a diagonal
      63              :  *    matrix chosen so that the rows and columns of $A'$ have similar norms.
      64              :  *    This improves the accuracy of the next steps and does not change the
      65              :  *    eigenvalues.
      66              :  * 2. Compute the real Schur form of the balanced matrix (`dgees`),
      67              :  *    $A' = Z T Z^T$, where $Z$ is orthogonal and $T$ is upper triangular with
      68              :  *    the eigenvalues on its diagonal. The first column of $Z$ is a right
      69              :  *    eigenvector of $A'$ for the first eigenvalue on the diagonal of $T$. In
      70              :  *    general, the other columns are not eigenvectors. The exception is a
      71              :  *    repeated eigenvalue (i.e., when we have a degeneracy): if the first $k$
      72              :  *    eigenvalues on the diagonal of $T$ are equal, the first $k$ columns of $Z$
      73              :  *    are $k$ orthonormal right eigenvectors for that degenerate subspace.
      74              :  * 3. Group the eigenvalues into degenerate families, i.e., sets of equal
      75              :  *    eigenvalues. For each family, of size $k$, reorder the Schur form
      76              :  *    (`dtrsen`), $T \to Q^T T Q$ and $Z \to Z Q$ with $Q$ orthogonal, so that
      77              :  *    the family's eigenvalues come first on the diagonal of $T$, and take the
      78              :  *    first $k$ columns of $Z$ as the family's right eigenvectors. The
      79              :  *    reordering rotates the columns of $Z$, keeping them orthonormal and $T$
      80              :  *    upper triangular.
      81              :  * 4. Compute the left eigenvectors as the inverse of the right eigenvectors
      82              :  *    (`dgesv`), so that $\sum_m L^{im} R_{jm} = \delta^{i}_{j}$.
      83              :  *
      84              :  * Finally, we undo the balancing: $R_{im} = D_{mm} R'_{im}$ and
      85              :  * $L^{im} = L'^{im} / D_{mm}$.
      86              :  *
      87              :  * Eigenvalues are treated as equal (degenerate) when they differ by at most
      88              :  * $10^{-10} \|A'\|_F$, where $\|A'\|_F$ is the Frobenius norm of the
      89              :  * balanced matrix.
      90              :  */
      91              : template <size_t MatrixSize>
      92            1 : void find_real_eigensystem(
      93              :     gsl::not_null<tnsr::i<DataVector, MatrixSize>*> eigenvalues,
      94              :     gsl::not_null<tnsr::ij<DataVector, MatrixSize>*> right_eigenvectors,
      95              :     gsl::not_null<tnsr::IJ<DataVector, MatrixSize>*> left_eigenvectors,
      96              :     const tnsr::iJ<DataVector, MatrixSize>& matrix);
        

Generated by: LCOV version 2.0-1