KrylovKit.jl

repository·master·Indexed 19 days ago

https://github.com/jutho/krylovkit.jl

A Julia package providing Krylov-based algorithms for solving linear systems, singular value problems, and eigenvalue problems. It features a high-level API including linsolve, lssolve, eigsolve, geneigsolve, and svdsolve, as well as functions for applying exponentials of linear maps. The library supports general functions or callable objects as linear maps, any object following the VectorInterface.jl interface as vectors, and provides reverse-mode AD support via ChainRulesCore.jl for select functions.

Tokens
6.2K
Snippets
13
Records
37
Agent score
65%

What's inside KrylovKit.jl

  1. Verbosity and output formatting in KrylovKit.jl

    master

    As of v0.9, the verbosity system has been redesigned. The default verbosity level is WARN_LEVEL.

    • Default behavior: Warnings are printed by default, but all other output (such as info messages) is suppressed.
    • This applies to both primal methods and rrules.
  2. Support for Reverse-mode Automatic Differentiation (AD)

    master

    KrylovKit.jl supports reverse-mode AD via ChainRulesCore.rrule definitions for the following functions:

    • linsolve
    • eigsolve
    • svdsolve

    Reverse-mode AD engines compatible with the ChainRules ecosystem can use these optimized adjoint implementations.

    Note: geneigsolve and expintegrator (including exponentiate) are planned for future support.

  3. Compute functions of matrices and linear operators using Krylov methods

    master

    For certain functions $f$ and a linear operator $A$, the action $f(A)b$ can be approximated using Krylov subspace methods. This is particularly useful when $A$ is large and only its action on a vector is available.

    Currently, KrylovKit.jl supports the $\phi_j(z)$ family of functions, which generalize the exponential function $\phi_0(z) = \exp(z)$. These functions are commonly used in the context of linear non-homogeneous Ordinary Differential Equations (ODEs).

    Available methods include:

    • expintegrator: An exponential integrator used for computing $\phi_j(z)$ functions.
    • exponentiate: A specialized wrapper for computing pure exponentials, used for linear homogeneous ODEs.
  4. Understand KrylovFactorization types and components

    master

    A KrylovFactorization represents a partial factorization or decomposition of a linear map.

    Concrete Implementations:

    • LanczosFactorization: For symmetric/Hermitian matrices.
    • BlockLanczosFactorization: For block versions of Lanczos.
    • ArnoldiFactorization: For general matrices.
    • GKLFactorization: For Golub-Kahan-Lanczos bidiagonalization.

    Accessing Components: You can access the defining components of a KrylovFactorization or GKLFactorization using these functions:

    • basis(f): Returns the basis.
    • rayleighquotient(f): Returns the Rayleigh quotient.
    • residual(f): Returns the residual.
    • normres(f): Returns the norm of the residual.
    • rayleighextension(f): Returns the Rayleigh extension (often a SimpleBasisVector).

    Specialized Types:

    • SimpleBasisVector: A dedicated type to represent the Rayleigh extension without allocating a full vector.
    • PackedHessenberg: A custom matrix type used to store the Hessenberg matrix of an Arnoldi factorization in a packed format (omitting zeros).
  5. Manage vector bases with Basis and OrthonormalBasis

    master

    KrylovKit uses the Basis{T} abstract type to represent a basis of vectors (e.g., a Krylov subspace). For algorithms requiring an orthogonal basis, use the OrthonormalBasis{T} implementation.

    To manipulate these bases, you can use the following operations:

    • Orthogonalization: Use orthogonalize or orthonormalize to orthogonalize/orthonormalize a vector against another vector or an existing OrthonormalBasis. Use the in-place versions orthogonalize!! and orthonormalize!! to modify vectors in place.
    • Projection: Use project!! to obtain the expansion coefficients of a vector in terms of an orthonormal basis. Use unproject!! to perform the inverse calculation.
    • Basis Updates: Use rank1update! to transform an orthonormal basis via a rank-1 update (this changes the subspace). Use basistransform! to perform a rotation of the basis that does not change the spanned subspace.
    # Example conceptual usage
    basis = OrthonormalBasis(T, vectors)
    # Orthogonalize a new vector against the basis
    orthonormalize!(basis, new_vector)
    
    # Project a vector onto the basis to get coefficients
    coeffs = project!!(basis, vector)
  6. How the KrylovKit common interface works

    master

    High-level functions such as linsolve, eigsolve, geneigsolve, svdsolve, exponentiate, and expintegrator follow a consistent interface.

    Input: The Linear Map

    The first argument A represents the linear map. This can be:

    1. An instance of AbstractMatrix.
    2. A function or callable object that encodes the action of the linear map on a vector.
    3. A Julia do block that implements the action on a vector x.

    Input: Arguments and Keywords

    • args...: Additional arguments required by the specific solver.
    • kwargs...: Configuration keywords:
      • Linear map properties: issymmetric, ishermitian, isposdef.
      • Solution strategy: tol (tolerance), krylovdim (Krylov subspace dimension), maxiter (maximum iterations).
      • Output control: verbosity.

    Output: Results and Convergence Info

    Functions return one or more solution entries followed by a final info object of type ConvergeInfo. This object contains convergence status, residuals, the norm of the residual, and the number of operations used.

    Verbosity Levels

    Control how much information is printed to STDOUT using the verbosity keyword:

    • SILENT_LEVEL (default): No information printed.
    • WARN_LEVEL: A single message at the end (warning if failed, info if succeeded).
    • STARTSTOP_LEVEL: Information about the current state is displayed after every iteration.
    • verbosity > STARTSTOP_LEVEL: Detailed information about individual Krylov expansion steps is displayed.
    # Using a do-block to define the linear map
    results..., info = linsolve(args...; kwargs...) do x
        y = # implement linear map on x
        return y
    end
  7. Solve real linear problems with complex vectors using reallinsolve, realeigsolve, and reallssolve

    master

    When working with vectors that use complex arithmetic, but where the linear map (function f) acts as a real linear map (i.e., it only satisfies f(α*x) = α*f(x) for real $\alpha$), you can use specialized functions:

    • reallinsolve
    • realeigsolve
    • reallssolve (available since v0.9.4)

    These functions work by wrapping the vector in a RealVec type. This InnerProductVec implementation redefines the inner product to ignore the imaginary part, effectively treating the vector as living in a real vector space.

    Note: In this mode, only real linear combinations of vectors are allowed. For realeigsolve, only real eigenvalues and eigenvectors are computed. An error will be thrown if you request complex eigenvalues.

  8. Use `eigsolve` with Automatic Differentiation (AD)

    master

    The eigsolve and realeigsolve routines are compatible with reverse-mode automatic differentiation via the ChainRules ecosystem.

    Key Details:

    • Adjoint Map: The adjoint problem requires the adjoint of the linear map. If the map is an AbstractMatrix, its adjoint is used. If it is a function f, the AD engine computes the adjoint via ChainRulesCore.rrule_via_ad.
    • Selecting Adjoint Algorithms: You can select how the adjoint problem is solved using the alg_rrule keyword argument:
      • If a linear solver (e.g., GMRES, BiCGStab) is specified, the adjoint problem solves multiple linear problems.
      • If an eigenvalue solver (e.g., Arnoldi) is specified, the adjoint problem is solved as a single, larger eigenvalue problem.
    • Gauge Invariance Warning: Because eigenvector phase is not unique, cost functions depending on eigenvectors should be 'gauge invariant'. If a cost function is 'gauge dependent', KrylovKit will print a warning. To suppress this warning, pass an algorithm to alg_rrule with verbosity=SILENT_LEVEL-1.
  9. Use linsolve with automatic differentiation

    master

    The linsolve routine is compatible with reverse-mode automatic differentiation (AD) engines that support the ChainRules ecosystem.

    Adjoint Behavior

    When performing reverse-mode AD, the adjoint (cotangent) problem is also a linear problem. KrylovKit handles the adjoint of the linear map as follows:

    • AbstractMatrix: If the linear map is an AbstractMatrix, its adjoint is used.
    • Function: If the linear map is a function f, the AD engine computes the adjoint via ChainRulesCore.rrule_via_ad.

    Customizing the Adjoint Algorithm

    By default, the adjoint problem is solved using the same Krylov algorithm as the primal problem. If you need to use a different algorithm for the adjoint step, you can specify the alg_rrule keyword argument. This argument accepts any value valid for the algorithm argument in linsolve.

  10. How KrylovKit handles linear maps and vectors

    master

    KrylovKit.jl is designed for flexibility regarding the types of inputs it accepts:

    Linear Maps

    KrylovKit accepts general functions or callable objects as linear maps.

    • If the first argument (the linear map) is a subtype of AbstractMatrix, the package uses matrix-vector multiplication.
    • Otherwise, the map is applied as a function call.
    • You do not need to wrap your function in LinearMap or LinearOperator types.

    Vectors

    KrylovKit does not require vectors to be subtypes of AbstractVector. It supports any Julia object that follows the VectorInterface.jl interface. This includes:

    • Higher-dimensional arrays.
    • Custom user types.
    • Tuples and NamedTuples.
    • Arbitrarily nested combinations of tuples and arrays.
    • CuArray objects (for GPU execution of the linear map application).

    Note: While the linear map application can run on a GPU (e.g., using CuArray), the internal Krylov subspace computations (like diagonalizing the projected matrix) are always performed on the CPU.

  11. Use svdsolve with automatic differentiation

    master

    The svdsolve routine is compatible with reverse-mode automatic differentiation (AD) via the ChainRules ecosystem.

    To use AD, the linear map $A$ must support both its action and its adjoint (conjugate transpose). The adjoint problem can be solved using different implementations via the alg_rrule keyword argument:

    1. Linear Solver Approach: If you specify a linear solver like GMRES or BiCGStab for alg_rrule, the adjoint problem is solved as a number of linear problems equal to the number of requested singular values/vectors.
    2. Eigenvalue Solver Approach: If an eigenvalue solver (such as Arnoldi) is specified, the adjoint problem is solved as a single, larger eigenvalue problem.

    Important: Gauge Invariance Warning Singular vectors have an arbitrary phase freedom. If your cost function is 'gauge dependent' (meaning its value changes when left and right singular vectors are simultaneously changed by a common phase factor), KrylovKit will print a warning during the adjoint calculation.

    To suppress this warning, pass an algorithm to alg_rrule with verbosity=SILENT_LEVEL-1.

    # Example concept: selecting an rrule implementation
    svdsolve(A, k, alg_rrule=GMRES(verbosity=SILENT_LEVEL-1))
  12. Enable multithreaded vector operations

    master

    For cases where the vector x is a Vector (specifically v::AbstractArray with IndexStyle(v) == IndexLinear()), KrylovKit can use a multithreaded implementation that resembles BLAS level 2 operations. This applies when using ClassicalGramSchmidt(), ClassicalGramSchmidt2(), or ClassicalGramSchmidtIR() as the orthogonalization routine.

    To enable this, set the JULIA_NUM_THREADS environment variable before starting Julia.

    export JULIA_NUM_THREADS=x  # replace x with the desired number of threads