SPARTA · GPU sparse direct solver Metal: availableVulkan: alpha

Sparse direct factorization on the GPU

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.

LDLᵀ and LUsupernodal multifrontal, GPU-resident
complex64 + complex128mixed-precision refinement
Nested dissectioncustom ordering algorithm
Rust, Python, C/C++plus MATLAB and Julia

Direct solver capabilities

Symbolic analysis runs on the CPU; every numeric kernel, including the triangular solves, runs on the GPU.

GPU factorization

  • Supernodal multifrontal method, level-scheduled over the assembly tree
  • Blocked panel factorization with deferred Schur-complement updates
  • Bunch–Kaufman 1×1 and 2×2 pivoting for LDLᵀ; partial pivoting for LU
  • GPU-resident factor store; workspace recycled between tree levels
  • Batched solves, eight right-hand sides per pass

Ordering and analysis

  • Custom nested-dissection ordering, deterministic and parallel
  • Supernode amalgamation and elimination-tree postordering
  • Pattern reuse: refactor new values on the same analysis and GPU memory, for frequency sweeps and time stepping

Accuracy and diagnostics

  • complex64 factorization with complex128 iterative refinement
  • complex128 CPU backend for ill-conditioned systems, selected explicitly
  • Pivot perturbation, counted per factorization
  • Factor-quality verdict per factorization; refinement report per solve

Integration and configuration

  • Python: SciPy sparse matrices in, NumPy arrays out
  • Rust native API; C ABI with a single header and a C++ wrapper
  • MATLAB and Julia bindings over the C library
  • One Config for ordering, supernodes, front geometry and dispatch widths
  • Presets for one-off solves, frequency sweeps and difficult systems
  • Backend selection and pivot failures always reported to the caller

Example integration

The same four steps in each interface: analyze the sparsity pattern, factor, solve and release the GPU memory.

  • Python — takes a SciPy sparse matrix; refinement is on by default.
  • Rust — the native API, with every setting in one Config.
  • C and C++ — one header and one shared library.
  • MATLAB — a SpartaSolver class used like decomposition, built as a MEX file. Not yet tested in MATLAB.
  • Julia — a Solver type with \ and factorize!, calling the library directly.
  • Installation — 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

Performance

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

SPARTA GPU solver: Metal on 20 GPU cores, complex64, no refinement SPARTA CPU solver: complex128 on 8 threads, Accelerate

Full-wave EM FEM problem #1

109,370 unknowns · 4.08 M nonzeros · complex symmetric, LDLᵀ

Factorization2.3× faster on GPU
120 ms
279 ms
Refactorization2.6× faster on GPU
108 ms
285 ms
Solve4.2× faster on GPU
13 ms
56 ms

Relative residual, no refinement: GPU 6·10-5 · CPU 2·10-13

Full-wave EM FEM problem #2

68,690 unknowns · 2.29 M nonzeros · complex symmetric, LDLᵀ

Factorization1.8× faster on GPU
41 ms
73 ms
Refactorization1.9× faster on GPU
37 ms
70 ms
Solve4.7× faster on GPU
5 ms
23 ms

Relative residual, no refinement: GPU 2·10-3 · CPU 5·10-12

Full-wave EM FEM problem #3

86,006 unknowns · 3.62 M nonzeros · unsymmetric, LU

Factorization12.2× faster on GPU
366 ms
4.47 s
Refactorization13.2× faster on GPU
338 ms
4.47 s
Solve3.4× faster on GPU
27 ms
91 ms

Relative residual, no refinement: GPU 3·10-5 · CPU 2·10-13

Full-wave EM FEM problem #4

457,054 unknowns · 17.63 M nonzeros · complex symmetric, LDLᵀ

Factorization2.7× faster on GPU
358 ms
953 ms
Refactorization2.5× faster on GPU
310 ms
762 ms
Solve9.6× faster on GPU
23 ms
225 ms

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.

All measurements
ProblemUnknownsMethod Analysis GPUAnalysis CPU Factor GPUFactor CPU Refactor GPURefactor CPU Solve GPUSolve CPU Residual GPUResidual CPU
#1109,370LDLT246 ms237 ms120 ms279 ms108 ms285 ms13 ms56 ms6·10-52·10-13
#268,690LDLT141 ms132 ms41 ms73 ms37 ms70 ms5 ms23 ms2·10-35·10-12
#386,006LU171 ms175 ms366 ms4.47 s338 ms4.47 s27 ms91 ms3·10-52·10-13
#4457,054LDLT1.04 s1.07 s358 ms953 ms310 ms762 ms23 ms225 ms1·10-12·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.

Platform support

One device-independent core; each build targets one GPU backend.

macOS

Available
GPU
Apple Silicon, M1 or later
Backend
Metal
Operating system
macOS 13 or later

Windows

Alpha
GPU
NVIDIA or AMD, Vulkan 1.3 driver
Backend
Vulkan
Status
Factorizes and solves; tested on an NVIDIA RTX 3080 and an AMD Radeon integrated GPU. Not yet tuned for speed.

Linux

Alpha
GPU
NVIDIA or AMD, Vulkan 1.3 driver
Backend
Vulkan
Status
The same Vulkan backend as on Windows, not yet tested on Linux. Not yet tuned for speed.

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.

Get SPARTA

SPARTA is open source under the GNU Affero General Public License (AGPL). Closed-source software needs a commercial licence.

Open source

Free, on GitHub

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"
  • For open-source software under the AGPL
  • Build from source for Metal or Vulkan
  • Issues and contributions through GitHub
Go to the repository ›

Closed-source software

Contact us

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 ›

Additional information

Licence

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.

Using SPARTA in closed-source software

Closed-source software needs a commercial licence. Email robertfennis@emerge-numerics.com for official inquiries.

Offline operation

SPARTA needs no internet connection and sends no data anywhere. No matrices, results or usage data leave the machine.

Accuracy of a single-precision GPU solve

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.

Supported GPUs

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.