Skip to main content

Backend-agnostic vector spaces and linear operators.

Project description

SpaceCore

CI PyPI Python License

Backend-agnostic vector spaces, linear operators, and iterative solvers for scientific computing.

Write your algorithm once. Run it on NumPy for development, JAX for GPU acceleration and autodiff, or PyTorch for ML pipelines — without changing a line.

import spacecore as sc
import numpy as np

# Define a space, a linear operator, and solve Ax = b
ctx = sc.Context(sc.NumpyOps(), dtype=np.float64)
X = sc.DenseCoordinateSpace((100,), ctx)
A = sc.DenseLinOp(np.random.randn(100, 100) @ np.random.randn(100, 100).T + np.eye(100), X, X, ctx)
b = ctx.asarray(np.random.randn(100))

result = sc.cg(A, b, tol=1e-8)
print(f"Converged in {result.num_iters} iterations.")

Same code on JAX with GPU?

ctx = sc.Context(sc.JaxOps(), dtype=jnp.float64)
# ... build A and b the same way using jax arrays ...
result = sc.cg(A, b, tol=1e-8)   # runs on GPU, JIT-compiled

Install

pip install spacecore                # core (numpy only)
pip install "spacecore[jax]"         # add JAX backend
pip install "spacecore[torch]"       # add PyTorch backend
pip install "spacecore[jax,torch]"   # both

Python 3.11+. Built on the Python Array API standard.

What is SpaceCore for?

SpaceCore is for people writing numerical algorithms — optimization, inverse problems, eigensolvers, quantum simulation, computational geometry — who don't want to choose between NumPy, JAX, and PyTorch.

Three things SpaceCore does well

1. Matrix-free linear operators with algebra. Write your operator once as apply and adjoint callables, then compose them:

# An FFT-based convolution operator, never materialized as a matrix
K = sc.MatrixFreeLinOp(apply=fft_convolve, rapply=fft_convolve_adjoint, dom=X, cod=X, ctx=ctx)
grad = sc.MatrixFreeLinOp(apply=finite_diff, rapply=neg_div, dom=X, cod=Y, ctx=ctx)

# Build the regularized system operator using algebra
lam = 0.01
system = K.H @ K + lam * grad.H @ grad     # SumLinOp of ComposedLinOps
rhs = K.H.apply(b)

# Solve — no matrices were assembled
solution = sc.cg(system, rhs).x

2. Cross-backend iterative solvers. CG, LSQR, Lanczos, power iteration — all work uniformly across NumPy, JAX, and PyTorch. JAX backends JIT-compile:

ctx = sc.Context(sc.JaxOps(), dtype=jnp.complex128)
A = build_hermitian_operator(ctx)

# Find the smallest eigenpair via Lanczos
result = sc.lanczos_smallest(A, initial_vector, max_iter=50)
print(f"E_0 = {result.eigenvalue}, converged={result.converged}")

3. Custom Hilbert spaces with non-Euclidean geometry. Subclass DenseCoordinateSpace, override inner, and every solver respects your geometry:

class WeightedL2(sc.DenseCoordinateSpace):
    def __init__(self, shape, weights, ctx=None):
        super().__init__(shape, ctx)
        self.weights = self.ctx.asarray(weights)

    def inner(self, x, y):
        return self.ops.vdot(x, self.weights * y)

# CG, LSQR, Lanczos all use this inner product automatically

This is the basis for RKHS spaces, truncated Fock spaces (quantum many-body), function spaces with quadrature, and anything else where the geometry isn't sum(x * y).

Quick examples

Conjugate gradient on a symmetric positive-definite system

import spacecore as sc

ctx = sc.Context(sc.NumpyOps(), dtype=np.float64)
X = sc.DenseCoordinateSpace((1000,), ctx)
A = sc.DenseLinOp(make_spd_matrix(), X, X, ctx)
b = ctx.asarray(rhs)

result = sc.cg(A, b, tol=1e-10, maxiter=500)
print(f"x = {result.x}, residual = {result.residual_norm}")

Least-squares with regularization

# min ||Ax - b||^2 + λ||x||^2  via normal equations
I = sc.IdentityLinOp(X)
system = A.H @ A + lam * I
rhs = A.H.apply(b)
x_hat = sc.cg(system, rhs).x

Smallest eigenpair of a Hermitian operator

result = sc.lanczos_smallest(A, initial_vector, max_iter=100)
print(f"E_0 ≈ {result.eigenvalue}")
print(f"Krylov dimension used: {result.krylov_dim}")
print(f"Converged: {result.converged}")

Building a custom operator

class Convolution(sc.LinOp):
    def __init__(self, kernel, space, ctx):
        super().__init__(space, space, ctx)
        self.kernel = kernel

    def apply(self, x):
        return self.ops.real(self.ops.fft.ifft(self.ops.fft.fft(x) * self.ops.fft.fft(self.kernel)))

    def rapply(self, y):
        return self.ops.real(self.ops.fft.ifft(self.ops.fft.fft(y) * self.ops.conj(self.ops.fft.fft(self.kernel))))

