Internal API Documentation
This page documents LinearSolve.jl's internal API, which is useful for developers who want to understand the package's architecture, contribute to the codebase, or develop custom linear solver algorithms.
Abstract Type Hierarchy
LinearSolve.jl uses a well-structured type hierarchy to organize different classes of linear solver algorithms:
LinearSolve.SciMLLinearSolveAlgorithm — Type
SciMLLinearSolveAlgorithm <: SciMLBase.AbstractLinearAlgorithmThe root abstract type for all linear solver algorithms in LinearSolve.jl. All concrete linear solver implementations should inherit from one of the specialized subtypes rather than directly from this type.
This type integrates with the SciMLBase ecosystem, providing a consistent interface for linear algebra operations across the Julia scientific computing ecosystem.
Interface
A concrete MyAlg <: SciMLLinearSolveAlgorithm must implement SciMLBase.solve!(cache::LinearCache, alg::MyAlg; kwargs...) and needs_concrete_A(alg::MyAlg)::Bool. It may implement init_cacheval, default_alias_A, default_alias_b, needs_square_A, and update_tolerances_internal!; each of these has a documented default.
Subtyping one of the categorized abstract types below supplies needs_concrete_A and the aliasing defaults. Direct subtypes must define needs_concrete_A themselves. The complete contract, including cache lifecycle rules and extension boundaries, is documented on the Linear Solver Algorithm Interface page.
Extension rules
Define the four traits needs_concrete_A, needs_square_A, default_alias_A, and default_alias_b in the package that defines MyAlg, next to the algorithm type. Downstream solvers query them before an optional backend is loaded. Methods that actually call the backend, such as solve! and init_cacheval, may be defined in the package extension instead.
Examples
struct MyAlg <: LinearSolve.AbstractKrylovSubspaceMethod end
LinearSolve.needs_square_A(::MyAlg) = trueUse algorithm_interface_issues to check a custom algorithm before passing it to init or solve.
LinearSolve.AbstractFactorization — Type
AbstractFactorization <: SciMLLinearSolveAlgorithmAbstract type for linear solvers that work by computing a matrix factorization. These algorithms typically decompose the matrix A into a product of simpler matrices (e.g., A = LU, A = QR, A = LDL') and then solve the system using forward/backward substitution.
Interface
Factorization algorithms receive a concrete representation of A, normally factorize it when cache.isfresh is true, store the factorization in cache.cacheval, and return a SciMLBase.build_linear_solution from solve!. The concrete subtypes are AbstractDenseFactorization and AbstractSparseFactorization.
Examples
LUFactorization, QRFactorization, CholeskyFactorization, UMFPACKFactorization, and KLUFactorization are concrete subtypes.
LinearSolve.AbstractDenseFactorization — Type
AbstractDenseFactorization <: AbstractFactorizationAbstract type for factorization-based linear solvers optimized for dense matrices. These algorithms assume the matrix has no particular sparsity structure and use dense linear algebra routines (typically from BLAS/LAPACK) for optimal performance.
Interface
Use this supertype when the algorithm needs the entries of a dense A to build a factorization. The default needs_concrete_A is true and the default aliasing traits are false, preserving the caller's matrix while a factorization is built.
Examples
LUFactorization, QRFactorization, CholeskyFactorization, and BunchKaufmanFactorization are concrete subtypes.
LinearSolve.AbstractSparseFactorization — Type
AbstractSparseFactorization <: AbstractFactorizationAbstract type for factorization-based linear solvers optimized for sparse matrices. These algorithms take advantage of sparsity patterns to reduce memory usage and computational cost compared to dense factorizations.
Interface
Use this supertype when the algorithm can preserve and exploit sparse structure. The default needs_concrete_A, default_alias_A, and default_alias_b traits are appropriate for the usual non-mutating sparse factorization workflow. An algorithm that mutates its input must override the aliasing traits and document that requirement.
Examples
UMFPACKFactorization, KLUFactorization, CHOLMODFactorization, SparspakFactorization, and ParUFactorization are concrete subtypes.
LinearSolve.AbstractKrylovSubspaceMethod — Type
AbstractKrylovSubspaceMethod <: SciMLLinearSolveAlgorithmAbstract type for iterative linear solvers based on Krylov subspace methods. These algorithms solve linear systems by iteratively building an approximation from a sequence of Krylov subspaces, without requiring explicit matrix factorization.
Interface
Use this supertype for algorithms that can solve from matrix-vector products without materializing A. needs_concrete_A defaults to false. The implementation reads the right-hand side and tolerances from LinearCache, uses cache.Pl and cache.Pr when it supports preconditioning, writes into cache.u, and returns a SciMLBase.build_linear_solution.
Examples
Krylov wrappers such as KrylovJL_GMRES, KrylovJL_CG, and IterativeSolversJL_GMRES are concrete subtypes. A matrix-free implementation must support the mul! operations required by its algorithm.
LinearSolve.AbstractSolveFunction — Type
AbstractSolveFunction <: SciMLLinearSolveAlgorithmAbstract type for linear solvers that wrap custom solving functions or provide direct interfaces to specific solve methods. These provide flexibility for integrating custom algorithms or simple solve strategies.
Interface
Use this supertype for an algorithm that delegates solving to a callable or a specialized direct operation. needs_concrete_A defaults to false, but the wrapped implementation is responsible for accepting the operator types that the algorithm advertises. The callable must return a solution compatible with cache.u.
Examples
LinearSolveFunction wraps a user callable, while DirectLdiv! delegates to Julia's ldiv! implementation.
Core Cache System
The caching system is central to LinearSolve.jl's performance and functionality:
LinearSolve.LinearCache — Type
LinearCache{TA, Tb, Tu, Tp, Talg, Tc, Tl, Tr, Ttol, issq, S}The mutable state passed to a linear solver algorithm by init and reused by solve!. Construct it with SciMLBase.init(::LinearProblem, alg) rather than calling the constructor directly.
Fields
A::TA: Operator or matrix for the system.b::Tb: Right-hand side. It may be a vector or a matrix of right-hand sides.u::Tu: Preallocated solution storage written bysolve!.p::Tp: Problem parameters forwarded to the algorithm.alg::Talg: Algorithm instance used by this cache.cacheval::Tc: Algorithm-owned factorization, workspace, or solver object.isfresh::Bool: Whethercachevalmust be rebuilt becauseAchanged.precsisfresh::Bool: Whether the preconditioners must be refreshed.Pl::Tl: Left preconditioner, ornothing.Pr::Tr: Right preconditioner, ornothing.abstol::Ttol: Absolute convergence tolerance.reltol::Ttol: Relative convergence tolerance.maxiters::Int: Maximum iteration count for iterative algorithms.verbose::Tlv: Verbosity specification.assumptions::OperatorAssumptions{issq}: Properties promised aboutA.sensealg::S: Sensitivity algorithm associated with the solve.sparse_reduction::Tred: State for persistent sparse-pattern reduction, ornothing.alias_A::Bool: Whether the caller permits replacing or mutatingA.
Interface rules
An algorithm's solve! method may update u, cacheval, and the freshness flags, but must preserve the meaning of the other fields. When isfresh is true, rebuild any factorization or backend object that depends on A; after doing so, set it to false. Algorithms that read tolerances at solve time use abstol, reltol, and maxiters directly. Algorithms that copy tolerances into cacheval must implement update_tolerances_internal!.
Examples
prob = LinearProblem(A, b)
cache = init(prob, LUFactorization())
sol = solve!(cache)
cache.b = b2
sol2 = solve!(cache)LinearSolve.init_cacheval — Function
init_cacheval(alg::SciMLLinearSolveAlgorithm, args...)Initialize algorithm-specific cache values for the given linear solver algorithm. This function returns nothing by default and is intended to be overloaded by specific algorithm implementations that need to store intermediate computations or factorizations.
Arguments
alg: The linear solver algorithm instanceargs...: Additional arguments passed to the cache initialization
Returns
Algorithm-specific cache value or nothing for algorithms that don't require caching.
cache.cacheval = NamedTuple(LUFactorization = cache of LUFactorization, ...)
Algorithm Selection
The automatic algorithm selection is one of LinearSolve.jl's key features:
LinearSolve.defaultalg — Function
defaultalg(A, b, assumptions::OperatorAssumptions)Select a default linear solver algorithm for the operator A, right-hand side b, and operator assumptions. This is the dispatch point used by solve(::LinearProblem) when no algorithm is supplied explicitly.
Arguments
A: Matrix, factorization, or abstract operator to solve with.b: Right-hand side vector or matrix.assumptions:OperatorAssumptionsdescribing whetherAis square, its conditioning, and its structural-zero behavior.
Returns
A concrete SciMLLinearSolveAlgorithm, usually wrapped in a DefaultLinearSolver, selected for the input representation and available extensions.
Examples
A = rand(100, 100)
b = rand(100)
alg = defaultalg(A, b, OperatorAssumptions(true))
solve(LinearProblem(A, b), alg)For an abstract matrix-free operator, the default is a Krylov algorithm when the operator does not provide a direct solve method:
A = SciMLOperators.MatrixOperator(rand(10, 10))
b = rand(10)
alg = defaultalg(A, b, OperatorAssumptions(true))Notes
The two-argument form assumes a square system. Use an explicit algorithm when the application requires a particular factorization or iterative method.
LinearSolve.get_tuned_algorithm — Function
get_tuned_algorithm(::Type{eltype_A}, ::Type{eltype_b}, matrix_size) where {eltype_A, eltype_b}Get the tuned algorithm preference for the given element type and matrix size. Returns nothing if no preference exists. Uses preloaded constants for efficiency. Fast path when no preferences are set.
LinearSolve.is_algorithm_available — Function
is_algorithm_available(alg::DefaultAlgorithmChoice.T)Check if the given algorithm is currently available (extensions loaded, etc.).
LinearSolve.show_algorithm_choices — Function
show_algorithm_choices()Print a report of the dense default algorithm selection to stdout and return nothing. Takes no arguments. Use it to check whether autotune preferences are set and took effect, or to see which LU variant solve(prob) will pick on this machine.
The report has three parts, followed by a short legend of the size categories:
- Current Preferences: the Preferences.jl entries
best_algorithm_<eltype>_<size>andbest_always_loaded_<eltype>_<size>stored for LinearSolve (typically written toLocalPreferences.tomlby LinearSolveAutotune.jl) for the eltypesFloat32,Float64,ComplexF32,ComplexF64and the size categoriestiny(n <= 20),small(21-100),medium(101-300),large(301-1000),big(> 1000), or "No autotune preferences currently set." if there are none. - Default Algorithm Choices: a table of the algorithm
defaultalgreturns for a dense random square matrix (withOperatorAssumptions(true)) of each eltype at one representative size per category: 8, 50, 200, 500, and 1500. Sizes of 10 or less always resolve toGenericLUFactorization. - System Information: whether MKL and Apple Accelerate are available and whether RecursiveFactorization.jl is enabled.
Preferences are read into constants when LinearSolve is compiled, so a preference set in the current session shows up in the first section but only changes the second section (and actual solves) after Julia is restarted.
LinearSolve.make_preferences_dynamic! — Function
make_preferences_dynamic!()Internal function for testing only. Makes preferences dynamic by redefining gettunedalgorithm to check preferences at runtime instead of using compile-time constants. This allows tests to verify that the preference system works correctly.
Preference System Architecture
The dual preference system provides intelligent algorithm selection with comprehensive fallbacks:
Core Functions
get_tuned_algorithm: Retrieves tuned algorithm preferences based on matrix size and element typeis_algorithm_available: Checks if a specific algorithm is currently available (extensions loaded)show_algorithm_choices: Analysis function displaying algorithm choices for all element typesmake_preferences_dynamic!: Testing function that enables runtime preference checking
Size Categorization
The system categorizes matrix sizes to match LinearSolveAutotune benchmarking:
- tiny: ≤20 elements (matrices ≤10 always override to GenericLU)
- small: 21-100 elements
- medium: 101-300 elements
- large: 301-1000 elements
- big: >1000 elements
SupernodalLU Panel Benchmarking
LinearSolve.supernodal_panel_solve! — Function
supernodal_panel_solve!(W, B, np; operation, algorithm = :auto)Apply a supernodal triangular-panel operation using the requested backend.
Arguments
W: Matrix containing the factored diagonal block.B: Panel or right-hand side to update in place.np: Width of the diagonal block inW.
Keywords
operation: which triangular operation to apply. One of:factor_right_upper:B := B / U11, a right solve with the non-unit upper triangle (used during numeric factorization to formL21).:factor_lower:B := L11 \ B, a left solve with the unit-lower triangle (used during numeric factorization to formU12).:lower:B := L11 \ B, the unit-lower forward substitution of the solve phase.:upper:B := U11 \ B, the non-unit upper back substitution of the solve phase.
Any other symbol throws an
ArgumentError.:factor_lowerand:lowercompute the same result; they differ only in which backend code path eachalgorithmroutes them to (see below).algorithm: backend to dispatch to throughsupernodal_panel_solve_backend!. Defaults to:auto. Accepted values::kernel: the in-tree column-oriented kernels (generic over the element type, allocation-free) for:lower/:upper; the:factor_*operations are forwarded to:triangularsolve.:blas:BLAS.trsm!for:lower/:upperwhenWandBare stridedBlasFloatmatrices, the kernels for other element types; the:factor_*operations are forwarded to:triangularsolve.:triangularsolve:LinearAlgebra.ldiv!/rdiv!on the triangular wrappers, replaced by TriangularSolve.jl kernels for stridedFloat32andFloat64panels when RecursiveFactorization.jl and TriangularSolve.jl are loaded.:auto::factor_right_upperand:factor_loweralways go to:triangularsolve.:lowerand:upperuse:kernelwhennp <= PANEL_KERNEL_MAX_NP(256), whenBhas a single column, or when the element type is not aBlasFloat; otherwise:blaswhennp > PANEL_BLAS_MIN_NP(1792) and:triangularsolvein between.
Returns
The updated B.
The TriangularSolve.jl backend is only active when both RecursiveFactorization.jl and TriangularSolve.jl are loaded; using RecursiveFactorization is enough, since RecursiveFactorization.jl depends on TriangularSolve.jl. Without them :triangularsolve routes :lower/:upper back to :blas and the :factor_* operations to the stdlib triangular solves.
LinearSolve.supernodal_panel_solve_backend! — Function
supernodal_panel_solve_backend!(algorithm, W, B, np; operation)Backend extension hook for supernodal_panel_solve!.
Interface rules
An extension may specialize algorithm::Val for supported operand types. The method must apply operation to B in place, return B, and treat the factored diagonal block W[1:np, 1:np] as read-only. B may be a view into the remainder of W. Unsupported operations must throw ArgumentError.
The built-in backends use Val(:kernel), Val(:blas), and Val(:triangularsolve). Extensions should add methods only for backend and operand combinations they implement; the generic methods provide the fallback behavior.
Built-in backends
Val(:kernel): runs:lower/:upperthrough the in-tree column-oriented kernels;:factor_right_upper/:factor_lowerare forwarded toVal(:triangularsolve).Val(:blas): runs:lower/:upperthroughBLAS.trsm!whenWandBare stridedBlasFloatmatrices, and through the kernels otherwise;:factor_right_upper/:factor_lowerare forwarded toVal(:triangularsolve).Val(:triangularsolve): the in-tree method runs:factor_right_upperthroughLinearAlgebra.rdiv!withUpperTriangularand:factor_lowerthroughLinearAlgebra.ldiv!withUnitLowerTriangular, and forwards:lower/:uppertoVal(:blas).
This is the extension hook: a package can add a more specific method for Val(:triangularsolve) and supported panel types. The LinearSolveRecursiveFactorizationExt extension defines
supernodal_panel_solve_backend!(::Val{:triangularsolve}, W::StridedMatrix{Tv},
B::StridedMatrix{Tv}, np::Int; operation::Symbol) where {Tv <: Union{Float32, Float64}}which runs all four operations through TriangularSolve.jl and is active once RecursiveFactorization.jl and TriangularSolve.jl are both loaded (using RecursiveFactorization is enough, since it depends on TriangularSolve.jl).
LinearSolve.SupernodalLU.AMD — Module
AMDDirect pure-Julia port of SuiteSparse's AMD (Approximate Minimum Degree) ordering algorithm. Matches the SuiteSparse implementation closely enough to produce identical permutations on the same inputs.
The entry point is amd_order!; supporting routines mirror amd_aat, amd_1, amd_2, amd_postorder and amd_post_tree from SuiteSparse.
LinearSolve.SupernodalLU.AMD.amd_order! — Function
amd_order!(n, Ap, Ai, P; dense_alpha=10.0, aggressive=true) -> (status, lnz)Compute the AMD ordering of the symmetric pattern of A+A'. P is the output permutation. Mirrors amd_order.c. Returns (AMD_OK, lnz) on success, where lnz is the number of off-diagonal nonzeros in L (SuiteSparse's Info[AMD_LNZ]). On failure returns (status, 0.0).
Dual Preference Structure
For each category and element type (Float32, Float64, ComplexF32, ComplexF64):
best_algorithm_{type}_{size}: Overall fastest algorithm from autotunebest_always_loaded_{type}_{size}: Fastest always-available algorithm (fallback)
Preference File Organization
All preference-related functionality is consolidated in src/preferences.jl:
Compile-Time Constants:
AUTOTUNE_PREFS: Preference structure loaded at package importAUTOTUNE_PREFS_SET: Fast path check for whether any preferences are set_string_to_algorithm_choice: Mapping from preference strings to algorithm enums
Runtime Functions:
_get_tuned_algorithm_runtime: Dynamic preference checking for testing_choose_available_algorithm: Algorithm availability and fallback logicshow_algorithm_choices: Comprehensive analysis and display function
Testing Infrastructure:
make_preferences_dynamic!: Eval-based function redefinition for testing- Enables runtime preference verification without affecting production performance
Testing Mode Operation
The testing system uses an elegant eval-based approach:
# Production: Uses compile-time constants (maximum performance)
get_tuned_algorithm(Float64, Float64, 200) # → Uses AUTOTUNE_PREFS constants
# Testing: Redefines function to use runtime checking
make_preferences_dynamic!()
get_tuned_algorithm(Float64, Float64, 200) # → Uses runtime preference loadingThis approach maintains type stability and inference while enabling comprehensive testing.
Algorithm Support Scope
The preference system focuses exclusively on LU algorithms for dense matrices:
Supported LU Algorithms:
LUFactorization,GenericLUFactorization,RFLUFactorizationMKLLUFactorization,AppleAccelerateLUFactorizationSimpleLUFactorization,FastLUFactorization(both map to LU)- GPU LU variants (CUDA, Metal, AMDGPU - all map to LU)
Non-LU algorithms (QR, Cholesky, SVD, etc.) are not included in the preference system as they serve different use cases and are not typically the focus of dense matrix autotune optimization.
Trait Functions
These trait functions help determine algorithm capabilities and requirements. The full set, and which of them an algorithm has to define, is on the Linear Solver Algorithm Interface page.
LinearSolve.needs_concrete_A — Function
needs_concrete_A(alg) -> BoolTrait function that determines whether a linear solver algorithm requires a concrete matrix representation or can work with abstract operators.
Arguments
alg: A linear solver algorithm instance
Returns
true: Algorithm requires a concrete matrix (e.g., for factorization)false: Algorithm can work with abstract operators (e.g., matrix-free methods)
Usage
This trait is used internally by LinearSolve.jl to optimize algorithm dispatch and determine when matrix operators need to be converted to concrete arrays. It is also queried by downstream solvers such as OrdinaryDiffEq.jl and NonlinearSolve.jl to decide whether to assemble a concrete Jacobian, which is why every algorithm must implement it, and why it must be implemented next to the algorithm struct rather than in a package extension: the callers run before the backend package is necessarily loaded.
Algorithm-Specific Behavior
AbstractFactorization:true(needs explicit matrix entries for factorization)AbstractKrylovSubspaceMethod:false(only needs matrix-vector products)AbstractSolveFunction:false(depends on the wrapped function's requirements)- Direct subtypes of
SciMLLinearSolveAlgorithm: no default; defining this is required
Example
needs_concrete_A(LUFactorization()) # true
needs_concrete_A(GMRESIteration()) # falseUtility Functions
Various utility functions support the core functionality:
LinearSolve.default_tol — Function
default_tol(T)Compute the default tolerance for iterative linear solvers based on the element type. The tolerance is typically set as the square root of the machine epsilon for the given floating point type, ensuring numerical accuracy appropriate for that precision.
Arguments
T: The element type of the linear system
Returns
- For floating point types:
√(eps(T)) - For exact types (Rational, Integer):
0(exact arithmetic) - For Any type:
0(conservative default)
LinearSolve.default_alias_A — Function
default_alias_A(alg, A, b) -> BoolDetermine the default aliasing behavior for the matrix A given the algorithm type. Aliasing allows the algorithm to modify the original matrix in-place for efficiency, but this may not be desirable or safe for all algorithm types.
Arguments
alg: The linear solver algorithmA: The matrix operatorb: The right-hand side vector
Returns
false: Safe default, algorithm will not modify the original matrixAtrue: Algorithm may modifyAin-place for efficiency
Algorithm-Specific Behavior
- Dense factorizations:
false(destructive, need to preserve original) - Krylov methods:
true(non-destructive, safe to alias) - Sparse factorizations:
true(typically preserve sparsity structure)
LinearSolve.default_alias_b — Function
default_alias_b(alg, A, b) -> BoolDetermine the default aliasing behavior for the right-hand side vector b given the algorithm type. Similar to default_alias_A but for the RHS vector.
Returns
false: Safe default, algorithm will not modify the original vectorbtrue: Algorithm may modifybin-place for efficiency
LinearSolve.__init_u0_from_Ab — Function
__init_u0_from_Ab(A, b)Initialize the solution vector u0 with appropriate size and type based on the matrix A and right-hand side b. The solution vector is allocated with the same element type as b and sized to match the number of columns in A.
Arguments
A: The matrix operator (determines solution vector size)b: The right-hand side vector (determines element type)
Returns
A zero-initialized vector of size (size(A, 2),) with element type matching b. For a matrix (batched) right-hand side b of size (size(A, 1), k), returns a zero-initialized matrix of size (size(A, 2), k) so that each column of u0 corresponds to a column of b.
Specializations
- For static matrices (
SMatrix): Returns a static vector (SVector) - For regular matrices: Returns a similar vector to
bwith appropriate size
Solve Functions
The user-facing solve-function algorithms are documented in the solver reference.
The generic CommonSolve.solve! method is the developer entry point used by LinearSolve's cache-based algorithms:
CommonSolve.solve! — Function
solve!(cache::LinearCache, args...; adjoint = false, kwargs...)adjoint = true solves adjoint(A) x = b instead of A x = b, reusing the factorization the cache already holds rather than factorizing the adjoint afresh:
cache = init(LinearProblem(A, b))
x = solve!(cache).u
cache.b = c
lambda = solve!(cache; adjoint = true).u # adjoint(A) lambda = c, same factorizationAlgorithms that have not opted into reusing their factorization for an adjoint solve fall back to factorizing adjoint(A), so the keyword is always answerable. The solution is written into cache.u as usual.
Preconditioner Infrastructure
The preconditioner system allows for flexible preconditioning strategies:
LinearSolve.ComposePreconditioner — Type
ComposePreconditioner{Ti, To}A preconditioner that composes two preconditioners by applying them sequentially. The inner preconditioner is applied first, followed by the outer preconditioner. This allows for building complex preconditioning strategies by combining simpler ones.
Fields
inner::Ti: The inner (first) preconditioner to applyouter::To: The outer (second) preconditioner to apply
Usage
# Compose a diagonal preconditioner with an ILU preconditioner
inner_prec = DiagonalPreconditioner(diag(A))
outer_prec = ILUFactorization()
composed = ComposePreconditioner(inner_prec, outer_prec)The composed preconditioner applies: outer(inner(x)) for any vector x.
Mathematical Interpretation
For a linear system Ax = b, if P₁ is the inner and P₂ is the outer preconditioner, then the composed preconditioner effectively applies P₂P₁ as the combined preconditioner.
LinearSolve.InvPreconditioner — Type
InvPreconditioner{T}A preconditioner wrapper that treats a matrix or operator as if it represents the inverse of the actual preconditioner. Instead of solving Px = y, it computes P*y where P is stored as the "inverse" preconditioner matrix.
Fields
P::T: The stored preconditioner matrix/operator (representingP⁻¹)
Usage
This is useful when you have a matrix that approximates the inverse of your desired preconditioner. For example, if you have computed an approximate inverse matrix Ainv ≈ A⁻¹, you can use:
prec = InvPreconditioner(Ainv)Mathematical Interpretation
For a linear system Ax = b with preconditioner M, normally we solve M⁻¹Ax = M⁻¹b. With InvPreconditioner, the stored matrix P represents M⁻¹ directly, so applying the preconditioner becomes a matrix-vector multiplication rather than a linear solve.
Methods
ldiv!(A::InvPreconditioner, x): Computesx ← P*x(in-place)ldiv!(y, A::InvPreconditioner, x): Computesy ← P*xmul!(y, A::InvPreconditioner, x): Computesy ← P⁻¹*x(inverse operation)
Internal Algorithm Types
LUSolver is an internal implementation detail. The user-facing factorization algorithms are documented in the solver reference.
Developer Notes
Adding New Algorithms
When adding a new linear solver algorithm to LinearSolve.jl:
- Choose the appropriate abstract type: Inherit from the most specific abstract type that fits your algorithm
- Implement the required methods:
SciMLBase.solve!andneeds_concrete_A, plusinit_cachevalif the algorithm caches anything - Define traits next to the struct: never in a package extension — see Linear Solver Algorithm Interface
- Check compliance:
LinearSolve.algorithm_interface_issues(alg)should come back empty - Document thoroughly: Add comprehensive docstrings following the patterns shown here
Performance Considerations
- The
LinearCachesystem is designed for efficient repeated solves - Use
cache.isfreshto avoid redundant computations when the matrix hasn't changed - Consider implementing specialized
init_cachevalfor algorithms that need setup - Leverage trait functions to optimize dispatch and memory usage
Testing Guidelines
When adding new functionality:
- Test with various matrix types (dense, sparse, GPU arrays)
- Verify caching behavior works correctly
- Ensure trait functions return appropriate values
- Test integration with the automatic algorithm selection system
Every algorithm the package knows about is swept against the algorithm interface in test/Core/interface.jl; a new algorithm is covered by that sweep automatically.