Spectra: Sparse Eigenvalue Computation Toolkit

repository·master·Indexed 21 days ago

https://github.com/yixuan/spectra

A C++ header-only library for large-scale eigenvalue problems, designed as a modern redesign of the FORTRAN ARPACK library. Built on top of the Eigen linear algebra library, Spectra provides various solvers including SymEigsSolver, GenEigsSolver, and HermEigsSolver for symmetric, general, and Hermitian matrices. It supports both standard and shift-and-invert modes and is designed for efficiency with sparse matrices by requiring only specific operations like matrix-vector multiplication.

Tokens
7.9K
Snippets
11
Records
22
Agent score
72%

What's inside Spectra

  1. Overview of Spectra

    master
    Spectra (Sparse Eigenvalue Computation Toolkit) is a header-only C++ library designed for large-scale eigenvalue problems. It is a redesigned version of the FORTRAN-based ARPACK, implemented in C++ and built on top of the Eigen linear algebra library. Because both Spectra and Eigen are header-only, Spectra can be easily embedded into existing C++ projects without complex build dependencies.
  2. How shift-and-invert mode works

    master

    When you need to find eigenvalues closest to a specific value σ (for example, the smallest eigenvalues of a positive definite matrix by setting σ = 0), use the shift-and-invert mode.

    In this mode, selection rules are applied to 1/(λ - σ) instead of λ (where λ are the eigenvalues of A). To use this, you must define a shift-solve matrix operation (e.g., y = inv(A - σ * I) * x). Refer to the documentation for SymEigsShiftSolver for implementation details.

  3. How to use Spectra for eigenvalue problems

    master

    Spectra calculates a specified number (k) of eigenvalues of a large square matrix (A). Instead of requiring the full matrix, the algorithms only require specific operations, most commonly matrix-vector multiplication (A * x). This makes Spectra highly efficient for sparse matrices.

    To use the library, follow these two steps:

    1. Define a matrix operation class: Implement a class that performs the required operation (e.g., y = A * x or the shift-solve y = inv(A - σ * I) * x). You can use Spectra's built-in helper classes (like DenseGenMatProd or SparseSymMatProd) or define your own custom class.
    2. Create and run an eigen solver: Instantiate a solver class (such as SymEigsSolver for symmetric matrices or GenEigsSolver for general matrices), initialize it, and call its computation methods to retrieve eigenvalues and eigenvectors.
  4. Use Shift-and-invert mode

    master

    To find eigenvalues closest to a specific number $\sigma$ (for example, the smallest eigenvalues of a positive definite matrix by setting $\sigma=0$), use the shift-and-invert mode.

    In this mode, selection rules are applied to $1/(\lambda-\sigma)$ instead of $\lambda$. To use this, you must use a solver designed for shift-and-invert (e.g., SymEigsShiftSolver) and define a shift-solve matrix operation (e.g., $y=(A-\sigma I)^{-1}x$).

  5. How to use Spectra eigen solvers

    master

    Spectra calculates a specified number ($k$) of eigenvalues of a large square matrix ($A$). Instead of requiring the full matrix, the algorithm only requires certain operations (like matrix-vector multiplication $Ax$).

    To use the library, follow these two steps:

    1. Define a matrix operation class: This class must implement the required operation (e.g., $y=Ax$ or the shift-solve $y=(A-\sigma I)^{-1}x$). You can use Spectra's built-in helper classes (like DenseSymMatProd or SparseGenMatProd) or implement your own custom class.
    2. Create and run a solver object: Instantiate one of the available solver classes (e.g., SymEigsSolver for symmetric matrices) by passing the operation object, the number of eigenvalues requested, and the number of Lanczos vectors. Call .init() and .compute() to perform the calculation, then use .eigenvalues() or .eigenvectors() to retrieve results.
  6. Migrate from Spectra 0.9.0 to 1.0.0

    master
    Spectra 1.0.0 introduced several breaking API changes. To migrate from version 0.9.0, you must update your toolchain requirements, modify user-defined matrix operation classes, refactor Eigen solver instantiation, and update enumeration usage to use enum class syntax.
  7. Implement a custom matrix operation class

    master

    If you have a custom matrix or a specific way to compute $y=Ax$, you can implement your own operation class. Your class must provide:

    • A using Scalar = ...; typedef.
    • int rows() const and int cols() const methods.
    • A void perform_op(const Scalar *x_in, Scalar *y_out) const method that performs the multiplication.
    #include <Eigen/Core>
    #include <Spectra/SymEigsSolver.h>
    #include <iostream>
    
    using namespace Spectra;
    
    // M = diag(1, 2, ..., 10)
    class MyDiagonalTen
    {
    public:
        using Scalar = double;  // A typedef named "Scalar" is required
        int rows() const { return 10; }
        int cols() const { return 10; }
        // y_out = M * x_in
        void perform_op(const double *x_in, double *y_out) const
        {
            for(int i = 0; i < rows(); i++)
            {
                y_out[i] = x_in[i] * (i + 1);
            }
        }
    };
    
    int main()
    {
        MyDiagonalTen op;
        SymEigsSolver<MyDiagonalTen> eigs(op, 3, 6);
        eigs.init();
        eigs.compute(SortRule::LargestAlge);
        if(eigs.info() == CompInfo::Successful)
        {
            Eigen::VectorXd evalues = eigs.eigenvalues();
            std::cout << "Eigenvalues found:\n" << evalues << std::endl;
        }
    
        return 0;
    }
  8. Install Spectra via CMake

    master

    Spectra supports installation via CMake (requires version 3.10 or higher). Installing via CMake creates the Spectra::Spectra CMake target, which allows you to easily link against the library in other projects using find_package(Spectra).

    Standard Installation

    mkdir build && cd build
    cmake .. -DCMAKE_INSTALL_PREFIX='intended installation directory' -DBUILD_TESTS=TRUE
    make all && make test && make install

    Configuring Eigen Path

    If Eigen is already installed on your system, you can specify its location using CMAKE_PREFIX_PATH or Eigen3_ROOT to ensure Spectra finds it correctly:

    cmake .. -DCMAKE_INSTALL_PREFIX='intended installation directory' -DCMAKE_PREFIX_PATH='path where the installation of Eigen3 can be found' -DBUILD_TESTS=TRUE
  9. Install and integrate Spectra

    master
    Spectra is a header-only C++ library designed for large-scale eigenvalue problems. It is built on top of the Eigen linear algebra library. Because both Spectra and Eigen are header-only, Spectra can be easily embedded into existing C++ projects by including its headers and ensuring the Eigen library is available in your include path.
  10. Control Eigen download behavior via environment variables

    master

    When building Spectra, you can use the following environment variables to control how the Eigen dependency is handled via CPM:

    • CPM_DOWNLOAD_ALL=ON: Forces the download of Eigen even if an installation is already present on the system.
    • CPM_LOCAL_PACKAGES_ONLY=ON: Forces the build to use only locally installed packages (prevents downloading Eigen).
    • CPM_SOURCE_CACHE: Sets the directory used for downloading and caching source files.
  11. Calculate eigenvalues of a symmetric matrix

    master

    This example uses DenseSymMatProd to wrap a dense Eigen matrix and SymEigsSolver to find the largest three eigenvalues.

    #include <Eigen/Core>
    #include <Spectra/SymEigsSolver.h>
    // <Spectra/MatOp/DenseSymMatProd.h> is implicitly included
    #include <iostream>
    
    using namespace Spectra;
    
    int main()
    {
        // We are going to calculate the eigenvalues of M
        Eigen::MatrixXd A = Eigen::MatrixXd::Random(10, 10);
        Eigen::MatrixXd M = A + A.transpose();
    
        // Construct matrix operation object using the wrapper class DenseSymMatProd
        DenseSymMatProd<double> op(M);
    
        // Construct eigen solver object, requesting the largest three eigenvalues
        SymEigsSolver<DenseSymMatProd<double>> eigs(op, 3, 6);
    
        // Initialize and compute
        eigs.init();
        int nconv = eigs.compute(SortRule::LargestAlge);
    
        // Retrieve results
        Eigen::VectorXd evalues;
        if(eigs.info() == CompInfo::Successful)
            evalues = eigs.eigenvalues();
    
        std::cout << "Eigenvalues found:\n" << evalues << std::endl;
    
        return 0;
    }
  12. Work with complex-valued matrices

    master

    Spectra supports complex-valued matrices using HermEigsSolver for Hermitian matrices and GenEigsSolver for general complex matrices. Note that for Hermitian matrices, eigenvalues are real-valued while eigenvectors are complex-valued.

    #include <Eigen/Core>
    #include <Spectra/HermEigsSolver.h>
    #include <Spectra/GenEigsSolver.h>
    #include <iostream>
    
    using namespace Spectra;
    
    int main()
    {
        std::srand(0);
    
        // We are going to calculate the eigenvalues of H and G
        Eigen::MatrixXcd G = Eigen::MatrixXcd::Random(10, 10);
        // H is Hermitian
        Eigen::MatrixXcd H = G + G.adjoint();
    
        // Construct matrix operation objects using the wrapper
        // classes DenseHermMatProd and DenseGenMatProd
        using OpHType = DenseHermMatProd<std::complex<double>>;
        using OpGType = DenseGenMatProd<std::complex<double>>;
        OpHType opH(H);
        OpGType opG(G);
    
        // Construct solver object for H, requesting the largest three eigenvalues
        HermEigsSolver<OpHType> eigsH(opH, 3, 6);
    
        // Initialize and compute
        eigsH.init();
        int nconvH = eigsH.compute(SortRule::LargestAlge);
    
        // Retrieve results
        // Eigenvalues are real-valued, and eigenvectors are complex-valued
        if (eigsH.info() == CompInfo::Successful)
        {
            Eigen::VectorXd evaluesH = eigsH.eigenvalues();
            std::cout << "Eigenvalues of H found:\n" << evaluesH << std::endl;
            Eigen::MatrixXcd evecsH = eigsH.eigenvectors();
            std::cout << "Eigenvectors of H:\n" << evecsH << std::endl;
        }
    
        // Similar procedure for matrix G
        GenEigsSolver<OpGType> eigsG(opG, 3, 6);
        eigsG.init();
        int nconvG = eigsG.compute(SortRule::LargestMagn);
    
        // Retrieve results
        Eigen::VectorXcd evaluesG;
        if (eigsG.info() == CompInfo::Successful)
        {
            evaluesG = eigsG.eigenvalues();
            std::cout << "Eigenvalues of G found:\n" << evaluesG << std::endl;
            Eigen::MatrixXcd evecsG = eigsG.eigenvectors();
            std::cout << "Eigenvectors of G:\n" << evecsG << std::endl;
        }
    
        return 0;
    }