Source code for spacecore.linop._base
from __future__ import annotations
from abc import abstractmethod
from typing import Any, Generic, TypeVar
from ..space import Space
from ..backend import Context
from .._contextual import ContextBound
from .._contextual.manager import ctx_manager
Domain = TypeVar('Domain', bound=Space)
Codomain = TypeVar('Codomain', bound=Space)
[docs]
class LinOp(ContextBound, Generic[Domain, Codomain]):
"""
Minimal linear operator (morphism) between two spaces.
This class is intentionally small. It defines no matrix semantics,
arithmetic, or storage assumptions.
Its sole purpose is to represent a linear map
``A : dom -> cod``
with access to both forward and adjoint actions.
"""
def __init__(self, dom: Domain, cod: Codomain, ctx: Context | str | None = None):
ctx = ctx_manager.resolve_context_priority(ctx, dom, cod)
super(LinOp, self).__init__(ctx)
self.dom = dom.convert(self.ctx)
self.cod = cod.convert(self.ctx)
self._enable_checks = self.ctx.enable_checks
[docs]
@abstractmethod
def apply(self, x: Any) -> Any:
"""
Forward application: y = A x
Contract:
- x is an element of self.dom
- return value is an element of self.cod
"""
[docs]
@abstractmethod
def rapply(self, y: Any) -> Any:
"""
Adjoint application: x = A^* y
Contract:
- y is an element of self.cod
- return value is an element of self.dom
"""
def __call__(self, x: Any) -> Any:
return self.apply(x)
[docs]
def assert_domain(self, x: Any) -> None:
self.dom.check_member(x)
[docs]
def assert_codomain(self, y: Any) -> None:
self.cod.check_member(y)
def __eq__(self, x: Any) -> bool:
raise NotImplementedError()
def tree_flatten(self):
raise NotImplementedError()
@classmethod
def tree_unflatten(cls, aux, children):
raise NotImplementedError()