Sparse linalg API#
The linalg namespace contains sparse-native solvers and factorizations. Public
functions accept CSRArray, COOArray, and CSCArray inputs, dense
arrays are not silently converted because dense linear algebra belongs in
mlx.linalg. COO and CSC inputs are normalized once at solver entry. The
native sparse kernels use CSR, Accelerate-enabled direct solves normalize
supported real inputs to canonical CSC before calling Apple’s framework.
See also
See Solvers for the solver support matrix, including Full CPU + GPU, CPU only, GPU only, Partial, and Accelerate coverage labels.
Iterative solvers#
- mlx_sparse.linalg.cg(A, b, *, x0=None, rtol=1e-05, atol=0.0, maxiter=None, M=None, callback=None, return_info=False)[source]#
Solve a sparse SPD linear system with the conjugate gradient method.
Conjugate gradients (CG) is an iterative Krylov solver for symmetric positive-definite (SPD) systems
A @ x = b. Each iteration requires one sparse matrix-vector product dispatched to a Metal kernel via the native CSR engine. CG converges in at mostnsteps in exact arithmetic and typically far fewer for well-conditioned problems.- GPU note:
When GPU execution is selected, the native CG iteration runs in a Metal kernel. Sparse matrix-vector products, vector updates, dot products, and residual checks stay on the GPU. Python argument validation and conversion of the returned
infoflag to a Python integer happen on the host.
- Parameters:
A – Coefficient matrix. Must be a
CSRArray,COOArray, orCSCArraythat is symmetric positive-definite. A sparse-backedLinearOperatoris also accepted. A fully matrix-freeLinearOperatoruses a documented host fallback loop.b – Right-hand side vector of shape
(n,). Must be a rank-1mlx.core.arrayor anything convertible to one.x0 – Initial guess of shape
(n,). Defaults to the zero vector whenNone.rtol (float) – Relative tolerance. The solver stops when
||r_k|| <= max(atol, rtol * ||b||). Defaults to1e-5.atol (float) – Absolute tolerance floor. Useful when
bis near zero. Defaults to0.0.maxiter (int | None) – Maximum number of iterations. Defaults to
10 * nwhenNone.M – Optional native-backed preconditioner.
Noneuses the existing unpreconditioned native CG path.preconditioners.identityalso uses that path.preconditioners.diagonalandpreconditioners.jacobidispatch to native Jacobi-preconditioned CG.preconditioners.ichol0dispatches to a native CPU IC(0)-preconditioned CG loop whose preconditioner application uses the stored incomplete Cholesky factors.preconditioners.chebyshevdispatches to a native Chebyshev-polynomial PCG loop whose preconditioner application uses only sparse matrix-vector products and vector updates. Fully matrix-freeLinearOperatorinputs accept arbitrary inverse-apply objects and callables through a slower host fallback.callback – Optional callable invoked once after the native solve completes. Native CPU/Metal Krylov loops do not call Python inside each iteration; using a callback synchronizes only the final solution.
return_info (bool) – If
True, return a structured diagnostic object instead of the integerinfoflag. The default remainsFalse.
- Returns:
A tuple
(x, info)wherexis the approximate solution array of shape(n,)andinfois an integer convergence flag by default. Withreturn_info=True,infois aSolverInfodiagnostic object.info == 0means the solver converged to the requested tolerance.info > 0is the iteration count at which the solver stopped without converging.info < 0indicates numerical breakdown, such as a non-positive preconditioned residual product, non-finite scalar, or scale-aware near-zero denominator.- Raises:
TypeError – If
Ais a densemlx.core.arrayor an unsupported type, or ifMis not a native-backed identity, diagonal, or Jacobi preconditioner.ValueError – If
bis not rank-1 or its length does not matchA.shape[0].
Example
Build a 2-D Poisson Laplacian and solve it with CG:
import mlx.core as mx import numpy as np import scipy.sparse import mlx_sparse as ms from mlx_sparse import linalg n = 16 L = scipy.sparse.diags([-1, 4, -1], [-1, 0, 1], shape=(n, n), format='csr').astype(np.float32) A = ms.csr_array( (mx.array(L.data), mx.array(L.indices), mx.array(L.indptr)), shape=L.shape, canonical=True, ) b = mx.ones((n,), dtype=mx.float32) x, info = linalg.cg(A, b, rtol=1e-6) print(info) # 0 means converged
- mlx_sparse.linalg.gmres(A, b, *, x0=None, rtol=1e-05, atol=0.0, restart=None, maxiter=None, M=None, callback=None, callback_type='x', return_info=False)[source]#
Solve a sparse linear system with restarted GMRES.
Generalised Minimum RESidual (GMRES) is an iterative Krylov solver for any non-singular square system
A @ x = b. Unlike CG it does not requireAto be symmetric or positive-definite, making it the default choice for non-symmetric PDEs and general sparse systems.Each restart cycle builds an Arnoldi basis of dimension
restartusing one sparse matrix-vector product per step, then minimises the residual over that Krylov subspace. Memory scales asO(restart * n).- GPU note:
When GPU execution is selected, Arnoldi basis construction uses the native Arnoldi kernel. The restart loop, residual setup, small least-squares solve, solution update, and convergence bookkeeping run on the CPU. The host also copies the Arnoldi basis and Hessenberg coefficients back before updating the solution.
- Parameters:
A – Coefficient matrix. Must be a
CSRArray,COOArray, orCSCArray. A sparse-backedLinearOperatoris also accepted. A fully matrix-freeLinearOperatoruses a documented host fallback loop. Need not be symmetric.b – Right-hand side vector of shape
(n,).x0 – Initial guess of shape
(n,). Defaults to the zero vector.rtol (float) – Relative tolerance for the residual stopping criterion. Defaults to
1e-5.atol (float) – Absolute tolerance floor. Defaults to
0.0.restart (int | None) – Size of the Krylov subspace built before each restart. Larger values accelerate convergence at the cost of more memory. Defaults to
min(20, n).maxiter (int | None) – Maximum total number of matrix-vector products across all restart cycles. Defaults to
10 * n.M – Optional inverse-apply preconditioner.
Noneuses the existing native unpreconditioned GMRES path.preconditioners.identityis treated equivalently.preconditioners.diagonalandpreconditioners.jacobiandpreconditioners.ilu0dispatch to native left-preconditioned GMRES. Custom callables and inverse-apply objects use a host fallback loop. Fully matrix-freeLinearOperatorinputs also accept arbitrary inverse-apply objects and callables through the same slower host loop. All preconditioned paths build Krylov vectors forM^{-1} Awhile convergence is tested against the true residualb - A @ x.callback – Optional callable invoked once after the native solve completes. Native CPU/Metal solver loops do not call Python inside each iteration.
callback_type="x"receives the final solution;"pr_norm"and"legacy"receive the final reported residual norm. The payload names mirror SciPy’s callback vocabulary, but native mlx-sparse paths intentionally do not call Python at every restart or inner iteration.callback_type (str) – One of
"x","pr_norm", or"legacy"."legacy"does not changemaxiteraccounting.return_info (bool) – If
True, return a structured diagnostic object instead of the integerinfoflag. The default remainsFalse.
- Returns:
A tuple
(x, info)wherexis the approximate solution of shape(n,)andinfois an integer convergence flag by default. Withreturn_info=True,infois aSolverInfodiagnostic object.info == 0means the solver converged.info > 0is the iteration count at termination without convergence.- Raises:
TypeError – If
Ais a dense array or an unsupported type.ValueError – If
bis not rank-1, its length does not matchA.shape[0], orrestartis not positive.
- mlx_sparse.linalg.minres(A, b, *, x0=None, rtol=1e-05, atol=0.0, shift=0.0, maxiter=None, M=None, check_preconditioner=True, callback=None, return_info=False)[source]#
Solve a sparse symmetric linear system with MINRES.
MINimum RESidual (MINRES) is an iterative Krylov solver for symmetric systems
A @ x = bwhereAmay be symmetric indefinite (having both positive and negative eigenvalues). It minimises the 2-norm of the residual at every step using a Paige-Saunders Lanczos recurrence and requires only a constant number of vectors in memory, making it more memory-efficient than GMRES for large symmetric indefinite problems.- GPU note:
When GPU execution is selected, the unpreconditioned and diagonal/Jacobi-preconditioned recurrences dispatch to native Metal kernels. The CPU path uses the matching native C++ recurrence. No Python callback is invoked inside the Krylov loop.
- Parameters:
A – Coefficient matrix. Must be a
CSRArray,COOArray, orCSCArraythat is real and symmetric.b – Right-hand side vector of shape
(n,).x0 – Initial guess of shape
(n,). Defaults to the zero vector.rtol (float) – Relative tolerance for the residual stopping criterion. Defaults to
1e-5.atol (float) – Absolute tolerance floor. Defaults to
0.0.shift (float) – Optional scalar shift. The solver applies MINRES to
(A - shift * I) @ x = b, matching SciPy’s convention.maxiter (int | None) – Maximum number of iterations. Defaults to
10 * n.M – Optional symmetric positive-definite inverse-apply preconditioner.
Noneandpreconditioners.identityuse the unpreconditioned path.preconditioners.diagonalandpreconditioners.jacobidispatch to native diagonal-preconditioned MINRES. Other preconditioner kinds are rejected until they have native SPD MINRES kernels.check_preconditioner (bool) – When
True(default), diagonal/Jacobi preconditioners must have finite strictly positive inverse diagonal entries before entering native MINRES. Setting this toFalsedisables the Python-side SPD validation but the native solver still reports numerical breakdown for invalid preconditioners.callback – Optional callable invoked once after the native solve completes. Native CPU/Metal Krylov loops do not call Python inside each iteration; using a callback synchronizes only the final solution.
return_info (bool) – If
True, return a structured diagnostic object instead of the integerinfoflag. The default remainsFalse.
- Returns:
A tuple
(x, info)wherexis the approximate solution of shape(n,)andinfois an integer convergence flag by default. Withreturn_info=True,infois aSolverInfodiagnostic object.info == 0means the solver converged to the requested tolerance.info > 0is the iteration count at which the solver stopped without converging.- Raises:
TypeError – If
Ais a dense array or an unsupported type.ValueError – If
bis not rank-1, its length does not matchA.shape[0], or a checked diagonal preconditioner is not SPD.
Preconditioners#
Native-backed sparse solver preconditioners.
The Python objects in this module are containers and dispatch helpers. Application and Krylov iteration dispatch to native mlx-sparse primitives rather than Python solver loops. Constructors may use existing sparse native kernels and MLX scalar array expressions to build immutable setup data.
- class mlx_sparse.linalg.preconditioners.DiagonalPreconditioner(inverse_diagonal, shape, kind='diagonal', is_symmetric=True, is_positive_definite=False)[source]#
Bases:
objectExplicit diagonal inverse-apply preconditioner.
The stored vector is the inverse diagonal that should multiply each row of a right-hand side. Application dispatches to the native
diagonal_preconditioner_applyprimitive, including rank-2 RHS support.Stored fields include the finite
float32inverse_diagonalvector, the compatible squareshape, the stablekindstring, and symmetry/positive-definiteness metadata.- Parameters:
- inverse_diagonal: mlx.core.array#
- property dtype#
Value dtype of
inverse_diagonal.
- property setup_info: Mapping[str, object]#
Structured metadata describing setup choices and assumptions.
- solve(x)[source]#
Apply the diagonal inverse to a vector or dense RHS matrix.
- Parameters:
x – Right-hand side with shape
(n,)or(n, nrhs).- Returns:
Native-applied
inverse_diagonal[:, None] * xfor matrix RHS, orinverse_diagonal * xfor vector RHS.- Return type:
mlx.core.array
- class mlx_sparse.linalg.preconditioners.CallablePreconditioner(apply, shape, dtype=mlx.core.float32, kind='callable', is_symmetric=False, is_positive_definite=False)[source]#
Bases:
objectPython host inverse-apply preconditioner wrapper.
CallablePreconditioneris the explicit normalization layer for custom inverse-apply objects. The wrapped callable receives a rank-1 or rank-2float32MLX array and must return the same shape containingM^{-1} @ x. Solver integrations may use this wrapper only on documented host fallback paths because each application crosses through Python.Stored fields include the callable
applyobject, compatible squareshape, stablekindmetadata, conservative symmetry/positive definiteness flags, and structured setup information.- Parameters:
- class mlx_sparse.linalg.preconditioners.ChebyshevPreconditioner(A, degree=2, lambda_min=0.0, lambda_max=0.0, estimate=True, spectral_info=<factory>, kind='chebyshev', is_symmetric=True, is_positive_definite=True)[source]#
Bases:
objectPolynomial inverse preconditioner for SPD sparse matrices.
ChebyshevPreconditionerstores a canonicalfloat32CSR operator and applies a fixed-degree first-kind Chebyshev semi-iteration with zero initial guess. Application uses only sparse matrix-vector/matrix products and vector updates, so it follows the selected native CPU or Metal device path without triangular solves or dense factorization.Stored fields include the CSR operator, polynomial
degree, validated positive spectral interval[lambda_min, lambda_max], whether setup used native spectralestimatedata, and detailedspectral_infometadata.- Parameters:
- property dtype#
Value dtype used by the stored operator.
- class mlx_sparse.linalg.preconditioners.ExactFactorPreconditioner(solver, shape, method, backend, kind='exact', is_symmetric=False, is_positive_definite=False, factor_nnz=-1, native_apply_kind=None, native_factorization=None)[source]#
Bases:
objectExact inverse-apply preconditioner backed by a sparse factorization.
This wrapper composes existing direct sparse solve objects with the iterative
Mprotocol. It does not refactorize on application: setup is completed before construction.solve()uses explicit native LU/Cholesky apply bindings when factors are available, uses the guarded Accelerate solver for real Accelerate factorized objects, and otherwise delegates to the stored reusable solve object.Stored fields include the reusable
solver, compatible squareshape, factorizationmethod, implementationbackend, and conservative symmetry/positive-definiteness metadata. Accelerate-backedFactorizedSolveinstances keep their Accelerate CPU apply boundary; native explicit factors keep their native CPU/Metal triangular-solve apply boundary.- Parameters:
- property dtype#
Value dtype used by current sparse direct solve backends.
- property setup_info: Mapping[str, object]#
Structured metadata describing the exact factorization wrapper.
- class mlx_sparse.linalg.preconditioners.IC0Preconditioner(L, shift=0.0, check=True, kind='ichol0', is_symmetric=True, is_positive_definite=True)[source]#
Bases:
objectNatural-order no-fill incomplete Cholesky preconditioner.
IC0Preconditionerstores an explicit lower CSR factorLproduced by native CPU IC(0) setup. The factor uses natural ordering, preserves the symmetric lower sparsity pattern of the canonical CSR input, and introduces no fill. Application performs two native triangular solves,L y = xfollowed byL.T z = y.Stored fields include the lower factor, explicit non-negative diagonal
shiftused during setup, strict positive-pivotcheckmode, and SPD metadata suitable for CG and MINRES-style solvers.- Parameters:
- property dtype#
Value dtype used by the stored factor.
- class mlx_sparse.linalg.preconditioners.ILU0Preconditioner(L, U, shift=0.0, check=True, reuse_analysis=False, kind='ilu0', is_symmetric=False, is_positive_definite=False)[source]#
Bases:
objectNatural-order no-fill incomplete LU preconditioner.
ILU0Preconditionerstores explicit CSR factorsLandUfrom a native CPU ILU(0) setup.Lhas a unit diagonal and the factors preserve the lower/upper sparsity pattern of the canonical CSR input without fill-reducing ordering or pivoting. Application performs the standard forward and backward triangular solvesL y = xandU z = yusing native CSR triangular-solve kernels.Stored fields include the lower/upper CSR factors, explicit diagonal
shiftused during setup, validationcheckmode, optional triangular-analysis reuse flag, and conservative nonsymmetric metadata.- Parameters:
- __post_init__()[source]#
Validate factor metadata and optionally cache triangular analysis.
- Return type:
None
- property dtype#
Value dtype used by the stored factors.
- class mlx_sparse.linalg.preconditioners.IdentityPreconditioner(shape, dtype=mlx.core.float32, kind='identity', is_symmetric=True, is_positive_definite=True)[source]#
Bases:
objectNo-op inverse-apply preconditioner.
IdentityPreconditioneris useful as an explicit baseline and as the normalized representation ofM=Noneinside solver plumbing.Stored fields include the compatible square
shape, the native valuedtype(currentlymlx.core.float32), the stablekindstring, and symmetry/positive-definiteness metadata.- Parameters:
- property setup_info: Mapping[str, object]#
Structured metadata describing setup choices and assumptions.
- class mlx_sparse.linalg.preconditioners.JacobiPreconditioner(inverse_diagonal, shape, kind='jacobi', is_symmetric=True, is_positive_definite=False, omega=1.0, shift=0.0, zero_policy='raise', zero_atol=0.0, checked=False, positive_diagonal=None)[source]#
Bases:
DiagonalPreconditionerJacobi preconditioner built from a sparse matrix diagonal.
JacobiPreconditioneris a specialized diagonal inverse-apply object that records the setup parameters used byjacobi(). Passing it tomlx_sparse.linalg.cg()dispatches to the native Jacobi-PCG primitive.Stored fields include
omega,shift,zero_policy,zero_atol, whether validation waschecked, andpositive_diagonalwhen the cheap positive shifted-diagonal check was requested.- Parameters:
- class mlx_sparse.linalg.preconditioners.Preconditioner(*args, **kwargs)[source]#
Bases:
ProtocolProtocol for objects that apply an approximate inverse.
Solver-facing preconditioners represent the operation
M^{-1} @ x, not the matrixMitself. Implementations expose a squareshape, valuedtype, a stablekindidentifier, symmetry and positive-definiteness metadata, setup/apply device descriptors, effective storagennz, and a structuredsetup_infomapping. The requiredsolve()method and__call__alias must accept rank-1 vector RHS and rank-2 dense RHS matrices without mutating the matrix used during setup.
- mlx_sparse.linalg.preconditioners.aspreconditioner(M, A=None, *, assume_inverse=True)[source]#
Normalize supported preconditioner-like objects.
- Parameters:
M –
None, an existing preconditioner, an object withsolve(x), or a callable. Sparse matrices are rejected because they do not explicitly define an inverse-apply contract.A – Optional reference matrix or shape used to validate compatibility.
assume_inverse (bool) – Must be
Truefor callables and custom objects, documenting that their output is already an inverse/preconditioner application.
- Returns:
A supported preconditioner object.
- Raises:
ValueError – If
Ais required or the preconditioner shape mismatches.TypeError – If
Mis a sparse matrix or unsupported object.
- Return type:
- mlx_sparse.linalg.preconditioners.chebyshev(A, *, degree=2, lambda_min=None, lambda_max=None, estimate=True)[source]#
Create a GPU-friendly Chebyshev polynomial preconditioner.
The setup normalizes
Ato canonical CSR, promotes real low-precision values tofloat32, and computes native Gershgorin spectral bounds plus optional native Lanczos Ritz estimates. The resulting preconditioner applies a fixed-degree first-kind Chebyshev semi-iteration with zero initial guess, using only sparse matrix products and vector updates.- Parameters:
A –
CSRArray,COOArray,CSCArray, or sparse-backedLinearOperatordescribing a real SPD square matrix.degree (int) – Positive polynomial degree. Defaults to
2.lambda_min (float | None) – Optional positive lower spectral bound. If omitted, setup uses a positive Gershgorin lower bound when available, otherwise a conservative Lanczos-derived lower estimate when
estimate=True.lambda_max (float | None) – Optional upper spectral bound. If omitted, setup uses the Gershgorin upper bound when available, with Lanczos metadata recorded for diagnostics.
estimate (bool) – Whether native Lanczos Ritz estimates should be computed as a fallback/refinement for the spectral interval. Defaults to
True.
- Returns:
A
ChebyshevPreconditionerwith native CPU/Metal apply support.- Raises:
ValueError – If no valid positive interval can be established.
- Return type:
- mlx_sparse.linalg.preconditioners.diagonal(inv_diag_or_diag, *, inverse=False, shape=None, dtype=None, zero_atol=0.0)[source]#
Create an explicit diagonal inverse-apply preconditioner.
- Parameters:
inv_diag_or_diag – Rank-1 diagonal values. Interpreted as a diagonal by default, or as an inverse diagonal when
inverse=True.inverse (bool) – If
True, useinv_diag_or_diagdirectly as the inverse diagonal. IfFalse, validate and invert it.shape – Optional square shape. Defaults to
(n, n)wherenis the vector length.dtype – Optional dtype. The current native preconditioner path accepts only
Noneormlx.core.float32.zero_atol (float) – Absolute threshold used when rejecting zero diagonal entries before inversion.
- Returns:
A
DiagonalPreconditionerwith finitefloat32inverse diagonal storage.- Return type:
- mlx_sparse.linalg.preconditioners.exact(A, *, method='auto')[source]#
Factorize
Aonce and return an exact inverse-apply preconditioner.exactis a convenience wrapper aroundmlx_sparse.linalg.factorized(). It is intended as a correctness baseline, diagnostic tool, and composition point for existing direct solvers rather than a performance headline.- Parameters:
A – Sparse coefficient matrix accepted by
mlx_sparse.linalg.factorized().method (str) – Direct factorization method. Defaults to
"auto".
- Returns:
An
ExactFactorPreconditionerwrapping the reusable factorized solve object.- Return type:
- mlx_sparse.linalg.preconditioners.from_factorized(solver)[source]#
Wrap an existing sparse factorization as an exact preconditioner.
- Parameters:
solver – A
FactorizedSolve,SparseLU, orSparseCholeskyinstance.- Returns:
An
ExactFactorPreconditionerwhose inverse application uses a native exact-apply path when the factorization exposes one.- Raises:
TypeError – If
solveris not one of the supported factorization objects.ValueError – If the factorization does not represent a square operator.
- Return type:
- mlx_sparse.linalg.preconditioners.identity(A_or_shape, *, dtype=None)[source]#
Create a no-op preconditioner for a square shape or sparse matrix.
- Parameters:
A_or_shape – Square sparse matrix,
(n, n)shape tuple, or integer dimension.dtype – Optional dtype. The current native solver integration accepts only
Noneormlx.core.float32.
- Returns:
- Return type:
- mlx_sparse.linalg.preconditioners.ichol0(A, *, shift=0.0, check=True)[source]#
Create a natural-order no-fill IC(0) preconditioner.
The setup normalizes
Ato canonical CSR, promotes real low-precision values tofloat32, and runs a native CPU incomplete Cholesky factorization with zero fill and natural ordering. The original sparse matrix is not mutated.shiftis a non-negative scalar added only to existing diagonal entries before setup; a missing diagonal remains an error and no pivot is silently perturbed.- Parameters:
A –
CSRArray,COOArray,CSCArray, or sparse-backedLinearOperatordescribing an SPD square matrix.shift (float) – Explicit non-negative diagonal shift added before factorization. Defaults to
0.0.check (bool) – When
True(default), native setup enforces symmetry for explicitly stored mirrored entries and uses a scale-aware positive pivot guard. WhenFalse, non-positive and non-finite pivots are still rejected, but near-zero pivot and symmetry checks are relaxed.
- Returns:
An
IC0Preconditionerwhose application uses native CSR triangular solvesLandL.T.- Return type:
- mlx_sparse.linalg.preconditioners.ilu0(A, *, shift=0.0, check=True, reuse_analysis=False)[source]#
Create a natural-order no-fill ILU(0) preconditioner.
The setup normalizes
Ato canonical CSR, promotes real low-precision values tofloat32, and runs a native CPU ILU(0) factorization with no fill-reducing ordering and no pivoting. The original sparse matrix is not mutated.shiftis added only to existing diagonal entries before setup; a missing diagonal remains an error.- Parameters:
A –
CSRArray,COOArray,CSCArray, or sparse-backedLinearOperatordescribing a square nonsingular matrix.shift (float) – Explicit diagonal shift added before factorization.
check (bool) – When
True(default), native setup uses a scale-aware near-zero pivot guard. WhenFalse, only exact zero and non-finite pivots are rejected during setup.reuse_analysis (bool) – When
True, cache triangular diagonal-position and level-schedule analysis for repeated explicitM(rhs)calls. The default isFalsebecause v0.0.4b1 triangular-analysis benchmarks showed this must be workload-measured before enabling.
- Returns:
An
ILU0Preconditionerwhose application uses native CSR triangular solves.- Return type:
- mlx_sparse.linalg.preconditioners.jacobi(A, *, omega=1.0, shift=0.0, zero_policy='raise', zero_atol=0.0, check=False)[source]#
Create a Jacobi preconditioner from a sparse matrix diagonal.
The inverse diagonal is computed as
omega / (diag(A) + shift)after normalizingAto canonical CSR so duplicate diagonal entries are summed. The input sparse matrix is never mutated.- Parameters:
A –
CSRArray,COOArray,CSCArray, or sparse-backedLinearOperator.omega (float) – Damping/weighting factor.
shift (float) – Explicit diagonal shift applied before inversion.
zero_policy (str) –
"raise"rejects zero/near-zero shifted diagonals."unit"replaces those entries with1before inversion.zero_atol (float) – Absolute threshold used to identify near-zero shifted diagonal entries.
check (bool) – When
True, requireomega > 0and a strictly positive shifted diagonal before anyzero_policyreplacement, then mark the preconditioner as positive definite.
- Returns:
A
JacobiPreconditionersuitable for native PCG.- Return type:
Spectral routines#
- mlx_sparse.linalg.lanczos(A, k, *, v0=None, reorthogonalize=True, return_basis=True)[source]#
Run the Lanczos iteration on a sparse symmetric matrix.
Builds a Krylov basis of dimension
kfor the symmetric matrixAusing the Lanczos three-term recurrence. The basis vectors, together with the tridiagonal matrix they define, contain the information needed to approximate eigenvalues and eigenvectors via the Ritz pairs ofA.This is a low-level routine. For eigenvalue computation, prefer
eigsh()which calls Lanczos internally and returns the final eigenpairs directly.- GPU note:
When GPU execution is selected, the Lanczos recurrence runs in a Metal kernel. Sparse matrix-vector products, orthogonalisation, tridiagonal coefficients, and basis writes stay on the GPU. Python argument validation and returned array handling happen on the host.
- Parameters:
A – Symmetric sparse matrix. Must be a
CSRArray,COOArray, orCSCArray. Float16 and bfloat16 inputs are promoted to float32.k (int) – Number of Lanczos steps. Must satisfy
0 < k <= A.shape[0].v0 – Optional starting vector of shape
(n,).Noneuses the deterministic all-ones start vector.reorthogonalize (bool) – Whether to apply full reorthogonalisation at each step to suppress numerical loss of orthogonality. Defaults to
True.return_basis (bool) – When
True(the default), return the Lanczos basis matrixQin addition to the tridiagonal coefficients.
- Returns:
When
return_basis=True, a tuple(alphas, betas, Q)wherealphasis the diagonal of shape(k,),betasis the sub-diagonal of shape(k-1,)or(k,), andQis the basis matrix of shape(n, k). Whenreturn_basis=False, returns(alphas, betas)without the basis.- Raises:
ValueError – If
kis out of range.
- mlx_sparse.linalg.eigsh(A, k=6, *, which='LM', v0=None, ncv=None, maxiter=None, tol=0.0, return_eigenvectors=True)[source]#
Compute a few eigenpairs of a sparse symmetric matrix.
Uses the native CSR Lanczos-based eigensolver to find the
keigenpairs of the real symmetric (Hermitian) sparse matrixAthat match the criterion specified bywhich. Each Lanczos step dispatches a sparse matrix-vector product to the GPU via the native Metal kernel.- GPU note:
When GPU execution is selected, Lanczos tridiagonalisation uses the native Lanczos kernel. The small tridiagonal eigensolve, Ritz pair selection, and eigenvector back transformation run on the CPU after the basis and coefficients are copied back to host memory.
- Parameters:
A – Real symmetric sparse matrix. Must be a
CSRArray,COOArray, orCSCArray. Float16 and bfloat16 inputs are promoted to float32.k (int) – Number of eigenpairs to compute. Must satisfy
0 < k < A.shape[0]. Defaults to6.which (str) –
Which eigenpairs to return. Accepted values:
"LM": eigenvalues Largest in Magnitude (default)"SM": eigenvalues Smallest in Magnitude"LA": Largest Algebraic (largest values)"SA": Smallest Algebraic (smallest values)
v0 – Optional starting vector of shape
(n,).Noneuses the deterministic all-ones start vector.ncv (int | None) – Number of Lanczos basis vectors to build before extracting Ritz pairs. A larger value improves accuracy at the cost of more memory. Defaults to
max(2*k+1, k+1).maxiter (int | None) – Not yet supported because the current implementation performs one
ncv-bounded Ritz extraction, not an implicitly restarted convergence loop. PassNone(the default).tol (float) – Not yet supported for the same reason. Pass
0.0(the default).return_eigenvectors (bool) – When
True(the default), return both eigenvalues and eigenvectors. WhenFalse, return only the eigenvalues.
- Returns:
When
return_eigenvectors=True, a tuple(values, vectors)wherevalueshas shape(k,)andvectorshas shape(n, k). Whenreturn_eigenvectors=False, returnsvaluesalone.- Raises:
NotImplementedError – If
maxiterortolare not at their default values.ValueError – If
kis out of range orAis not square.
- mlx_sparse.linalg.eigs(A, k=6, *, which='LM', v0=None, ncv=None, maxiter=None, tol=0.0, return_eigenvectors=True)[source]#
Compute a few eigenpairs of a general sparse square matrix.
Uses the native CSR Arnoldi-based eigensolver (an implicitly restarted Arnoldi method) to find the
keigenpairs of the general (possibly non-symmetric) sparse matrixAthat match the criterion specified bywhich. Each Arnoldi step dispatches a sparse matrix-vector product to the GPU via the native Metal kernel.For symmetric matrices,
eigsh()is faster and more accurate because it uses the symmetric Lanczos recurrence instead of the full Arnoldi factorization.- GPU note:
When GPU execution is selected, Arnoldi factorisation uses the native Arnoldi kernel. The small Hessenberg eigensolve, Ritz value selection, and output vector assembly run on the CPU after the basis and Hessenberg matrix are copied back to host memory.
- Parameters:
A – Sparse square matrix. Must be a
CSRArray,COOArray, orCSCArray. Float16 and bfloat16 inputs are promoted to float32.k (int) – Number of eigenpairs to compute. Must satisfy
0 < k < A.shape[0]. Defaults to6.which (str) –
Which eigenpairs to return. Accepted values:
"LM": eigenvalues Largest in Magnitude (default)"SM": eigenvalues Smallest in Magnitude"LR": Largest Real part"SR": Smallest Real part
v0 – Optional starting vector of shape
(n,).Noneuses the deterministic all-ones start vector.ncv (int | None) – Dimension of the Arnoldi factorization before restart. Defaults to
max(2*k+1, k+1).maxiter (int | None) – Not yet supported because the current implementation performs one
ncv-bounded Ritz extraction, not an implicitly restarted convergence loop. PassNone(the default).tol (float) – Not yet supported for the same reason. Pass
0.0(the default).return_eigenvectors (bool) – When
True(the default), return both eigenvalues and eigenvectors. WhenFalse, return only the eigenvalues.
- Returns:
When
return_eigenvectors=True, a tuple(values, vectors)wherevalueshas shape(k,)andvectorshas shape(n, k). Whenreturn_eigenvectors=False, returnsvaluesalone.- Raises:
NotImplementedError – If
maxiterortolare not at their default values.ValueError – If
kis out of range orAis not square.
- mlx_sparse.linalg.svds(A, k=6, *, which='LM', v0=None, ncv=None, maxiter=None, tol=0.0, return_singular_vectors=True)[source]#
Compute a few singular triplets of a sparse matrix.
Uses the native CSR Lanczos iteration applied to the normal operator
A.T @ Ato find theksingular triplets (left singular vectors, singular values, and right singular vectors) of the sparse matrixAthat match the criterion specified bywhich.- GPU note:
When GPU execution is selected, the normal-operator Lanczos recurrence uses a dedicated native
A.T @ (A @ v)path. The two sparse products are kept inside one native step and the intermediateA @ vvector is not materialized on the host. The small tridiagonal eigensolve, Ritz vector back transformation, and returned singular-vector assembly still run on the CPU after the Lanczos basis is synchronized.
- Parameters:
A – Sparse matrix of shape
(m, n). Must be aCSRArray,COOArray, orCSCArray. Float16 and bfloat16 inputs are promoted to float32.k (int) – Number of singular triplets to compute. Must satisfy
0 < k < min(A.shape). Defaults to6.which (str) –
Which singular values to return. Accepted values:
"LM": Largest in Magnitude (default)"SM": Smallest in Magnitude
v0 – Optional starting vector for the right singular-vector Krylov basis, with shape
(A.shape[1],).Noneuses the deterministic all-ones vector.ncv (int | None) – Number of Lanczos basis vectors to build. Defaults to
max(2*k+1, k+1).maxiter (int | None) – Not yet supported because the current implementation performs one
ncv-bounded normal-operator Ritz extraction. PassNone(the default).tol (float) – Not yet supported for the same reason. Pass
0.0(the default).return_singular_vectors (bool | str) –
Controls which vectors are returned.
True: return(u, s, vh)(default)False: return onlys(the singular values)"u": return(u, s, None)"vh": return(None, s, vh)
- Returns:
When
return_singular_vectors=True, a tuple(u, s, vh)whereuhas shape(m, k),shas shape(k,), andvhhas shape(k, n). Seereturn_singular_vectorsfor other forms.- Raises:
NotImplementedError – If
maxiterortolare not at their default values.ValueError – If
kis out of range orreturn_singular_vectorsis not a recognised value.
Sparse direct factorizations#
- mlx_sparse.linalg.sparse_cholesky(A, *, upper=False)[source]#
Compute the sparse Cholesky factorization
A = L @ L.T.Performs a left-looking sparse Cholesky factorization on a real symmetric positive-definite (SPD) matrix stored in CSR, COO, or CSC format. COO/CSC inputs are converted once to canonical CSR before factorization. The resulting lower-triangular factor
Lis returned as aSparseCholeskyobject whosesolve()method applies both triangular solves in sequence.- GPU note:
The factorization step runs on the CPU using the native sparse routine. The resulting
SparseCholesky.solvedispatches triangular-solve kernels to the GPU when GPU execution is selected.
- Parameters:
- Returns:
A
SparseCholeskydataclass holding the lower-triangular factorLas aCSRArray.- Raises:
NotImplementedError – If
upper=True.TypeError – If
Ais a dense array or has an unsupported dtype.
- Return type:
Example
Factorize a small SPD matrix and solve a linear system:
import mlx.core as mx import numpy as np import scipy.sparse import mlx_sparse as ms from mlx_sparse import linalg n = 8 L_sp = scipy.sparse.diags([-1, 4, -1], [-1, 0, 1], shape=(n, n), format='csr').astype(np.float32) A = ms.csr_array( (mx.array(L_sp.data), mx.array(L_sp.indices), mx.array(L_sp.indptr)), shape=L_sp.shape, canonical=True, ) factor = linalg.sparse_cholesky(A) b = mx.ones((n,), dtype=mx.float32) x = factor.solve(b)
- mlx_sparse.linalg.cholesky(A, *, upper=False)[source]#
Alias for
sparse_cholesky().Provided for compatibility with SciPy-style naming. All arguments and return values are identical to
sparse_cholesky().- GPU note:
The factorization step runs on the CPU. The returned factor uses GPU triangular-solve kernels when GPU execution is selected.
- Parameters:
- Returns:
A
SparseCholeskyholding the lower-triangular factorL.- Return type:
- mlx_sparse.linalg.sparse_lu(A)[source]#
Compute the sparse LU factorization
P @ A = L @ U.Performs a sparse LU factorization with partial pivoting on a general (possibly non-symmetric) real square matrix stored in CSR, COO, or CSC format. COO/CSC inputs are converted once to canonical CSR before factorization. The row permutation
P, unit lower-triangular factorL, and upper-triangular factorUare returned as aSparseLUobject whosesolve()method applies the full solve sequence.- GPU note:
The factorization step runs on the CPU using the native sparse routine. The resulting
SparseLU.solvedispatches permutation and triangular-solve kernels to the GPU when GPU execution is selected.
- Parameters:
A – The matrix to factorize. Must be a
CSRArray,COOArray, orCSCArraythat is real and non-singular. Float16 and bfloat16 inputs are promoted to float32 automatically.- Returns:
A
SparseLUdataclass with fieldsperm(row permutation as anmlx.core.array),L(unit lower-triangularCSRArray), andU(upper-triangularCSRArray).- Raises:
TypeError – If
Ais a dense array or has an unsupported dtype.- Return type:
Example
Factorize a non-symmetric sparse matrix and solve a system:
import mlx.core as mx import numpy as np import scipy.sparse import mlx_sparse as ms from mlx_sparse import linalg n = 8 rng = np.random.default_rng(0) B = scipy.sparse.random(n, n, density=0.4, format='csr', dtype=np.float32, random_state=rng) B = B + scipy.sparse.eye(n, dtype=np.float32) * n A = ms.csr_array( (mx.array(B.data), mx.array(B.indices), mx.array(B.indptr)), shape=B.shape, canonical=True, ) factor = linalg.sparse_lu(A) b = mx.ones((n,), dtype=mx.float32) x = factor.solve(b)
- mlx_sparse.linalg.splu(A)[source]#
Alias for
sparse_lu().Provided for compatibility with SciPy-style naming. All arguments and return values are identical to
sparse_lu().- GPU note:
The factorization step runs on the CPU. The returned factor uses GPU permutation and triangular-solve kernels when GPU execution is selected.
- mlx_sparse.linalg.factorized(A, *, method='auto')[source]#
Factorize a sparse matrix once and return a reusable solve object.
method="auto"chooses LU for square matrices and QR for rectangular matrices. On Accelerate-enabled Apple builds, supported realfloat32direct solves use opaque Accelerate factorization objects. Without Accelerate, square LU and Cholesky methods fall back to the existing native explicit sparse factors.- Parameters:
A – Coefficient matrix in CSR, CSC, or COO format. Float16 and bfloat16 inputs are promoted to float32 automatically.
method (str) – One of
"auto","lu","cholesky","ldlt","qr", or"cholesky_ata"."ldlt","qr", and"cholesky_ata"require an Accelerate-enabled Apple build.
- Returns:
A
FactorizedSolveobject withsolve()and__call__methods.- Raises:
TypeError – If
Ais dense or has an unsupported dtype.ValueError – If the selected method is incompatible with
A.shape.NotImplementedError – If the selected method requires Accelerate but this build does not provide it.
- Return type:
- mlx_sparse.linalg.spsolve(A, b)[source]#
Solve the sparse linear system
A @ x = bdirectly.Computes a direct sparse factorization of
Aand immediately applies it tob. Accelerate-enabled Apple builds transparently use the Accelerate sparse LU path for supported real square systems. Other builds and unsupported cases use the nativesparse_lu()path.For repeated solves with the same
Abut different right-hand sides, callfactorized()once and reuse the resultingFactorizedSolveobject to avoid re-factorizing.- GPU note:
Direct factorization runs on the CPU. The native fallback row permutation and triangular solves use GPU kernels when GPU execution is selected. The Accelerate fast path uses Apple’s CPU sparse solver.
- Parameters:
- Returns:
Solution vector
xof shape(n,)as anmlx.core.array.- Raises:
TypeError – If
Ais a dense array or has an unsupported dtype.ValueError – If
Ais not square orbhas an incompatible shape.
- Return type:
mlx.core.array
- class mlx_sparse.linalg.FactorizedSolve(_solver, shape, method, backend, rhs_size, solution_size)[source]#
Bases:
objectReusable sparse solve object.
FactorizedSolveintentionally exposes only solve behavior and metadata, not explicit sparse factors. Accelerate-enabled Apple builds use opaque Accelerate factorization objects for supported methods. Other supported square methods fall back to the existing native explicit-factor path.- Parameters:
- class mlx_sparse.linalg.SparseCholesky(L)[source]#
Bases:
objectSparse Cholesky factorization
A = L @ L.T.The factor
Lis stored as amlx_sparse.CSRArray. Numeric factorization is performed by the native sparse left-looking routine and the solves use sparse triangular CSR kernels.- GPU note:
The numeric factorization that creates
Lruns on the CPU. Calls tosolve()use native triangular-solve kernels, which run on the GPU when GPU execution is selected.
- Parameters:
L (CSRArray)
- solve(b)[source]#
Solve
A @ x = busing the stored Cholesky factor.Performs two sparse triangular solves: a forward solve with
Lfollowed by a backward solve withL.T. Both steps use native CSR triangular-solve kernels.- GPU note:
When GPU execution is selected, both triangular solves dispatch native GPU kernels. The Python method call and shape checks run on the host.
- Parameters:
b – Right-hand side array of shape
(n,)or(n, nrhs).- Returns:
Solution array of shape
(n,)or(n, nrhs)as anmlx.core.array.- Raises:
ValueError – If
bhas the wrong shape.- Return type:
mlx.core.array
- class mlx_sparse.linalg.SparseLU(perm, L, U)[source]#
Bases:
objectSparse LU factorization
P @ A = L @ U.LandUare CSR sparse factors.permstores the row permutation applied before factorization.- GPU note:
The numeric LU factorization that creates
perm,L, andUruns on the CPU. Calls tosolve()use native permutation and triangular-solve kernels, which run on the GPU when GPU execution is selected.
- perm: mlx.core.array#
- solve(b)[source]#
Solve
A @ x = busing the stored LU factors.Applies the row permutation
P, then performs a forward solve with the unit lower-triangular factorLand a backward solve with the upper-triangular factorU. All steps use native CSR kernels.- GPU note:
When GPU execution is selected, the row permutation and both triangular solves dispatch native GPU kernels. The Python method call and shape checks run on the host.
- Parameters:
b – Right-hand side array of shape
(n,)or(n, nrhs).- Returns:
Solution array of shape
(n,)or(n, nrhs)as anmlx.core.array.- Raises:
ValueError – If
bhas the wrong shape.- Return type:
mlx.core.array
Operators and sparse reductions#
- class mlx_sparse.linalg.LinearOperator(shape, matvec=None, *, matvec_fn=None, dtype=None, matmat=None, matmat_fn=None, rmatvec=None, rmatvec_fn=None, _sparse_array=None)[source]#
Bases:
objectSparse/matrix-free operator interface.
This class stores callables only. It does not densify an operator or provide dense fallbacks. Sparse arrays are normalized to canonical CSR and wrapped with native CSR matvec/matmat kernels through
aslinearoperator().- Parameters:
matvec (Matvec | None)
matvec_fn (Matvec | None)
matmat (Matmat | None)
matmat_fn (Matmat | None)
rmatvec (Matvec | None)
rmatvec_fn (Matvec | None)
- shape#
- matvec_fn#
- dtype#
- matmat_fn#
- rmatvec_fn#
- matvec(x)[source]#
Apply the operator to a vector: compute
A @ x.- Parameters:
x – Input vector of shape
(n,).- Returns:
Output vector of shape
(m,)as anmlx.core.array.- Raises:
ValueError – If
xis not rank-1 or has the wrong length.- Return type:
mlx.core.array
- matmat(X)[source]#
Apply the operator to a matrix: compute
A @ X.- Parameters:
X – Input matrix of shape
(n, k).- Returns:
Output matrix of shape
(m, k)as anmlx.core.array.- Raises:
NotImplementedError – If no
matmat_fnwas provided at construction time.ValueError – If
Xis not rank-2 or has the wrong leading dimension.
- Return type:
mlx.core.array
- rmatvec(x)[source]#
Apply the adjoint operator to a vector: compute
A.H @ x.- Parameters:
x – Input vector of shape
(m,).- Returns:
Output vector of shape
(n,)as anmlx.core.array.- Raises:
NotImplementedError – If no
rmatvec_fnwas provided at construction time.ValueError – If
xis not rank-1 or has the wrong length.
- Return type:
mlx.core.array
- property T: LinearOperator#
Transpose operator.
(op.T) @ xcomputesA.T @ x.For real operators
A.T == A.H. For complex operators the formulaA.T @ x = conj(A.H @ conj(x))is used so no extra kernel is needed. Requiresrmatvec_fnto be defined.
- property H: LinearOperator#
Hermitian (conjugate) transpose operator.
(op.H) @ xcomputesA.H @ x.Requires
rmatvec_fnto be defined (which storesA.H). The double adjoint(A.H).Hrecovers the originalA.
- mlx_sparse.linalg.aslinearoperator(A)[source]#
Wrap a sparse matrix or callable as a
LinearOperator.Accepts several input forms and returns a
LinearOperatorthat exposesmatvec(),matmat(), andrmatvec()via the native sparse kernels where possible.- Parameters:
A –
The object to wrap. Accepted types:
LinearOperator: returned unchanged.CSRArray,COOArray, orCSCArray: converted once to canonical CSR and wrapped with native CSR matvec/matmat/rmatvec kernels.SciPy sparse matrix (
scipy.sparse): converted to CSR viafrom_scipy()then wrapped.(shape, matvec)or(shape, matvec, matmat)tuple: the callables are stored directly with no conversion.
- Returns:
A
LinearOperatorinstance.- Raises:
TypeError – If
Ais not one of the accepted types.- Return type:
- mlx_sparse.linalg.dot(a, b)[source]#
Compute the Frobenius dot product of two sparse matrices.
Returns
sum(a * b)over all stored non-zero pairs (no conjugation), using the native CSR sorted-merge kernel for efficient sparse-sparse element-wise accumulation.