Spaces tutorial#

This tutorial follows tutorials/3_Space.ipynb. It introduces Space as the abstraction for the geometry of admissible numerical objects.

Current implemented spaces are:

  • VectorSpace

  • HermitianSpace

  • ProductSpace

What a Space signifies#

A Space represents a Hilbert space of numerical objects. It encodes the geometric structure of its elements together with operations that are natural on them.

A space may encode:

  • shape;

  • linear structure;

  • inner product and norm;

  • projections;

  • structural constraints such as Hermitian symmetry;

  • product structure.

Thus a space captures geometry, not merely storage format.

\[\texttt{BackendOps} \to \texttt{Context} \to \texttt{Space} \to \texttt{LinOp}.\]

Every space stores a Context#

Each space carries a Context. This means a space knows under which backend, dtype, and checking policy its elements live. If X is a space, then X.ctx determines which backend arrays are expected, which dtype is targeted, and whether runtime validation checks are enabled.

Core operations#

Common Space methods
  • zeros()

  • add(x, y)

  • scale(a, x)

  • axpy(a, x, y)

  • inner(x, y)

  • norm(x)

  • flatten(x)

  • unflatten(v)

  • apply(x, f)

Concrete spaces differ, but they share the same idea: define valid elements, provide linear operations, define geometry, and create or validate elements in a backend-aware way.

VectorSpace#

VectorSpace represents dense backend arrays with a fixed shape and Euclidean geometry. If

\[X = \texttt{VectorSpace}(\texttt{shape}=(n_1,\dots,n_k)),\]

then elements of X are dense arrays of shape (n_1, ..., n_k) compatible with the stored context.

import numpy as np
from spacecore.backend import Context, NumpyOps
from spacecore.space import VectorSpace

ctx = Context(NumpyOps(), dtype=np.float64, enable_checks=True)
X = VectorSpace((2, 3), ctx=ctx)

x = X.zeros()
y = ctx.asarray([[1, 2, 3], [4, 5, 6]])

A vector space supports the standard operations

\[x + y,\qquad \alpha x,\qquad \langle x,y\rangle,\qquad \|x\|.\]

Membership is contextual and geometric: correct shape, correct backend representation, and correct dtype when checks are enabled.

HermitianSpace#

HermitianSpace represents Hermitian matrices of fixed square shape. If H = HermitianSpace(n), then its elements satisfy

\[A \in \mathbb{F}^{n \times n}, \qquad A = A^*.\]

This space encodes Hermitian symmetry in addition to shape. Because of that, it provides geometry-specific operations such as symmetrization, eigendecomposition, and projection onto the positive semidefinite cone.

Given a square matrix \(M\), symmetrization computes

\[\frac{M + M^*}{2}.\]

Hermitian eigendecomposition has the form

\[A = U \operatorname{diag}(\lambda) U^*.\]

Projection onto the PSD cone clips negative eigenvalues:

\[U \operatorname{diag}(\lambda) U^* \mapsto U \operatorname{diag}(\max(\lambda,0)) U^*.\]
import numpy as np
from spacecore.backend import Context, NumpyOps
from spacecore.space import HermitianSpace

ctx = Context(NumpyOps(), dtype=np.complex128, enable_checks=True)
H = HermitianSpace(3, ctx=ctx)

A = ctx.asarray([
    [1, 1 + 2j, 0],
    [1 - 2j, 3, 4j],
    [0, -4j, 2],
])
H.check_member(A)

ProductSpace#

ProductSpace represents a Cartesian product. Elements are tuples, one component per factor space. If

\[X = X_1 \times \cdots \times X_k,\]

then an element is a tuple

\[(x_1,\dots,x_k), \qquad x_i \in X_i.\]

This is useful whenever a variable is naturally block-structured.

Addition, scaling, and inner products are componentwise:

\[(x_1,\dots,x_k) + (y_1,\dots,y_k) = (x_1+y_1,\dots,x_k+y_k).\]

Flattening moves between tuple form and flat coordinates:

\[(x_1,\dots,x_k) \mapsto \operatorname{concat}(\operatorname{flatten}(x_1),\dots,\operatorname{flatten}(x_k)).\]
from spacecore.space import ProductSpace, VectorSpace

X1 = VectorSpace((2,), ctx=ctx)
X2 = VectorSpace((3,), ctx=ctx)
X_prod = ProductSpace((X1, X2), ctx=ctx)

x = (ctx.asarray([1.0, 2.0]), ctx.asarray([3.0, 4.0, 5.0]))
flat = X_prod.flatten(x)
x_back = X_prod.unflatten(flat)

Choosing the right space#

Use VectorSpace for generic dense arrays, HermitianSpace when Hermitian structure matters, and ProductSpace when variables are naturally block-structured.

Summary#

Space turns raw arrays into explicit geometric objects. It stores a context, defines valid elements, and provides the operations algorithms should use.