sTiles targets the full Cholesky → solve → selected inverse pipeline on a single shared-memory node, using tile-based parallelism. Today's release handles symmetric positive-definite matrices across the entire spectrum, from very sparse to fully dense, with one unified solver. Distributed-memory support is on the roadmap.
Peer-reviewed research papers describing the sTiles framework and its applications.
Core paper focused on the sTiles solver architecture and tile-based algorithms.
Read on IEEE Xplore →Focus on GPU acceleration for selected inversion computations.
Read on arXiv →Designed for high-performance sparse matrix computations with modern hardware.
Configurable tile sizes for cache-friendly Cholesky factorizations. Smart tiles adapt storage format based on fill-in density.
Multiple ordering algorithms including AMD, RCM, and SCOTCH nested dissection, with auto, parallel, and smart ordering strategies.
Efficient computation of selected inverse elements matching the sparsity pattern. Much faster than full matrix inversion.
Solve multiple right-hand sides efficiently by reusing factorizations. Triangular solves: L, L^T, LL^T.
Use sTiles from Python (pip install sTiles), R, or C/C++. Pre-built for Linux, macOS, and Windows. The native library downloads automatically, no compiler needed.
Pick your language, install in one line, and run.
pip install sTiles
import numpy as np, scipy.sparse as sp
from sTiles import sTiles
# Q: a symmetric positive-definite sparse matrix
Q = sp.diags([[-1.]*5, [4.]*6, [-1.]*5], [-1, 0, 1], format="csc")
s = sTiles(Q, cores=4, inverse=True) # analyze + Cholesky factorize
s.logdet # log|Q|
s.solve(np.ones(6)) # solve Q x = b
s.selinv_diag() # diag(Q^-1), the marginal variances
s.selinv_elm(0, 0) # any inverse element within the factor pattern
s.close()
Pure Python (ctypes), no compiler. The native libstiles downloads automatically on first import.
remotes::install_github("esmail-abdulfattah/sTiles", subdir = "R/sTiles")
library(sTiles); library(Matrix)
# Q: a symmetric positive-definite sparse matrix
Q <- as(bandSparse(6, k = c(0, 1),
diagonals = list(rep(4, 6), rep(-1, 5)), symmetric = TRUE), "CsparseMatrix")
s <- sTiles(Q, cores = 4, inverse = TRUE) # analyze + Cholesky factorize
sTiles_logdet(s) # log|Q|
sTiles_solve(s, rep(1, 6)) # solve Q x = b
sTiles_selinv_diag(s) # diag(Q^-1), the marginal variances
sTiles_selinv_elm(s, 1, 1) # any inverse element within the factor pattern
sTiles_close(s)
No compiler. The native libstiles downloads automatically on first use.
# Easiest: let pkg-config supply the paths (the .pc is relocatable,
# so it resolves against wherever you unpacked the archive).
export PKG_CONFIG_PATH=/path/to/stiles/lib/pkgconfig
g++ -O3 -fopenmp app.cpp $(pkg-config --cflags --libs stiles) -o app
# Linux (libstiles.so)
g++ -O3 -fopenmp app.cpp \
-I/path/to/stiles/include \
-L/path/to/stiles/lib -Wl,-rpath,/path/to/stiles/lib -lstiles -o app
# macOS, Apple Silicon (libstiles.dylib -- self-contained;
# -lomp here is for YOUR app's own OpenMP, not for sTiles)
clang++ -O3 -Xpreprocessor -fopenmp app.cpp \
-I/path/to/stiles/include \
-L/path/to/stiles/lib -Wl,-rpath,/path/to/stiles/lib -lstiles -lomp -o app
# Windows, MinGW-w64 UCRT64 (libstiles.dll)
g++ -O3 -fopenmp app.cpp \
-I/path/to/stiles/include \
-L/path/to/stiles/lib -lstiles -o app.exe
# then run app.exe with the archive's lib\ on PATH -- the .dll ships
# beside its runtime dependencies (OpenBLAS, gfortran, gomp, ...).
#include "stiles.h"
#include <vector>
#include <cstdio>
int main() {
int N = 4, NNZ = 7; // 4x4 SPD, one triangle (row >= col)
std::vector<int> rows = {0,1,1,2,2,3,3};
std::vector<int> cols = {0,0,1,1,2,2,3};
std::vector<double> vals = {10,-1,10,-1,10,-1,10};
int calls[]={1}, cores[]={4}, variant[]={0};
bool need_inv[]={true};
void* h = nullptr;
sTiles_create(&h, 1, calls, cores, variant, need_inv);
sTiles_assign_graph_one_call(0, 0, &h, N, NNZ, rows.data(), cols.data());
sTiles_init_group(0, &h); // symbolic factorization
sTiles_assign_values(0, 0, &h, vals.data());
sTiles_bind(0, 0, &h);
sTiles_chol(0, 0, &h); // Cholesky
sTiles_selinv(0, 0, &h); // selected inverse
sTiles_unbind(0, 0, &h);
printf("logdet = %.6f\n", sTiles_get_logdet(0, 0, &h));
printf("Var[0] = %.6f\n", sTiles_get_selinv_elm(0, 0, 0, 0, &h));
sTiles_quit();
}
#include "stiles.h"
#include <vector>
#include <cstdio>
int main() {
int N = 4, NNZ = 7;
std::vector<int> rows = {0,1,1,2,2,3,3};
std::vector<int> cols = {0,0,1,1,2,2,3};
std::vector<double> vals = {10,-1,10,-1,10,-1,10};
int calls[]={1}, cores[]={4}, variant[]={0};
bool need_inv[]={false};
void* h = nullptr;
sTiles_create(&h, 1, calls, cores, variant, need_inv);
sTiles_assign_graph_one_call(0, 0, &h, N, NNZ, rows.data(), cols.data());
sTiles_init_group(0, &h);
sTiles_assign_values(0, 0, &h, vals.data());
sTiles_bind(0, 0, &h);
sTiles_chol(0, 0, &h);
double b[4] = {1, 2, 3, 4}; // b, overwritten with the solution x
sTiles_solve_LLT(0, 0, &h, b, 1); // solve A x = b (nrhs = 1)
sTiles_unbind(0, 0, &h);
printf("x = [%.4f %.4f %.4f %.4f]\n", b[0], b[1], b[2], b[3]);
sTiles_quit();
}
Download the pre-built library from the download page. Full C API in the API Reference below.
Conference talks and workshop presentations on sTiles.
INLA Workshop, University of Glasgow, Scotland (2025)
Tailored for statisticians working with INLA methodology.
ISC High Performance 2025, Hamburg, Germany
Technical presentation for HPC audience.
CIRAD, Montpellier, France (Apr. 2026)
Seminar on computational bottlenecks in spatial statistical models and how tiling-based algorithms (sTiles) accelerate them.
SIAM PP26, Minisymposium (Mar. 4, 2026)
Minisymposium talk on scalable tiling algorithms for structured sparse matrices.
SIAM PP26, Contributed Talk (2026)
GPU-accelerated selected inversion using sTiles for structured sparse matrices.
C API for integrating sTiles into your applications. Click to expand function details.
sTiles_create and sTiles_assign_graph_one_call
Use sTiles_create to declare how many matrices you need to factorize and how many threads to use, then
sTiles_assign_graph_one_call to hand off each matrix's sparsity pattern, and
sTiles_init_group to run the symbolic phase.
The two parameters that govern this setup are groups and calls per group:
a group owns a sparsity pattern (symbolic factorization runs once per group), and each group holds one or more calls,
independent matrices with different values that are factorized in parallel.
int sTiles_create(void** stile, int num_groups, const int* calls_per_group, const int* cores_per_group, const int* factor_type, const bool* get_inverse);
void* variable.
num_groups = 1.
num_groups.
calls_per_group[g] is the number of independent matrices in group g, all sharing group g's sparsity pattern but with different numerical values.
Each call gets its own factor storage and is factorized independently via sTiles_chol / sTiles_selinv.
Calls within a group run in parallel (launch one OpenMP thread per call).
Use calls_per_group[g] = 1 for a single matrix.
Use calls_per_group[g] = N_θ to factorize Nθ hyperparameter samples simultaneously (INLA pattern).
num_groups.
cores_per_group[g] is the number of CPU threads allocated to each call in group g for tile-level parallelism inside sTiles_chol / sTiles_selinv.
Total threads consumed at peak ≈ calls_per_group[g] × cores_per_group[g] per group.
For a single-call setup this is simply the number of cores for the factorization.
num_groups. Factorization variant per group (0 = standard Cholesky).
num_groups. Set get_inverse[g] = true to enable selected inversion (sTiles_selinv) for group g. Memory for the inverse is pre-allocated during sTiles_init_group; calling sTiles_selinv on a group where this is false will fail.
Returns: 0 on success, negative error code on failure.
int sTiles_assign_graph_one_call(int group_id, int call_id, void** stile, int N, int NNZ, int* rows, int* cols);
Returns: 0 on success.
int sTiles_init_group(int group_id, void** stile);
Performs symbolic factorization, ordering, and memory allocation. Call after assigning graphs.
int sTiles_assign_values(int group_id, int call_id, void** stile, double* values);
Values can be updated between solves without re-initializing.
void sTiles_set_tile_size(int size);
void sTiles_set_tile_type_mode(int value);
int sTiles_bind(int group_id, int call_id, void** stile);
int sTiles_unbind(int group_id, int call_id, void** stile);
sTiles_bind: Activates a persistent thread team for the specified call. This does not create new threads but activates pre-allocated worker threads for parallel tile operations. Must be called before sTiles_chol, sTiles_selinv, or solve functions.
sTiles_unbind: Deactivates the thread team, releasing workers back to the pool. Always call after finishing computations on a call. Forgetting to unbind may cause resource leaks or deadlocks.
Returns: 0 on success.
int sTiles_chol(int group_id, int call_id, void** stile);
Returns 0 on success, non-zero if matrix is not positive definite.
int sTiles_selinv(int group_id, int call_id, void** stile);
Computes A^{-1} elements matching the sparsity pattern. Call sTiles_chol first.
int sTiles_solve_LLT(int group_id, int call_id, void** stile, double* b, int nrhs);
In-place solve. b is overwritten with solution x. Column-major for multiple RHS.
double sTiles_get_logdet(int group_id, int call_id, void** stile);
Returns log|A| = 2 * sum(log(L_ii)). Computed efficiently during factorization.
double sTiles_get_selinv_elm(int group_id, int call_id, int row, int col, void** stile);
Returns A^{-1}[row][col] if within the sparsity pattern (0-based indices).
void sTiles_quit(void);
Releases all allocated memory and destroys all thread contexts. Call once at program termination.
For C/C++ projects: download the pre-built library and link against it. (Python and R: see Examples above.)
Register and download → the sTiles package for your platform
#include "stiles.h"
Link against libstiles.so (Linux), libstiles.dylib (macOS), or libstiles.dll (Windows)
Call sTiles API functions from your C/C++ application
Pre-built binaries are available for Linux (x86_64 and arm64), macOS (Apple Silicon), and Windows (x86_64). The x86_64 build runs on any x86-64 CPU (AVX2 baseline with runtime AVX-512 acceleration). Register to see the full platform list and download links.
Register & Download →Free for research and academic use. A short form helps us understand our user community.
# Linux (x86_64 or arm64)
# BLAS/LAPACK are embedded inside libstiles, so -lstiles is all you need.
g++ -O3 -fopenmp myapp.cpp \
-I/path/to/stiles/include \
-L/path/to/stiles/lib -Wl,-rpath,/path/to/stiles/lib -lstiles -o myapp
# macOS (Apple Silicon)
# The dylib is self-contained; libomp provides the OpenMP runtime.
clang++ -O3 -Xpreprocessor -fopenmp myapp.cpp \
-I/path/to/stiles/include \
-L/path/to/stiles/lib -Wl,-rpath,/path/to/stiles/lib -lstiles -lomp -o myapp
# Windows (x86_64): build in the MinGW-w64 UCRT64 shell (MSYS2 / Rtools44), not MSVC.
# Note: link uses the libstiles.dll.a import lib, and there is no -rpath on Windows.
g++ -O3 -fopenmp myapp.cpp \
-I/path/to/stiles/include \
-L/path/to/stiles/lib -lstiles -o myapp.exe
# libstiles.dll links its BLAS and runtime dynamically, but the archive now
# SHIPS them beside it (libopenblas, libgfortran-5, libquadmath-0, libgomp-1,
# libgcc_s_seh-1, libstdc++-6, libwinpthread-1, libhwloc-15, libltdl-7).
# Keep that lib\ directory on PATH, or copy its contents beside myapp.exe.
If you use sTiles in your research, please cite the appropriate paper(s) below.
@inproceedings{fattah2025stiles,
title = {{sTiles}: An Accelerated Computational
Framework for Sparse Factorizations
of Structured Matrices},
author = {Fattah, Esmail Abdul and Ltaief, Hatem
and Rue, H{\aa}vard and Keyes, David},
booktitle = {ISC High Performance 2025 Research Paper
Proceedings (40th International Conference)},
pages = {1--14},
year = {2025},
organization = {Prometeus GmbH}
}
@article{fattah2025gpu,
title = {{GPU}-Accelerated Parallel Selected
Inversion for Structured Matrices
Using {sTiles}},
author = {Fattah, Esmail Abdul and Ltaief, Hatem
and Rue, H{\aa}vard and Keyes, David},
journal = {arXiv preprint arXiv:2504.19171},
year = {2025}
}
Developer & Maintainer
King Abdullah University of Science and Technology (KAUST)
Thuwal, Saudi Arabia
Join the sTiles mailing list to receive updates about releases, new features, and research developments.
Subscribe →Interested in contributing to sTiles? We're looking for help with Python wrappers and additional language bindings.
Get Involved →Have matrices that perform poorly with current solvers? Share them with us to help improve sTiles robustness.
Send Matrices →sTiles builds upon excellent open-source libraries and research. We gratefully acknowledge the following projects and their contributors.