Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
96 changes: 95 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,2 +1,96 @@
# SpaceCore
Framework for working with vector spaces and linear operators.

SpaceCore is a lightweight backend-agnostic library for working with vector spaces and linear operators.

It provides a small set of abstractions for:

- backend-aware numerical operations
- contexts carrying backend and dtype information
- structured vector spaces
- structured linear operators
- conversion between compatible contexts

## Installation

Base install:

```bash
pip install spacecore
````

With JAX support:

```bash
pip install "spacecore[jax]"
```

* `spacecore[jax]`: installs optional JAX support.
* GPU users should install the appropriate CUDA-enabled JAX build first, following the official JAX installation guide.

## Main concepts

### `Context`

A `Context` specifies how objects are represented, in particular:

* backend (`NumPy`, `JAX`, etc.)
* dtype
* validation/conversion behavior

### `Space`

A `Space` describes the structure of objects space, for example:

* `VectorSpace` - Euclidean space
* `HermitianSpace` - space of Hermitian (symmetric) matrices
* `ProductSpace` - Cartesian product of spaces

### `LinOp`

A `LinOp` represents a linear operator between spaces, for example:

* `DenseLinOp` - linear operator represented by dense matrix
* `SparseLinOp` - linear operator represented by sparse matrix
* `BlockDiagonalLinOp` - linear operator from $X_1 \times \dots \times X_k$ to $Y_1 \times \dots \times Y_k$
* `StackedLinOp` - linear operator from $X$ to $Y_1 \times \dots \times Y_k$
* `SumToSingleLinOp` - linear operator from $X_1 \times \dots \times X_k$ to $Y$

## Minimal example

```python
import numpy as np
import spacecore as sc

sc.set_context('numpy', dtype='float64')

X = sc.VectorSpace((3,))
Y = sc.VectorSpace((2,))

A = np.array(
[[1.0, 2.0, 3.0],
[0.0, 1.0, 0.0]]
)
linop = sc.DenseLinOp(
A,
dom=X,
cod=Y,
)

x = X.ctx.asarray([1.0, 0.0, -1.0])
y = linop.apply(x)

print(y)
```

## Status

SpaceCore is currently experimental and under active development.
The public API may still evolve.

## Tutorials

See the `tutorials/` directory for usage examples and design guidance.

## License

Apache License 2.0
18 changes: 16 additions & 2 deletions spacecore/_contextual/contextual.py
Original file line number Diff line number Diff line change
Expand Up @@ -69,10 +69,24 @@ def __init__(self,
self.resolution_policy = resolution_policy
self.dtype_resolution_policy = dtype_resolution_policy

def normalize_context(self, ctx: Context | BackendFamily | str | None = None) -> Context:
def normalize_context(self,
ctx: Context | BackendFamily | str | None = None,
dtype: Any = None,
enable_checks: bool | None = None
) -> Context:
if ctx is None:
if dtype is not None or enable_checks is not None:
warn(
'Provided context is None, dtype and enable_checks parameters are ignored.',
UserWarning,
)
return self.default_ctx
if isinstance(ctx, Context):
if dtype is not None or enable_checks is not None:
warn(
'Provided concrete context, dtype and enable_checks parameters are ignored.',
UserWarning,
)
return Context(
ops=ctx.ops,
dtype=ctx.ops.sanitize_dtype(ctx.dtype),
Expand All @@ -81,7 +95,7 @@ def normalize_context(self, ctx: Context | BackendFamily | str | None = None) ->
if isinstance(ctx, (str, BackendFamily)):
ctx = self._backend_key(ctx)
ops = self.get_ops(ctx)
return self.ctx_from_ops(ops)
return self.ctx_from_ops(ops, dtype=dtype, enable_checks=enable_checks)
else:
raise TypeError(f'Expected Context, BackendFamily, str, or None, got {type(ctx)}.')

Expand Down
17 changes: 12 additions & 5 deletions spacecore/_contextual/manager.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
from typing import Any

from ..backend import Context, BackendOps
from .contextual import Contextual, ContextPolicy, DtypePreservePolicy
from ..backend import BackendFamily
Expand All @@ -6,7 +8,12 @@
ctx_manager = Contextual()


def set_context(ctx: Context | BackendFamily | str | None = None) -> None:
def set_context(
ctx: Context | BackendFamily | str | None = None,
dtype: Any = None,
enable_checks: bool | None = None
) -> None:
ctx = ctx_manager.normalize_context(ctx, dtype=dtype, enable_checks=enable_checks)
ctx_manager.default_ctx = ctx


Expand All @@ -22,8 +29,8 @@ def set_resolution_policy(policy: ContextPolicy | str | None = None) -> None:
ctx_manager.resolution_policy = policy


def get_resolution_policy() -> ContextPolicy:
return ctx_manager.resolution_policy
def get_resolution_policy() -> str:
return ctx_manager.resolution_policy.value


def set_dtype_resolution_policy(
Expand All @@ -32,5 +39,5 @@ def set_dtype_resolution_policy(
ctx_manager.dtype_resolution_policy = policy


def get_dtype_resolution_policy() -> DtypePreservePolicy:
return ctx_manager.dtype_resolution_policy
def get_dtype_resolution_policy() -> str:
return ctx_manager.dtype_resolution_policy.value
Loading