Spatial Adapter
A post-hoc cascade adapter that extracts explicit low-rank spatial representations from the residuals of any frozen first-stage predictor, yielding closed-form covariance estimation and uncertainty quantification.
Installation
Requires Python 3.10+, Conda, and (optionally) CUDA 12.8+ for GPU.
git clone https://github.com/STLABTW/spatial-adapter.git
cd spatial-adapter
make conda-env # recommended: conda env + C++ extensions
# or
pip install -e ".[all]" # pip-only
For Blackwell / sm_120 GPUs (e.g. RTX 5070 Ti):
pip install torch torchvision --index-url https://download.pytorch.org/whl/cu128 --force-reinstall
Quick Start
Option A — one-shot tuned fit (recommended)
Hides the (τ₁, τ₂) grid search behind a single call: runs a short Optuna sweep, refits at the best weights, returns the trained adapter plus the chosen τ's and the trials dataframe.
import torch
from spatial_adapter import SpatialAdapter, TrendModel
trend = TrendModel(num_continuous_features=5, hidden_layer_sizes=[], n_locations=100)
result = SpatialAdapter.fit_tuned(
trend, train_loader,
val_cont=val_X, val_y=val_Y, locs=station_coords,
device=torch.device("cpu"),
latent_dim=10,
n_trials=10, # per-seed Optuna budget (defaults to 10)
seed=42,
criterion="auto", # see table below
)
result.adapter.reconstruct(val_X, val_Y) # trained; ready to use
result.tau1, result.tau2 # best weights chosen by Optuna
result.trials # pandas DataFrame of all trials
Validation criterion — what Optuna minimizes/maximizes over (τ₁, τ₂):
criterion |
Task | Direction | What it measures |
|---|---|---|---|
"auto" (default) |
any | — | regression → rmse, binary → accuracy |
"rmse" |
regression | min | point-prediction RMSE on val |
"accuracy" |
binary | max | classification accuracy on val |
"auc" |
binary | max | ROC AUC on val |
"cov_frob" |
regression | min | relative Frobenius covariance error, ||Σ̂_pred − Σ̂_obs||_F / ||Σ̂_obs||_F |
"sv_score" |
regression | min | weighted L² distance between empirical semivariograms of val and prediction (gstools) |
For the paper's KAUST Table 4 ablation (RMSE vs CovFrob vs SV_score
selection), use these criteria directly. For domain-specific ground-truth
covariance (e.g. a known Matérn model), fall back to AdapterTuner with a
custom evaluate_fn.
Option B — manual control (power users)
Bypasses tuning when you already have (τ₁, τ₂) or want direct control of the ADMM loop.
import torch
from spatial_adapter import (
SpatialAdapter, SpatialAdapterConfig,
SpatialBasisLearner, TrendModel,
)
trend = TrendModel(num_continuous_features=5, hidden_layer_sizes=[], n_locations=100)
basis = SpatialBasisLearner(num_locations=100, latent_dim=10)
adapter = SpatialAdapter(
trend, basis, train_loader,
val_cont=val_X, val_y=val_Y, locs=station_coords,
config=SpatialAdapterConfig(),
device=torch.device("cpu"),
tau1=1.0, tau2=1.0,
)
adapter.pretrain_trend(epochs=5)
adapter.init_basis_dense()
adapter.run() # ADMM optimization
Examples & paper experiments
End-to-end scripts, configs, and notebooks live under examples/.
To reproduce the paper tables (data download, config → table mapping,
expected output) see examples/experiments/README.md.
Project layout
spatial_adapter/— core library:models/,data/,metrics.py,prediction.py,tuning/,utils/, andcpp_extensions/(pybind11 C++ kernels).examples/— runnable experiments (experiments/) and baselines (baselines/stdk/).tests/— pytest suite; seemake test.data/— external datasets (git-ignored; seedata/README.md).
Development
make conda-env # set up environment
make build-cpp # build C++ extensions
make test # run tests
make test-cov # tests with HTML coverage
Citation
@misc{wang2026spatialadapterstructuredspatial,
title={Spatial Adapter: Structured Spatial Decomposition and Closed-Form Covariance for Frozen Predictors},
author={Wen-Ting Wang and Wei-Ying Wu and Hao-Yun Huang and Xuan-Chun Wang},
year={2026},
eprint={2605.11394},
archivePrefix={arXiv},
primaryClass={stat.ML},
url={https://arxiv.org/abs/2605.11394},
}
License
MIT — see LICENSE.
Metadata
Release files for spatial-adapter 0.6.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| spatial_adapter-0.6.0.tar.gz | 2.1 MB | Details |
Built distributions (wheels)
| File | Reset | |||
|---|---|---|---|---|
| spatial_adapter-0.6.0-cp313-cp313-manylinux_2_28_x86_64.whl | CPython 3.13 | CPython 3.13 | Linux glibc 2.28+ x86-64 | Details |
| spatial_adapter-0.6.0-cp313-cp313-macosx_14_0_arm64.whl | CPython 3.13 | CPython 3.13 | macOS 14.0+ ARM64 | Details |
| spatial_adapter-0.6.0-cp312-cp312-manylinux_2_28_x86_64.whl | CPython 3.12 | CPython 3.12 | Linux glibc 2.28+ x86-64 | Details |
| spatial_adapter-0.6.0-cp312-cp312-macosx_14_0_arm64.whl | CPython 3.12 | CPython 3.12 | macOS 14.0+ ARM64 | Details |
| spatial_adapter-0.6.0-cp311-cp311-manylinux_2_28_x86_64.whl | CPython 3.11 | CPython 3.11 | Linux glibc 2.28+ x86-64 | Details |
| spatial_adapter-0.6.0-cp311-cp311-macosx_14_0_arm64.whl | CPython 3.11 | CPython 3.11 | macOS 14.0+ ARM64 | Details |
| spatial_adapter-0.6.0-cp310-cp310-manylinux_2_28_x86_64.whl | CPython 3.10 | CPython 3.10 | Linux glibc 2.28+ x86-64 | Details |
| spatial_adapter-0.6.0-cp310-cp310-macosx_14_0_arm64.whl | CPython 3.10 | CPython 3.10 | macOS 14.0+ ARM64 | Details |
Total release size: 222.8 MB
Release files / spatial_adapter-0.6.0.tar.gz
| Download URL | spatial_adapter-0.6.0.tar.gz |
|---|---|
| Size | 2.1 MB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
403cfce541798d1e55ac35b15a03b7eff7a50baebdb6d01a3c4cf4bc86b78d07
|
|
BLAKE2b-256 checksum How to use checksums |
ce60db503eaeac31d439328dbe49f3c797f98df2e1b5a7f102b7e8ea65fb4338
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.10.20
|
Release files / spatial_adapter-0.6.0-cp313-cp313-manylinux_2_28_x86_64.whl
| Download URL | spatial_adapter-0.6.0-cp313-cp313-manylinux_2_28_x86_64.whl |
|---|---|
| Size | 43.2 MB |
| Tags | CPython 3.13 Linux glibc 2.28+ x86-64 |
|
SHA-256 checksum How to use checksums |
ae000e05649ec0a10b9d73e2ea4161591355e76c63483f027f8cc645e9c4bbc2
|
|
BLAKE2b-256 checksum How to use checksums |
cc36844b43f5eda9fc86d67f2c986a54391142b54fdd530050ee1e7f40d1bce7
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.10.20
|
Release files / spatial_adapter-0.6.0-cp313-cp313-macosx_14_0_arm64.whl
| Download URL | spatial_adapter-0.6.0-cp313-cp313-macosx_14_0_arm64.whl |
|---|---|
| Size | 12.0 MB |
| Tags | CPython 3.13 macOS 14.0+ ARM64 |
|
SHA-256 checksum How to use checksums |
a7e83f2aabee3d6c5840847a493fdfeb62980b5c79f927d328623a7bb4830759
|
|
BLAKE2b-256 checksum How to use checksums |
8433017da7dff3158c4d514ed7bf0d7e3731484b76056b9ebd5b60e6d78853b6
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.10.20
|
Release files / spatial_adapter-0.6.0-cp312-cp312-manylinux_2_28_x86_64.whl
| Download URL | spatial_adapter-0.6.0-cp312-cp312-manylinux_2_28_x86_64.whl |
|---|---|
| Size | 43.2 MB |
| Tags | CPython 3.12 Linux glibc 2.28+ x86-64 |
|
SHA-256 checksum How to use checksums |
7040141c9c3b0cf292d5bd3ebe3b5187695c3a2c0703087823fa6bdd2141b0a4
|
|
BLAKE2b-256 checksum How to use checksums |
17c06689565c5e06dfb936949fa4c8d32d846ddbb57d38134e852e01f77632fa
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.10.20
|
Release files / spatial_adapter-0.6.0-cp312-cp312-macosx_14_0_arm64.whl
| Download URL | spatial_adapter-0.6.0-cp312-cp312-macosx_14_0_arm64.whl |
|---|---|
| Size | 12.0 MB |
| Tags | CPython 3.12 macOS 14.0+ ARM64 |
|
SHA-256 checksum How to use checksums |
d732aef3274e5924f6fd54f46375db4949905a6984a856a755b2aaf4cd60af10
|
|
BLAKE2b-256 checksum How to use checksums |
983fee2ce05650d203f82e5c9b964a20ea9525a0112123ae56451bc7077b4754
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.10.20
|
Release files / spatial_adapter-0.6.0-cp311-cp311-manylinux_2_28_x86_64.whl
| Download URL | spatial_adapter-0.6.0-cp311-cp311-manylinux_2_28_x86_64.whl |
|---|---|
| Size | 43.2 MB |
| Tags | CPython 3.11 Linux glibc 2.28+ x86-64 |
|
SHA-256 checksum How to use checksums |
c00284ecc9af373884f27ef622be82d8fdd9363fdd1c19cf008180d1b5369177
|
|
BLAKE2b-256 checksum How to use checksums |
494b48199c83a5c79ce9f3bd94d15a96ab80542740835dc0f48061f81d93cc77
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.10.20
|
Release files / spatial_adapter-0.6.0-cp311-cp311-macosx_14_0_arm64.whl
| Download URL | spatial_adapter-0.6.0-cp311-cp311-macosx_14_0_arm64.whl |
|---|---|
| Size | 12.0 MB |
| Tags | CPython 3.11 macOS 14.0+ ARM64 |
|
SHA-256 checksum How to use checksums |
3cbc41afc6148694fb203cc9c78c98970768deb7bf495d60555cc46c89ebbda4
|
|
BLAKE2b-256 checksum How to use checksums |
7ad55cede98c0ddc92f902c319a3617e99bd82b9a62a021759bffcde6ebcc8ba
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.10.20
|
Release files / spatial_adapter-0.6.0-cp310-cp310-manylinux_2_28_x86_64.whl
| Download URL | spatial_adapter-0.6.0-cp310-cp310-manylinux_2_28_x86_64.whl |
|---|---|
| Size | 43.2 MB |
| Tags | CPython 3.10 Linux glibc 2.28+ x86-64 |
|
SHA-256 checksum How to use checksums |
485e604574aeb6ec80118ccea40840146ca5b73fdf89e31d3e3a2f875cb5633e
|
|
BLAKE2b-256 checksum How to use checksums |
d0fe238a8b07a27330b9724f753eaf7c52d979ceb1c56ec78ba6061a7c2e98c5
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.10.20
|
Release files / spatial_adapter-0.6.0-cp310-cp310-macosx_14_0_arm64.whl
| Download URL | spatial_adapter-0.6.0-cp310-cp310-macosx_14_0_arm64.whl |
|---|---|
| Size | 12.0 MB |
| Tags | CPython 3.10 macOS 14.0+ ARM64 |
|
SHA-256 checksum How to use checksums |
6afd4b8d88c00c9f5860007c6c8454efbb03de3c1c355dd4576a9c691cdb042d
|
|
BLAKE2b-256 checksum How to use checksums |
ec1b2710fc890a64f478054964091df55d550aff5465ef21074a11aad2aaaecb
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.10.20
|