API reference¶
solve¶
Solve A x = right_hand_side for a sparse matrix A given in CSR format.
Solves A^T x = right_hand_side instead when transpose is set, using the same factorization Pardiso would use for A: no separate factorization of A^T is needed. Runs analysis, factorization, and solve in a single call, and does not keep the factorization around afterward: use PardisoSolver instead if the same pattern will be solved again. Works under jit and vmap, batching over values, right_hand_side, or both.
Source code in .venv/lib/python3.12/site-packages/pardiso_mkl_jax/primitive.py
PardisoSolver¶
Reuses a single Pardiso factorization across many solves.
The sparsity pattern (indptr and indices) is fixed for the solver's lifetime. The three Pardiso stages are kept as separate calls so callers control exactly what work happens on each one:
- analyze() runs the symbolic phase once for the pattern.
- factorize() runs the first numeric factorization, and requires a prior analyze().
- refactorize() updates the numeric factorization for new values on the same pattern, and requires a prior factorize(). It runs the same Pardiso phase as factorize(); the separate name and precondition make the reuse explicit at the call site.
- solve() solves against whatever factorization is currently stored, and requires a prior factorize().
- refactor_and_solve() factorizes for new values and solves in one call, reusing the analysis and requiring only a prior analyze(). It keeps no reference to the values, so unlike factorize() plus solve() it is safe to call from inside a jitted function where the values and right-hand side are tracers.
PardisoSolver must be used as a context manager. Its native memory is released in exit, not in a destructor: Python does not guarantee when or whether del runs, so relying on it could leave the native factorization alive far longer than intended, or leak it entirely if the interpreter is shutting down.
with PardisoSolver(indptr, indices, matrix_type=MatrixType.REAL_NONSYMMETRIC) as solver:
solver.analyze(values)
solver.factorize(values)
x = solver.solve(b)
Source code in .venv/lib/python3.12/site-packages/pardiso_mkl_jax/solver.py
15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 | |
analyze(values)
¶
Run the symbolic analysis (fill-reducing ordering) for the stored pattern.
Takes a representative values array because Pardiso's default heuristics for non-symmetric matrices, scaling and matching, look at the numeric values during analysis. The permutation and scaling this produces stay valid for a later factorize() call with different values on the same pattern, so this only needs to run once.
Source code in .venv/lib/python3.12/site-packages/pardiso_mkl_jax/solver.py
close()
¶
Release the native factorization. Called automatically by exit.
factorize(values)
¶
Run the first numeric factorization for values. Requires a prior analyze().
Source code in .venv/lib/python3.12/site-packages/pardiso_mkl_jax/solver.py
refactor_and_solve(values, right_hand_side, *, transpose=False)
¶
Factorize for values and solve in one call, reusing the analysis.
Requires a prior analyze(). Runs the numeric factorization and the solve as one combined Pardiso step (phase 23), reusing the symbolic analysis rather than re-running it. Because it is a single FFI call it stays correct inside a jitted function, where a separate factorize() and solve() would not be ordered, and it keeps no reference to values on the solver, so values and right_hand_side may be tracers.
Solves against A^T instead of A when transpose is set.
Source code in .venv/lib/python3.12/site-packages/pardiso_mkl_jax/solver.py
refactorize(values)
¶
Update the numeric factorization with new values on the same pattern.
Requires a prior factorize(). Skips the analysis phase, which is the cheap path when only the matrix values change between solves.
Source code in .venv/lib/python3.12/site-packages/pardiso_mkl_jax/solver.py
solve(right_hand_side, *, transpose=False)
¶
Solve against the current factorization. Requires a prior factorize().
Solves against A^T instead of A when transpose is set, reusing the same factorization: no extra factorize() call is needed to switch between the two, and consecutive calls with different transpose values are safe.
Source code in .venv/lib/python3.12/site-packages/pardiso_mkl_jax/solver.py
MatrixType¶
Bases: IntEnum
Pardiso matrix type codes, matching the mtype parameter.
Only the real-valued members can be used in this version of the package, since it works with float64 values throughout. The complex members are included so the full set of matrix types Pardiso itself supports is documented here, and raise NotImplementedError if selected.
The members whose values are mathematically symmetric or Hermitian (REAL_SYMMETRIC_POSITIVE_DEFINITE, REAL_SYMMETRIC_INDEFINITE, COMPLEX_HERMITIAN_POSITIVE_DEFINITE, COMPLEX_HERMITIAN_INDEFINITE, and COMPLEX_SYMMETRIC) require the CSR arrays to hold only the upper triangle, including the diagonal, not the full matrix: passing the full matrix corrupts Pardiso's factorization instead of raising a clear error. check_upper_triangular enforces this.
The structurally symmetric members (REAL_STRUCTURALLY_SYMMETRIC and COMPLEX_STRUCTURALLY_SYMMETRIC) only assume a symmetric sparsity pattern, not symmetric values, so they need the full matrix like the nonsymmetric members do.
Source code in .venv/lib/python3.12/site-packages/pardiso_mkl_jax/matrix.py
COMPLEX_HERMITIAN_INDEFINITE = -4
class-attribute
instance-attribute
¶
Complex and Hermitian, not guaranteed positive definite. Not yet supported.
COMPLEX_HERMITIAN_POSITIVE_DEFINITE = 4
class-attribute
instance-attribute
¶
Complex and Hermitian positive definite. Not yet supported: requires complex values.
COMPLEX_NONSYMMETRIC = 13
class-attribute
instance-attribute
¶
Complex, with no assumed symmetry. Not yet supported: requires complex values.
COMPLEX_STRUCTURALLY_SYMMETRIC = 3
class-attribute
instance-attribute
¶
Complex values, symmetric sparsity pattern. Not yet supported: requires complex values.
COMPLEX_SYMMETRIC = 6
class-attribute
instance-attribute
¶
Complex and symmetric. Not yet supported: requires complex values.
REAL_NONSYMMETRIC = 11
class-attribute
instance-attribute
¶
Real, with no assumed symmetry. The general-purpose default matrix type.
REAL_STRUCTURALLY_SYMMETRIC = 1
class-attribute
instance-attribute
¶
Real values, symmetric sparsity pattern, no assumption on the values themselves.
REAL_SYMMETRIC_INDEFINITE = -2
class-attribute
instance-attribute
¶
Real and symmetric, but not guaranteed positive definite.
REAL_SYMMETRIC_POSITIVE_DEFINITE = 2
class-attribute
instance-attribute
¶
Real, symmetric, and positive definite. The cheapest and most stable case to factor.
primitive¶
The low-level building blocks PardisoSolver is built from, for callers who
want to manage a factorization's handle explicitly. See
Building on the low-level primitives.
Run the analyze (phase 11) step and allocate a fresh native factorization.
Returns the handle for the new factorization, an int64 array value that every later call (factor, solve_stateful, factor_and_solve_stateful, release) takes as an input. Threading the handle as data, rather than addressing the native state by a Python-side id, is what lets XLA order the whole analyze-factor-solve-release lifecycle and lets it run inside a jitted function.
Source code in .venv/lib/python3.12/site-packages/pardiso_mkl_jax/primitive.py
Run the numeric factorization (phase 22) step against handle.
Returns handle unchanged, so a later call that consumes this function's return value is ordered after the factorization it performed.
Source code in .venv/lib/python3.12/site-packages/pardiso_mkl_jax/primitive.py
Solve (phase 33) against the factorization already produced for handle.
transpose solves A^T x = right_hand_side instead of A x = right_hand_side, reusing the same factorization: no call to factor() is needed to switch between the two for a given handle.
Source code in .venv/lib/python3.12/site-packages/pardiso_mkl_jax/primitive.py
Refactor and solve in one call, reusing the analysis produced for handle.
Runs Pardiso's combined phase 23 (numeric factorization then solve) for the given values against the stored analysis. This is a single FFI call, so the factorization and the solve stay ordered under jit, unlike a factor() followed by a separate solve_stateful(): those share no data dependency XLA must honor, so the solve could otherwise run before the factor.