Context, dtype and conversion#
A Context is a frozen pair (ops, dtype): the backend operations and the
dtype of the arrays it creates. Arrays, devices, autograd state and
check_level are not part of it; the check level belongs to each object
(Checking policy).
Normalization#
sc.normalize_context(ctx, dtype=None) turns any context specification into
a Context:
|
result |
|---|---|
a |
a copy, dtype re-sanitized by |
a backend name or |
a new context for that backend with |
|
the active default context |
dtype is ignored, with a warning, for a Context or None.
A constructor with several context-bearing inputs uses an explicit ctx= when
given. Otherwise the inputs must share one backend family (else ValueError)
and their dtypes are promoted by that backend’s result_type.
Process-wide defaults#
Set the backend, dtype and check levels once; objects built without them use
the defaults. An explicit ctx or check_level argument always wins.
Default |
Set for the process |
Set inside a |
|---|---|---|
context (backend + dtype) |
|
|
check level of new objects |
|
|
check cap while tracing ( |
|
— |
Read them back with
get_context(),get_check_level(),get_traced_check_level().use_*overrides are scoped to the current thread or async task;set_*is visible to every thread, but ause_*block in progress keeps winning until it exits.Defaults are read at construction: changing them does not modify existing objects. Move an existing object with
convert.Nonerestores the built-in default for both check-level setters ("standard"and"none").set_context(None)keeps the current context; restore the built-in one withset_context("numpy", dtype="float64").
Dtype and scalar field#
The dtype is the representation; space.field ("real" or "complex")
is derived from it and has no separate override.
ctx.asarrayandctx.assparsealways producectx.dtype.float32/float64give a real space,complex64/complex128a complex one.FieldChecktests real/complex compatibility;DTypeCheckrequires the exact dtype, precision included. Real data passes the field check of a complex space and fails its dtype check.Conversion never narrows complex to real: converting a complex array to a real dtype raises
TypeErroreven when every imaginary part is zero. Passx.realto discard it.WeightedInnerProductweights must be real, finite and positive, also in a complex space (ValueError, checked fromstandard).EuclideanElementwiseJordanSpacerequires a real field (ValueError); useElementwiseJordanSpacefor complex data.
Membership failures raise SpaceValidationError, a subclass of both
TypeError and ValueError.
Where conversion happens#
SpaceCore converts arrays only in constructors and on request; operations such
as space.add or A.apply never convert their arguments. The object’s check
level decides how much of an argument is validated; under "none" it is
forwarded unchanged and a backend error may surface later.
ctx.asarray(x),ctx.assparse(x): a dense or sparse array inctx.obj.convert(new_ctx): the object rebuilt innew_ctx. It returnsobjwhen the context is unchanged and keepsobj.check_level.
How convert rebuilds an object:
By default from its declared
_fields(Extending SpaceCore):ctxis replaced, fields with aconvertmethod (spaces, operators, geometries such asWeightedInnerProduct) convert recursively, dense arrays go throughnew_ctx.asarray. A class with other needs overrides_convert, as sparse operators do withassparse.MatrixFreeLinOpkeeps its callables and converts only its spaces and context, so the callables must already run on the target backend.
Conversion fails when the target backend lacks a needed sparse format or dtype,
when user callables cannot run on the target arrays, or when the converted data
fails validation. JAX follows jax_enable_x64; Torch tensors are never moved
across devices.
Example#
import numpy as np
import spacecore as sc
src = sc.Context(sc.NumpyOps(), dtype=np.float32)
dst = sc.Context(sc.NumpyOps(), dtype=np.float64)
X = sc.DenseCoordinateSpace((2,), src, check_level="cheap")
Y = X.convert(dst)
print(Y.dtype == np.dtype("float64"), Y.check_level)
try:
sc.EuclideanElementwiseJordanSpace((2,), sc.Context(sc.NumpyOps(), dtype=np.complex128))
except ValueError as exc:
print(exc)
Expected output:
True cheap
EuclideanElementwiseJordanSpace requires a real scalar field.