This operator works on NumPy, JAX, and PyTorch backends without modification.

How is SpaceCore different from...?

...scipy.sparse.linalg? SciPy's iterative solvers are great but tied to NumPy/SciPy. SpaceCore gives you the same algorithms across NumPy, JAX, and PyTorch, plus operator algebra (A @ B + lam * I actually returns a usable operator), plus first-class custom Hilbert spaces.

...PyLops? PyLops is excellent for inverse problems but assumes Euclidean vectors and is tied to NumPy/CuPy. SpaceCore handles non-Euclidean geometry (RKHS, weighted spaces, function spaces) and works on JAX/PyTorch for autodiff and ML pipelines.

...QuTiP? QuTiP is the standard for quantum optics on top of SciPy. SpaceCore lets you build the same quantum operators on JAX or PyTorch for GPU acceleration and gradient-based parameter learning. Less prebuilt, more composable.

...array_api_compat? That package gives you portable arrays. SpaceCore builds on top of it to give you portable vector spaces, linear operators, and iterative algorithms — the abstractions one level up from arrays.

Documentation

Features at a glance

Spaces. DenseCoordinateSpace, DenseVectorSpace, ElementwiseJordanSpace, EuclideanElementwiseJordanSpace, HermitianSpace, ProductSpace, and StackedSpace. Generic dense spaces can use custom inner products; DenseVectorSpace has no Jordan capability by default; real Euclidean elementwise spaces get the Euclidean-Jordan capability.

Linear operators. DenseLinOp, SparseLinOp, DiagonalLinOp, MatrixFreeLinOp, plus operator algebra (A @ B, A + B, 2 * A, A.H, IdentityLinOp, ZeroLinOp).

Functionals. LinearFunctional, QuadraticForm, with value, grad, hess_apply, and compose(linop) for pull-back.

Iterative solvers. cg, lsqr, lanczos_smallest, power_iteration.

Backends. NumPy (always), JAX (spacecore[jax]), PyTorch (spacecore[torch]), CuPy (spacecore[cupy]). Adding a backend is ~100 LOC; the registry is public.

Project status

v0.3 alpha. API may still change in minor ways. Core abstractions are stable. Suitable for research code; not yet recommended for production deployment.

The library is being developed in the open and is looking for early users and feedback. If you try it on your problem, please open an issue with what worked and what didn't — that's the single most valuable contribution right now.

Contributing

Bug reports, feature requests, and PRs welcome. See CONTRIBUTING.md.

Specific areas where help is wanted:

  • Tutorials. If SpaceCore solves your problem, a notebook example helps everyone.
  • Backends. CuPy and Dask integration is partial; adding a new backend is well-scoped (~100 LOC).
  • Performance. Cross-backend benchmarks on real workloads.
  • Documentation. Concept pages, FAQ, gotchas.

License

Apache 2.0. See LICENSE.

Citation

If SpaceCore is useful in your research, a citation is appreciated:

@software{spacecore,
  author = {Pavlo, Pelikh},
  title = {SpaceCore: Backend-agnostic vector spaces and linear operators},
  url = {https://github.com/Pavlo3P/SpaceCore},
  year = {2026},
}

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

spacecore-0.3.0.tar.gz (98.6 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

spacecore-0.3.0-py3-none-any.whl (133.6 kB view details)

Uploaded Python 3

File details

Details for the file spacecore-0.3.0.tar.gz.

File metadata

  • Download URL: spacecore-0.3.0.tar.gz
  • Upload date:
  • Size: 98.6 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for spacecore-0.3.0.tar.gz
Algorithm Hash digest
SHA256 00475823fab5a4b6d824f9813823338673a57248eb2bb7c918698f657f4c5191
MD5 4795dda8aba0cc1ca9cb63ba5fd54910
BLAKE2b-256 c37ae2628920cdeb86d7bf29b10e4f8fbd0a44027f722b052367ded70d28ce31

See more details on using hashes here.

Provenance

The following attestation bundles were made for spacecore-0.3.0.tar.gz:

Publisher: ci.yml on Pavlo3P/SpaceCore

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file spacecore-0.3.0-py3-none-any.whl.

File metadata

  • Download URL: spacecore-0.3.0-py3-none-any.whl
  • Upload date:
  • Size: 133.6 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for spacecore-0.3.0-py3-none-any.whl
Algorithm Hash digest
SHA256 cbf7529217848476c6dd622ae902658900085a22a3d295a8fb8ef028abd2fa1e
MD5 70a74627b2a4b120e40f17face2beeb9
BLAKE2b-256 b771be7f450ba6457456acbd7574729cb5e3fda949cfd9263d51a9da2eef1b1e

See more details on using hashes here.

Provenance

The following attestation bundles were made for spacecore-0.3.0-py3-none-any.whl:

Publisher: ci.yml on Pavlo3P/SpaceCore

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page