SPARSE ACCELERATED RAPID TRIANGULAR ANALYSER
Supernodal multifrontal LDLᵀ and LU for large sparse real and complex systems, with every numeric kernel on the GPU. A device-independent Rust core with Python, C/C++, MATLAB and Julia interfaces.
Symbolic analysis runs on the CPU; every numeric kernel, including the triangular solves, runs on the GPU.
Config for ordering, supernodes, front geometry and dispatch widthsThe same four steps in each interface: analyze the sparsity pattern, factor, solve and release the GPU memory.
Config.SpartaSolver class used like decomposition, built as a MEX
file. Not yet tested in MATLAB.Solver type with \ and factorize!, calling the
library directly.pip install from the GitHub repository builds and installs the Python
package.import numpy as np from scipy.sparse import csc_matrix import sparta A = csc_matrix([[4.0, 1.0], [1.0, 3.0]]) b = np.array([1.0, 2.0]) F = sparta.analyze(A) # 1. analyze the pattern (CPU) F.factorize() # 2. build the factors (GPU) x = F.solve(b) # 3. find x (GPU) F.destroy() # 4. hand back the GPU memory
use sparta::{Analysis, Complex32, Config, Solver}; // The lower triangle of [[4, 1], [1, 3]], in CSC form. let analysis = Analysis::ldlt(2, &[0, 2, 3], &[0, 1, 1], &Config::default())?; let mut solver = Solver::new(analysis)?; solver.factor(&[4.0, 1.0, 3.0].map(|v| Complex32::new(v, 0.0)))?; let x = solver.solve(&[1.0, 2.0].map(|v| Complex32::new(v, 0.0)))?; solver.destroy();
#include "sparta.h" sparta_analysis *plan; sparta_solver *solver; sparta_analyze(n, col_ptr, row_index, SPARTA_SYMMETRIC, &config, &plan); sparta_solver_create(&plan, &solver); sparta_factor(solver, values); sparta_solve(solver, b, x); sparta_solver_free(solver);
A = sparse([4 1; 1 3]); b = [1; 2]; S = SpartaSolver(A); % 1-2. analyze and factor x = S \ b; % 3. solve % A sweep: same pattern, new values factorize(S, A2); x2 = S \ b; clear S % 4. free the GPU memory
using SPARTA, SparseArrays A = sparse([4.0 1; 1 3]) b = [1.0, 2] F = SPARTA.Solver(A) # 1-2. analyze and factor x = F \ b # 3. solve # A sweep: same pattern, new values factorize!(F, A2) x2 = F \ b close(F) # 4. free the GPU memory
Four full-wave electromagnetic finite-element problems, each solved by SPARTA's GPU solver and by its CPU solver on the same machine, without iterative refinement. Wall time through the Python API, median of three runs.
Apple M4 Pro · 14-core CPU (10 performance + 4 efficiency) · 20-core GPU · 24 GB unified memory · macOS 26.6.2
Relative residual, no refinement: GPU 6·10-5 · CPU 2·10-13
Relative residual, no refinement: GPU 2·10-3 · CPU 5·10-12
Relative residual, no refinement: GPU 3·10-5 · CPU 2·10-13
Relative residual, no refinement: GPU 1·10-1 · CPU 2·10-11
This test system is ill-conditioned, so single precision alone is far from accurate on it; it is shown for speed.
| Problem | Unknowns | Method | Analysis GPU | Analysis CPU | Factor GPU | Factor CPU | Refactor GPU | Refactor CPU | Solve GPU | Solve CPU | Residual GPU | Residual CPU |
|---|---|---|---|---|---|---|---|---|---|---|---|---|
| #1 | 109,370 | LDLT | 246 ms | 237 ms | 120 ms | 279 ms | 108 ms | 285 ms | 13 ms | 56 ms | 6·10-5 | 2·10-13 |
| #2 | 68,690 | LDLT | 141 ms | 132 ms | 41 ms | 73 ms | 37 ms | 70 ms | 5 ms | 23 ms | 2·10-3 | 5·10-12 |
| #3 | 86,006 | LU | 171 ms | 175 ms | 366 ms | 4.47 s | 338 ms | 4.47 s | 27 ms | 91 ms | 3·10-5 | 2·10-13 |
| #4 | 457,054 | LDLT | 1.04 s | 1.07 s | 358 ms | 953 ms | 310 ms | 762 ms | 23 ms | 225 ms | 1·10-1 | 2·10-11 |
Refactorization reuses the analysis with new values on the same pattern, as in a frequency sweep;
problem #4 refactors with its own values scaled. The CPU backend is limited to 8 threads
(RAYON_NUM_THREADS=8, VECLIB_MAXIMUM_THREADS=8), fewer than the 10 performance cores,
so background processes and the slower efficiency cores do not distort its times. Iterative refinement is off throughout, so these are the raw
single-precision GPU and double-precision CPU times. In normal use SPARTA refines the GPU solution to
double-precision accuracy, which adds a few solves per right-hand side. The analysis runs on the CPU for both.
Results for NVIDIA and AMD GPUs follow once the Vulkan backend is tuned.
One device-independent core; each build targets one GPU backend.
Interfaces: Python 3.9 or later with NumPy and SciPy, a Rust toolchain, a C11 or C++17 compiler, MATLAB R2018a or later with a C compiler, or Julia 1.9 or later.
SPARTA is open source under the GNU Affero General Public License (AGPL). Closed-source software needs a commercial licence.
The source code, the Python package, the C/C++, MATLAB and Julia bindings and the user guide are all in the repository.
pip install "git+https://github.com/FennisRobert/SPARTA.git"Including SPARTA in closed-source software, distributed or run as a service, needs a commercial licence from us. For official inquiries, email robertfennis@emerge-numerics.com.
Send an email ›SPARTA is released under the GNU Affero General Public License, version 3 or later. Software that includes SPARTA and is distributed, or offered to users over a network, must make its own source available under the AGPL too. The full terms are in the repository.
Closed-source software needs a commercial licence. Email robertfennis@emerge-numerics.com for official inquiries.
SPARTA needs no internet connection and sends no data anywhere. No matrices, results or usage data leave the machine.
On its own, a relative residual around 1e-5. With iterative refinement, the default in Python, it reaches double-precision accuracy on all but the most badly conditioned systems, and every solve reports how far it got.
Apple Silicon GPUs through Metal are supported. AMD and NVIDIA GPUs on Windows and Linux run through the Vulkan backend, built on the same device-independent core. It is in alpha: it factorizes and solves correctly, but its kernels are not yet tuned, so expect it to be slower than it will be.