diff --git a/docs/make.jl b/docs/make.jl index 4584ff1c3..a92d1d8b0 100644 --- a/docs/make.jl +++ b/docs/make.jl @@ -51,6 +51,7 @@ makedocs(; "User Interface" => [ "user_interface/compositions.md", "user_interface/decompositions.md", + "user_interface/algorithms.md", "user_interface/truncations.md", "user_interface/properties.md", "user_interface/matrix_functions.md", diff --git a/docs/src/index.md b/docs/src/index.md index 7055ba3ec..d5e298529 100644 --- a/docs/src/index.md +++ b/docs/src/index.md @@ -26,6 +26,7 @@ These operations typically follow some common skeleton, and here we go into a li ```@contents Pages = ["user_interface/compositions.md", "user_interface/decompositions.md", + "user_interface/algorithms.md", "user_interface/truncations.md", "user_interface/properties.md", "user_interface/matrix_functions.md"] Depth = 2 diff --git a/docs/src/user_interface/algorithms.md b/docs/src/user_interface/algorithms.md new file mode 100644 index 000000000..74c85a9b9 --- /dev/null +++ b/docs/src/user_interface/algorithms.md @@ -0,0 +1,144 @@ +```@meta +CurrentModule = MatrixAlgebraKit +CollapsedDocStrings = true +``` + +# [Algorithm Selection](@id sec_algorithmselection) + +All factorization functions in MatrixAlgebraKit accept an optional `alg` keyword argument that controls which algorithm is used and how it is configured. +By default, an appropriate algorithm is selected automatically based on the function and the input types. +This page explains how to override that default, what algorithm types are available, and how to configure them. + +## The `alg` Keyword + +The `alg` keyword is interpreted by [`MatrixAlgebraKit.select_algorithm`](@ref), which accepts five different forms for specifying an algorithm and its configuration. +For example, for `qr_compact` these forms look like: + +```julia +# Form 1: No alg — algorithm selected automatically based on function and input type. +Q, R = qr_compact(A); + +# Form 2: Symbol — creates Algorithm{:Householder}(; positive=false). +Q, R = qr_compact(A; alg = :Householder, positive = false); + +# Form 3: Algorithm type — calls Householder(; positive=false). +Q, R = qr_compact(A; alg = Householder, positive = false); + +# Form 4: Algorithm instance — used as-is; no additional kwargs are allowed. +Q, R = qr_compact(A; alg = Householder(; positive = false)); + +# Form 5: NamedTuple — equivalent to qr_compact(A; positive=false). +Q, R = qr_compact(A; alg = (; positive = false)); +``` + +!!! note + When passing an already-constructed algorithm instance (form 4), additional keyword arguments at the call site are not permitted and will throw an `ArgumentError`. + All configuration must go into the constructor in that case. + +```@docs; canonical=false +MatrixAlgebraKit.select_algorithm +``` + +## Discovering the Default Algorithm + +To check which algorithm is used by default for a given function and input type, call [`MatrixAlgebraKit.default_algorithm`](@ref). +The available keyword arguments depend on the algorithm type; refer to the docstrings listed in [Available Algorithm Types](@ref) below. + +```@docs; canonical=false +MatrixAlgebraKit.default_algorithm +``` + +## Configuring Algorithms + +Each algorithm accepts keyword arguments that control its behavior. +These can be provided either at the call site (forms 1–3) or inside the algorithm constructor: + +```julia +# The following four calls are all equivalent: +U, S, Vᴴ = svd_compact(A; fixgauge = false) +U, S, Vᴴ = svd_compact(A; alg = :SafeDivideAndConquer, fixgauge = false) +U, S, Vᴴ = svd_compact(A; alg = SafeDivideAndConquer, fixgauge = false) +U, S, Vᴴ = svd_compact(A; alg = SafeDivideAndConquer(; fixgauge = false)) +``` + +## The `DefaultAlgorithm` Sentinel + +Package developers who want to store an algorithm configuration without committing to a specific algorithm can use `DefaultAlgorithm`. +It defers algorithm selection to call time, forwarding its stored keyword arguments to [`MatrixAlgebraKit.select_algorithm`](@ref): + +```julia +# Store configuration without picking a specific algorithm: +alg = DefaultAlgorithm(; positive = true) + +# Equivalent to qr_compact(A; positive = true): +Q, R = qr_compact(A; alg) +``` + +```@docs; canonical=false +DefaultAlgorithm +``` + +## Available Algorithm Types + +The following high-level algorithm types are available. +They all accept an optional `driver` keyword to select the computational backend; see [Driver Selection](@ref sec_driverselection) for details. + +| Algorithm | Applicable decompositions | Key keyword arguments | +|:----------|:--------------------------|:----------------------| +| [`Householder`](@ref) | QR, LQ | `positive`, `pivoted`, `blocksize` | +| [`DivideAndConquer`](@ref) | SVD, eigh | `fixgauge` | +| [`SafeDivideAndConquer`](@ref) | SVD, eigh | `fixgauge` | +| [`QRIteration`](@ref) | SVD, eigh, eig, Schur | `fixgauge`, `expert`, `permute`, `scale` | +| [`Bisection`](@ref) | eigh, SVD | `fixgauge` | +| [`Jacobi`](@ref) | eigh, SVD | `fixgauge` | +| [`RobustRepresentations`](@ref) | eigh | `fixgauge` | +| [`SVDViaPolar`](@ref) | SVD | `fixgauge`, `tol` | +| [`PolarViaSVD`](@ref) | polar | positional `svd_alg` argument | +| [`PolarNewton`](@ref) | polar | `maxiter`, `tol` | + +For full docstring details on each algorithm type, see the corresponding section in [Decompositions](@ref). + +## [Driver Selection](@id sec_driverselection) + +!!! note "Expert use case" + Selecting a specific driver is an advanced feature intended for users who need to target a specific computational backend, such as a GPU. + For most use cases, the default driver selection is sufficient. + +Each algorithm in MatrixAlgebraKit can optionally accept a `driver` keyword argument to explicitly select the computational backend. +By default, the driver is set to `DefaultDriver()`, which automatically selects the most appropriate backend based on the input matrix type. +The available drivers are: + +```@autodocs; canonical=false +Modules = [MatrixAlgebraKit] +Filter = t -> t isa Type && t <: MatrixAlgebraKit.Driver +``` + +For example, to force LAPACK for a generic matrix type, or to use a GPU backend: + +```julia +using MatrixAlgebraKit +using MatrixAlgebraKit: LAPACK, CUSOLVER # driver types are not exported by default + +# Default: driver is selected automatically based on the input type +U, S, Vᴴ = svd_compact(A) +U, S, Vᴴ = svd_compact(A; alg = SafeDivideAndConquer()) + +# Expert: explicitly select LAPACK +U, S, Vᴴ = svd_compact(A; alg = SafeDivideAndConquer(; driver = LAPACK())) + +# Expert: use a GPU backend (requires loading the appropriate extension) +U, S, Vᴴ = svd_compact(A; alg = QRIteration(; driver = CUSOLVER())) +``` + +Similarly, for QR decompositions: + +```julia +using MatrixAlgebraKit: LAPACK # driver types are not exported by default + +# Default: driver is selected automatically +Q, R = qr_compact(A) +Q, R = qr_compact(A; alg = Householder()) + +# Expert: explicitly select a driver +Q, R = qr_compact(A; alg = Householder(; driver = LAPACK())) +``` diff --git a/docs/src/user_interface/decompositions.md b/docs/src/user_interface/decompositions.md index c2df35b13..1e74e71d8 100644 --- a/docs/src/user_interface/decompositions.md +++ b/docs/src/user_interface/decompositions.md @@ -16,7 +16,7 @@ f!(A, [F]; kwargs...) -> F... Here, the input matrix is always the first argument, and optionally the output can be provided as well. The keywords are algorithm-specific, and can be used to influence the behavior of the algorithms. -To check what algorithm is used by default for a given factorization `f` and input `A`, and by extension which keyword arguments it takes, you can call [`MatrixAlgebraKit.default_algorithm(f, A)`](@ref) and check the documentation of resulting algorithm type. +For a full description of how to select and configure algorithms, see [Algorithm Selection](@ref sec_algorithmselection). Importantly, for generic code patterns it is recommended to always use the output `F` explicitly, since some implementations may not be able to reuse the provided memory. Additionally, the `f!` method typically assumes that it is allowed to destroy the input `A`, and making use of the contents of `A` afterwards should be deemed as undefined behavior. @@ -40,10 +40,11 @@ lq_full lq_compact ``` -The following algorithm is available for QR and LQ decompositions: +The following algorithms are available for QR and LQ decompositions: -```@docs; canonical=false -Householder +```@autodocs; canonical=false +Modules = [MatrixAlgebraKit] +Filter = t -> t isa Type && (t <: MatrixAlgebraKit.QRAlgorithms || t <: MatrixAlgebraKit.LQAlgorithms) ``` ## Eigenvalue Decomposition @@ -387,54 +388,6 @@ norm(A * N1') < 1e-14 && norm(A * N2') < 1e-14 && true ``` -## [Driver Selection](@id sec_driverselection) - -!!! note "Expert use case" - Selecting a specific driver is an advanced feature intended for users who need to target a specific computational backend, such as a GPU. For most use cases, the default driver selection is sufficient. - -Each algorithm in MatrixAlgebraKit can optionally accept a `driver` keyword argument to explicitly select the computational backend. -By default, the driver is set to `DefaultDriver()`, which automatically selects the most appropriate backend based on the input matrix type. -The available drivers are: - -```@docs; canonical=false -MatrixAlgebraKit.DefaultDriver -MatrixAlgebraKit.LAPACK -MatrixAlgebraKit.CUSOLVER -MatrixAlgebraKit.ROCSOLVER -MatrixAlgebraKit.GLA -MatrixAlgebraKit.Native -``` - -For example, to force LAPACK for a generic matrix type, or to use a GPU backend: - -```julia -using MatrixAlgebraKit -using MatrixAlgebraKit: LAPACK, CUSOLVER # driver types are not exported by default - -# Default: driver is selected automatically based on the input type -U, S, Vᴴ = svd_compact(A) -U, S, Vᴴ = svd_compact(A; alg = SafeDivideAndConquer()) - -# Expert: explicitly select LAPACK -U, S, Vᴴ = svd_compact(A; alg = SafeDivideAndConquer(; driver = LAPACK())) - -# Expert: use a GPU backend (requires loading the appropriate extension) -U, S, Vᴴ = svd_compact(A; alg = QRIteration(; driver = CUSOLVER())) -``` - -Similarly, for QR decompositions: - -```julia -using MatrixAlgebraKit: LAPACK # driver types are not exported by default - -# Default: driver is selected automatically -Q, R = qr_compact(A) -Q, R = qr_compact(A; alg = Householder()) - -# Expert: explicitly select a driver -Q, R = qr_compact(A; alg = Householder(; driver = LAPACK())) -``` - ## [Gauge choices](@id sec_gaugefix) Both eigenvalue and singular value decompositions have residual gauge degrees of freedom even when the eigenvalues or singular values are unique.