Skip to content

Every concrete transformation stores its parameter as one array, data, together with the encoding flags that say what that array holds. What a transformation means is read through named, read-only views, which are always the map, as values, whatever the flags:

Class data holds Flags Views
DisplacementField the values, or their spline coefficients coeff, degree, bound, log field
CoordinatesField the values, or their spline coefficients coeff, degree, bound field
Affine the (No, Ni + 1) matrix log matrix, homogeneous_matrix
Linear, Rotation the (No, Ni) matrix log matrix
Scaling the scaling factors log scale
Translation the translation vector translation
Permutation the permutation vector permutation
CartesianField the grid, derived from shape coeff, degree, bound field
Identity nothing: always None

A field whose coeff flag is set stores the coefficients of the spline of degree degree (with boundary condition bound) that interpolates its values. Its field view decodes them, once, and caches the result on the instance, so code that reads a field never has to know how it is stored. Any other encoding is reached by conversion, never by a view: the coefficients of a field are t.to(coeff=True).data, and its values are t.field (or t.to(coeff=False).data).

A CartesianField stores its shape rather than an array, and derives its data from it, encoded under its flags. A lazy inverse, such as an InverseDisplacementField, derives its data from the transformation it inverts, in that transformation's encoding.

Inverting a field is approximate

The inverse of a displacement or coordinates field is computed from the field's values at its grid nodes only: they define a piecewise-affine map, which is inverted exactly (Ashburner's mesh inversion), and the result is interpolated with the field's degree. A field of degree 3 is therefore inverted as its piecewise-linear interpolant, about as accurately as a field of degree 1. On smooth fields of a few voxels' amplitude, fwd(inv(x)) - x is typically a few hundredths of a voxel in the interior and a few tenths near the border.

A StationaryVelocityField is the exception: its inverse is exp(-v), exact in the tangent, and integrated as accurately as the field itself; no mesh is inverted.

Constructors take data (positionally, as the first argument) and the flags. The view's name is also a keyword, a convenience meaning "the map, as values". One rule holds everywhere: a convenience keyword is the map, as values, and the flags describe how it is stored.

DisplacementField(u)  # u is displacement values
DisplacementField(field=u)  # the same
DisplacementField(data=c, degree=3, coeff=True)  # c is coefficients
DisplacementField(field=u, degree=3, coeff=True)  # stores u's coefficients
Affine(m), Affine(data=m), Affine(matrix=m)  # the same affine, thrice

So DisplacementField(field=u, degree=3, coeff=True) holds the same data as DisplacementField(field=u, degree=3).to(coeff=True): the constructor encodes u the way .to(...) does. A convenience keyword cannot be combined with data=, which already is the stored array.

data and the flags can be assigned in place (t.data = d, t.coeff = True, t.steps = 6). A cached view (field, or the matrix and scale of a tangent) is cleared when they are, so the next read reflects them. log selects the class, which an assignment cannot change: a class that holds the map refuses log = True. Such an assignment stores what it is given: t.coeff = True says that the array already in data holds coefficients, and reinterprets it. To change the map of an existing transformation, or how it is stored, use .to(...). Within a type, it re-encodes rather than reinterprets: t.to(field=u) stores u in the encoding of t, t.to(coeff=True) fits coefficients to the values, and t.to(degree=3) on a field of coefficients refits them. Passing data= to .to(...) stores the array as given, under the flags of the result. bagof.magic.replace is not the way to do it: it carries data over, so a convenience keyword passed through it (as in replace(t, field=u)) meets that data and raises whenever t has one, and a flag passed through it (as in replace(t, coeff=True)) reinterprets the stored array instead of re-encoding it.

Transformations compare, and hash, by identity: a == b is a is b, so two distinct transformations are never equal, whatever their data and flags (see Comparing transformations and images). The same map stored as values and as coefficients is two different objects either way. To test whether two transformations are the same map, use is_identity((a.inverse() @ b).compute(), compute=True); to compare how they are stored, compare their data and flags explicitly.

Tangents: the log flag

The log flag says which function data describes: the map itself, or its tangent about the identity, whose exponential is the map. A tangent is always about the identity, so unset or zero data is the identity whatever the flag. log=True builds a subclass whose views read data as a tangent:

Class data holds, with log=True Views
StationaryVelocityField(DisplacementField) the velocity: values, or coefficients field: the displacement of its flow at time one
AffineExponential(Affine) the (N, N + 1) tangent [L, l] matrix: expm([[L, l], [0, ..., 0]])[:-1]
LinearExponential(Linear) the (N, N) tangent L matrix: expm(L)
RotationExponential(Rotation) the antisymmetric (N, N) tangent L matrix: expm(L)
ScalingExponential(Scaling) the logarithms s of the factors scale: exp(s)

So DisplacementField(data=v, log=True) and StationaryVelocityField(data=v) are one object, and so are Affine(data=L, log=True) and AffineExponential(data=L). A tangent is never a matrix: LinearExponential(data=I) is the scaling by e, not the identity. Translation, Permutation, CoordinatesField, CartesianField and Identity take no log flag. A convenience keyword is still the map: Affine(matrix=M, log=True) stores the principal logarithm of M, while DisplacementField(field=u, log=True) raises, since a field has no logarithm that brainhops computes.

A field has the two flags, which combine; data is decoded from coefficients first, and integrated second:

log coeff data holds
False False the displacement, as values
False True the displacement's spline coefficients
True False the velocity, as values
True True the velocity's spline coefficients (NiftyReg -vel -cpp)

The field view of a StationaryVelocityField is always the displacement, as values. The velocity is integrated by scaling and squaring: it is divided by 2 ** steps, which is its own flow to first order, and composed with itself steps times. steps exists only on a StationaryVelocityField; left None, it is the smallest number for which the first step moves no point by more than an eighth of a voxel. A velocity of coefficients is refitted at each step. Any other encoding is reached by conversion: the velocity's coefficients are t.to(coeff=True).data, and its displacement is t.to(log=False).

The encoding changes with .to(log=...):

  • .to(log=True) takes the principal logarithm of a matrix (of the scaling factors), and raises DomainError when it has an eigenvalue on the closed negative real axis (a factor that is not positive). A field has no logarithm that brainhops computes: it raises NotImplementedError, unless the field is unset.
  • .to(log=False) builds the base class (Affine, DisplacementField, ...) from the exponential: the matrix, or the integrated displacement, which keeps its coeff, degree and bound.
  • The flags combine: .to(coeff=False) on a velocity decodes its coefficients and keeps log, and .to(log=False) keeps coeff.
  • A SubspaceTransformation converts its inner transformation (the axes it does not act on are the identity, whose tangent is zero).
  • A Sequence converts the transformation it reduces to: a chain that simplifies to one transformation; the middle of a change of coordinates [P, *X, P^-1], whose ends are kept (the flow commutes with them, so a velocity read between a world-to-voxel affine and its inverse becomes its displacement exactly); or the affine a chain of affines composes to. Any other chain is refused before anything is computed.

A tangent makes some operations exact: inverse() is a lazy Inverse whose data is the negated tangent, which still cancels against its forward in a Sequence; sqrt() halves the tangent (a velocity integrates with one squaring fewer), and square() doubles it.

brainhops.datamodel.transformations

Attributes

is_kind module-attribute

is_kind: IsKind = IsKind()

Public membership predicate, that dispatches on its input types.

ModeLike module-attribute

ModeLike = (
    None | bool | FamilyLike | tx.Iterable[FamilyLike]
)

Possible input to the mode argument of [compute()][].

UNARY_OPERATORS module-attribute

UNARY_OPERATORS: Mapping[
    str, Callable[[Transformation], Transformation]
] = MappingProxyType(
    {
        name: methodcaller(name)
        for name in ("inverse", "square", "sqrt")
    }
)

The unary operators of a transformation, by name.

Each value takes a transformation and returns the result of the method of the same name, with its defaults: a lazy result where there is one. It is the table an expression parser looks names up in, so that the operators it accepts are exactly the ones a transformation implements.

SimplifyLike module-attribute

SimplifyLike = (
    PolicyLike
    | FamilyLike
    | tx.Iterable[FamilyLike]
    | tx.Mapping[FamilyLike, PolicyLike]
)

Possible input to the simplify argument of [compute()][].

Classes

Transformation magic

Transformation(
    data_fields: ClassVar[tuple[str, ...]] = (),
    metadata_fields: ClassVar[tuple[str, ...]] = (),
    derived_fields: ClassVar[tuple[str, ...]] = (),
    *,
    _input: CoordinateSystem | None = None,
    _output: CoordinateSystem | None = None,
)

Bases: IdentityComparison, DataModelBase

A transformation between coordinate systems.

It maps coordinates from an input coordinate system to an output coordinate system. Transformations can be applied and/or composed using different syntaxes:

  1. Functional: t(x) applies the transform t to coordinates x, and t2(t1) composes the transform t1 with the transform t2 (i.e., applies t1 first, then t2).

  2. Matrix-like: t @ x applies the transform t to coordinates x, and t2 @ t1 composes the transform t1 with the transform t2.

This abuses the matrix multiplication operator @ because linear and affine transformations can be represented as matrices, and are typically applied to coordinates using matrix multiplication, with the input space "on the right" and the output space "on the left".

Direction of transformation

This mapping direction is the opposite of the direction that is typically used to transform images. For example, a transformation that deforms an image from space A to space B, will actually map coordinates from space B to space A. In our model, this transformation would be represented as Transform(input=B, output=A).

Transformations compare by identity

t1 == t2 is t1 is t2: two distinct transformations are never equal, even when they hold the same parameters in the same systems, and == never raises. A transformation hashes by identity too, so it can be put in a set or used as a dictionary key. Whether two transformations represent the same map has no single answer, so none is picked. To test whether two map coordinates the same way, check that one composed with the inverse of the other is the identity -- is_identity((t1.inverse() @ t2).compute(), compute=True) -- and compare their input/output systems explicitly.

Methods:

from_dict classmethod
from_dict(other: Mapping, *args, **kwargs) -> Self

Create an instance of the class from a dictionary-like object.

Only keys in the dictionary that match keyword-like fields of this class, or the keywords its constructor takes without storing them (its InitVars, such as the matrix= of an Affine), will be used. Other keys are ignored, but see from_other, which refuses them.

Additional positional and/or keyword arguments can be provided, and will take precedence over the values in the dictionary.

A key naming a field that this class fixes (a field that cannot be passed to its constructor) is checked instead of used: a dictionary that sets it to anything other than None or the value of this class is refused with a ValueError.

from_instance classmethod
from_instance(other: Self, *args, **kwargs) -> Self

Create an instance of the class from an instance of a similar class.

Only attributes of the other instance that match keyword-like fields of this class will be used. An attribute that is None is unset, and leaves the default of this class in place.

Additional positional and/or keyword arguments can be provided, and will take precedence over the attributes in the instance.

Unless the other instance is already an instance of this class, an attribute naming a field that this class fixes (a field that cannot be passed to its constructor) is checked instead of used: an instance that sets it to anything other than None or the value of this class is refused with a ValueError. A generic Axis whose orientation is right-to-left, for example, cannot be read as a LeftToRightAxis.

from_other classmethod
from_other(other: Any, *args, **kwargs) -> Self

Create an instance of the class from any object that can be interpreted as a dictionary, or an instance of a similar class, or an arguments to be passed to the constructor.

A similar class is this class or one of its parents within the data model, or another member of a polymorphic family this class belongs to: calling a polymorphic class such as Axis builds the subclass its arguments select, so a "generic" axis is usually an instance of a sibling (a RightToLeftAxis, a TimeAxis) rather than of a parent. Any other object, including an instance of a parent that is not a data model (such as a plain object), is passed to the constructor.

Unlike from_dict, a dictionary with a key that matches no field of this class is refused with a TypeError naming the keys, so that a misspelt key is not silently dropped.

compute
compute(
    mode: ModeLike = True,
    *,
    simplify: SimplifyLike = "analytic",
    factor: bool = False,
) -> Self

Compute the transformation, if it is not already fully defined.

Parameters:

Name Type Description Default
mode [list of] name or type

Which kinds of transformations to materialize. True (the default) admits every kind. On a leaf transformation, if a mode is given and this leaf is not admitted by it, the leaf is returned unchanged. Keys are transformation types, names or symbols (e.g., "affine", "Aff", "rigid", "SO(3)").

True
simplify SimplifyLike
"analytic"
What

Whether to simplify the transformation prior if possible, and how hard to try to simplify them. * "analytic" (the default) looks at the type structure only; * "numeric" looks at the numeric values of the transformation; * False/"none"/None disables simplification.

required
factor bool

Whether to rewrite the transformation into its axis-group normal form, splitting it into independent factors that each act on a group of axes that transform together. Off by default, so a plain compute() result is unchanged. Nothing is ever composed across axis groups; mode still decides whether the restricted pieces inside a group compose.

False
simplify
simplify(
    policy: SimplifyLike = "analytic",
    *,
    compute: ModeLike | bool | None = False,
) -> Self

Simplify this transformation under a per-kind policy.

Convenience sugar for compute: t.simplify(policy, compute=mode) is t.compute(mode, simplify=policy).

By default simplify() does no computation at all: compute=False maps to mode=False, which composes nothing (no matrices multiplied, no fields sampled, no lazy inverse materialized). It only downcasts each leaf under policy (analytic by default). Pass an explicit compute=<mode> to also compose that kind.

Parameters:

Name Type Description Default
policy simplify policy

The simplify policy, in the grammar compute accepts.

"analytic"
compute [list of] name or type

The compose mode. The default, False, composes nothing (mode=False in compute); None would compose every kind. A real mode passes straight through.

False
inverse
inverse(compute: bool = False, **kwargs) -> Self

Return the inverse of this transformation.

Some classes of transformations return a lazy inverse by default, which is only evaluated when the compute() method is called. This allows for efficient composition of transformations. Or the inverse can be computed immediately by setting compute=True.

The inverse can also be obtained using the __invert__ operator: T.inverse() is equivalent to ~T.

square
square(compute: bool = False, **kwargs) -> Transformation

Return the square of this transformation, self @ self.

The square is the sequence [self, self], which composes when it is computed. It is defined for a transformation that maps a space to itself.

Parameters:

Name Type Description Default
compute bool

Whether to compute the result now rather than return it lazily.

False
**kwargs

Passed to compute when compute is true.

{}

Raises:

Type Description
DomainError

If the transformation does not map a space to itself.

sqrt
sqrt(compute: bool = False, **kwargs) -> Transformation

Return the principal square root of this transformation.

The square root S of T is the transformation with S @ S == T, the half-transformation. The principal one, whose linear part has its eigenvalues in the open right half-plane, is unique, and it is of the same kind as T: the square root of a rotation is a rotation, of a translation a translation, of a scaling a scaling, of an affine an affine. The square root of a permutation is a Linear transformation.

The square root is lazy: an Sqrt wrapper is returned, and computed when it is applied, computed or converted. A transformation that needs no wrapper (an identity) is returned as is. A Sequence is reduced first (see Sequence.sqrt).

Parameters:

Name Type Description Default
compute bool

Whether to compute the result now rather than return it lazily.

False
**kwargs

Passed to compute when compute is true.

{}

Raises:

Type Description
DomainError

If the transformation does not map a space to itself, or, when the result is computed, if its linear part has an eigenvalue on the closed negative real axis (a reflection, a rotation by a half turn, a singular matrix), so that it has no real principal square root.

NotImplementedError

If brainhops does not compute the square root of this kind of transformation. A displacement field has one only when it is a stationary velocity field (log=True), whose square root halves its velocity.

to
to(
    cls: Type[Self] | None = None,
    *,
    lossy: bool = False,
    error: Type[Exception] | Exception | bool = True,
    **kwargs,
) -> Self

Convert this transformation to a different type.

Conversion can be

  • between type: linear.to(Affine) ; or
  • within type: displacement.to(coeff=True) ; or
  • both: coords.to(DisplacementField, coeff=True) .

Parameters:

Name Type Description Default
cls type

The type to convert to. If None, keep the current type.

None
lossy bool

Whether to allow lossy conversions.

False
error bool or Exception

Whether to raise an error if the conversion fails:

  • If an Exception, raise it.
  • If True, raise the original error.
  • Otherwise, return the value of error.
True
**kwargs dict

Attributes to override in the converted transform. This allows transformations to be modified within their type. For example, a DisplacementField can be converted from a field of values to a field of spline coefficients by setting coeff=True in kwargs: a change of encoding flag re-encodes the stored data, and keeps the map. A view's name (field=, matrix=, ...) sets the map, as values, and it is stored in the encoding of the result; data= is stored as given.

{}

Returns:

Type Description
Transformation

The converted transformation.

Affine magic

Affine(
    _data: npmatrix[Real] | None = None,
    *,
    _log: bool = False,
    _matrix: InitVar[npmatrix[Real] | None] = None,
)

Bases: ConcreteTransformation

An affine transformation.

data holds its (No, Ni + 1) matrix. log=True builds an AffineExponential, whose data is the tangent of the map about the identity instead.

Attributes

matrix property
matrix: ArrayProtocol | None

The affine matrix, of shape (No, Ni + 1), whose last column is the translation component.

homogeneous_matrix property
homogeneous_matrix: ArrayProtocol

The homogeneous matrix of the affine transformation, of shape (No + 1, Ni + 1). The last row of the homogeneous matrix is [0, 0, ..., 1].

Methods:

from_dict classmethod
from_dict(other: Mapping, *args, **kwargs) -> Self

Create an instance of the class from a dictionary-like object.

Only keys in the dictionary that match keyword-like fields of this class, or the keywords its constructor takes without storing them (its InitVars, such as the matrix= of an Affine), will be used. Other keys are ignored, but see from_other, which refuses them.

Additional positional and/or keyword arguments can be provided, and will take precedence over the values in the dictionary.

A key naming a field that this class fixes (a field that cannot be passed to its constructor) is checked instead of used: a dictionary that sets it to anything other than None or the value of this class is refused with a ValueError.

from_other classmethod
from_other(other: Any, *args, **kwargs) -> Self

Create an instance of the class from any object that can be interpreted as a dictionary, or an instance of a similar class, or an arguments to be passed to the constructor.

A similar class is this class or one of its parents within the data model, or another member of a polymorphic family this class belongs to: calling a polymorphic class such as Axis builds the subclass its arguments select, so a "generic" axis is usually an instance of a sibling (a RightToLeftAxis, a TimeAxis) rather than of a parent. Any other object, including an instance of a parent that is not a data model (such as a plain object), is passed to the constructor.

Unlike from_dict, a dictionary with a key that matches no field of this class is refused with a TypeError naming the keys, so that a misspelt key is not silently dropped.

compute
compute(
    mode: ModeLike = True,
    *,
    simplify: SimplifyLike = "analytic",
    factor: bool = False,
) -> Self

Compute the transformation, downcasting it to the cheapest compatible kind.

A concrete transformation holds a parameter, so it simplifies to the simplest compatible kind, whose compatibility can be detected with (almost) no overhead. For example, a transformation whose parameter is set to None is treated as an identity.

Parameters:

Name Type Description Default
mode [list of] name or type

Ignored on a leaf. mode gates which kinds compose, and a leaf has nothing to compose; its downcast is gated only by simplify (simplification is decoupled from the compose mode).

True
simplify simplify policy

How hard this leaf may be looked at. The resolved SimplifyPolicy decides whether the kind-checks run structure-only (analytic) or read values (numeric), or are skipped entirely (none).

"analytic"
factor bool

Whether to factor this leaf into its axis-group normal form. A leaf factors by wrapping itself in a one-element sequence, so a diagonal affine (say) splits into its per-axis blocks. Off by default.

False
simplify
simplify(
    policy: SimplifyLike = "analytic",
    *,
    compute: ModeLike | bool | None = False,
) -> Self

Simplify this transformation under a per-kind policy.

Convenience sugar for compute: t.simplify(policy, compute=mode) is t.compute(mode, simplify=policy).

By default simplify() does no computation at all: compute=False maps to mode=False, which composes nothing (no matrices multiplied, no fields sampled, no lazy inverse materialized). It only downcasts each leaf under policy (analytic by default). Pass an explicit compute=<mode> to also compose that kind.

Parameters:

Name Type Description Default
policy simplify policy

The simplify policy, in the grammar compute accepts.

"analytic"
compute [list of] name or type

The compose mode. The default, False, composes nothing (mode=False in compute); None would compose every kind. A real mode passes straight through.

False
square
square(compute: bool = False, **kwargs) -> Transformation

Return the square of this transformation, self @ self.

The square is the sequence [self, self], which composes when it is computed. It is defined for a transformation that maps a space to itself.

Parameters:

Name Type Description Default
compute bool

Whether to compute the result now rather than return it lazily.

False
**kwargs

Passed to compute when compute is true.

{}

Raises:

Type Description
DomainError

If the transformation does not map a space to itself.

to
to(
    cls: Type[Self] | None = None,
    *,
    lossy: bool = False,
    error: Type[Exception] | Exception | bool = True,
    **kwargs,
) -> Self

Convert this transformation to a different type.

Conversion can be

  • between type: linear.to(Affine) ; or
  • within type: displacement.to(coeff=True) ; or
  • both: coords.to(DisplacementField, coeff=True) .

Parameters:

Name Type Description Default
cls type

The type to convert to. If None, keep the current type.

None
lossy bool

Whether to allow lossy conversions.

False
error bool or Exception

Whether to raise an error if the conversion fails:

  • If an Exception, raise it.
  • If True, raise the original error.
  • Otherwise, return the value of error.
True
**kwargs dict

Attributes to override in the converted transform. This allows transformations to be modified within their type. For example, a DisplacementField can be converted from a field of values to a field of spline coefficients by setting coeff=True in kwargs: a change of encoding flag re-encodes the stored data, and keeps the map. A view's name (field=, matrix=, ...) sets the map, as values, and it is stored in the encoding of the result; data= is stored as given.

{}

Returns:

Type Description
Transformation

The converted transformation.

from_instance classmethod
from_instance(other: Any, *args, **kwargs) -> Self

Create an instance from an instance of a similar class.

See DataModelBase.from_instance. The map of an Affine is copied through its matrix view, not its stored data, which a lazy wrapper derives and a tangent (log=True) stores as its logarithm. A tangent is copied into a tangent through its data.

AffineExponential

AffineExponential(
    _data: npmatrix[Real] | None = None,
    *,
    _log: bool = False,
    _matrix: InitVar[npmatrix[Real] | None] = None,
)

Bases: Affine

An affine transformation stored as its tangent (log=True).

data is the (N, N + 1) tangent [L, l] of the map about the identity, and the map is its exponential: matrix is the top N rows of expm([[L, l], [0, ..., 0]]), computed once, then cached. L may be singular -- a translation has the tangent [0, t]. Unset or zero data is the identity, and AffineExponential(data=I) is the scaling by e, not the identity: a tangent is never a matrix.

The exponential of a real tangent has a positive determinant, so it is a PositiveAffine. Its inverse, square root and square are exact: the tangent negated, halved and doubled. .to(log=False) gives the plain Affine of matrix, and Affine.to(log=True) takes the principal logarithm of a matrix, which is refused (DomainError) when its linear part has an eigenvalue on the closed negative real axis.

Attributes

homogeneous_matrix property
homogeneous_matrix: ArrayProtocol

The homogeneous matrix of the affine transformation, of shape (No + 1, Ni + 1). The last row of the homogeneous matrix is [0, 0, ..., 1].

Methods:

from_dict classmethod
from_dict(other: Mapping, *args, **kwargs) -> Self

Create an instance of the class from a dictionary-like object.

Only keys in the dictionary that match keyword-like fields of this class, or the keywords its constructor takes without storing them (its InitVars, such as the matrix= of an Affine), will be used. Other keys are ignored, but see from_other, which refuses them.

Additional positional and/or keyword arguments can be provided, and will take precedence over the values in the dictionary.

A key naming a field that this class fixes (a field that cannot be passed to its constructor) is checked instead of used: a dictionary that sets it to anything other than None or the value of this class is refused with a ValueError.

from_instance classmethod
from_instance(other: Any, *args, **kwargs) -> Self

Create an instance from an instance of a similar class.

See DataModelBase.from_instance. The map of an Affine is copied through its matrix view, not its stored data, which a lazy wrapper derives and a tangent (log=True) stores as its logarithm. A tangent is copied into a tangent through its data.

from_other classmethod
from_other(other: Any, *args, **kwargs) -> Self

Create an instance of the class from any object that can be interpreted as a dictionary, or an instance of a similar class, or an arguments to be passed to the constructor.

A similar class is this class or one of its parents within the data model, or another member of a polymorphic family this class belongs to: calling a polymorphic class such as Axis builds the subclass its arguments select, so a "generic" axis is usually an instance of a sibling (a RightToLeftAxis, a TimeAxis) rather than of a parent. Any other object, including an instance of a parent that is not a data model (such as a plain object), is passed to the constructor.

Unlike from_dict, a dictionary with a key that matches no field of this class is refused with a TypeError naming the keys, so that a misspelt key is not silently dropped.

compute
compute(
    mode: ModeLike = True,
    *,
    simplify: SimplifyLike = "analytic",
    factor: bool = False,
) -> Self

Compute the transformation, downcasting it to the cheapest compatible kind.

A concrete transformation holds a parameter, so it simplifies to the simplest compatible kind, whose compatibility can be detected with (almost) no overhead. For example, a transformation whose parameter is set to None is treated as an identity.

Parameters:

Name Type Description Default
mode [list of] name or type

Ignored on a leaf. mode gates which kinds compose, and a leaf has nothing to compose; its downcast is gated only by simplify (simplification is decoupled from the compose mode).

True
simplify simplify policy

How hard this leaf may be looked at. The resolved SimplifyPolicy decides whether the kind-checks run structure-only (analytic) or read values (numeric), or are skipped entirely (none).

"analytic"
factor bool

Whether to factor this leaf into its axis-group normal form. A leaf factors by wrapping itself in a one-element sequence, so a diagonal affine (say) splits into its per-axis blocks. Off by default.

False
simplify
simplify(
    policy: SimplifyLike = "analytic",
    *,
    compute: ModeLike | bool | None = False,
) -> Self

Simplify this transformation under a per-kind policy.

Convenience sugar for compute: t.simplify(policy, compute=mode) is t.compute(mode, simplify=policy).

By default simplify() does no computation at all: compute=False maps to mode=False, which composes nothing (no matrices multiplied, no fields sampled, no lazy inverse materialized). It only downcasts each leaf under policy (analytic by default). Pass an explicit compute=<mode> to also compose that kind.

Parameters:

Name Type Description Default
policy simplify policy

The simplify policy, in the grammar compute accepts.

"analytic"
compute [list of] name or type

The compose mode. The default, False, composes nothing (mode=False in compute); None would compose every kind. A real mode passes straight through.

False
matrix
matrix() -> ArrayProtocol | None

The affine matrix, of shape (N, N + 1): the exponential of the tangent data.

CartesianField magic

CartesianField(_shape: tuple[int, ...] | None = None, _data: Deactivated[ArrayProtocol | None], _field: Deactivated[ArrayProtocol | None])

Bases: CoordinatesField

An identity transform over a regular grid of coordinates.

Both the input and output spaces correspond to the underlying grid.

It stores the shape of the grid rather than an array. Its field (the coordinates of the grid points) and its data (the same coordinates, encoded under the flags) are generated on demand, and cached until shape or a flag is assigned.

Methods:

from_dict classmethod
from_dict(other: Mapping, *args, **kwargs) -> Self

Create an instance of the class from a dictionary-like object.

Only keys in the dictionary that match keyword-like fields of this class, or the keywords its constructor takes without storing them (its InitVars, such as the matrix= of an Affine), will be used. Other keys are ignored, but see from_other, which refuses them.

Additional positional and/or keyword arguments can be provided, and will take precedence over the values in the dictionary.

A key naming a field that this class fixes (a field that cannot be passed to its constructor) is checked instead of used: a dictionary that sets it to anything other than None or the value of this class is refused with a ValueError.

from_instance classmethod
from_instance(other: Any, *args, **kwargs) -> Self

Create an instance from an instance of a similar class.

See DataModelBase.from_instance. A lazy wrapper derives its data and its flags, so they are read through their public names.

from_other classmethod
from_other(other: Any, *args, **kwargs) -> Self

Create an instance of the class from any object that can be interpreted as a dictionary, or an instance of a similar class, or an arguments to be passed to the constructor.

A similar class is this class or one of its parents within the data model, or another member of a polymorphic family this class belongs to: calling a polymorphic class such as Axis builds the subclass its arguments select, so a "generic" axis is usually an instance of a sibling (a RightToLeftAxis, a TimeAxis) rather than of a parent. Any other object, including an instance of a parent that is not a data model (such as a plain object), is passed to the constructor.

Unlike from_dict, a dictionary with a key that matches no field of this class is refused with a TypeError naming the keys, so that a misspelt key is not silently dropped.

compute
compute(
    mode: ModeLike = True,
    *,
    simplify: SimplifyLike = "analytic",
    factor: bool = False,
) -> Self

Compute the transformation, downcasting it to the cheapest compatible kind.

A concrete transformation holds a parameter, so it simplifies to the simplest compatible kind, whose compatibility can be detected with (almost) no overhead. For example, a transformation whose parameter is set to None is treated as an identity.

Parameters:

Name Type Description Default
mode [list of] name or type

Ignored on a leaf. mode gates which kinds compose, and a leaf has nothing to compose; its downcast is gated only by simplify (simplification is decoupled from the compose mode).

True
simplify simplify policy

How hard this leaf may be looked at. The resolved SimplifyPolicy decides whether the kind-checks run structure-only (analytic) or read values (numeric), or are skipped entirely (none).

"analytic"
factor bool

Whether to factor this leaf into its axis-group normal form. A leaf factors by wrapping itself in a one-element sequence, so a diagonal affine (say) splits into its per-axis blocks. Off by default.

False
simplify
simplify(
    policy: SimplifyLike = "analytic",
    *,
    compute: ModeLike | bool | None = False,
) -> Self

Simplify this transformation under a per-kind policy.

Convenience sugar for compute: t.simplify(policy, compute=mode) is t.compute(mode, simplify=policy).

By default simplify() does no computation at all: compute=False maps to mode=False, which composes nothing (no matrices multiplied, no fields sampled, no lazy inverse materialized). It only downcasts each leaf under policy (analytic by default). Pass an explicit compute=<mode> to also compose that kind.

Parameters:

Name Type Description Default
policy simplify policy

The simplify policy, in the grammar compute accepts.

"analytic"
compute [list of] name or type

The compose mode. The default, False, composes nothing (mode=False in compute); None would compose every kind. A real mode passes straight through.

False
to
to(
    cls: Type[Self] | None = None,
    *,
    lossy: bool = False,
    error: Type[Exception] | Exception | bool = True,
    **kwargs,
) -> Self

Convert this transformation to a different type.

Conversion can be

  • between type: linear.to(Affine) ; or
  • within type: displacement.to(coeff=True) ; or
  • both: coords.to(DisplacementField, coeff=True) .

Parameters:

Name Type Description Default
cls type

The type to convert to. If None, keep the current type.

None
lossy bool

Whether to allow lossy conversions.

False
error bool or Exception

Whether to raise an error if the conversion fails:

  • If an Exception, raise it.
  • If True, raise the original error.
  • Otherwise, return the value of error.
True
**kwargs dict

Attributes to override in the converted transform. This allows transformations to be modified within their type. For example, a DisplacementField can be converted from a field of values to a field of spline coefficients by setting coeff=True in kwargs: a change of encoding flag re-encodes the stored data, and keeps the map. A view's name (field=, matrix=, ...) sets the map, as values, and it is stored in the encoding of the result; data= is stored as given.

{}

Returns:

Type Description
Transformation

The converted transformation.

field
field() -> ArrayProtocol | None

The coordinates of the grid points, of shape (*shape, ndim).

They are real coordinates, so they are built in the backend's default floating dtype (float64 with NumPy), and so are their spline coefficients in data.

data
data() -> ArrayProtocol | None

The coordinates of the grid points, encoded under the flags.

CoordinatesField

CoordinatesField(
    _data: ArrayProtocol | None = None,
    _degree: InterpolationOrder = linear,
    _bound: BoundaryCondition | float = nearest,
    _coeff: bool = False,
    *,
    _field: InitVar[ArrayProtocol | None] = None,
)

Bases: TransformationField

A field of coordinates defined on a regular grid.

The input space corresponds to the regular grid on which the coordinates are defined.

Methods:

from_dict classmethod
from_dict(other: Mapping, *args, **kwargs) -> Self

Create an instance of the class from a dictionary-like object.

Only keys in the dictionary that match keyword-like fields of this class, or the keywords its constructor takes without storing them (its InitVars, such as the matrix= of an Affine), will be used. Other keys are ignored, but see from_other, which refuses them.

Additional positional and/or keyword arguments can be provided, and will take precedence over the values in the dictionary.

A key naming a field that this class fixes (a field that cannot be passed to its constructor) is checked instead of used: a dictionary that sets it to anything other than None or the value of this class is refused with a ValueError.

from_other classmethod
from_other(other: Any, *args, **kwargs) -> Self

Create an instance of the class from any object that can be interpreted as a dictionary, or an instance of a similar class, or an arguments to be passed to the constructor.

A similar class is this class or one of its parents within the data model, or another member of a polymorphic family this class belongs to: calling a polymorphic class such as Axis builds the subclass its arguments select, so a "generic" axis is usually an instance of a sibling (a RightToLeftAxis, a TimeAxis) rather than of a parent. Any other object, including an instance of a parent that is not a data model (such as a plain object), is passed to the constructor.

Unlike from_dict, a dictionary with a key that matches no field of this class is refused with a TypeError naming the keys, so that a misspelt key is not silently dropped.

compute
compute(
    mode: ModeLike = True,
    *,
    simplify: SimplifyLike = "analytic",
    factor: bool = False,
) -> Self

Compute the transformation, downcasting it to the cheapest compatible kind.

A concrete transformation holds a parameter, so it simplifies to the simplest compatible kind, whose compatibility can be detected with (almost) no overhead. For example, a transformation whose parameter is set to None is treated as an identity.

Parameters:

Name Type Description Default
mode [list of] name or type

Ignored on a leaf. mode gates which kinds compose, and a leaf has nothing to compose; its downcast is gated only by simplify (simplification is decoupled from the compose mode).

True
simplify simplify policy

How hard this leaf may be looked at. The resolved SimplifyPolicy decides whether the kind-checks run structure-only (analytic) or read values (numeric), or are skipped entirely (none).

"analytic"
factor bool

Whether to factor this leaf into its axis-group normal form. A leaf factors by wrapping itself in a one-element sequence, so a diagonal affine (say) splits into its per-axis blocks. Off by default.

False
simplify
simplify(
    policy: SimplifyLike = "analytic",
    *,
    compute: ModeLike | bool | None = False,
) -> Self

Simplify this transformation under a per-kind policy.

Convenience sugar for compute: t.simplify(policy, compute=mode) is t.compute(mode, simplify=policy).

By default simplify() does no computation at all: compute=False maps to mode=False, which composes nothing (no matrices multiplied, no fields sampled, no lazy inverse materialized). It only downcasts each leaf under policy (analytic by default). Pass an explicit compute=<mode> to also compose that kind.

Parameters:

Name Type Description Default
policy simplify policy

The simplify policy, in the grammar compute accepts.

"analytic"
compute [list of] name or type

The compose mode. The default, False, composes nothing (mode=False in compute); None would compose every kind. A real mode passes straight through.

False
square
square(compute: bool = False, **kwargs) -> Transformation

Return the square of this transformation, self @ self.

The square is the sequence [self, self], which composes when it is computed. It is defined for a transformation that maps a space to itself.

Parameters:

Name Type Description Default
compute bool

Whether to compute the result now rather than return it lazily.

False
**kwargs

Passed to compute when compute is true.

{}

Raises:

Type Description
DomainError

If the transformation does not map a space to itself.

to
to(
    cls: Type[Self] | None = None,
    *,
    lossy: bool = False,
    error: Type[Exception] | Exception | bool = True,
    **kwargs,
) -> Self

Convert this transformation to a different type.

Conversion can be

  • between type: linear.to(Affine) ; or
  • within type: displacement.to(coeff=True) ; or
  • both: coords.to(DisplacementField, coeff=True) .

Parameters:

Name Type Description Default
cls type

The type to convert to. If None, keep the current type.

None
lossy bool

Whether to allow lossy conversions.

False
error bool or Exception

Whether to raise an error if the conversion fails:

  • If an Exception, raise it.
  • If True, raise the original error.
  • Otherwise, return the value of error.
True
**kwargs dict

Attributes to override in the converted transform. This allows transformations to be modified within their type. For example, a DisplacementField can be converted from a field of values to a field of spline coefficients by setting coeff=True in kwargs: a change of encoding flag re-encodes the stored data, and keeps the map. A view's name (field=, matrix=, ...) sets the map, as values, and it is stored in the encoding of the result; data= is stored as given.

{}

Returns:

Type Description
Transformation

The converted transformation.

field
field() -> ArrayProtocol | None

The field, as values: an array of shape (*shape, ndim).

It is data itself when coeff is false, and data decoded from spline coefficients (once, then cached) when it is true.

from_instance classmethod
from_instance(other: Any, *args, **kwargs) -> Self

Create an instance from an instance of a similar class.

See DataModelBase.from_instance. A lazy wrapper derives its data and its flags, so they are read through their public names.

DisplacementField magic

DisplacementField(*, _log: bool = False)

Bases: TransformationField

A field of displacements defined on a regular grid.

Both the input and output spaces correspond to the underlying grid.

The log flag says which function data describes: the displacement itself, or, when log is true, the stationary velocity whose flow at time one is the map. log=True builds a StationaryVelocityField, whose field view integrates that velocity; a plain DisplacementField always holds displacements.

Methods:

from_dict classmethod
from_dict(other: Mapping, *args, **kwargs) -> Self

Create an instance of the class from a dictionary-like object.

Only keys in the dictionary that match keyword-like fields of this class, or the keywords its constructor takes without storing them (its InitVars, such as the matrix= of an Affine), will be used. Other keys are ignored, but see from_other, which refuses them.

Additional positional and/or keyword arguments can be provided, and will take precedence over the values in the dictionary.

A key naming a field that this class fixes (a field that cannot be passed to its constructor) is checked instead of used: a dictionary that sets it to anything other than None or the value of this class is refused with a ValueError.

from_other classmethod
from_other(other: Any, *args, **kwargs) -> Self

Create an instance of the class from any object that can be interpreted as a dictionary, or an instance of a similar class, or an arguments to be passed to the constructor.

A similar class is this class or one of its parents within the data model, or another member of a polymorphic family this class belongs to: calling a polymorphic class such as Axis builds the subclass its arguments select, so a "generic" axis is usually an instance of a sibling (a RightToLeftAxis, a TimeAxis) rather than of a parent. Any other object, including an instance of a parent that is not a data model (such as a plain object), is passed to the constructor.

Unlike from_dict, a dictionary with a key that matches no field of this class is refused with a TypeError naming the keys, so that a misspelt key is not silently dropped.

compute
compute(
    mode: ModeLike = True,
    *,
    simplify: SimplifyLike = "analytic",
    factor: bool = False,
) -> Self

Compute the transformation, downcasting it to the cheapest compatible kind.

A concrete transformation holds a parameter, so it simplifies to the simplest compatible kind, whose compatibility can be detected with (almost) no overhead. For example, a transformation whose parameter is set to None is treated as an identity.

Parameters:

Name Type Description Default
mode [list of] name or type

Ignored on a leaf. mode gates which kinds compose, and a leaf has nothing to compose; its downcast is gated only by simplify (simplification is decoupled from the compose mode).

True
simplify simplify policy

How hard this leaf may be looked at. The resolved SimplifyPolicy decides whether the kind-checks run structure-only (analytic) or read values (numeric), or are skipped entirely (none).

"analytic"
factor bool

Whether to factor this leaf into its axis-group normal form. A leaf factors by wrapping itself in a one-element sequence, so a diagonal affine (say) splits into its per-axis blocks. Off by default.

False
simplify
simplify(
    policy: SimplifyLike = "analytic",
    *,
    compute: ModeLike | bool | None = False,
) -> Self

Simplify this transformation under a per-kind policy.

Convenience sugar for compute: t.simplify(policy, compute=mode) is t.compute(mode, simplify=policy).

By default simplify() does no computation at all: compute=False maps to mode=False, which composes nothing (no matrices multiplied, no fields sampled, no lazy inverse materialized). It only downcasts each leaf under policy (analytic by default). Pass an explicit compute=<mode> to also compose that kind.

Parameters:

Name Type Description Default
policy simplify policy

The simplify policy, in the grammar compute accepts.

"analytic"
compute [list of] name or type

The compose mode. The default, False, composes nothing (mode=False in compute); None would compose every kind. A real mode passes straight through.

False
square
square(compute: bool = False, **kwargs) -> Transformation

Return the square of this transformation, self @ self.

The square is the sequence [self, self], which composes when it is computed. It is defined for a transformation that maps a space to itself.

Parameters:

Name Type Description Default
compute bool

Whether to compute the result now rather than return it lazily.

False
**kwargs

Passed to compute when compute is true.

{}

Raises:

Type Description
DomainError

If the transformation does not map a space to itself.

to
to(
    cls: Type[Self] | None = None,
    *,
    lossy: bool = False,
    error: Type[Exception] | Exception | bool = True,
    **kwargs,
) -> Self

Convert this transformation to a different type.

Conversion can be

  • between type: linear.to(Affine) ; or
  • within type: displacement.to(coeff=True) ; or
  • both: coords.to(DisplacementField, coeff=True) .

Parameters:

Name Type Description Default
cls type

The type to convert to. If None, keep the current type.

None
lossy bool

Whether to allow lossy conversions.

False
error bool or Exception

Whether to raise an error if the conversion fails:

  • If an Exception, raise it.
  • If True, raise the original error.
  • Otherwise, return the value of error.
True
**kwargs dict

Attributes to override in the converted transform. This allows transformations to be modified within their type. For example, a DisplacementField can be converted from a field of values to a field of spline coefficients by setting coeff=True in kwargs: a change of encoding flag re-encodes the stored data, and keeps the map. A view's name (field=, matrix=, ...) sets the map, as values, and it is stored in the encoding of the result; data= is stored as given.

{}

Returns:

Type Description
Transformation

The converted transformation.

field
field() -> ArrayProtocol | None

The field, as values: an array of shape (*shape, ndim).

It is data itself when coeff is false, and data decoded from spline coefficients (once, then cached) when it is true.

from_instance classmethod
from_instance(other: Any, *args, **kwargs) -> Self

Create an instance from an instance of a similar class.

See DataModelBase.from_instance. A lazy wrapper derives its data and its flags, so they are read through their public names. A field that holds its displacement is copied as its displacement: a velocity (log=True) is integrated, unless the copy is a velocity too.

Identity

Identity(
    data_fields: ClassVar[tuple[str, ...]] = (),
    metadata_fields: ClassVar[tuple[str, ...]] = (),
    derived_fields: ClassVar[tuple[str, ...]] = (),
    *,
    _input: CoordinateSystem | None = None,
    _output: CoordinateSystem | None = None,
)

Bases: ConcreteTransformation

An identity transformation.

If the input and output coordinate systems are different, it maps the input axes to the output axes, while preserving their orders.

It has no parameter: its data is always None, and is not a constructor argument.

Attributes

data property
data: None

Always None: the identity has no parameter to store.

Methods:

from_dict classmethod
from_dict(other: Mapping, *args, **kwargs) -> Self

Create an instance of the class from a dictionary-like object.

Only keys in the dictionary that match keyword-like fields of this class, or the keywords its constructor takes without storing them (its InitVars, such as the matrix= of an Affine), will be used. Other keys are ignored, but see from_other, which refuses them.

Additional positional and/or keyword arguments can be provided, and will take precedence over the values in the dictionary.

A key naming a field that this class fixes (a field that cannot be passed to its constructor) is checked instead of used: a dictionary that sets it to anything other than None or the value of this class is refused with a ValueError.

from_instance classmethod
from_instance(other: Self, *args, **kwargs) -> Self

Create an instance of the class from an instance of a similar class.

Only attributes of the other instance that match keyword-like fields of this class will be used. An attribute that is None is unset, and leaves the default of this class in place.

Additional positional and/or keyword arguments can be provided, and will take precedence over the attributes in the instance.

Unless the other instance is already an instance of this class, an attribute naming a field that this class fixes (a field that cannot be passed to its constructor) is checked instead of used: an instance that sets it to anything other than None or the value of this class is refused with a ValueError. A generic Axis whose orientation is right-to-left, for example, cannot be read as a LeftToRightAxis.

from_other classmethod
from_other(other: Any, *args, **kwargs) -> Self

Create an instance of the class from any object that can be interpreted as a dictionary, or an instance of a similar class, or an arguments to be passed to the constructor.

A similar class is this class or one of its parents within the data model, or another member of a polymorphic family this class belongs to: calling a polymorphic class such as Axis builds the subclass its arguments select, so a "generic" axis is usually an instance of a sibling (a RightToLeftAxis, a TimeAxis) rather than of a parent. Any other object, including an instance of a parent that is not a data model (such as a plain object), is passed to the constructor.

Unlike from_dict, a dictionary with a key that matches no field of this class is refused with a TypeError naming the keys, so that a misspelt key is not silently dropped.

compute
compute(
    mode: ModeLike = True,
    *,
    simplify: SimplifyLike = "analytic",
    factor: bool = False,
) -> Self

Compute the transformation, downcasting it to the cheapest compatible kind.

A concrete transformation holds a parameter, so it simplifies to the simplest compatible kind, whose compatibility can be detected with (almost) no overhead. For example, a transformation whose parameter is set to None is treated as an identity.

Parameters:

Name Type Description Default
mode [list of] name or type

Ignored on a leaf. mode gates which kinds compose, and a leaf has nothing to compose; its downcast is gated only by simplify (simplification is decoupled from the compose mode).

True
simplify simplify policy

How hard this leaf may be looked at. The resolved SimplifyPolicy decides whether the kind-checks run structure-only (analytic) or read values (numeric), or are skipped entirely (none).

"analytic"
factor bool

Whether to factor this leaf into its axis-group normal form. A leaf factors by wrapping itself in a one-element sequence, so a diagonal affine (say) splits into its per-axis blocks. Off by default.

False
simplify
simplify(
    policy: SimplifyLike = "analytic",
    *,
    compute: ModeLike | bool | None = False,
) -> Self

Simplify this transformation under a per-kind policy.

Convenience sugar for compute: t.simplify(policy, compute=mode) is t.compute(mode, simplify=policy).

By default simplify() does no computation at all: compute=False maps to mode=False, which composes nothing (no matrices multiplied, no fields sampled, no lazy inverse materialized). It only downcasts each leaf under policy (analytic by default). Pass an explicit compute=<mode> to also compose that kind.

Parameters:

Name Type Description Default
policy simplify policy

The simplify policy, in the grammar compute accepts.

"analytic"
compute [list of] name or type

The compose mode. The default, False, composes nothing (mode=False in compute); None would compose every kind. A real mode passes straight through.

False
to
to(
    cls: Type[Self] | None = None,
    *,
    lossy: bool = False,
    error: Type[Exception] | Exception | bool = True,
    **kwargs,
) -> Self

Convert this transformation to a different type.

Conversion can be

  • between type: linear.to(Affine) ; or
  • within type: displacement.to(coeff=True) ; or
  • both: coords.to(DisplacementField, coeff=True) .

Parameters:

Name Type Description Default
cls type

The type to convert to. If None, keep the current type.

None
lossy bool

Whether to allow lossy conversions.

False
error bool or Exception

Whether to raise an error if the conversion fails:

  • If an Exception, raise it.
  • If True, raise the original error.
  • Otherwise, return the value of error.
True
**kwargs dict

Attributes to override in the converted transform. This allows transformations to be modified within their type. For example, a DisplacementField can be converted from a field of values to a field of spline coefficients by setting coeff=True in kwargs: a change of encoding flag re-encodes the stored data, and keeps the map. A view's name (field=, matrix=, ...) sets the map, as values, and it is stored in the encoding of the result; data= is stored as given.

{}

Returns:

Type Description
Transformation

The converted transformation.

Linear magic

Linear(
    _data: npmatrix[Real] | None = None,
    *,
    _log: bool = False,
    _matrix: InitVar[npmatrix[Real] | None] = None,
)

Bases: ConcreteTransformation

A linear transformation.

data holds its (No, Ni) matrix. log=True builds a LinearExponential, whose data is the tangent of the map about the identity instead.

Attributes

matrix property
matrix: ArrayProtocol | None

The matrix, of shape (No, Ni).

Methods:

from_dict classmethod
from_dict(other: Mapping, *args, **kwargs) -> Self

Create an instance of the class from a dictionary-like object.

Only keys in the dictionary that match keyword-like fields of this class, or the keywords its constructor takes without storing them (its InitVars, such as the matrix= of an Affine), will be used. Other keys are ignored, but see from_other, which refuses them.

Additional positional and/or keyword arguments can be provided, and will take precedence over the values in the dictionary.

A key naming a field that this class fixes (a field that cannot be passed to its constructor) is checked instead of used: a dictionary that sets it to anything other than None or the value of this class is refused with a ValueError.

from_other classmethod
from_other(other: Any, *args, **kwargs) -> Self

Create an instance of the class from any object that can be interpreted as a dictionary, or an instance of a similar class, or an arguments to be passed to the constructor.

A similar class is this class or one of its parents within the data model, or another member of a polymorphic family this class belongs to: calling a polymorphic class such as Axis builds the subclass its arguments select, so a "generic" axis is usually an instance of a sibling (a RightToLeftAxis, a TimeAxis) rather than of a parent. Any other object, including an instance of a parent that is not a data model (such as a plain object), is passed to the constructor.

Unlike from_dict, a dictionary with a key that matches no field of this class is refused with a TypeError naming the keys, so that a misspelt key is not silently dropped.

compute
compute(
    mode: ModeLike = True,
    *,
    simplify: SimplifyLike = "analytic",
    factor: bool = False,
) -> Self

Compute the transformation, downcasting it to the cheapest compatible kind.

A concrete transformation holds a parameter, so it simplifies to the simplest compatible kind, whose compatibility can be detected with (almost) no overhead. For example, a transformation whose parameter is set to None is treated as an identity.

Parameters:

Name Type Description Default
mode [list of] name or type

Ignored on a leaf. mode gates which kinds compose, and a leaf has nothing to compose; its downcast is gated only by simplify (simplification is decoupled from the compose mode).

True
simplify simplify policy

How hard this leaf may be looked at. The resolved SimplifyPolicy decides whether the kind-checks run structure-only (analytic) or read values (numeric), or are skipped entirely (none).

"analytic"
factor bool

Whether to factor this leaf into its axis-group normal form. A leaf factors by wrapping itself in a one-element sequence, so a diagonal affine (say) splits into its per-axis blocks. Off by default.

False
simplify
simplify(
    policy: SimplifyLike = "analytic",
    *,
    compute: ModeLike | bool | None = False,
) -> Self

Simplify this transformation under a per-kind policy.

Convenience sugar for compute: t.simplify(policy, compute=mode) is t.compute(mode, simplify=policy).

By default simplify() does no computation at all: compute=False maps to mode=False, which composes nothing (no matrices multiplied, no fields sampled, no lazy inverse materialized). It only downcasts each leaf under policy (analytic by default). Pass an explicit compute=<mode> to also compose that kind.

Parameters:

Name Type Description Default
policy simplify policy

The simplify policy, in the grammar compute accepts.

"analytic"
compute [list of] name or type

The compose mode. The default, False, composes nothing (mode=False in compute); None would compose every kind. A real mode passes straight through.

False
square
square(compute: bool = False, **kwargs) -> Transformation

Return the square of this transformation, self @ self.

The square is the sequence [self, self], which composes when it is computed. It is defined for a transformation that maps a space to itself.

Parameters:

Name Type Description Default
compute bool

Whether to compute the result now rather than return it lazily.

False
**kwargs

Passed to compute when compute is true.

{}

Raises:

Type Description
DomainError

If the transformation does not map a space to itself.

to
to(
    cls: Type[Self] | None = None,
    *,
    lossy: bool = False,
    error: Type[Exception] | Exception | bool = True,
    **kwargs,
) -> Self

Convert this transformation to a different type.

Conversion can be

  • between type: linear.to(Affine) ; or
  • within type: displacement.to(coeff=True) ; or
  • both: coords.to(DisplacementField, coeff=True) .

Parameters:

Name Type Description Default
cls type

The type to convert to. If None, keep the current type.

None
lossy bool

Whether to allow lossy conversions.

False
error bool or Exception

Whether to raise an error if the conversion fails:

  • If an Exception, raise it.
  • If True, raise the original error.
  • Otherwise, return the value of error.
True
**kwargs dict

Attributes to override in the converted transform. This allows transformations to be modified within their type. For example, a DisplacementField can be converted from a field of values to a field of spline coefficients by setting coeff=True in kwargs: a change of encoding flag re-encodes the stored data, and keeps the map. A view's name (field=, matrix=, ...) sets the map, as values, and it is stored in the encoding of the result; data= is stored as given.

{}

Returns:

Type Description
Transformation

The converted transformation.

from_instance classmethod
from_instance(other: Any, *args, **kwargs) -> Self

Create an instance from an instance of a similar class.

See DataModelBase.from_instance. The map of a Linear is copied through its matrix view, not its stored data, which a lazy wrapper derives and a tangent (log=True) stores as its logarithm. A tangent is copied into a tangent through its data.

LinearExponential

LinearExponential(
    _data: npmatrix[Real] | None = None,
    *,
    _log: bool = False,
    _matrix: InitVar[npmatrix[Real] | None] = None,
)

Bases: Linear

A linear transformation stored as its tangent (log=True).

data is the (N, N) tangent L of the map about the identity, and the map is its exponential: matrix is expm(L), computed once, then cached. Unset or zero data is the identity, and LinearExponential(data=I) is the scaling by e.

The exponential of a real tangent has a positive determinant, so it is a PositiveLinear. Its inverse, square root and square are exact: the tangent negated, halved and doubled. .to(log=False) gives the plain Linear of matrix, and Linear.to(log=True) takes the principal logarithm of a matrix, which is refused (DomainError) when it has an eigenvalue on the closed negative real axis.

Methods:

from_dict classmethod
from_dict(other: Mapping, *args, **kwargs) -> Self

Create an instance of the class from a dictionary-like object.

Only keys in the dictionary that match keyword-like fields of this class, or the keywords its constructor takes without storing them (its InitVars, such as the matrix= of an Affine), will be used. Other keys are ignored, but see from_other, which refuses them.

Additional positional and/or keyword arguments can be provided, and will take precedence over the values in the dictionary.

A key naming a field that this class fixes (a field that cannot be passed to its constructor) is checked instead of used: a dictionary that sets it to anything other than None or the value of this class is refused with a ValueError.

from_instance classmethod
from_instance(other: Any, *args, **kwargs) -> Self

Create an instance from an instance of a similar class.

See DataModelBase.from_instance. The map of a Linear is copied through its matrix view, not its stored data, which a lazy wrapper derives and a tangent (log=True) stores as its logarithm. A tangent is copied into a tangent through its data.

from_other classmethod
from_other(other: Any, *args, **kwargs) -> Self

Create an instance of the class from any object that can be interpreted as a dictionary, or an instance of a similar class, or an arguments to be passed to the constructor.

A similar class is this class or one of its parents within the data model, or another member of a polymorphic family this class belongs to: calling a polymorphic class such as Axis builds the subclass its arguments select, so a "generic" axis is usually an instance of a sibling (a RightToLeftAxis, a TimeAxis) rather than of a parent. Any other object, including an instance of a parent that is not a data model (such as a plain object), is passed to the constructor.

Unlike from_dict, a dictionary with a key that matches no field of this class is refused with a TypeError naming the keys, so that a misspelt key is not silently dropped.

compute
compute(
    mode: ModeLike = True,
    *,
    simplify: SimplifyLike = "analytic",
    factor: bool = False,
) -> Self

Compute the transformation, downcasting it to the cheapest compatible kind.

A concrete transformation holds a parameter, so it simplifies to the simplest compatible kind, whose compatibility can be detected with (almost) no overhead. For example, a transformation whose parameter is set to None is treated as an identity.

Parameters:

Name Type Description Default
mode [list of] name or type

Ignored on a leaf. mode gates which kinds compose, and a leaf has nothing to compose; its downcast is gated only by simplify (simplification is decoupled from the compose mode).

True
simplify simplify policy

How hard this leaf may be looked at. The resolved SimplifyPolicy decides whether the kind-checks run structure-only (analytic) or read values (numeric), or are skipped entirely (none).

"analytic"
factor bool

Whether to factor this leaf into its axis-group normal form. A leaf factors by wrapping itself in a one-element sequence, so a diagonal affine (say) splits into its per-axis blocks. Off by default.

False
simplify
simplify(
    policy: SimplifyLike = "analytic",
    *,
    compute: ModeLike | bool | None = False,
) -> Self

Simplify this transformation under a per-kind policy.

Convenience sugar for compute: t.simplify(policy, compute=mode) is t.compute(mode, simplify=policy).

By default simplify() does no computation at all: compute=False maps to mode=False, which composes nothing (no matrices multiplied, no fields sampled, no lazy inverse materialized). It only downcasts each leaf under policy (analytic by default). Pass an explicit compute=<mode> to also compose that kind.

Parameters:

Name Type Description Default
policy simplify policy

The simplify policy, in the grammar compute accepts.

"analytic"
compute [list of] name or type

The compose mode. The default, False, composes nothing (mode=False in compute); None would compose every kind. A real mode passes straight through.

False
matrix
matrix() -> ArrayProtocol | None

The matrix, of shape (N, N): the exponential of data.

Permutation magic

Permutation(
    _data: npvector[Integral] | None = None,
    *,
    _permutation: InitVar[npvector[Integral] | None] = None,
)

Bases: ConcreteTransformation

A permutation of axes.

Attributes

permutation property
permutation: ArrayProtocol | None

The permutation vector, of shape (N,).

Methods:

from_dict classmethod
from_dict(other: Mapping, *args, **kwargs) -> Self

Create an instance of the class from a dictionary-like object.

Only keys in the dictionary that match keyword-like fields of this class, or the keywords its constructor takes without storing them (its InitVars, such as the matrix= of an Affine), will be used. Other keys are ignored, but see from_other, which refuses them.

Additional positional and/or keyword arguments can be provided, and will take precedence over the values in the dictionary.

A key naming a field that this class fixes (a field that cannot be passed to its constructor) is checked instead of used: a dictionary that sets it to anything other than None or the value of this class is refused with a ValueError.

from_other classmethod
from_other(other: Any, *args, **kwargs) -> Self

Create an instance of the class from any object that can be interpreted as a dictionary, or an instance of a similar class, or an arguments to be passed to the constructor.

A similar class is this class or one of its parents within the data model, or another member of a polymorphic family this class belongs to: calling a polymorphic class such as Axis builds the subclass its arguments select, so a "generic" axis is usually an instance of a sibling (a RightToLeftAxis, a TimeAxis) rather than of a parent. Any other object, including an instance of a parent that is not a data model (such as a plain object), is passed to the constructor.

Unlike from_dict, a dictionary with a key that matches no field of this class is refused with a TypeError naming the keys, so that a misspelt key is not silently dropped.

compute
compute(
    mode: ModeLike = True,
    *,
    simplify: SimplifyLike = "analytic",
    factor: bool = False,
) -> Self

Compute the transformation, downcasting it to the cheapest compatible kind.

A concrete transformation holds a parameter, so it simplifies to the simplest compatible kind, whose compatibility can be detected with (almost) no overhead. For example, a transformation whose parameter is set to None is treated as an identity.

Parameters:

Name Type Description Default
mode [list of] name or type

Ignored on a leaf. mode gates which kinds compose, and a leaf has nothing to compose; its downcast is gated only by simplify (simplification is decoupled from the compose mode).

True
simplify simplify policy

How hard this leaf may be looked at. The resolved SimplifyPolicy decides whether the kind-checks run structure-only (analytic) or read values (numeric), or are skipped entirely (none).

"analytic"
factor bool

Whether to factor this leaf into its axis-group normal form. A leaf factors by wrapping itself in a one-element sequence, so a diagonal affine (say) splits into its per-axis blocks. Off by default.

False
simplify
simplify(
    policy: SimplifyLike = "analytic",
    *,
    compute: ModeLike | bool | None = False,
) -> Self

Simplify this transformation under a per-kind policy.

Convenience sugar for compute: t.simplify(policy, compute=mode) is t.compute(mode, simplify=policy).

By default simplify() does no computation at all: compute=False maps to mode=False, which composes nothing (no matrices multiplied, no fields sampled, no lazy inverse materialized). It only downcasts each leaf under policy (analytic by default). Pass an explicit compute=<mode> to also compose that kind.

Parameters:

Name Type Description Default
policy simplify policy

The simplify policy, in the grammar compute accepts.

"analytic"
compute [list of] name or type

The compose mode. The default, False, composes nothing (mode=False in compute); None would compose every kind. A real mode passes straight through.

False
square
square(compute: bool = False, **kwargs) -> Transformation

Return the square of this transformation, self @ self.

The square is the sequence [self, self], which composes when it is computed. It is defined for a transformation that maps a space to itself.

Parameters:

Name Type Description Default
compute bool

Whether to compute the result now rather than return it lazily.

False
**kwargs

Passed to compute when compute is true.

{}

Raises:

Type Description
DomainError

If the transformation does not map a space to itself.

to
to(
    cls: Type[Self] | None = None,
    *,
    lossy: bool = False,
    error: Type[Exception] | Exception | bool = True,
    **kwargs,
) -> Self

Convert this transformation to a different type.

Conversion can be

  • between type: linear.to(Affine) ; or
  • within type: displacement.to(coeff=True) ; or
  • both: coords.to(DisplacementField, coeff=True) .

Parameters:

Name Type Description Default
cls type

The type to convert to. If None, keep the current type.

None
lossy bool

Whether to allow lossy conversions.

False
error bool or Exception

Whether to raise an error if the conversion fails:

  • If an Exception, raise it.
  • If True, raise the original error.
  • Otherwise, return the value of error.
True
**kwargs dict

Attributes to override in the converted transform. This allows transformations to be modified within their type. For example, a DisplacementField can be converted from a field of values to a field of spline coefficients by setting coeff=True in kwargs: a change of encoding flag re-encodes the stored data, and keeps the map. A view's name (field=, matrix=, ...) sets the map, as values, and it is stored in the encoding of the result; data= is stored as given.

{}

Returns:

Type Description
Transformation

The converted transformation.

from_instance classmethod
from_instance(other: Any, *args, **kwargs) -> Self

Create an instance from an instance of a similar class.

See DataModelBase.from_instance. The map of a Permutation is copied through its permutation view, not its stored data, which a lazy wrapper derives.

Rotation magic

Rotation(_data: npmatrix[Real] | None = None)

Bases: Linear

An orthogonal transformation with determinant 1, i.e., a rotation.

data holds its (N, N) matrix. log=True builds a RotationExponential, whose data is the tangent of the map about the identity instead.

Attributes

matrix property
matrix: ArrayProtocol | None

The matrix, of shape (No, Ni).

Methods:

from_dict classmethod
from_dict(other: Mapping, *args, **kwargs) -> Self

Create an instance of the class from a dictionary-like object.

Only keys in the dictionary that match keyword-like fields of this class, or the keywords its constructor takes without storing them (its InitVars, such as the matrix= of an Affine), will be used. Other keys are ignored, but see from_other, which refuses them.

Additional positional and/or keyword arguments can be provided, and will take precedence over the values in the dictionary.

A key naming a field that this class fixes (a field that cannot be passed to its constructor) is checked instead of used: a dictionary that sets it to anything other than None or the value of this class is refused with a ValueError.

from_instance classmethod
from_instance(other: Any, *args, **kwargs) -> Self

Create an instance from an instance of a similar class.

See DataModelBase.from_instance. The map of a Linear is copied through its matrix view, not its stored data, which a lazy wrapper derives and a tangent (log=True) stores as its logarithm. A tangent is copied into a tangent through its data.

from_other classmethod
from_other(other: Any, *args, **kwargs) -> Self

Create an instance of the class from any object that can be interpreted as a dictionary, or an instance of a similar class, or an arguments to be passed to the constructor.

A similar class is this class or one of its parents within the data model, or another member of a polymorphic family this class belongs to: calling a polymorphic class such as Axis builds the subclass its arguments select, so a "generic" axis is usually an instance of a sibling (a RightToLeftAxis, a TimeAxis) rather than of a parent. Any other object, including an instance of a parent that is not a data model (such as a plain object), is passed to the constructor.

Unlike from_dict, a dictionary with a key that matches no field of this class is refused with a TypeError naming the keys, so that a misspelt key is not silently dropped.

compute
compute(
    mode: ModeLike = True,
    *,
    simplify: SimplifyLike = "analytic",
    factor: bool = False,
) -> Self

Compute the transformation, downcasting it to the cheapest compatible kind.

A concrete transformation holds a parameter, so it simplifies to the simplest compatible kind, whose compatibility can be detected with (almost) no overhead. For example, a transformation whose parameter is set to None is treated as an identity.

Parameters:

Name Type Description Default
mode [list of] name or type

Ignored on a leaf. mode gates which kinds compose, and a leaf has nothing to compose; its downcast is gated only by simplify (simplification is decoupled from the compose mode).

True
simplify simplify policy

How hard this leaf may be looked at. The resolved SimplifyPolicy decides whether the kind-checks run structure-only (analytic) or read values (numeric), or are skipped entirely (none).

"analytic"
factor bool

Whether to factor this leaf into its axis-group normal form. A leaf factors by wrapping itself in a one-element sequence, so a diagonal affine (say) splits into its per-axis blocks. Off by default.

False
simplify
simplify(
    policy: SimplifyLike = "analytic",
    *,
    compute: ModeLike | bool | None = False,
) -> Self

Simplify this transformation under a per-kind policy.

Convenience sugar for compute: t.simplify(policy, compute=mode) is t.compute(mode, simplify=policy).

By default simplify() does no computation at all: compute=False maps to mode=False, which composes nothing (no matrices multiplied, no fields sampled, no lazy inverse materialized). It only downcasts each leaf under policy (analytic by default). Pass an explicit compute=<mode> to also compose that kind.

Parameters:

Name Type Description Default
policy simplify policy

The simplify policy, in the grammar compute accepts.

"analytic"
compute [list of] name or type

The compose mode. The default, False, composes nothing (mode=False in compute); None would compose every kind. A real mode passes straight through.

False
square
square(compute: bool = False, **kwargs) -> Transformation

Return the square of this transformation, self @ self.

The square is the sequence [self, self], which composes when it is computed. It is defined for a transformation that maps a space to itself.

Parameters:

Name Type Description Default
compute bool

Whether to compute the result now rather than return it lazily.

False
**kwargs

Passed to compute when compute is true.

{}

Raises:

Type Description
DomainError

If the transformation does not map a space to itself.

to
to(
    cls: Type[Self] | None = None,
    *,
    lossy: bool = False,
    error: Type[Exception] | Exception | bool = True,
    **kwargs,
) -> Self

Convert this transformation to a different type.

Conversion can be

  • between type: linear.to(Affine) ; or
  • within type: displacement.to(coeff=True) ; or
  • both: coords.to(DisplacementField, coeff=True) .

Parameters:

Name Type Description Default
cls type

The type to convert to. If None, keep the current type.

None
lossy bool

Whether to allow lossy conversions.

False
error bool or Exception

Whether to raise an error if the conversion fails:

  • If an Exception, raise it.
  • If True, raise the original error.
  • Otherwise, return the value of error.
True
**kwargs dict

Attributes to override in the converted transform. This allows transformations to be modified within their type. For example, a DisplacementField can be converted from a field of values to a field of spline coefficients by setting coeff=True in kwargs: a change of encoding flag re-encodes the stored data, and keeps the map. A view's name (field=, matrix=, ...) sets the map, as values, and it is stored in the encoding of the result; data= is stored as given.

{}

Returns:

Type Description
Transformation

The converted transformation.

RotationExponential

RotationExponential(_data: npmatrix[Real] | None = None)

Bases: Rotation

A rotation stored as its tangent (log=True).

data is the (N, N) antisymmetric tangent L of the rotation about the identity -- its axis and angle -- and the map is its exponential: matrix is expm(L), computed once, then cached. Unset or zero data is the identity.

Its inverse, square root and square are exact: the tangent negated, halved and doubled. .to(log=False) gives the plain Rotation of matrix, and Rotation.to(log=True) takes the principal logarithm of a rotation, which is refused (DomainError) for a rotation by a half turn, whose logarithm is not unique.

Methods:

from_dict classmethod
from_dict(other: Mapping, *args, **kwargs) -> Self

Create an instance of the class from a dictionary-like object.

Only keys in the dictionary that match keyword-like fields of this class, or the keywords its constructor takes without storing them (its InitVars, such as the matrix= of an Affine), will be used. Other keys are ignored, but see from_other, which refuses them.

Additional positional and/or keyword arguments can be provided, and will take precedence over the values in the dictionary.

A key naming a field that this class fixes (a field that cannot be passed to its constructor) is checked instead of used: a dictionary that sets it to anything other than None or the value of this class is refused with a ValueError.

from_instance classmethod
from_instance(other: Any, *args, **kwargs) -> Self

Create an instance from an instance of a similar class.

See DataModelBase.from_instance. The map of a Linear is copied through its matrix view, not its stored data, which a lazy wrapper derives and a tangent (log=True) stores as its logarithm. A tangent is copied into a tangent through its data.

from_other classmethod
from_other(other: Any, *args, **kwargs) -> Self

Create an instance of the class from any object that can be interpreted as a dictionary, or an instance of a similar class, or an arguments to be passed to the constructor.

A similar class is this class or one of its parents within the data model, or another member of a polymorphic family this class belongs to: calling a polymorphic class such as Axis builds the subclass its arguments select, so a "generic" axis is usually an instance of a sibling (a RightToLeftAxis, a TimeAxis) rather than of a parent. Any other object, including an instance of a parent that is not a data model (such as a plain object), is passed to the constructor.

Unlike from_dict, a dictionary with a key that matches no field of this class is refused with a TypeError naming the keys, so that a misspelt key is not silently dropped.

compute
compute(
    mode: ModeLike = True,
    *,
    simplify: SimplifyLike = "analytic",
    factor: bool = False,
) -> Self

Compute the transformation, downcasting it to the cheapest compatible kind.

A concrete transformation holds a parameter, so it simplifies to the simplest compatible kind, whose compatibility can be detected with (almost) no overhead. For example, a transformation whose parameter is set to None is treated as an identity.

Parameters:

Name Type Description Default
mode [list of] name or type

Ignored on a leaf. mode gates which kinds compose, and a leaf has nothing to compose; its downcast is gated only by simplify (simplification is decoupled from the compose mode).

True
simplify simplify policy

How hard this leaf may be looked at. The resolved SimplifyPolicy decides whether the kind-checks run structure-only (analytic) or read values (numeric), or are skipped entirely (none).

"analytic"
factor bool

Whether to factor this leaf into its axis-group normal form. A leaf factors by wrapping itself in a one-element sequence, so a diagonal affine (say) splits into its per-axis blocks. Off by default.

False
simplify
simplify(
    policy: SimplifyLike = "analytic",
    *,
    compute: ModeLike | bool | None = False,
) -> Self

Simplify this transformation under a per-kind policy.

Convenience sugar for compute: t.simplify(policy, compute=mode) is t.compute(mode, simplify=policy).

By default simplify() does no computation at all: compute=False maps to mode=False, which composes nothing (no matrices multiplied, no fields sampled, no lazy inverse materialized). It only downcasts each leaf under policy (analytic by default). Pass an explicit compute=<mode> to also compose that kind.

Parameters:

Name Type Description Default
policy simplify policy

The simplify policy, in the grammar compute accepts.

"analytic"
compute [list of] name or type

The compose mode. The default, False, composes nothing (mode=False in compute); None would compose every kind. A real mode passes straight through.

False
matrix
matrix() -> ArrayProtocol | None

The rotation matrix, of shape (N, N): the exponential of data.

Scaling magic

Scaling(
    _data: npvector[Real] | None = None,
    *,
    _log: bool = False,
    _scale: InitVar[npvector[Real] | None] = None,
)

Bases: ConcreteTransformation

A scaling of axes.

data holds its scaling factors. log=True builds a ScalingExponential, whose data is their logarithm instead.

Attributes

scale property
scale: ArrayProtocol | None

The scaling factors, of shape (N,).

Methods:

from_dict classmethod
from_dict(other: Mapping, *args, **kwargs) -> Self

Create an instance of the class from a dictionary-like object.

Only keys in the dictionary that match keyword-like fields of this class, or the keywords its constructor takes without storing them (its InitVars, such as the matrix= of an Affine), will be used. Other keys are ignored, but see from_other, which refuses them.

Additional positional and/or keyword arguments can be provided, and will take precedence over the values in the dictionary.

A key naming a field that this class fixes (a field that cannot be passed to its constructor) is checked instead of used: a dictionary that sets it to anything other than None or the value of this class is refused with a ValueError.

from_other classmethod
from_other(other: Any, *args, **kwargs) -> Self

Create an instance of the class from any object that can be interpreted as a dictionary, or an instance of a similar class, or an arguments to be passed to the constructor.

A similar class is this class or one of its parents within the data model, or another member of a polymorphic family this class belongs to: calling a polymorphic class such as Axis builds the subclass its arguments select, so a "generic" axis is usually an instance of a sibling (a RightToLeftAxis, a TimeAxis) rather than of a parent. Any other object, including an instance of a parent that is not a data model (such as a plain object), is passed to the constructor.

Unlike from_dict, a dictionary with a key that matches no field of this class is refused with a TypeError naming the keys, so that a misspelt key is not silently dropped.

compute
compute(
    mode: ModeLike = True,
    *,
    simplify: SimplifyLike = "analytic",
    factor: bool = False,
) -> Self

Compute the transformation, downcasting it to the cheapest compatible kind.

A concrete transformation holds a parameter, so it simplifies to the simplest compatible kind, whose compatibility can be detected with (almost) no overhead. For example, a transformation whose parameter is set to None is treated as an identity.

Parameters:

Name Type Description Default
mode [list of] name or type

Ignored on a leaf. mode gates which kinds compose, and a leaf has nothing to compose; its downcast is gated only by simplify (simplification is decoupled from the compose mode).

True
simplify simplify policy

How hard this leaf may be looked at. The resolved SimplifyPolicy decides whether the kind-checks run structure-only (analytic) or read values (numeric), or are skipped entirely (none).

"analytic"
factor bool

Whether to factor this leaf into its axis-group normal form. A leaf factors by wrapping itself in a one-element sequence, so a diagonal affine (say) splits into its per-axis blocks. Off by default.

False
simplify
simplify(
    policy: SimplifyLike = "analytic",
    *,
    compute: ModeLike | bool | None = False,
) -> Self

Simplify this transformation under a per-kind policy.

Convenience sugar for compute: t.simplify(policy, compute=mode) is t.compute(mode, simplify=policy).

By default simplify() does no computation at all: compute=False maps to mode=False, which composes nothing (no matrices multiplied, no fields sampled, no lazy inverse materialized). It only downcasts each leaf under policy (analytic by default). Pass an explicit compute=<mode> to also compose that kind.

Parameters:

Name Type Description Default
policy simplify policy

The simplify policy, in the grammar compute accepts.

"analytic"
compute [list of] name or type

The compose mode. The default, False, composes nothing (mode=False in compute); None would compose every kind. A real mode passes straight through.

False
square
square(compute: bool = False, **kwargs) -> Transformation

Return the square of this transformation, self @ self.

The square is the sequence [self, self], which composes when it is computed. It is defined for a transformation that maps a space to itself.

Parameters:

Name Type Description Default
compute bool

Whether to compute the result now rather than return it lazily.

False
**kwargs

Passed to compute when compute is true.

{}

Raises:

Type Description
DomainError

If the transformation does not map a space to itself.

to
to(
    cls: Type[Self] | None = None,
    *,
    lossy: bool = False,
    error: Type[Exception] | Exception | bool = True,
    **kwargs,
) -> Self

Convert this transformation to a different type.

Conversion can be

  • between type: linear.to(Affine) ; or
  • within type: displacement.to(coeff=True) ; or
  • both: coords.to(DisplacementField, coeff=True) .

Parameters:

Name Type Description Default
cls type

The type to convert to. If None, keep the current type.

None
lossy bool

Whether to allow lossy conversions.

False
error bool or Exception

Whether to raise an error if the conversion fails:

  • If an Exception, raise it.
  • If True, raise the original error.
  • Otherwise, return the value of error.
True
**kwargs dict

Attributes to override in the converted transform. This allows transformations to be modified within their type. For example, a DisplacementField can be converted from a field of values to a field of spline coefficients by setting coeff=True in kwargs: a change of encoding flag re-encodes the stored data, and keeps the map. A view's name (field=, matrix=, ...) sets the map, as values, and it is stored in the encoding of the result; data= is stored as given.

{}

Returns:

Type Description
Transformation

The converted transformation.

from_instance classmethod
from_instance(other: Any, *args, **kwargs) -> Self

Create an instance from an instance of a similar class.

See DataModelBase.from_instance. The map of a Scaling is copied through its scale view, not its stored data, which a lazy wrapper derives and a tangent (log=True) stores as its logarithm. A tangent is copied into a tangent through its data.

ScalingExponential

ScalingExponential(
    _data: npvector[Real] | None = None,
    *,
    _log: bool = False,
    _scale: InitVar[npvector[Real] | None] = None,
)

Bases: Scaling

A scaling stored as the logarithm of its factors (log=True).

data is the tangent s of the map about the identity, and scale is exp(s), computed once, then cached: the factors are positive, so it is a PositiveDiagonal. Unset or zero data is the identity.

Its inverse, square root and square are exact: the tangent negated, halved and doubled. .to(log=False) gives the plain Scaling of scale, and Scaling.to(log=True) takes the logarithm of the factors, which is refused (DomainError) unless they are all positive.

Methods:

from_dict classmethod
from_dict(other: Mapping, *args, **kwargs) -> Self

Create an instance of the class from a dictionary-like object.

Only keys in the dictionary that match keyword-like fields of this class, or the keywords its constructor takes without storing them (its InitVars, such as the matrix= of an Affine), will be used. Other keys are ignored, but see from_other, which refuses them.

Additional positional and/or keyword arguments can be provided, and will take precedence over the values in the dictionary.

A key naming a field that this class fixes (a field that cannot be passed to its constructor) is checked instead of used: a dictionary that sets it to anything other than None or the value of this class is refused with a ValueError.

from_instance classmethod
from_instance(other: Any, *args, **kwargs) -> Self

Create an instance from an instance of a similar class.

See DataModelBase.from_instance. The map of a Scaling is copied through its scale view, not its stored data, which a lazy wrapper derives and a tangent (log=True) stores as its logarithm. A tangent is copied into a tangent through its data.

from_other classmethod
from_other(other: Any, *args, **kwargs) -> Self

Create an instance of the class from any object that can be interpreted as a dictionary, or an instance of a similar class, or an arguments to be passed to the constructor.

A similar class is this class or one of its parents within the data model, or another member of a polymorphic family this class belongs to: calling a polymorphic class such as Axis builds the subclass its arguments select, so a "generic" axis is usually an instance of a sibling (a RightToLeftAxis, a TimeAxis) rather than of a parent. Any other object, including an instance of a parent that is not a data model (such as a plain object), is passed to the constructor.

Unlike from_dict, a dictionary with a key that matches no field of this class is refused with a TypeError naming the keys, so that a misspelt key is not silently dropped.

compute
compute(
    mode: ModeLike = True,
    *,
    simplify: SimplifyLike = "analytic",
    factor: bool = False,
) -> Self

Compute the transformation, downcasting it to the cheapest compatible kind.

A concrete transformation holds a parameter, so it simplifies to the simplest compatible kind, whose compatibility can be detected with (almost) no overhead. For example, a transformation whose parameter is set to None is treated as an identity.

Parameters:

Name Type Description Default
mode [list of] name or type

Ignored on a leaf. mode gates which kinds compose, and a leaf has nothing to compose; its downcast is gated only by simplify (simplification is decoupled from the compose mode).

True
simplify simplify policy

How hard this leaf may be looked at. The resolved SimplifyPolicy decides whether the kind-checks run structure-only (analytic) or read values (numeric), or are skipped entirely (none).

"analytic"
factor bool

Whether to factor this leaf into its axis-group normal form. A leaf factors by wrapping itself in a one-element sequence, so a diagonal affine (say) splits into its per-axis blocks. Off by default.

False
simplify
simplify(
    policy: SimplifyLike = "analytic",
    *,
    compute: ModeLike | bool | None = False,
) -> Self

Simplify this transformation under a per-kind policy.

Convenience sugar for compute: t.simplify(policy, compute=mode) is t.compute(mode, simplify=policy).

By default simplify() does no computation at all: compute=False maps to mode=False, which composes nothing (no matrices multiplied, no fields sampled, no lazy inverse materialized). It only downcasts each leaf under policy (analytic by default). Pass an explicit compute=<mode> to also compose that kind.

Parameters:

Name Type Description Default
policy simplify policy

The simplify policy, in the grammar compute accepts.

"analytic"
compute [list of] name or type

The compose mode. The default, False, composes nothing (mode=False in compute); None would compose every kind. A real mode passes straight through.

False
scale
scale() -> ArrayProtocol | None

The scaling factors, of shape (N,): exp(data).

StationaryVelocityField magic

StationaryVelocityField(*, _steps: int | None = None)

Bases: DisplacementField

A displacement field stored as its stationary velocity (log=True).

data holds the velocity v, the tangent of the map about the identity: its values, or their spline coefficients when coeff is true (as NiftyReg's -vel -cpp grids and torch-diffeo store it). The map is the flow of v at time one, exp(v), and the field view is always its displacement, as values. It is integrated by scaling and squaring: v is divided by 2 ** steps, which is its own flow to first order, and composed with itself steps times, with the field composition and the field's own degree and bound. A field of coefficients is refitted at each step, so its squaring stays in coefficients. The displacements are in the voxels of the field's own grid, as for any DisplacementField.

Squaring on the knot grid

A field of coefficients is squared on its own grid: the grid of its knots. NiftyReg evaluates a velocity grid (-vel -cpp) onto the dense reference grid first, and squares there, so the two do not match reg_transform -def exactly, although both converge to the same flow.

DisplacementField(data=v, log=True), d.to(log=True) (for an unset d) and StationaryVelocityField(data=v) build the same object. Unset or zero data is the identity.

The tangent makes some operations exact: the inverse is exp(-v), the square root exp(v / 2) and the square exp(2 v). A displacement has no logarithm that brainhops computes, so .to(log=True) refuses a DisplacementField that holds one; .to(log=False) integrates a velocity into a plain DisplacementField.

Attributes

squarings property
squarings: int | None

The number of squaring steps the field view integrates with: steps, or the number the default rule picks when it is None. None when data is unset.

Methods:

from_dict classmethod
from_dict(other: Mapping, *args, **kwargs) -> Self

Create an instance of the class from a dictionary-like object.

Only keys in the dictionary that match keyword-like fields of this class, or the keywords its constructor takes without storing them (its InitVars, such as the matrix= of an Affine), will be used. Other keys are ignored, but see from_other, which refuses them.

Additional positional and/or keyword arguments can be provided, and will take precedence over the values in the dictionary.

A key naming a field that this class fixes (a field that cannot be passed to its constructor) is checked instead of used: a dictionary that sets it to anything other than None or the value of this class is refused with a ValueError.

from_instance classmethod
from_instance(other: Any, *args, **kwargs) -> Self

Create an instance from an instance of a similar class.

See DataModelBase.from_instance. A lazy wrapper derives its data and its flags, so they are read through their public names. A field that holds its displacement is copied as its displacement: a velocity (log=True) is integrated, unless the copy is a velocity too.

from_other classmethod
from_other(other: Any, *args, **kwargs) -> Self

Create an instance of the class from any object that can be interpreted as a dictionary, or an instance of a similar class, or an arguments to be passed to the constructor.

A similar class is this class or one of its parents within the data model, or another member of a polymorphic family this class belongs to: calling a polymorphic class such as Axis builds the subclass its arguments select, so a "generic" axis is usually an instance of a sibling (a RightToLeftAxis, a TimeAxis) rather than of a parent. Any other object, including an instance of a parent that is not a data model (such as a plain object), is passed to the constructor.

Unlike from_dict, a dictionary with a key that matches no field of this class is refused with a TypeError naming the keys, so that a misspelt key is not silently dropped.

compute
compute(
    mode: ModeLike = True,
    *,
    simplify: SimplifyLike = "analytic",
    factor: bool = False,
) -> Self

Compute the transformation, downcasting it to the cheapest compatible kind.

A concrete transformation holds a parameter, so it simplifies to the simplest compatible kind, whose compatibility can be detected with (almost) no overhead. For example, a transformation whose parameter is set to None is treated as an identity.

Parameters:

Name Type Description Default
mode [list of] name or type

Ignored on a leaf. mode gates which kinds compose, and a leaf has nothing to compose; its downcast is gated only by simplify (simplification is decoupled from the compose mode).

True
simplify simplify policy

How hard this leaf may be looked at. The resolved SimplifyPolicy decides whether the kind-checks run structure-only (analytic) or read values (numeric), or are skipped entirely (none).

"analytic"
factor bool

Whether to factor this leaf into its axis-group normal form. A leaf factors by wrapping itself in a one-element sequence, so a diagonal affine (say) splits into its per-axis blocks. Off by default.

False
simplify
simplify(
    policy: SimplifyLike = "analytic",
    *,
    compute: ModeLike | bool | None = False,
) -> Self

Simplify this transformation under a per-kind policy.

Convenience sugar for compute: t.simplify(policy, compute=mode) is t.compute(mode, simplify=policy).

By default simplify() does no computation at all: compute=False maps to mode=False, which composes nothing (no matrices multiplied, no fields sampled, no lazy inverse materialized). It only downcasts each leaf under policy (analytic by default). Pass an explicit compute=<mode> to also compose that kind.

Parameters:

Name Type Description Default
policy simplify policy

The simplify policy, in the grammar compute accepts.

"analytic"
compute [list of] name or type

The compose mode. The default, False, composes nothing (mode=False in compute); None would compose every kind. A real mode passes straight through.

False
field
field() -> ArrayProtocol | None

The displacement of the map, as values: the flow at time one of the velocity data holds, integrated once, then cached.

Translation magic

Translation(
    _data: npvector[Real] | None = None,
    *,
    _translation: InitVar[npvector[Real] | None] = None,
)

Bases: ConcreteTransformation

A translation.

Attributes

translation property
translation: ArrayProtocol | None

The translation vector, of shape (N,).

Methods:

from_dict classmethod
from_dict(other: Mapping, *args, **kwargs) -> Self

Create an instance of the class from a dictionary-like object.

Only keys in the dictionary that match keyword-like fields of this class, or the keywords its constructor takes without storing them (its InitVars, such as the matrix= of an Affine), will be used. Other keys are ignored, but see from_other, which refuses them.

Additional positional and/or keyword arguments can be provided, and will take precedence over the values in the dictionary.

A key naming a field that this class fixes (a field that cannot be passed to its constructor) is checked instead of used: a dictionary that sets it to anything other than None or the value of this class is refused with a ValueError.

from_other classmethod
from_other(other: Any, *args, **kwargs) -> Self

Create an instance of the class from any object that can be interpreted as a dictionary, or an instance of a similar class, or an arguments to be passed to the constructor.

A similar class is this class or one of its parents within the data model, or another member of a polymorphic family this class belongs to: calling a polymorphic class such as Axis builds the subclass its arguments select, so a "generic" axis is usually an instance of a sibling (a RightToLeftAxis, a TimeAxis) rather than of a parent. Any other object, including an instance of a parent that is not a data model (such as a plain object), is passed to the constructor.

Unlike from_dict, a dictionary with a key that matches no field of this class is refused with a TypeError naming the keys, so that a misspelt key is not silently dropped.

compute
compute(
    mode: ModeLike = True,
    *,
    simplify: SimplifyLike = "analytic",
    factor: bool = False,
) -> Self

Compute the transformation, downcasting it to the cheapest compatible kind.

A concrete transformation holds a parameter, so it simplifies to the simplest compatible kind, whose compatibility can be detected with (almost) no overhead. For example, a transformation whose parameter is set to None is treated as an identity.

Parameters:

Name Type Description Default
mode [list of] name or type

Ignored on a leaf. mode gates which kinds compose, and a leaf has nothing to compose; its downcast is gated only by simplify (simplification is decoupled from the compose mode).

True
simplify simplify policy

How hard this leaf may be looked at. The resolved SimplifyPolicy decides whether the kind-checks run structure-only (analytic) or read values (numeric), or are skipped entirely (none).

"analytic"
factor bool

Whether to factor this leaf into its axis-group normal form. A leaf factors by wrapping itself in a one-element sequence, so a diagonal affine (say) splits into its per-axis blocks. Off by default.

False
simplify
simplify(
    policy: SimplifyLike = "analytic",
    *,
    compute: ModeLike | bool | None = False,
) -> Self

Simplify this transformation under a per-kind policy.

Convenience sugar for compute: t.simplify(policy, compute=mode) is t.compute(mode, simplify=policy).

By default simplify() does no computation at all: compute=False maps to mode=False, which composes nothing (no matrices multiplied, no fields sampled, no lazy inverse materialized). It only downcasts each leaf under policy (analytic by default). Pass an explicit compute=<mode> to also compose that kind.

Parameters:

Name Type Description Default
policy simplify policy

The simplify policy, in the grammar compute accepts.

"analytic"
compute [list of] name or type

The compose mode. The default, False, composes nothing (mode=False in compute); None would compose every kind. A real mode passes straight through.

False
square
square(compute: bool = False, **kwargs) -> Transformation

Return the square of this transformation, self @ self.

The square is the sequence [self, self], which composes when it is computed. It is defined for a transformation that maps a space to itself.

Parameters:

Name Type Description Default
compute bool

Whether to compute the result now rather than return it lazily.

False
**kwargs

Passed to compute when compute is true.

{}

Raises:

Type Description
DomainError

If the transformation does not map a space to itself.

to
to(
    cls: Type[Self] | None = None,
    *,
    lossy: bool = False,
    error: Type[Exception] | Exception | bool = True,
    **kwargs,
) -> Self

Convert this transformation to a different type.

Conversion can be

  • between type: linear.to(Affine) ; or
  • within type: displacement.to(coeff=True) ; or
  • both: coords.to(DisplacementField, coeff=True) .

Parameters:

Name Type Description Default
cls type

The type to convert to. If None, keep the current type.

None
lossy bool

Whether to allow lossy conversions.

False
error bool or Exception

Whether to raise an error if the conversion fails:

  • If an Exception, raise it.
  • If True, raise the original error.
  • Otherwise, return the value of error.
True
**kwargs dict

Attributes to override in the converted transform. This allows transformations to be modified within their type. For example, a DisplacementField can be converted from a field of values to a field of spline coefficients by setting coeff=True in kwargs: a change of encoding flag re-encodes the stored data, and keeps the map. A view's name (field=, matrix=, ...) sets the map, as values, and it is stored in the encoding of the result; data= is stored as given.

{}

Returns:

Type Description
Transformation

The converted transformation.

from_instance classmethod
from_instance(other: Any, *args, **kwargs) -> Self

Create an instance from an instance of a similar class.

See DataModelBase.from_instance. The map of a Translation is copied through its translation view, not its stored data, which a lazy wrapper derives.

AdaptationError

Bases: TypeError

Raised when one coordinate system cannot be adapted to another.

Adaptation reorders, rescales, and flips the axes that two coordinate systems share, so it succeeds only when every axis of one system corresponds to an axis of the other. This error is raised when an axis that must be matched has no correspondence, or when two matched axes carry incompatible units. Its message names the two systems and the axes that could not be reconciled.

CompositionError

Bases: TypeError

Raised when two transformations cannot be composed.

ConversionError

Bases: TypeError

Raised when a transformation cannot be converted to another type.

DomainError

Bases: ValueError

Raised when a transformation lies outside the domain of an operator.

The square and the square root of a transformation (see Transformation.square and Transformation.sqrt) are defined only for a transformation that maps a space to itself. The principal square root, and the principal logarithm that .to(log=True) takes of a matrix, also need the linear part to have no eigenvalue on the closed negative real axis: a singular matrix, a reflection and a rotation by a half turn have neither. Rather than return a complex, a non-principal or an approximate result, the operation raises this error, whose message names it and the reason.

A transformation the operator is defined for, but that brainhops does not know how to compute it for, raises NotImplementedError instead.

LossyConversionError

LossyConversionError(
    *args, result: Transformation | None = None, **kwargs
)

Bases: ConversionError

Raised when a conversion would discard information.

This error is raised by Transformation.to when a conversion is only possible at the cost of losing information, and the conversion was not explicitly allowed to be lossy. The result attribute holds the transformation that the conversion would have produced.

Inverse magic

Inverse(forward: Transformation | None = None)

Bases: Transformation, Generic[TRANSFORMATION]

The inverse of a transformation, resolved on demand.

An Inverse holds a forward transformation and represents its inverse. The inverse is not computed when the wrapper is built. It is computed only when the wrapper is applied, computed, or converted to a concrete type. Placed next to its forward transformation in a Sequence, the two cancel to the identity, and no inverse is ever computed.

Constructing Inverse(forward=t) represents the inverse of any transformation t. Each family of transformations also has its own typed inverse, such as InverseAffine or InverseDisplacementField, which a transformation returns from its inverse() method. A typed inverse remains an instance of the family it inverts, so composition and the kind checks treat it exactly like a forward transformation of that family.

Methods:

from_dict classmethod
from_dict(other: Mapping, *args, **kwargs) -> Self

Create an instance of the class from a dictionary-like object.

Only keys in the dictionary that match keyword-like fields of this class, or the keywords its constructor takes without storing them (its InitVars, such as the matrix= of an Affine), will be used. Other keys are ignored, but see from_other, which refuses them.

Additional positional and/or keyword arguments can be provided, and will take precedence over the values in the dictionary.

A key naming a field that this class fixes (a field that cannot be passed to its constructor) is checked instead of used: a dictionary that sets it to anything other than None or the value of this class is refused with a ValueError.

from_instance classmethod
from_instance(other: Self, *args, **kwargs) -> Self

Create an instance of the class from an instance of a similar class.

Only attributes of the other instance that match keyword-like fields of this class will be used. An attribute that is None is unset, and leaves the default of this class in place.

Additional positional and/or keyword arguments can be provided, and will take precedence over the attributes in the instance.

Unless the other instance is already an instance of this class, an attribute naming a field that this class fixes (a field that cannot be passed to its constructor) is checked instead of used: an instance that sets it to anything other than None or the value of this class is refused with a ValueError. A generic Axis whose orientation is right-to-left, for example, cannot be read as a LeftToRightAxis.

from_other classmethod
from_other(other: Any, *args, **kwargs) -> Self

Create an instance of the class from any object that can be interpreted as a dictionary, or an instance of a similar class, or an arguments to be passed to the constructor.

A similar class is this class or one of its parents within the data model, or another member of a polymorphic family this class belongs to: calling a polymorphic class such as Axis builds the subclass its arguments select, so a "generic" axis is usually an instance of a sibling (a RightToLeftAxis, a TimeAxis) rather than of a parent. Any other object, including an instance of a parent that is not a data model (such as a plain object), is passed to the constructor.

Unlike from_dict, a dictionary with a key that matches no field of this class is refused with a TypeError naming the keys, so that a misspelt key is not silently dropped.

simplify
simplify(
    policy: SimplifyLike = "analytic",
    *,
    compute: ModeLike | bool | None = False,
) -> Self

Simplify this transformation under a per-kind policy.

Convenience sugar for compute: t.simplify(policy, compute=mode) is t.compute(mode, simplify=policy).

By default simplify() does no computation at all: compute=False maps to mode=False, which composes nothing (no matrices multiplied, no fields sampled, no lazy inverse materialized). It only downcasts each leaf under policy (analytic by default). Pass an explicit compute=<mode> to also compose that kind.

Parameters:

Name Type Description Default
policy simplify policy

The simplify policy, in the grammar compute accepts.

"analytic"
compute [list of] name or type

The compose mode. The default, False, composes nothing (mode=False in compute); None would compose every kind. A real mode passes straight through.

False
square
square(compute: bool = False, **kwargs) -> Transformation

Return the square of this transformation, self @ self.

The square is the sequence [self, self], which composes when it is computed. It is defined for a transformation that maps a space to itself.

Parameters:

Name Type Description Default
compute bool

Whether to compute the result now rather than return it lazily.

False
**kwargs

Passed to compute when compute is true.

{}

Raises:

Type Description
DomainError

If the transformation does not map a space to itself.

sqrt
sqrt(compute: bool = False, **kwargs) -> Transformation

Return the principal square root of this transformation.

The square root S of T is the transformation with S @ S == T, the half-transformation. The principal one, whose linear part has its eigenvalues in the open right half-plane, is unique, and it is of the same kind as T: the square root of a rotation is a rotation, of a translation a translation, of a scaling a scaling, of an affine an affine. The square root of a permutation is a Linear transformation.

The square root is lazy: an Sqrt wrapper is returned, and computed when it is applied, computed or converted. A transformation that needs no wrapper (an identity) is returned as is. A Sequence is reduced first (see Sequence.sqrt).

Parameters:

Name Type Description Default
compute bool

Whether to compute the result now rather than return it lazily.

False
**kwargs

Passed to compute when compute is true.

{}

Raises:

Type Description
DomainError

If the transformation does not map a space to itself, or, when the result is computed, if its linear part has an eigenvalue on the closed negative real axis (a reflection, a rotation by a half turn, a singular matrix), so that it has no real principal square root.

NotImplementedError

If brainhops does not compute the square root of this kind of transformation. A displacement field has one only when it is a stationary velocity field (log=True), whose square root halves its velocity.

inverse
inverse(compute: bool = False, **kwargs) -> Transformation

Return the forward transformation, with the endpoints restored.

The inverse of an inverse is the original forward transformation. An endpoint edit made on the wrapper is carried onto it. With compute, the other keywords are passed on to compute().

compute
compute(
    mode: ModeLike = True,
    *,
    simplify: SimplifyLike = "analytic",
    factor: bool = False,
) -> Transformation

Resolve the inverse, if the mode admits it.

Materializing an inverse is the one thing this wrapper exists to put off, so it happens here and nowhere else: never in a simplifier, which may only rewrite for free. The compose mode is the gate -- a mode that does not admit this wrapper leaves it lazy, so an adjacent pair can still cancel in a sequence -- and simplify then still downcasts what it wraps. factor is forwarded to the materialized result.

InverseAffine magic

InverseAffine(forward: Affine | None = None, _data: Derived[npmatrix[Real] | None], _log: Derived[bool], _matrix: Deactivated[None])

Bases: Inverse[Affine], Affine

The inverse of an Affine transformation, resolved on demand.

Attributes

matrix property
matrix: ArrayProtocol | None

The affine matrix, of shape (No, Ni + 1), whose last column is the translation component.

homogeneous_matrix property
homogeneous_matrix: ArrayProtocol

The homogeneous matrix of the affine transformation, of shape (No + 1, Ni + 1). The last row of the homogeneous matrix is [0, 0, ..., 1].

Methods:

from_dict classmethod
from_dict(other: Mapping, *args, **kwargs) -> Self

Create an instance of the class from a dictionary-like object.

Only keys in the dictionary that match keyword-like fields of this class, or the keywords its constructor takes without storing them (its InitVars, such as the matrix= of an Affine), will be used. Other keys are ignored, but see from_other, which refuses them.

Additional positional and/or keyword arguments can be provided, and will take precedence over the values in the dictionary.

A key naming a field that this class fixes (a field that cannot be passed to its constructor) is checked instead of used: a dictionary that sets it to anything other than None or the value of this class is refused with a ValueError.

from_instance classmethod
from_instance(other: Any, *args, **kwargs) -> Self

Create an instance from an instance of a similar class.

See DataModelBase.from_instance. The map of an Affine is copied through its matrix view, not its stored data, which a lazy wrapper derives and a tangent (log=True) stores as its logarithm. A tangent is copied into a tangent through its data.

from_other classmethod
from_other(other: Any, *args, **kwargs) -> Self

Create an instance of the class from any object that can be interpreted as a dictionary, or an instance of a similar class, or an arguments to be passed to the constructor.

A similar class is this class or one of its parents within the data model, or another member of a polymorphic family this class belongs to: calling a polymorphic class such as Axis builds the subclass its arguments select, so a "generic" axis is usually an instance of a sibling (a RightToLeftAxis, a TimeAxis) rather than of a parent. Any other object, including an instance of a parent that is not a data model (such as a plain object), is passed to the constructor.

Unlike from_dict, a dictionary with a key that matches no field of this class is refused with a TypeError naming the keys, so that a misspelt key is not silently dropped.

compute
compute(
    mode: ModeLike = True,
    *,
    simplify: SimplifyLike = "analytic",
    factor: bool = False,
) -> Transformation

Resolve the inverse, if the mode admits it.

Materializing an inverse is the one thing this wrapper exists to put off, so it happens here and nowhere else: never in a simplifier, which may only rewrite for free. The compose mode is the gate -- a mode that does not admit this wrapper leaves it lazy, so an adjacent pair can still cancel in a sequence -- and simplify then still downcasts what it wraps. factor is forwarded to the materialized result.

simplify
simplify(
    policy: SimplifyLike = "analytic",
    *,
    compute: ModeLike | bool | None = False,
) -> Self

Simplify this transformation under a per-kind policy.

Convenience sugar for compute: t.simplify(policy, compute=mode) is t.compute(mode, simplify=policy).

By default simplify() does no computation at all: compute=False maps to mode=False, which composes nothing (no matrices multiplied, no fields sampled, no lazy inverse materialized). It only downcasts each leaf under policy (analytic by default). Pass an explicit compute=<mode> to also compose that kind.

Parameters:

Name Type Description Default
policy simplify policy

The simplify policy, in the grammar compute accepts.

"analytic"
compute [list of] name or type

The compose mode. The default, False, composes nothing (mode=False in compute); None would compose every kind. A real mode passes straight through.

False
inverse
inverse(compute: bool = False, **kwargs) -> Transformation

Return the forward transformation, with the endpoints restored.

The inverse of an inverse is the original forward transformation. An endpoint edit made on the wrapper is carried onto it. With compute, the other keywords are passed on to compute().

square
square(compute: bool = False, **kwargs) -> Transformation

Return the square of this transformation, self @ self.

The square is the sequence [self, self], which composes when it is computed. It is defined for a transformation that maps a space to itself.

Parameters:

Name Type Description Default
compute bool

Whether to compute the result now rather than return it lazily.

False
**kwargs

Passed to compute when compute is true.

{}

Raises:

Type Description
DomainError

If the transformation does not map a space to itself.

InverseAffineExponential magic

InverseAffineExponential(forward: AffineExponential | None = None, _data: Derived[npmatrix[Real] | None], _log: Derived[bool], _matrix: Deactivated[None])

Bases: Inverse[AffineExponential], AffineExponential

The inverse of an AffineExponential: the tangent negated.

Attributes

homogeneous_matrix property
homogeneous_matrix: ArrayProtocol

The homogeneous matrix of the affine transformation, of shape (No + 1, Ni + 1). The last row of the homogeneous matrix is [0, 0, ..., 1].

Methods:

from_dict classmethod
from_dict(other: Mapping, *args, **kwargs) -> Self

Create an instance of the class from a dictionary-like object.

Only keys in the dictionary that match keyword-like fields of this class, or the keywords its constructor takes without storing them (its InitVars, such as the matrix= of an Affine), will be used. Other keys are ignored, but see from_other, which refuses them.

Additional positional and/or keyword arguments can be provided, and will take precedence over the values in the dictionary.

A key naming a field that this class fixes (a field that cannot be passed to its constructor) is checked instead of used: a dictionary that sets it to anything other than None or the value of this class is refused with a ValueError.

from_instance classmethod
from_instance(other: Any, *args, **kwargs) -> Self

Create an instance from an instance of a similar class.

See DataModelBase.from_instance. The map of an Affine is copied through its matrix view, not its stored data, which a lazy wrapper derives and a tangent (log=True) stores as its logarithm. A tangent is copied into a tangent through its data.

from_other classmethod
from_other(other: Any, *args, **kwargs) -> Self

Create an instance of the class from any object that can be interpreted as a dictionary, or an instance of a similar class, or an arguments to be passed to the constructor.

A similar class is this class or one of its parents within the data model, or another member of a polymorphic family this class belongs to: calling a polymorphic class such as Axis builds the subclass its arguments select, so a "generic" axis is usually an instance of a sibling (a RightToLeftAxis, a TimeAxis) rather than of a parent. Any other object, including an instance of a parent that is not a data model (such as a plain object), is passed to the constructor.

Unlike from_dict, a dictionary with a key that matches no field of this class is refused with a TypeError naming the keys, so that a misspelt key is not silently dropped.

compute
compute(
    mode: ModeLike = True,
    *,
    simplify: SimplifyLike = "analytic",
    factor: bool = False,
) -> Transformation

Resolve the inverse, if the mode admits it.

Materializing an inverse is the one thing this wrapper exists to put off, so it happens here and nowhere else: never in a simplifier, which may only rewrite for free. The compose mode is the gate -- a mode that does not admit this wrapper leaves it lazy, so an adjacent pair can still cancel in a sequence -- and simplify then still downcasts what it wraps. factor is forwarded to the materialized result.

simplify
simplify(
    policy: SimplifyLike = "analytic",
    *,
    compute: ModeLike | bool | None = False,
) -> Self

Simplify this transformation under a per-kind policy.

Convenience sugar for compute: t.simplify(policy, compute=mode) is t.compute(mode, simplify=policy).

By default simplify() does no computation at all: compute=False maps to mode=False, which composes nothing (no matrices multiplied, no fields sampled, no lazy inverse materialized). It only downcasts each leaf under policy (analytic by default). Pass an explicit compute=<mode> to also compose that kind.

Parameters:

Name Type Description Default
policy simplify policy

The simplify policy, in the grammar compute accepts.

"analytic"
compute [list of] name or type

The compose mode. The default, False, composes nothing (mode=False in compute); None would compose every kind. A real mode passes straight through.

False
inverse
inverse(compute: bool = False, **kwargs) -> Transformation

Return the forward transformation, with the endpoints restored.

The inverse of an inverse is the original forward transformation. An endpoint edit made on the wrapper is carried onto it. With compute, the other keywords are passed on to compute().

matrix
matrix() -> ArrayProtocol | None

The affine matrix, of shape (N, N + 1): the exponential of the tangent data.

InverseCoordinatesField magic

InverseCoordinatesField(forward: CoordinatesField | None = None, _data: Derived[ArrayProtocol | None], _degree: Derived[InterpolationOrder], _bound: Derived[BoundaryCondition | float], _coeff: Derived[bool], _field: Deactivated[None])

Bases: Inverse[CoordinatesField], CoordinatesField

The inverse of a CoordinatesField, resolved on demand.

The wrapper reports the degree, bound and coeff of the forward field, and its data is the inverse field in that same encoding: the forward field's values are inverted, and the result is fitted back to spline coefficients when the forward field holds coefficients. Its field view is the inverse field, as values, either way.

Accuracy

As for InverseDisplacementField, the inversion only sees the forward field's values at the grid nodes and inverts the piecewise-affine map they define, whatever the forward's degree; the result is approximate between nodes, and more so near the border.

Placed next to the field it inverts in a Sequence, the two cancel and nothing is computed. That is the cheap path, and the one worth reaching for: a coordinate field has no closed-form inverse, so materializing this wrapper runs a mesh inversion.

The coordinates must live on the grid they are sampled on

A coordinate field is inverted by reading it as the identity grid plus a displacement, inverting that displacement, and adding the grid back. The mesh inversion therefore assumes the coordinates are expressed in the units of the grid they are sampled on -- voxels, in practice. A field whose coordinates are in world units is inverted as though they were voxel coordinates, and the result, while well defined, falls outside the output lattice and is of little use. Compose the world-to-voxel affine into the field first.

Methods:

from_dict classmethod
from_dict(other: Mapping, *args, **kwargs) -> Self

Create an instance of the class from a dictionary-like object.

Only keys in the dictionary that match keyword-like fields of this class, or the keywords its constructor takes without storing them (its InitVars, such as the matrix= of an Affine), will be used. Other keys are ignored, but see from_other, which refuses them.

Additional positional and/or keyword arguments can be provided, and will take precedence over the values in the dictionary.

A key naming a field that this class fixes (a field that cannot be passed to its constructor) is checked instead of used: a dictionary that sets it to anything other than None or the value of this class is refused with a ValueError.

from_instance classmethod
from_instance(other: Any, *args, **kwargs) -> Self

Create an instance from an instance of a similar class.

See DataModelBase.from_instance. A lazy wrapper derives its data and its flags, so they are read through their public names.

from_other classmethod
from_other(other: Any, *args, **kwargs) -> Self

Create an instance of the class from any object that can be interpreted as a dictionary, or an instance of a similar class, or an arguments to be passed to the constructor.

A similar class is this class or one of its parents within the data model, or another member of a polymorphic family this class belongs to: calling a polymorphic class such as Axis builds the subclass its arguments select, so a "generic" axis is usually an instance of a sibling (a RightToLeftAxis, a TimeAxis) rather than of a parent. Any other object, including an instance of a parent that is not a data model (such as a plain object), is passed to the constructor.

Unlike from_dict, a dictionary with a key that matches no field of this class is refused with a TypeError naming the keys, so that a misspelt key is not silently dropped.

compute
compute(
    mode: ModeLike = True,
    *,
    simplify: SimplifyLike = "analytic",
    factor: bool = False,
) -> Transformation

Resolve the inverse, if the mode admits it.

Materializing an inverse is the one thing this wrapper exists to put off, so it happens here and nowhere else: never in a simplifier, which may only rewrite for free. The compose mode is the gate -- a mode that does not admit this wrapper leaves it lazy, so an adjacent pair can still cancel in a sequence -- and simplify then still downcasts what it wraps. factor is forwarded to the materialized result.

simplify
simplify(
    policy: SimplifyLike = "analytic",
    *,
    compute: ModeLike | bool | None = False,
) -> Self

Simplify this transformation under a per-kind policy.

Convenience sugar for compute: t.simplify(policy, compute=mode) is t.compute(mode, simplify=policy).

By default simplify() does no computation at all: compute=False maps to mode=False, which composes nothing (no matrices multiplied, no fields sampled, no lazy inverse materialized). It only downcasts each leaf under policy (analytic by default). Pass an explicit compute=<mode> to also compose that kind.

Parameters:

Name Type Description Default
policy simplify policy

The simplify policy, in the grammar compute accepts.

"analytic"
compute [list of] name or type

The compose mode. The default, False, composes nothing (mode=False in compute); None would compose every kind. A real mode passes straight through.

False
inverse
inverse(compute: bool = False, **kwargs) -> Transformation

Return the forward transformation, with the endpoints restored.

The inverse of an inverse is the original forward transformation. An endpoint edit made on the wrapper is carried onto it. With compute, the other keywords are passed on to compute().

square
square(compute: bool = False, **kwargs) -> Transformation

Return the square of this transformation, self @ self.

The square is the sequence [self, self], which composes when it is computed. It is defined for a transformation that maps a space to itself.

Parameters:

Name Type Description Default
compute bool

Whether to compute the result now rather than return it lazily.

False
**kwargs

Passed to compute when compute is true.

{}

Raises:

Type Description
DomainError

If the transformation does not map a space to itself.

InverseDisplacementField magic

InverseDisplacementField(forward: DisplacementField | None = None, _data: Derived[ArrayProtocol | None], _degree: Derived[InterpolationOrder], _bound: Derived[BoundaryCondition | float], _coeff: Derived[bool], _log: Derived[bool], _field: Deactivated[None])

Bases: Inverse[DisplacementField], DisplacementField

The inverse of a DisplacementField, resolved on demand.

The wrapper reports the degree, bound and coeff of the forward field, and its data is the inverse field in that same encoding: the forward field's values are inverted, and the result is fitted back to spline coefficients when the forward field holds coefficients. Its field view is the inverse field, as values, either way.

Accuracy

The inversion only sees the forward field's values at the grid nodes: it inverts the piecewise-affine map they define (see brainhops._ext.invfield.inverse), whatever the forward's degree. The inverse is then interpolated with that degree. It is exact at the level of that piecewise-affine map only, so a cubic field is inverted about as accurately as a linear one, and the error grows near the border. On smooth fields of a few voxels' amplitude, fwd(inv(x)) - x is typically a few hundredths of a voxel in the interior, and a few tenths near the border.

Methods:

from_dict classmethod
from_dict(other: Mapping, *args, **kwargs) -> Self

Create an instance of the class from a dictionary-like object.

Only keys in the dictionary that match keyword-like fields of this class, or the keywords its constructor takes without storing them (its InitVars, such as the matrix= of an Affine), will be used. Other keys are ignored, but see from_other, which refuses them.

Additional positional and/or keyword arguments can be provided, and will take precedence over the values in the dictionary.

A key naming a field that this class fixes (a field that cannot be passed to its constructor) is checked instead of used: a dictionary that sets it to anything other than None or the value of this class is refused with a ValueError.

from_instance classmethod
from_instance(other: Any, *args, **kwargs) -> Self

Create an instance from an instance of a similar class.

See DataModelBase.from_instance. A lazy wrapper derives its data and its flags, so they are read through their public names. A field that holds its displacement is copied as its displacement: a velocity (log=True) is integrated, unless the copy is a velocity too.

from_other classmethod
from_other(other: Any, *args, **kwargs) -> Self

Create an instance of the class from any object that can be interpreted as a dictionary, or an instance of a similar class, or an arguments to be passed to the constructor.

A similar class is this class or one of its parents within the data model, or another member of a polymorphic family this class belongs to: calling a polymorphic class such as Axis builds the subclass its arguments select, so a "generic" axis is usually an instance of a sibling (a RightToLeftAxis, a TimeAxis) rather than of a parent. Any other object, including an instance of a parent that is not a data model (such as a plain object), is passed to the constructor.

Unlike from_dict, a dictionary with a key that matches no field of this class is refused with a TypeError naming the keys, so that a misspelt key is not silently dropped.

compute
compute(
    mode: ModeLike = True,
    *,
    simplify: SimplifyLike = "analytic",
    factor: bool = False,
) -> Transformation

Resolve the inverse, if the mode admits it.

Materializing an inverse is the one thing this wrapper exists to put off, so it happens here and nowhere else: never in a simplifier, which may only rewrite for free. The compose mode is the gate -- a mode that does not admit this wrapper leaves it lazy, so an adjacent pair can still cancel in a sequence -- and simplify then still downcasts what it wraps. factor is forwarded to the materialized result.

simplify
simplify(
    policy: SimplifyLike = "analytic",
    *,
    compute: ModeLike | bool | None = False,
) -> Self

Simplify this transformation under a per-kind policy.

Convenience sugar for compute: t.simplify(policy, compute=mode) is t.compute(mode, simplify=policy).

By default simplify() does no computation at all: compute=False maps to mode=False, which composes nothing (no matrices multiplied, no fields sampled, no lazy inverse materialized). It only downcasts each leaf under policy (analytic by default). Pass an explicit compute=<mode> to also compose that kind.

Parameters:

Name Type Description Default
policy simplify policy

The simplify policy, in the grammar compute accepts.

"analytic"
compute [list of] name or type

The compose mode. The default, False, composes nothing (mode=False in compute); None would compose every kind. A real mode passes straight through.

False
inverse
inverse(compute: bool = False, **kwargs) -> Transformation

Return the forward transformation, with the endpoints restored.

The inverse of an inverse is the original forward transformation. An endpoint edit made on the wrapper is carried onto it. With compute, the other keywords are passed on to compute().

square
square(compute: bool = False, **kwargs) -> Transformation

Return the square of this transformation, self @ self.

The square is the sequence [self, self], which composes when it is computed. It is defined for a transformation that maps a space to itself.

Parameters:

Name Type Description Default
compute bool

Whether to compute the result now rather than return it lazily.

False
**kwargs

Passed to compute when compute is true.

{}

Raises:

Type Description
DomainError

If the transformation does not map a space to itself.

InverseLinear magic

InverseLinear(forward: Linear | None = None, _data: Derived[npmatrix[Real] | None], _log: Derived[bool], _matrix: Deactivated[None])

Bases: Inverse[Linear], Linear

The inverse of a Linear transformation, resolved on demand.

Attributes

matrix property
matrix: ArrayProtocol | None

The matrix, of shape (No, Ni).

Methods:

from_dict classmethod
from_dict(other: Mapping, *args, **kwargs) -> Self

Create an instance of the class from a dictionary-like object.

Only keys in the dictionary that match keyword-like fields of this class, or the keywords its constructor takes without storing them (its InitVars, such as the matrix= of an Affine), will be used. Other keys are ignored, but see from_other, which refuses them.

Additional positional and/or keyword arguments can be provided, and will take precedence over the values in the dictionary.

A key naming a field that this class fixes (a field that cannot be passed to its constructor) is checked instead of used: a dictionary that sets it to anything other than None or the value of this class is refused with a ValueError.

from_instance classmethod
from_instance(other: Any, *args, **kwargs) -> Self

Create an instance from an instance of a similar class.

See DataModelBase.from_instance. The map of a Linear is copied through its matrix view, not its stored data, which a lazy wrapper derives and a tangent (log=True) stores as its logarithm. A tangent is copied into a tangent through its data.

from_other classmethod
from_other(other: Any, *args, **kwargs) -> Self

Create an instance of the class from any object that can be interpreted as a dictionary, or an instance of a similar class, or an arguments to be passed to the constructor.

A similar class is this class or one of its parents within the data model, or another member of a polymorphic family this class belongs to: calling a polymorphic class such as Axis builds the subclass its arguments select, so a "generic" axis is usually an instance of a sibling (a RightToLeftAxis, a TimeAxis) rather than of a parent. Any other object, including an instance of a parent that is not a data model (such as a plain object), is passed to the constructor.

Unlike from_dict, a dictionary with a key that matches no field of this class is refused with a TypeError naming the keys, so that a misspelt key is not silently dropped.

compute
compute(
    mode: ModeLike = True,
    *,
    simplify: SimplifyLike = "analytic",
    factor: bool = False,
) -> Transformation

Resolve the inverse, if the mode admits it.

Materializing an inverse is the one thing this wrapper exists to put off, so it happens here and nowhere else: never in a simplifier, which may only rewrite for free. The compose mode is the gate -- a mode that does not admit this wrapper leaves it lazy, so an adjacent pair can still cancel in a sequence -- and simplify then still downcasts what it wraps. factor is forwarded to the materialized result.

simplify
simplify(
    policy: SimplifyLike = "analytic",
    *,
    compute: ModeLike | bool | None = False,
) -> Self

Simplify this transformation under a per-kind policy.

Convenience sugar for compute: t.simplify(policy, compute=mode) is t.compute(mode, simplify=policy).

By default simplify() does no computation at all: compute=False maps to mode=False, which composes nothing (no matrices multiplied, no fields sampled, no lazy inverse materialized). It only downcasts each leaf under policy (analytic by default). Pass an explicit compute=<mode> to also compose that kind.

Parameters:

Name Type Description Default
policy simplify policy

The simplify policy, in the grammar compute accepts.

"analytic"
compute [list of] name or type

The compose mode. The default, False, composes nothing (mode=False in compute); None would compose every kind. A real mode passes straight through.

False
inverse
inverse(compute: bool = False, **kwargs) -> Transformation

Return the forward transformation, with the endpoints restored.

The inverse of an inverse is the original forward transformation. An endpoint edit made on the wrapper is carried onto it. With compute, the other keywords are passed on to compute().

square
square(compute: bool = False, **kwargs) -> Transformation

Return the square of this transformation, self @ self.

The square is the sequence [self, self], which composes when it is computed. It is defined for a transformation that maps a space to itself.

Parameters:

Name Type Description Default
compute bool

Whether to compute the result now rather than return it lazily.

False
**kwargs

Passed to compute when compute is true.

{}

Raises:

Type Description
DomainError

If the transformation does not map a space to itself.

InverseLinearExponential magic

InverseLinearExponential(forward: LinearExponential | None = None, _data: Derived[npmatrix[Real] | None], _log: Derived[bool], _matrix: Deactivated[None])

Bases: Inverse[LinearExponential], LinearExponential

The inverse of a LinearExponential: the tangent negated.

Methods:

from_dict classmethod
from_dict(other: Mapping, *args, **kwargs) -> Self

Create an instance of the class from a dictionary-like object.

Only keys in the dictionary that match keyword-like fields of this class, or the keywords its constructor takes without storing them (its InitVars, such as the matrix= of an Affine), will be used. Other keys are ignored, but see from_other, which refuses them.

Additional positional and/or keyword arguments can be provided, and will take precedence over the values in the dictionary.

A key naming a field that this class fixes (a field that cannot be passed to its constructor) is checked instead of used: a dictionary that sets it to anything other than None or the value of this class is refused with a ValueError.

from_instance classmethod
from_instance(other: Any, *args, **kwargs) -> Self

Create an instance from an instance of a similar class.

See DataModelBase.from_instance. The map of a Linear is copied through its matrix view, not its stored data, which a lazy wrapper derives and a tangent (log=True) stores as its logarithm. A tangent is copied into a tangent through its data.

from_other classmethod
from_other(other: Any, *args, **kwargs) -> Self

Create an instance of the class from any object that can be interpreted as a dictionary, or an instance of a similar class, or an arguments to be passed to the constructor.

A similar class is this class or one of its parents within the data model, or another member of a polymorphic family this class belongs to: calling a polymorphic class such as Axis builds the subclass its arguments select, so a "generic" axis is usually an instance of a sibling (a RightToLeftAxis, a TimeAxis) rather than of a parent. Any other object, including an instance of a parent that is not a data model (such as a plain object), is passed to the constructor.

Unlike from_dict, a dictionary with a key that matches no field of this class is refused with a TypeError naming the keys, so that a misspelt key is not silently dropped.

compute
compute(
    mode: ModeLike = True,
    *,
    simplify: SimplifyLike = "analytic",
    factor: bool = False,
) -> Transformation

Resolve the inverse, if the mode admits it.

Materializing an inverse is the one thing this wrapper exists to put off, so it happens here and nowhere else: never in a simplifier, which may only rewrite for free. The compose mode is the gate -- a mode that does not admit this wrapper leaves it lazy, so an adjacent pair can still cancel in a sequence -- and simplify then still downcasts what it wraps. factor is forwarded to the materialized result.

simplify
simplify(
    policy: SimplifyLike = "analytic",
    *,
    compute: ModeLike | bool | None = False,
) -> Self

Simplify this transformation under a per-kind policy.

Convenience sugar for compute: t.simplify(policy, compute=mode) is t.compute(mode, simplify=policy).

By default simplify() does no computation at all: compute=False maps to mode=False, which composes nothing (no matrices multiplied, no fields sampled, no lazy inverse materialized). It only downcasts each leaf under policy (analytic by default). Pass an explicit compute=<mode> to also compose that kind.

Parameters:

Name Type Description Default
policy simplify policy

The simplify policy, in the grammar compute accepts.

"analytic"
compute [list of] name or type

The compose mode. The default, False, composes nothing (mode=False in compute); None would compose every kind. A real mode passes straight through.

False
inverse
inverse(compute: bool = False, **kwargs) -> Transformation

Return the forward transformation, with the endpoints restored.

The inverse of an inverse is the original forward transformation. An endpoint edit made on the wrapper is carried onto it. With compute, the other keywords are passed on to compute().

matrix
matrix() -> ArrayProtocol | None

The matrix, of shape (N, N): the exponential of data.

InversePermutation magic

InversePermutation(forward: Permutation | None = None, _data: Derived[npvector[Integral] | None], _permutation: Deactivated[None])

Bases: Inverse, Permutation

The inverse of a Permutation, resolved on demand.

Attributes

permutation property
permutation: ArrayProtocol | None

The permutation vector, of shape (N,).

Methods:

from_dict classmethod
from_dict(other: Mapping, *args, **kwargs) -> Self

Create an instance of the class from a dictionary-like object.

Only keys in the dictionary that match keyword-like fields of this class, or the keywords its constructor takes without storing them (its InitVars, such as the matrix= of an Affine), will be used. Other keys are ignored, but see from_other, which refuses them.

Additional positional and/or keyword arguments can be provided, and will take precedence over the values in the dictionary.

A key naming a field that this class fixes (a field that cannot be passed to its constructor) is checked instead of used: a dictionary that sets it to anything other than None or the value of this class is refused with a ValueError.

from_instance classmethod
from_instance(other: Any, *args, **kwargs) -> Self

Create an instance from an instance of a similar class.

See DataModelBase.from_instance. The map of a Permutation is copied through its permutation view, not its stored data, which a lazy wrapper derives.

from_other classmethod
from_other(other: Any, *args, **kwargs) -> Self

Create an instance of the class from any object that can be interpreted as a dictionary, or an instance of a similar class, or an arguments to be passed to the constructor.

A similar class is this class or one of its parents within the data model, or another member of a polymorphic family this class belongs to: calling a polymorphic class such as Axis builds the subclass its arguments select, so a "generic" axis is usually an instance of a sibling (a RightToLeftAxis, a TimeAxis) rather than of a parent. Any other object, including an instance of a parent that is not a data model (such as a plain object), is passed to the constructor.

Unlike from_dict, a dictionary with a key that matches no field of this class is refused with a TypeError naming the keys, so that a misspelt key is not silently dropped.

compute
compute(
    mode: ModeLike = True,
    *,
    simplify: SimplifyLike = "analytic",
    factor: bool = False,
) -> Transformation

Resolve the inverse, if the mode admits it.

Materializing an inverse is the one thing this wrapper exists to put off, so it happens here and nowhere else: never in a simplifier, which may only rewrite for free. The compose mode is the gate -- a mode that does not admit this wrapper leaves it lazy, so an adjacent pair can still cancel in a sequence -- and simplify then still downcasts what it wraps. factor is forwarded to the materialized result.

simplify
simplify(
    policy: SimplifyLike = "analytic",
    *,
    compute: ModeLike | bool | None = False,
) -> Self

Simplify this transformation under a per-kind policy.

Convenience sugar for compute: t.simplify(policy, compute=mode) is t.compute(mode, simplify=policy).

By default simplify() does no computation at all: compute=False maps to mode=False, which composes nothing (no matrices multiplied, no fields sampled, no lazy inverse materialized). It only downcasts each leaf under policy (analytic by default). Pass an explicit compute=<mode> to also compose that kind.

Parameters:

Name Type Description Default
policy simplify policy

The simplify policy, in the grammar compute accepts.

"analytic"
compute [list of] name or type

The compose mode. The default, False, composes nothing (mode=False in compute); None would compose every kind. A real mode passes straight through.

False
inverse
inverse(compute: bool = False, **kwargs) -> Transformation

Return the forward transformation, with the endpoints restored.

The inverse of an inverse is the original forward transformation. An endpoint edit made on the wrapper is carried onto it. With compute, the other keywords are passed on to compute().

square
square(compute: bool = False, **kwargs) -> Transformation

Return the square of this transformation, self @ self.

The square is the sequence [self, self], which composes when it is computed. It is defined for a transformation that maps a space to itself.

Parameters:

Name Type Description Default
compute bool

Whether to compute the result now rather than return it lazily.

False
**kwargs

Passed to compute when compute is true.

{}

Raises:

Type Description
DomainError

If the transformation does not map a space to itself.

InverseRotation magic

InverseRotation(forward: Rotation | None = None, _data: Derived[npmatrix[Real] | None], _log: Derived[bool], _matrix: Deactivated[None])

Bases: Inverse[Rotation], Rotation

The inverse of a Rotation, resolved on demand.

Attributes

matrix property
matrix: ArrayProtocol | None

The matrix, of shape (No, Ni).

Methods:

from_dict classmethod
from_dict(other: Mapping, *args, **kwargs) -> Self

Create an instance of the class from a dictionary-like object.

Only keys in the dictionary that match keyword-like fields of this class, or the keywords its constructor takes without storing them (its InitVars, such as the matrix= of an Affine), will be used. Other keys are ignored, but see from_other, which refuses them.

Additional positional and/or keyword arguments can be provided, and will take precedence over the values in the dictionary.

A key naming a field that this class fixes (a field that cannot be passed to its constructor) is checked instead of used: a dictionary that sets it to anything other than None or the value of this class is refused with a ValueError.

from_instance classmethod
from_instance(other: Any, *args, **kwargs) -> Self

Create an instance from an instance of a similar class.

See DataModelBase.from_instance. The map of a Linear is copied through its matrix view, not its stored data, which a lazy wrapper derives and a tangent (log=True) stores as its logarithm. A tangent is copied into a tangent through its data.

from_other classmethod
from_other(other: Any, *args, **kwargs) -> Self

Create an instance of the class from any object that can be interpreted as a dictionary, or an instance of a similar class, or an arguments to be passed to the constructor.

A similar class is this class or one of its parents within the data model, or another member of a polymorphic family this class belongs to: calling a polymorphic class such as Axis builds the subclass its arguments select, so a "generic" axis is usually an instance of a sibling (a RightToLeftAxis, a TimeAxis) rather than of a parent. Any other object, including an instance of a parent that is not a data model (such as a plain object), is passed to the constructor.

Unlike from_dict, a dictionary with a key that matches no field of this class is refused with a TypeError naming the keys, so that a misspelt key is not silently dropped.

compute
compute(
    mode: ModeLike = True,
    *,
    simplify: SimplifyLike = "analytic",
    factor: bool = False,
) -> Transformation

Resolve the inverse, if the mode admits it.

Materializing an inverse is the one thing this wrapper exists to put off, so it happens here and nowhere else: never in a simplifier, which may only rewrite for free. The compose mode is the gate -- a mode that does not admit this wrapper leaves it lazy, so an adjacent pair can still cancel in a sequence -- and simplify then still downcasts what it wraps. factor is forwarded to the materialized result.

simplify
simplify(
    policy: SimplifyLike = "analytic",
    *,
    compute: ModeLike | bool | None = False,
) -> Self

Simplify this transformation under a per-kind policy.

Convenience sugar for compute: t.simplify(policy, compute=mode) is t.compute(mode, simplify=policy).

By default simplify() does no computation at all: compute=False maps to mode=False, which composes nothing (no matrices multiplied, no fields sampled, no lazy inverse materialized). It only downcasts each leaf under policy (analytic by default). Pass an explicit compute=<mode> to also compose that kind.

Parameters:

Name Type Description Default
policy simplify policy

The simplify policy, in the grammar compute accepts.

"analytic"
compute [list of] name or type

The compose mode. The default, False, composes nothing (mode=False in compute); None would compose every kind. A real mode passes straight through.

False
inverse
inverse(compute: bool = False, **kwargs) -> Transformation

Return the forward transformation, with the endpoints restored.

The inverse of an inverse is the original forward transformation. An endpoint edit made on the wrapper is carried onto it. With compute, the other keywords are passed on to compute().

square
square(compute: bool = False, **kwargs) -> Transformation

Return the square of this transformation, self @ self.

The square is the sequence [self, self], which composes when it is computed. It is defined for a transformation that maps a space to itself.

Parameters:

Name Type Description Default
compute bool

Whether to compute the result now rather than return it lazily.

False
**kwargs

Passed to compute when compute is true.

{}

Raises:

Type Description
DomainError

If the transformation does not map a space to itself.

InverseRotationExponential magic

InverseRotationExponential(forward: RotationExponential | None = None, _data: Derived[npmatrix[Real] | None], _log: Derived[bool], _matrix: Deactivated[None])

Bases: Inverse[RotationExponential], RotationExponential

The inverse of a RotationExponential: the tangent negated.

Methods:

from_dict classmethod
from_dict(other: Mapping, *args, **kwargs) -> Self

Create an instance of the class from a dictionary-like object.

Only keys in the dictionary that match keyword-like fields of this class, or the keywords its constructor takes without storing them (its InitVars, such as the matrix= of an Affine), will be used. Other keys are ignored, but see from_other, which refuses them.

Additional positional and/or keyword arguments can be provided, and will take precedence over the values in the dictionary.

A key naming a field that this class fixes (a field that cannot be passed to its constructor) is checked instead of used: a dictionary that sets it to anything other than None or the value of this class is refused with a ValueError.

from_instance classmethod
from_instance(other: Any, *args, **kwargs) -> Self

Create an instance from an instance of a similar class.

See DataModelBase.from_instance. The map of a Linear is copied through its matrix view, not its stored data, which a lazy wrapper derives and a tangent (log=True) stores as its logarithm. A tangent is copied into a tangent through its data.

from_other classmethod
from_other(other: Any, *args, **kwargs) -> Self

Create an instance of the class from any object that can be interpreted as a dictionary, or an instance of a similar class, or an arguments to be passed to the constructor.

A similar class is this class or one of its parents within the data model, or another member of a polymorphic family this class belongs to: calling a polymorphic class such as Axis builds the subclass its arguments select, so a "generic" axis is usually an instance of a sibling (a RightToLeftAxis, a TimeAxis) rather than of a parent. Any other object, including an instance of a parent that is not a data model (such as a plain object), is passed to the constructor.

Unlike from_dict, a dictionary with a key that matches no field of this class is refused with a TypeError naming the keys, so that a misspelt key is not silently dropped.

compute
compute(
    mode: ModeLike = True,
    *,
    simplify: SimplifyLike = "analytic",
    factor: bool = False,
) -> Transformation

Resolve the inverse, if the mode admits it.

Materializing an inverse is the one thing this wrapper exists to put off, so it happens here and nowhere else: never in a simplifier, which may only rewrite for free. The compose mode is the gate -- a mode that does not admit this wrapper leaves it lazy, so an adjacent pair can still cancel in a sequence -- and simplify then still downcasts what it wraps. factor is forwarded to the materialized result.

simplify
simplify(
    policy: SimplifyLike = "analytic",
    *,
    compute: ModeLike | bool | None = False,
) -> Self

Simplify this transformation under a per-kind policy.

Convenience sugar for compute: t.simplify(policy, compute=mode) is t.compute(mode, simplify=policy).

By default simplify() does no computation at all: compute=False maps to mode=False, which composes nothing (no matrices multiplied, no fields sampled, no lazy inverse materialized). It only downcasts each leaf under policy (analytic by default). Pass an explicit compute=<mode> to also compose that kind.

Parameters:

Name Type Description Default
policy simplify policy

The simplify policy, in the grammar compute accepts.

"analytic"
compute [list of] name or type

The compose mode. The default, False, composes nothing (mode=False in compute); None would compose every kind. A real mode passes straight through.

False
inverse
inverse(compute: bool = False, **kwargs) -> Transformation

Return the forward transformation, with the endpoints restored.

The inverse of an inverse is the original forward transformation. An endpoint edit made on the wrapper is carried onto it. With compute, the other keywords are passed on to compute().

matrix
matrix() -> ArrayProtocol | None

The rotation matrix, of shape (N, N): the exponential of data.

InverseScaling magic

InverseScaling(forward: Scaling | None = None, _data: Derived[npvector[Real] | None], _log: Derived[bool], _scale: Deactivated[None])

Bases: Inverse, Scaling

The inverse of a Scaling, resolved on demand.

Attributes

scale property
scale: ArrayProtocol | None

The scaling factors, of shape (N,).

Methods:

from_dict classmethod
from_dict(other: Mapping, *args, **kwargs) -> Self

Create an instance of the class from a dictionary-like object.

Only keys in the dictionary that match keyword-like fields of this class, or the keywords its constructor takes without storing them (its InitVars, such as the matrix= of an Affine), will be used. Other keys are ignored, but see from_other, which refuses them.

Additional positional and/or keyword arguments can be provided, and will take precedence over the values in the dictionary.

A key naming a field that this class fixes (a field that cannot be passed to its constructor) is checked instead of used: a dictionary that sets it to anything other than None or the value of this class is refused with a ValueError.

from_instance classmethod
from_instance(other: Any, *args, **kwargs) -> Self

Create an instance from an instance of a similar class.

See DataModelBase.from_instance. The map of a Scaling is copied through its scale view, not its stored data, which a lazy wrapper derives and a tangent (log=True) stores as its logarithm. A tangent is copied into a tangent through its data.

from_other classmethod
from_other(other: Any, *args, **kwargs) -> Self

Create an instance of the class from any object that can be interpreted as a dictionary, or an instance of a similar class, or an arguments to be passed to the constructor.

A similar class is this class or one of its parents within the data model, or another member of a polymorphic family this class belongs to: calling a polymorphic class such as Axis builds the subclass its arguments select, so a "generic" axis is usually an instance of a sibling (a RightToLeftAxis, a TimeAxis) rather than of a parent. Any other object, including an instance of a parent that is not a data model (such as a plain object), is passed to the constructor.

Unlike from_dict, a dictionary with a key that matches no field of this class is refused with a TypeError naming the keys, so that a misspelt key is not silently dropped.

compute
compute(
    mode: ModeLike = True,
    *,
    simplify: SimplifyLike = "analytic",
    factor: bool = False,
) -> Transformation

Resolve the inverse, if the mode admits it.

Materializing an inverse is the one thing this wrapper exists to put off, so it happens here and nowhere else: never in a simplifier, which may only rewrite for free. The compose mode is the gate -- a mode that does not admit this wrapper leaves it lazy, so an adjacent pair can still cancel in a sequence -- and simplify then still downcasts what it wraps. factor is forwarded to the materialized result.

simplify
simplify(
    policy: SimplifyLike = "analytic",
    *,
    compute: ModeLike | bool | None = False,
) -> Self

Simplify this transformation under a per-kind policy.

Convenience sugar for compute: t.simplify(policy, compute=mode) is t.compute(mode, simplify=policy).

By default simplify() does no computation at all: compute=False maps to mode=False, which composes nothing (no matrices multiplied, no fields sampled, no lazy inverse materialized). It only downcasts each leaf under policy (analytic by default). Pass an explicit compute=<mode> to also compose that kind.

Parameters:

Name Type Description Default
policy simplify policy

The simplify policy, in the grammar compute accepts.

"analytic"
compute [list of] name or type

The compose mode. The default, False, composes nothing (mode=False in compute); None would compose every kind. A real mode passes straight through.

False
inverse
inverse(compute: bool = False, **kwargs) -> Transformation

Return the forward transformation, with the endpoints restored.

The inverse of an inverse is the original forward transformation. An endpoint edit made on the wrapper is carried onto it. With compute, the other keywords are passed on to compute().

square
square(compute: bool = False, **kwargs) -> Transformation

Return the square of this transformation, self @ self.

The square is the sequence [self, self], which composes when it is computed. It is defined for a transformation that maps a space to itself.

Parameters:

Name Type Description Default
compute bool

Whether to compute the result now rather than return it lazily.

False
**kwargs

Passed to compute when compute is true.

{}

Raises:

Type Description
DomainError

If the transformation does not map a space to itself.

InverseScalingExponential magic

InverseScalingExponential(forward: ScalingExponential | None = None, _data: Derived[npvector[Real] | None], _log: Derived[bool], _scale: Deactivated[None])

Bases: Inverse[ScalingExponential], ScalingExponential

The inverse of a ScalingExponential: the tangent negated.

Methods:

from_dict classmethod
from_dict(other: Mapping, *args, **kwargs) -> Self

Create an instance of the class from a dictionary-like object.

Only keys in the dictionary that match keyword-like fields of this class, or the keywords its constructor takes without storing them (its InitVars, such as the matrix= of an Affine), will be used. Other keys are ignored, but see from_other, which refuses them.

Additional positional and/or keyword arguments can be provided, and will take precedence over the values in the dictionary.

A key naming a field that this class fixes (a field that cannot be passed to its constructor) is checked instead of used: a dictionary that sets it to anything other than None or the value of this class is refused with a ValueError.

from_instance classmethod
from_instance(other: Any, *args, **kwargs) -> Self

Create an instance from an instance of a similar class.

See DataModelBase.from_instance. The map of a Scaling is copied through its scale view, not its stored data, which a lazy wrapper derives and a tangent (log=True) stores as its logarithm. A tangent is copied into a tangent through its data.

from_other classmethod
from_other(other: Any, *args, **kwargs) -> Self

Create an instance of the class from any object that can be interpreted as a dictionary, or an instance of a similar class, or an arguments to be passed to the constructor.

A similar class is this class or one of its parents within the data model, or another member of a polymorphic family this class belongs to: calling a polymorphic class such as Axis builds the subclass its arguments select, so a "generic" axis is usually an instance of a sibling (a RightToLeftAxis, a TimeAxis) rather than of a parent. Any other object, including an instance of a parent that is not a data model (such as a plain object), is passed to the constructor.

Unlike from_dict, a dictionary with a key that matches no field of this class is refused with a TypeError naming the keys, so that a misspelt key is not silently dropped.

compute
compute(
    mode: ModeLike = True,
    *,
    simplify: SimplifyLike = "analytic",
    factor: bool = False,
) -> Transformation

Resolve the inverse, if the mode admits it.

Materializing an inverse is the one thing this wrapper exists to put off, so it happens here and nowhere else: never in a simplifier, which may only rewrite for free. The compose mode is the gate -- a mode that does not admit this wrapper leaves it lazy, so an adjacent pair can still cancel in a sequence -- and simplify then still downcasts what it wraps. factor is forwarded to the materialized result.

simplify
simplify(
    policy: SimplifyLike = "analytic",
    *,
    compute: ModeLike | bool | None = False,
) -> Self

Simplify this transformation under a per-kind policy.

Convenience sugar for compute: t.simplify(policy, compute=mode) is t.compute(mode, simplify=policy).

By default simplify() does no computation at all: compute=False maps to mode=False, which composes nothing (no matrices multiplied, no fields sampled, no lazy inverse materialized). It only downcasts each leaf under policy (analytic by default). Pass an explicit compute=<mode> to also compose that kind.

Parameters:

Name Type Description Default
policy simplify policy

The simplify policy, in the grammar compute accepts.

"analytic"
compute [list of] name or type

The compose mode. The default, False, composes nothing (mode=False in compute); None would compose every kind. A real mode passes straight through.

False
inverse
inverse(compute: bool = False, **kwargs) -> Transformation

Return the forward transformation, with the endpoints restored.

The inverse of an inverse is the original forward transformation. An endpoint edit made on the wrapper is carried onto it. With compute, the other keywords are passed on to compute().

scale
scale() -> ArrayProtocol | None

The scaling factors, of shape (N,): exp(data).

InverseStationaryVelocityField magic

InverseStationaryVelocityField(forward: StationaryVelocityField | None = None, _data: Derived[ArrayProtocol | None], _degree: Derived[InterpolationOrder], _bound: Derived[BoundaryCondition | float], _coeff: Derived[bool], _log: Derived[bool], _steps: Derived[int | None], _field: Deactivated[None])

Bases: Inverse[StationaryVelocityField], StationaryVelocityField

The inverse of a StationaryVelocityField: exp(-v).

Its data is the negated velocity, in the encoding of the forward field, whose flags (steps included) it reports. Its field view integrates that velocity -- exactly as the forward integrates its own, rather than by inverting the forward's displacement. The accuracy note of InverseDisplacementField does not apply: no mesh is inverted, the inverse is exact in the tangent, and exp(-v) is integrated as accurately as exp(v) is.

Attributes

squarings property
squarings: int | None

The number of squaring steps the field view integrates with: steps, or the number the default rule picks when it is None. None when data is unset.

Methods:

from_dict classmethod
from_dict(other: Mapping, *args, **kwargs) -> Self

Create an instance of the class from a dictionary-like object.

Only keys in the dictionary that match keyword-like fields of this class, or the keywords its constructor takes without storing them (its InitVars, such as the matrix= of an Affine), will be used. Other keys are ignored, but see from_other, which refuses them.

Additional positional and/or keyword arguments can be provided, and will take precedence over the values in the dictionary.

A key naming a field that this class fixes (a field that cannot be passed to its constructor) is checked instead of used: a dictionary that sets it to anything other than None or the value of this class is refused with a ValueError.

from_instance classmethod
from_instance(other: Any, *args, **kwargs) -> Self

Create an instance from an instance of a similar class.

See DataModelBase.from_instance. A lazy wrapper derives its data and its flags, so they are read through their public names. A field that holds its displacement is copied as its displacement: a velocity (log=True) is integrated, unless the copy is a velocity too.

from_other classmethod
from_other(other: Any, *args, **kwargs) -> Self

Create an instance of the class from any object that can be interpreted as a dictionary, or an instance of a similar class, or an arguments to be passed to the constructor.

A similar class is this class or one of its parents within the data model, or another member of a polymorphic family this class belongs to: calling a polymorphic class such as Axis builds the subclass its arguments select, so a "generic" axis is usually an instance of a sibling (a RightToLeftAxis, a TimeAxis) rather than of a parent. Any other object, including an instance of a parent that is not a data model (such as a plain object), is passed to the constructor.

Unlike from_dict, a dictionary with a key that matches no field of this class is refused with a TypeError naming the keys, so that a misspelt key is not silently dropped.

compute
compute(
    mode: ModeLike = True,
    *,
    simplify: SimplifyLike = "analytic",
    factor: bool = False,
) -> Transformation

Resolve the inverse, if the mode admits it.

Materializing an inverse is the one thing this wrapper exists to put off, so it happens here and nowhere else: never in a simplifier, which may only rewrite for free. The compose mode is the gate -- a mode that does not admit this wrapper leaves it lazy, so an adjacent pair can still cancel in a sequence -- and simplify then still downcasts what it wraps. factor is forwarded to the materialized result.

simplify
simplify(
    policy: SimplifyLike = "analytic",
    *,
    compute: ModeLike | bool | None = False,
) -> Self

Simplify this transformation under a per-kind policy.

Convenience sugar for compute: t.simplify(policy, compute=mode) is t.compute(mode, simplify=policy).

By default simplify() does no computation at all: compute=False maps to mode=False, which composes nothing (no matrices multiplied, no fields sampled, no lazy inverse materialized). It only downcasts each leaf under policy (analytic by default). Pass an explicit compute=<mode> to also compose that kind.

Parameters:

Name Type Description Default
policy simplify policy

The simplify policy, in the grammar compute accepts.

"analytic"
compute [list of] name or type

The compose mode. The default, False, composes nothing (mode=False in compute); None would compose every kind. A real mode passes straight through.

False
inverse
inverse(compute: bool = False, **kwargs) -> Transformation

Return the forward transformation, with the endpoints restored.

The inverse of an inverse is the original forward transformation. An endpoint edit made on the wrapper is carried onto it. With compute, the other keywords are passed on to compute().

InverseTranslation magic

InverseTranslation(forward: Translation | None = None, _data: Derived[npvector[Real] | None], _translation: Deactivated[None])

Bases: Inverse[Translation], Translation

The inverse of a Translation, resolved on demand.

Attributes

translation property
translation: ArrayProtocol | None

The translation vector, of shape (N,).

Methods:

from_dict classmethod
from_dict(other: Mapping, *args, **kwargs) -> Self

Create an instance of the class from a dictionary-like object.

Only keys in the dictionary that match keyword-like fields of this class, or the keywords its constructor takes without storing them (its InitVars, such as the matrix= of an Affine), will be used. Other keys are ignored, but see from_other, which refuses them.

Additional positional and/or keyword arguments can be provided, and will take precedence over the values in the dictionary.

A key naming a field that this class fixes (a field that cannot be passed to its constructor) is checked instead of used: a dictionary that sets it to anything other than None or the value of this class is refused with a ValueError.

from_instance classmethod
from_instance(other: Any, *args, **kwargs) -> Self

Create an instance from an instance of a similar class.

See DataModelBase.from_instance. The map of a Translation is copied through its translation view, not its stored data, which a lazy wrapper derives.

from_other classmethod
from_other(other: Any, *args, **kwargs) -> Self

Create an instance of the class from any object that can be interpreted as a dictionary, or an instance of a similar class, or an arguments to be passed to the constructor.

A similar class is this class or one of its parents within the data model, or another member of a polymorphic family this class belongs to: calling a polymorphic class such as Axis builds the subclass its arguments select, so a "generic" axis is usually an instance of a sibling (a RightToLeftAxis, a TimeAxis) rather than of a parent. Any other object, including an instance of a parent that is not a data model (such as a plain object), is passed to the constructor.

Unlike from_dict, a dictionary with a key that matches no field of this class is refused with a TypeError naming the keys, so that a misspelt key is not silently dropped.

compute
compute(
    mode: ModeLike = True,
    *,
    simplify: SimplifyLike = "analytic",
    factor: bool = False,
) -> Transformation

Resolve the inverse, if the mode admits it.

Materializing an inverse is the one thing this wrapper exists to put off, so it happens here and nowhere else: never in a simplifier, which may only rewrite for free. The compose mode is the gate -- a mode that does not admit this wrapper leaves it lazy, so an adjacent pair can still cancel in a sequence -- and simplify then still downcasts what it wraps. factor is forwarded to the materialized result.

simplify
simplify(
    policy: SimplifyLike = "analytic",
    *,
    compute: ModeLike | bool | None = False,
) -> Self

Simplify this transformation under a per-kind policy.

Convenience sugar for compute: t.simplify(policy, compute=mode) is t.compute(mode, simplify=policy).

By default simplify() does no computation at all: compute=False maps to mode=False, which composes nothing (no matrices multiplied, no fields sampled, no lazy inverse materialized). It only downcasts each leaf under policy (analytic by default). Pass an explicit compute=<mode> to also compose that kind.

Parameters:

Name Type Description Default
policy simplify policy

The simplify policy, in the grammar compute accepts.

"analytic"
compute [list of] name or type

The compose mode. The default, False, composes nothing (mode=False in compute); None would compose every kind. A real mode passes straight through.

False
inverse
inverse(compute: bool = False, **kwargs) -> Transformation

Return the forward transformation, with the endpoints restored.

The inverse of an inverse is the original forward transformation. An endpoint edit made on the wrapper is carried onto it. With compute, the other keywords are passed on to compute().

square
square(compute: bool = False, **kwargs) -> Transformation

Return the square of this transformation, self @ self.

The square is the sequence [self, self], which composes when it is computed. It is defined for a transformation that maps a space to itself.

Parameters:

Name Type Description Default
compute bool

Whether to compute the result now rather than return it lazily.

False
**kwargs

Passed to compute when compute is true.

{}

Raises:

Type Description
DomainError

If the transformation does not map a space to itself.

Bijection magic

Bijection(
    forward: TRANSFORMATION | None = None,
    backward: TRANSFORMATION | None = None,
)

Bases: MetaTransformation, Generic[TRANSFORMATION]

A transformation whose inverse is explicitly defined.

Generic in the forward transformation type: Bijection[TRANSFORMATION] wraps a TRANSFORMATION. Declared bijective; a checker registered in checkers refines its membership from the forward map.

Methods:

from_dict classmethod
from_dict(other: Mapping, *args, **kwargs) -> Self

Create an instance of the class from a dictionary-like object.

Only keys in the dictionary that match keyword-like fields of this class, or the keywords its constructor takes without storing them (its InitVars, such as the matrix= of an Affine), will be used. Other keys are ignored, but see from_other, which refuses them.

Additional positional and/or keyword arguments can be provided, and will take precedence over the values in the dictionary.

A key naming a field that this class fixes (a field that cannot be passed to its constructor) is checked instead of used: a dictionary that sets it to anything other than None or the value of this class is refused with a ValueError.

from_instance classmethod
from_instance(other: Self, *args, **kwargs) -> Self

Create an instance of the class from an instance of a similar class.

Only attributes of the other instance that match keyword-like fields of this class will be used. An attribute that is None is unset, and leaves the default of this class in place.

Additional positional and/or keyword arguments can be provided, and will take precedence over the attributes in the instance.

Unless the other instance is already an instance of this class, an attribute naming a field that this class fixes (a field that cannot be passed to its constructor) is checked instead of used: an instance that sets it to anything other than None or the value of this class is refused with a ValueError. A generic Axis whose orientation is right-to-left, for example, cannot be read as a LeftToRightAxis.

from_other classmethod
from_other(other: Any, *args, **kwargs) -> Self

Create an instance of the class from any object that can be interpreted as a dictionary, or an instance of a similar class, or an arguments to be passed to the constructor.

A similar class is this class or one of its parents within the data model, or another member of a polymorphic family this class belongs to: calling a polymorphic class such as Axis builds the subclass its arguments select, so a "generic" axis is usually an instance of a sibling (a RightToLeftAxis, a TimeAxis) rather than of a parent. Any other object, including an instance of a parent that is not a data model (such as a plain object), is passed to the constructor.

Unlike from_dict, a dictionary with a key that matches no field of this class is refused with a TypeError naming the keys, so that a misspelt key is not silently dropped.

simplify
simplify(
    policy: SimplifyLike = "analytic",
    *,
    compute: ModeLike | bool | None = False,
) -> Self

Simplify this transformation under a per-kind policy.

Convenience sugar for compute: t.simplify(policy, compute=mode) is t.compute(mode, simplify=policy).

By default simplify() does no computation at all: compute=False maps to mode=False, which composes nothing (no matrices multiplied, no fields sampled, no lazy inverse materialized). It only downcasts each leaf under policy (analytic by default). Pass an explicit compute=<mode> to also compose that kind.

Parameters:

Name Type Description Default
policy simplify policy

The simplify policy, in the grammar compute accepts.

"analytic"
compute [list of] name or type

The compose mode. The default, False, composes nothing (mode=False in compute); None would compose every kind. A real mode passes straight through.

False
square
square(compute: bool = False, **kwargs) -> Transformation

Return the square of this transformation, self @ self.

The square is the sequence [self, self], which composes when it is computed. It is defined for a transformation that maps a space to itself.

Parameters:

Name Type Description Default
compute bool

Whether to compute the result now rather than return it lazily.

False
**kwargs

Passed to compute when compute is true.

{}

Raises:

Type Description
DomainError

If the transformation does not map a space to itself.

to
to(
    cls: Type[Self] | None = None,
    *,
    lossy: bool = False,
    error: Type[Exception] | Exception | bool = True,
    **kwargs,
) -> Self

Convert this transformation to a different type.

Conversion can be

  • between type: linear.to(Affine) ; or
  • within type: displacement.to(coeff=True) ; or
  • both: coords.to(DisplacementField, coeff=True) .

Parameters:

Name Type Description Default
cls type

The type to convert to. If None, keep the current type.

None
lossy bool

Whether to allow lossy conversions.

False
error bool or Exception

Whether to raise an error if the conversion fails:

  • If an Exception, raise it.
  • If True, raise the original error.
  • Otherwise, return the value of error.
True
**kwargs dict

Attributes to override in the converted transform. This allows transformations to be modified within their type. For example, a DisplacementField can be converted from a field of values to a field of spline coefficients by setting coeff=True in kwargs: a change of encoding flag re-encodes the stored data, and keeps the map. A view's name (field=, matrix=, ...) sets the map, as values, and it is stored in the encoding of the result; data= is stored as given.

{}

Returns:

Type Description
Transformation

The converted transformation.

Projection magic

Projection(
    dropped: npvector[Integral] = (),
    created: npvector[Integral] = (),
)

Bases: MetaTransformation

A transformation that acts as a projection from a higher dimensional space to a lower-dimensional space by removing one or more axes.

Or its inverse (i.e., an embedding) that adds one or more axes to a lower-dimensional space.

Methods:

from_dict classmethod
from_dict(other: Mapping, *args, **kwargs) -> Self

Create an instance of the class from a dictionary-like object.

Only keys in the dictionary that match keyword-like fields of this class, or the keywords its constructor takes without storing them (its InitVars, such as the matrix= of an Affine), will be used. Other keys are ignored, but see from_other, which refuses them.

Additional positional and/or keyword arguments can be provided, and will take precedence over the values in the dictionary.

A key naming a field that this class fixes (a field that cannot be passed to its constructor) is checked instead of used: a dictionary that sets it to anything other than None or the value of this class is refused with a ValueError.

from_instance classmethod
from_instance(other: Self, *args, **kwargs) -> Self

Create an instance of the class from an instance of a similar class.

Only attributes of the other instance that match keyword-like fields of this class will be used. An attribute that is None is unset, and leaves the default of this class in place.

Additional positional and/or keyword arguments can be provided, and will take precedence over the attributes in the instance.

Unless the other instance is already an instance of this class, an attribute naming a field that this class fixes (a field that cannot be passed to its constructor) is checked instead of used: an instance that sets it to anything other than None or the value of this class is refused with a ValueError. A generic Axis whose orientation is right-to-left, for example, cannot be read as a LeftToRightAxis.

from_other classmethod
from_other(other: Any, *args, **kwargs) -> Self

Create an instance of the class from any object that can be interpreted as a dictionary, or an instance of a similar class, or an arguments to be passed to the constructor.

A similar class is this class or one of its parents within the data model, or another member of a polymorphic family this class belongs to: calling a polymorphic class such as Axis builds the subclass its arguments select, so a "generic" axis is usually an instance of a sibling (a RightToLeftAxis, a TimeAxis) rather than of a parent. Any other object, including an instance of a parent that is not a data model (such as a plain object), is passed to the constructor.

Unlike from_dict, a dictionary with a key that matches no field of this class is refused with a TypeError naming the keys, so that a misspelt key is not silently dropped.

simplify
simplify(
    policy: SimplifyLike = "analytic",
    *,
    compute: ModeLike | bool | None = False,
) -> Self

Simplify this transformation under a per-kind policy.

Convenience sugar for compute: t.simplify(policy, compute=mode) is t.compute(mode, simplify=policy).

By default simplify() does no computation at all: compute=False maps to mode=False, which composes nothing (no matrices multiplied, no fields sampled, no lazy inverse materialized). It only downcasts each leaf under policy (analytic by default). Pass an explicit compute=<mode> to also compose that kind.

Parameters:

Name Type Description Default
policy simplify policy

The simplify policy, in the grammar compute accepts.

"analytic"
compute [list of] name or type

The compose mode. The default, False, composes nothing (mode=False in compute); None would compose every kind. A real mode passes straight through.

False
square
square(compute: bool = False, **kwargs) -> Transformation

Return the square of this transformation, self @ self.

The square is the sequence [self, self], which composes when it is computed. It is defined for a transformation that maps a space to itself.

Parameters:

Name Type Description Default
compute bool

Whether to compute the result now rather than return it lazily.

False
**kwargs

Passed to compute when compute is true.

{}

Raises:

Type Description
DomainError

If the transformation does not map a space to itself.

sqrt
sqrt(compute: bool = False, **kwargs) -> Transformation

Return the principal square root of this transformation.

The square root S of T is the transformation with S @ S == T, the half-transformation. The principal one, whose linear part has its eigenvalues in the open right half-plane, is unique, and it is of the same kind as T: the square root of a rotation is a rotation, of a translation a translation, of a scaling a scaling, of an affine an affine. The square root of a permutation is a Linear transformation.

The square root is lazy: an Sqrt wrapper is returned, and computed when it is applied, computed or converted. A transformation that needs no wrapper (an identity) is returned as is. A Sequence is reduced first (see Sequence.sqrt).

Parameters:

Name Type Description Default
compute bool

Whether to compute the result now rather than return it lazily.

False
**kwargs

Passed to compute when compute is true.

{}

Raises:

Type Description
DomainError

If the transformation does not map a space to itself, or, when the result is computed, if its linear part has an eigenvalue on the closed negative real axis (a reflection, a rotation by a half turn, a singular matrix), so that it has no real principal square root.

NotImplementedError

If brainhops does not compute the square root of this kind of transformation. A displacement field has one only when it is a stationary velocity field (log=True), whose square root halves its velocity.

to
to(
    cls: Type[Self] | None = None,
    *,
    lossy: bool = False,
    error: Type[Exception] | Exception | bool = True,
    **kwargs,
) -> Self

Convert this transformation to a different type.

Conversion can be

  • between type: linear.to(Affine) ; or
  • within type: displacement.to(coeff=True) ; or
  • both: coords.to(DisplacementField, coeff=True) .

Parameters:

Name Type Description Default
cls type

The type to convert to. If None, keep the current type.

None
lossy bool

Whether to allow lossy conversions.

False
error bool or Exception

Whether to raise an error if the conversion fails:

  • If an Exception, raise it.
  • If True, raise the original error.
  • Otherwise, return the value of error.
True
**kwargs dict

Attributes to override in the converted transform. This allows transformations to be modified within their type. For example, a DisplacementField can be converted from a field of values to a field of spline coefficients by setting coeff=True in kwargs: a change of encoding flag re-encodes the stored data, and keeps the map. A view's name (field=, matrix=, ...) sets the map, as values, and it is stored in the encoding of the result; data= is stored as given.

{}

Returns:

Type Description
Transformation

The converted transformation.

SubspaceTransformation magic

SubspaceTransformation(
    transformation: TRANSFORMATION | None = None,
    input_axes: npvector[Integral] | None = None,
    output_axes: npvector[Integral] | None = None,
)

Bases: MetaTransformation, Generic[TRANSFORMATION]

A transformation that is applied to a subset of the input and output axes.

The transformation acts on the axes named by input_axes and output_axes, and leaves every other axis unchanged. The dimensionality of the space is preserved. An axis that is not named passes through as the identity. This embeds a transformation defined over a few axes, such as a spatial transformation over (x, y, z), into a larger space, such as (x, y, z, t), where it acts on the spatial axes and leaves time untouched.

Generic in the wrapped transformation type: SubspaceTransformation[TRANSFORMATION] embeds a TRANSFORMATION. Its membership is decided by a checker registered in checkers that recurses into the wrapped transform.

Methods:

from_dict classmethod
from_dict(other: Mapping, *args, **kwargs) -> Self

Create an instance of the class from a dictionary-like object.

Only keys in the dictionary that match keyword-like fields of this class, or the keywords its constructor takes without storing them (its InitVars, such as the matrix= of an Affine), will be used. Other keys are ignored, but see from_other, which refuses them.

Additional positional and/or keyword arguments can be provided, and will take precedence over the values in the dictionary.

A key naming a field that this class fixes (a field that cannot be passed to its constructor) is checked instead of used: a dictionary that sets it to anything other than None or the value of this class is refused with a ValueError.

from_instance classmethod
from_instance(other: Self, *args, **kwargs) -> Self

Create an instance of the class from an instance of a similar class.

Only attributes of the other instance that match keyword-like fields of this class will be used. An attribute that is None is unset, and leaves the default of this class in place.

Additional positional and/or keyword arguments can be provided, and will take precedence over the attributes in the instance.

Unless the other instance is already an instance of this class, an attribute naming a field that this class fixes (a field that cannot be passed to its constructor) is checked instead of used: an instance that sets it to anything other than None or the value of this class is refused with a ValueError. A generic Axis whose orientation is right-to-left, for example, cannot be read as a LeftToRightAxis.

from_other classmethod
from_other(other: Any, *args, **kwargs) -> Self

Create an instance of the class from any object that can be interpreted as a dictionary, or an instance of a similar class, or an arguments to be passed to the constructor.

A similar class is this class or one of its parents within the data model, or another member of a polymorphic family this class belongs to: calling a polymorphic class such as Axis builds the subclass its arguments select, so a "generic" axis is usually an instance of a sibling (a RightToLeftAxis, a TimeAxis) rather than of a parent. Any other object, including an instance of a parent that is not a data model (such as a plain object), is passed to the constructor.

Unlike from_dict, a dictionary with a key that matches no field of this class is refused with a TypeError naming the keys, so that a misspelt key is not silently dropped.

simplify
simplify(
    policy: SimplifyLike = "analytic",
    *,
    compute: ModeLike | bool | None = False,
) -> Self

Simplify this transformation under a per-kind policy.

Convenience sugar for compute: t.simplify(policy, compute=mode) is t.compute(mode, simplify=policy).

By default simplify() does no computation at all: compute=False maps to mode=False, which composes nothing (no matrices multiplied, no fields sampled, no lazy inverse materialized). It only downcasts each leaf under policy (analytic by default). Pass an explicit compute=<mode> to also compose that kind.

Parameters:

Name Type Description Default
policy simplify policy

The simplify policy, in the grammar compute accepts.

"analytic"
compute [list of] name or type

The compose mode. The default, False, composes nothing (mode=False in compute); None would compose every kind. A real mode passes straight through.

False
square
square(compute: bool = False, **kwargs) -> Transformation

Return the square of this transformation, self @ self.

The square is the sequence [self, self], which composes when it is computed. It is defined for a transformation that maps a space to itself.

Parameters:

Name Type Description Default
compute bool

Whether to compute the result now rather than return it lazily.

False
**kwargs

Passed to compute when compute is true.

{}

Raises:

Type Description
DomainError

If the transformation does not map a space to itself.

to
to(
    cls: Type[Self] | None = None,
    *,
    lossy: bool = False,
    error: Type[Exception] | Exception | bool = True,
    **kwargs,
) -> Self

Convert this transformation to a different type.

Conversion can be

  • between type: linear.to(Affine) ; or
  • within type: displacement.to(coeff=True) ; or
  • both: coords.to(DisplacementField, coeff=True) .

Parameters:

Name Type Description Default
cls type

The type to convert to. If None, keep the current type.

None
lossy bool

Whether to allow lossy conversions.

False
error bool or Exception

Whether to raise an error if the conversion fails:

  • If an Exception, raise it.
  • If True, raise the original error.
  • Otherwise, return the value of error.
True
**kwargs dict

Attributes to override in the converted transform. This allows transformations to be modified within their type. For example, a DisplacementField can be converted from a field of values to a field of spline coefficients by setting coeff=True in kwargs: a change of encoding flag re-encodes the stored data, and keeps the map. A view's name (field=, matrix=, ...) sets the map, as values, and it is stored in the encoding of the result; data= is stored as given.

{}

Returns:

Type Description
Transformation

The converted transformation.

Multiscale magic

Multiscale(scales: list[Any] = ())

Bases: DataModelBase, Generic[SINGLE_SCALE]

A pyramid of resolution scales, ordered from finest to coarsest.

This mixin gives a transformation a list of scales and the operations that select one of them. The scales are ordered from finest to coarsest, so the first scale is the highest resolution one.

The mixin does not say what a scale is. A subclass supplies the scales and, through the _level_resolution hook, the physical grid size of each one. With those, _nearest_level picks the scale whose resolution is closest to a target grid.

Attributes

nscales property
nscales: int

The number of resolution scales.

Methods:

from_dict classmethod
from_dict(other: Mapping, *args, **kwargs) -> Self

Create an instance of the class from a dictionary-like object.

Only keys in the dictionary that match keyword-like fields of this class, or the keywords its constructor takes without storing them (its InitVars, such as the matrix= of an Affine), will be used. Other keys are ignored, but see from_other, which refuses them.

Additional positional and/or keyword arguments can be provided, and will take precedence over the values in the dictionary.

A key naming a field that this class fixes (a field that cannot be passed to its constructor) is checked instead of used: a dictionary that sets it to anything other than None or the value of this class is refused with a ValueError.

from_instance classmethod
from_instance(other: Self, *args, **kwargs) -> Self

Create an instance of the class from an instance of a similar class.

Only attributes of the other instance that match keyword-like fields of this class will be used. An attribute that is None is unset, and leaves the default of this class in place.

Additional positional and/or keyword arguments can be provided, and will take precedence over the attributes in the instance.

Unless the other instance is already an instance of this class, an attribute naming a field that this class fixes (a field that cannot be passed to its constructor) is checked instead of used: an instance that sets it to anything other than None or the value of this class is refused with a ValueError. A generic Axis whose orientation is right-to-left, for example, cannot be read as a LeftToRightAxis.

from_other classmethod
from_other(other: Any, *args, **kwargs) -> Self

Create an instance of the class from any object that can be interpreted as a dictionary, or an instance of a similar class, or an arguments to be passed to the constructor.

A similar class is this class or one of its parents within the data model, or another member of a polymorphic family this class belongs to: calling a polymorphic class such as Axis builds the subclass its arguments select, so a "generic" axis is usually an instance of a sibling (a RightToLeftAxis, a TimeAxis) rather than of a parent. Any other object, including an instance of a parent that is not a data model (such as a plain object), is passed to the constructor.

Unlike from_dict, a dictionary with a key that matches no field of this class is refused with a TypeError naming the keys, so that a misspelt key is not silently dropped.

to_singlescale
to_singlescale(index: int = 0) -> Any

Return the resolution scale at a given index.

Index 0 is the finest scale. The scale is returned as it is stored, so for a field it is the plain transformation of that scale rather than the multiscale field.

MultiscaleField magic

MultiscaleField(scales: list[Sequence] = ())

Bases: Multiscale[Sequence], ImmutableSequence

A field of coordinates or displacements at several resolutions.

Each scale is a Sequence that maps the multiscale's input space to its output space, sampled on that scale's grid. A coordinate scale is a two-element sequence of a world-to-voxel affine and a field of coordinates. A displacement scale is a three-element sequence of a world-to-voxel affine, a field of displacements in voxel units, and the voxel-to-world affine. The container treats a scale as a plain sequence, so the same class carries both kinds.

A MultiscaleField behaves as its finest scale. It composes with other transformations exactly as the finest scale would, and reduces to the finest scale when it is computed. The finest scale is the one used unless a scale is selected with to_singlescale.

The scales replace this class as the unit that is edited. A scale is selected with to_singlescale, and the returned sequence is edited in place. The container itself does not support item assignment, insertion, or deletion.

Attributes

nscales property
nscales: int

The number of resolution scales.

transformations property writable
transformations: tuple[Transformation, ...]

The transformations of the finest scale.

Methods:

from_dict classmethod
from_dict(other: Mapping, *args, **kwargs) -> Self

Create an instance of the class from a dictionary-like object.

Only keys in the dictionary that match keyword-like fields of this class, or the keywords its constructor takes without storing them (its InitVars, such as the matrix= of an Affine), will be used. Other keys are ignored, but see from_other, which refuses them.

Additional positional and/or keyword arguments can be provided, and will take precedence over the values in the dictionary.

A key naming a field that this class fixes (a field that cannot be passed to its constructor) is checked instead of used: a dictionary that sets it to anything other than None or the value of this class is refused with a ValueError.

from_instance classmethod
from_instance(other: Self, *args, **kwargs) -> Self

Create an instance of the class from an instance of a similar class.

Only attributes of the other instance that match keyword-like fields of this class will be used. An attribute that is None is unset, and leaves the default of this class in place.

Additional positional and/or keyword arguments can be provided, and will take precedence over the attributes in the instance.

Unless the other instance is already an instance of this class, an attribute naming a field that this class fixes (a field that cannot be passed to its constructor) is checked instead of used: an instance that sets it to anything other than None or the value of this class is refused with a ValueError. A generic Axis whose orientation is right-to-left, for example, cannot be read as a LeftToRightAxis.

from_other classmethod
from_other(other: Any, *args, **kwargs) -> Self

Create an instance of the class from any object that can be interpreted as a dictionary, or an instance of a similar class, or an arguments to be passed to the constructor.

A similar class is this class or one of its parents within the data model, or another member of a polymorphic family this class belongs to: calling a polymorphic class such as Axis builds the subclass its arguments select, so a "generic" axis is usually an instance of a sibling (a RightToLeftAxis, a TimeAxis) rather than of a parent. Any other object, including an instance of a parent that is not a data model (such as a plain object), is passed to the constructor.

Unlike from_dict, a dictionary with a key that matches no field of this class is refused with a TypeError naming the keys, so that a misspelt key is not silently dropped.

simplify
simplify(
    policy: SimplifyLike = "analytic",
    *,
    compute: ModeLike | bool | None = False,
) -> Self

Simplify this transformation under a per-kind policy.

Convenience sugar for compute: t.simplify(policy, compute=mode) is t.compute(mode, simplify=policy).

By default simplify() does no computation at all: compute=False maps to mode=False, which composes nothing (no matrices multiplied, no fields sampled, no lazy inverse materialized). It only downcasts each leaf under policy (analytic by default). Pass an explicit compute=<mode> to also compose that kind.

Parameters:

Name Type Description Default
policy simplify policy

The simplify policy, in the grammar compute accepts.

"analytic"
compute [list of] name or type

The compose mode. The default, False, composes nothing (mode=False in compute); None would compose every kind. A real mode passes straight through.

False
square
square(compute: bool = False, **kwargs) -> Transformation

Return the square of this transformation, self @ self.

The square is the sequence [self, self], which composes when it is computed. It is defined for a transformation that maps a space to itself.

Parameters:

Name Type Description Default
compute bool

Whether to compute the result now rather than return it lazily.

False
**kwargs

Passed to compute when compute is true.

{}

Raises:

Type Description
DomainError

If the transformation does not map a space to itself.

sqrt
sqrt(compute: bool = False, **kwargs) -> Transformation

Return the principal square root of this chain.

The chain is first simplified, which costs nothing. A chain [P, *X, P^-1], where P^-1 is the lazy inverse of P, or both are affines whose product is exactly the identity, is a change of coordinates around X, and its square root is [P, sqrt(X), P^-1]: a field stored in voxels between a world-to-voxel affine and its lazy inverse keeps that form. Any other chain is composed now, and the square root of the transformation it composes to is returned.

Raises:

Type Description
DomainError

If the chain does not map a space to itself, or if the square root of what it reduces to is not defined.

NotImplementedError

If the chain does not compose to a single transformation.

to
to(
    cls: Type[Transformation] | None = None, **kwargs
) -> Transformation

Convert this chain to a different type or encoding.

See Transformation.to. A chain has no tangent of its own -- the tangent of a composition is not the sum of the tangents -- so log= re-encodes the transformation it reduces to, and anything else is refused before it is computed:

  • a chain that simplifies to one transformation is that one;
  • a change of coordinates [P, *X, P^-1] (see sqrt) keeps its ends, and re-encodes X: the flow of a velocity commutes with the conjugation, so this is exact. A velocity read between a world-to-voxel affine and its inverse (|svf) is turned into its displacement that way;
  • a chain of affines is composed, which is cheap and exact.

Any other chain -- one with a field, between ends that do not undo each other -- raises ConversionError.

to_singlescale
to_singlescale(index: int = 0) -> Any

Return the resolution scale at a given index.

Index 0 is the finest scale. The scale is returned as it is stored, so for a field it is the plain transformation of that scale rather than the multiscale field.

compute
compute(
    mode: ModeLike | None = None,
    *,
    simplify: SimplifyLike = "analytic",
    factor: bool = False,
) -> Transformation

Compute the field as a plain transformation.

The finest scale is composed and returned. The result is an ordinary transformation, with no pyramid, so it computes exactly as the finest scale would on its own.

Sqrt

Sqrt(forward: Transformation | None = None)

Bases: Operation

The principal square root of a transformation, resolved on demand.

The square root S of T is the transformation with S @ S == T -- the half-transformation. Among the many square roots a map may have, the principal one is the one whose linear part has its eigenvalues in the open right half-plane. It exists, and is real, when the linear part of T has no eigenvalue on the closed negative real axis; otherwise the wrapper raises DomainError when it is resolved. A field has a square root here only when it is stored as its velocity (a StationaryVelocityField), whose square root halves the velocity and needs no wrapper.

Build it with Transformation.sqrt. Constructing Sqrt(forward=t) builds the typed wrapper of t's family, and refuses a family that has none.

Methods:

from_dict classmethod
from_dict(other: Mapping, *args, **kwargs) -> Self

Create an instance of the class from a dictionary-like object.

Only keys in the dictionary that match keyword-like fields of this class, or the keywords its constructor takes without storing them (its InitVars, such as the matrix= of an Affine), will be used. Other keys are ignored, but see from_other, which refuses them.

Additional positional and/or keyword arguments can be provided, and will take precedence over the values in the dictionary.

A key naming a field that this class fixes (a field that cannot be passed to its constructor) is checked instead of used: a dictionary that sets it to anything other than None or the value of this class is refused with a ValueError.

from_instance classmethod
from_instance(other: Self, *args, **kwargs) -> Self

Create an instance of the class from an instance of a similar class.

Only attributes of the other instance that match keyword-like fields of this class will be used. An attribute that is None is unset, and leaves the default of this class in place.

Additional positional and/or keyword arguments can be provided, and will take precedence over the attributes in the instance.

Unless the other instance is already an instance of this class, an attribute naming a field that this class fixes (a field that cannot be passed to its constructor) is checked instead of used: an instance that sets it to anything other than None or the value of this class is refused with a ValueError. A generic Axis whose orientation is right-to-left, for example, cannot be read as a LeftToRightAxis.

from_other classmethod
from_other(other: Any, *args, **kwargs) -> Self

Create an instance of the class from any object that can be interpreted as a dictionary, or an instance of a similar class, or an arguments to be passed to the constructor.

A similar class is this class or one of its parents within the data model, or another member of a polymorphic family this class belongs to: calling a polymorphic class such as Axis builds the subclass its arguments select, so a "generic" axis is usually an instance of a sibling (a RightToLeftAxis, a TimeAxis) rather than of a parent. Any other object, including an instance of a parent that is not a data model (such as a plain object), is passed to the constructor.

Unlike from_dict, a dictionary with a key that matches no field of this class is refused with a TypeError naming the keys, so that a misspelt key is not silently dropped.

compute
compute(
    mode: ModeLike = True,
    *,
    simplify: SimplifyLike = "analytic",
    factor: bool = False,
) -> Transformation

Resolve the operator, if the mode admits it.

As for Inverse.compute, the compose mode is the gate: a mode that does not admit the wrapper leaves it unresolved, and simplify then still simplifies what it wraps. factor is forwarded to the materialized result.

simplify
simplify(
    policy: SimplifyLike = "analytic",
    *,
    compute: ModeLike | bool | None = False,
) -> Self

Simplify this transformation under a per-kind policy.

Convenience sugar for compute: t.simplify(policy, compute=mode) is t.compute(mode, simplify=policy).

By default simplify() does no computation at all: compute=False maps to mode=False, which composes nothing (no matrices multiplied, no fields sampled, no lazy inverse materialized). It only downcasts each leaf under policy (analytic by default). Pass an explicit compute=<mode> to also compose that kind.

Parameters:

Name Type Description Default
policy simplify policy

The simplify policy, in the grammar compute accepts.

"analytic"
compute [list of] name or type

The compose mode. The default, False, composes nothing (mode=False in compute); None would compose every kind. A real mode passes straight through.

False
inverse
inverse(compute: bool = False, **kwargs) -> Self

Return the inverse of this transformation.

Some classes of transformations return a lazy inverse by default, which is only evaluated when the compute() method is called. This allows for efficient composition of transformations. Or the inverse can be computed immediately by setting compute=True.

The inverse can also be obtained using the __invert__ operator: T.inverse() is equivalent to ~T.

sqrt
sqrt(compute: bool = False, **kwargs) -> Transformation

Return the principal square root of this transformation.

The square root S of T is the transformation with S @ S == T, the half-transformation. The principal one, whose linear part has its eigenvalues in the open right half-plane, is unique, and it is of the same kind as T: the square root of a rotation is a rotation, of a translation a translation, of a scaling a scaling, of an affine an affine. The square root of a permutation is a Linear transformation.

The square root is lazy: an Sqrt wrapper is returned, and computed when it is applied, computed or converted. A transformation that needs no wrapper (an identity) is returned as is. A Sequence is reduced first (see Sequence.sqrt).

Parameters:

Name Type Description Default
compute bool

Whether to compute the result now rather than return it lazily.

False
**kwargs

Passed to compute when compute is true.

{}

Raises:

Type Description
DomainError

If the transformation does not map a space to itself, or, when the result is computed, if its linear part has an eigenvalue on the closed negative real axis (a reflection, a rotation by a half turn, a singular matrix), so that it has no real principal square root.

NotImplementedError

If brainhops does not compute the square root of this kind of transformation. A displacement field has one only when it is a stationary velocity field (log=True), whose square root halves its velocity.

square
square(compute: bool = False, **kwargs) -> Transformation

Return the forward transformation: sqrt(T) squared is T.

ImmutableSequence magic

ImmutableSequence(
    _transformations: tuple[Transformation, ...]
    | None = None,
)

Bases: Sequence

A Sequence whose contents cannot be edited in place.

Every in-place edit -- item assignment, deletion, insertion -- raises TypeError.

Methods:

from_dict classmethod
from_dict(other: Mapping, *args, **kwargs) -> Self

Create an instance of the class from a dictionary-like object.

Only keys in the dictionary that match keyword-like fields of this class, or the keywords its constructor takes without storing them (its InitVars, such as the matrix= of an Affine), will be used. Other keys are ignored, but see from_other, which refuses them.

Additional positional and/or keyword arguments can be provided, and will take precedence over the values in the dictionary.

A key naming a field that this class fixes (a field that cannot be passed to its constructor) is checked instead of used: a dictionary that sets it to anything other than None or the value of this class is refused with a ValueError.

from_instance classmethod
from_instance(other: Self, *args, **kwargs) -> Self

Create an instance of the class from an instance of a similar class.

Only attributes of the other instance that match keyword-like fields of this class will be used. An attribute that is None is unset, and leaves the default of this class in place.

Additional positional and/or keyword arguments can be provided, and will take precedence over the attributes in the instance.

Unless the other instance is already an instance of this class, an attribute naming a field that this class fixes (a field that cannot be passed to its constructor) is checked instead of used: an instance that sets it to anything other than None or the value of this class is refused with a ValueError. A generic Axis whose orientation is right-to-left, for example, cannot be read as a LeftToRightAxis.

from_other classmethod
from_other(other: Any, *args, **kwargs) -> Self

Create an instance of the class from any object that can be interpreted as a dictionary, or an instance of a similar class, or an arguments to be passed to the constructor.

A similar class is this class or one of its parents within the data model, or another member of a polymorphic family this class belongs to: calling a polymorphic class such as Axis builds the subclass its arguments select, so a "generic" axis is usually an instance of a sibling (a RightToLeftAxis, a TimeAxis) rather than of a parent. Any other object, including an instance of a parent that is not a data model (such as a plain object), is passed to the constructor.

Unlike from_dict, a dictionary with a key that matches no field of this class is refused with a TypeError naming the keys, so that a misspelt key is not silently dropped.

compute
compute(
    mode: ModeLike = True,
    *,
    simplify: SimplifyLike = "analytic",
    factor: bool = False,
) -> Transformation

Compute the resulting transform of the sequence of transformations.

Assuming that mode=True:

  • If all transformations in the sequence are affine-like transformations, compute() returns an affine-like transform.

  • If the first (= rightmost) transform in the sequence is a coordinate field, compute() returns a coordinate field.

  • If the first (= rightmost) transform in the sequence is an affine-like transform, and the sequence contains at least one non-affine-like transform, compute() returns a sequence of two transformations:

  • the composition of all affine-like transformations that appear before the first non-affine-like transform in the sequence, and

  • the composition of all transformations in the sequence, starting from the first non-affine-like transform in the sequence.
Parameters

mode : [list of] name or type, optional Kinds of transformations to compose. * If True (default): compose every kind in the sequence. * If False: compose nothing (simplify-only). * If a (list of) transformation type(s): compose only pairs of transformations of these kinds. simplify : simplify policy, default="analytic" Whether to simplify sub-transformations prior to composition, and how hard to try to simplify them. * "analytic" (the default) looks at the type structure only; * "numeric" looks at the numeric values of the transformation; * False/"none"/None disables simplification. factor : bool, default=False Whether to rewrite the sequence into its axis-group normal form [grid?, F_1..F_m, Pi_perm?]: a leading grid (if any), one axis-preserving subspace factor per group of axes that transform together, and a trailing reindex permutation. Off by default, so the result is byte-for-byte the plain compute() result. Nothing is ever composed across groups; mode still decides whether the restricted pieces inside a group compose. A chain that creates or drops axes is left unfactored. With mode=False nothing is computed, so factor has nothing to act on and is ignored.

simplify
simplify(
    policy: SimplifyLike = "analytic",
    *,
    compute: ModeLike | bool | None = False,
) -> Self

Simplify this transformation under a per-kind policy.

Convenience sugar for compute: t.simplify(policy, compute=mode) is t.compute(mode, simplify=policy).

By default simplify() does no computation at all: compute=False maps to mode=False, which composes nothing (no matrices multiplied, no fields sampled, no lazy inverse materialized). It only downcasts each leaf under policy (analytic by default). Pass an explicit compute=<mode> to also compose that kind.

Parameters:

Name Type Description Default
policy simplify policy

The simplify policy, in the grammar compute accepts.

"analytic"
compute [list of] name or type

The compose mode. The default, False, composes nothing (mode=False in compute); None would compose every kind. A real mode passes straight through.

False
square
square(compute: bool = False, **kwargs) -> Transformation

Return the square of this transformation, self @ self.

The square is the sequence [self, self], which composes when it is computed. It is defined for a transformation that maps a space to itself.

Parameters:

Name Type Description Default
compute bool

Whether to compute the result now rather than return it lazily.

False
**kwargs

Passed to compute when compute is true.

{}

Raises:

Type Description
DomainError

If the transformation does not map a space to itself.

sqrt
sqrt(compute: bool = False, **kwargs) -> Transformation

Return the principal square root of this chain.

The chain is first simplified, which costs nothing. A chain [P, *X, P^-1], where P^-1 is the lazy inverse of P, or both are affines whose product is exactly the identity, is a change of coordinates around X, and its square root is [P, sqrt(X), P^-1]: a field stored in voxels between a world-to-voxel affine and its lazy inverse keeps that form. Any other chain is composed now, and the square root of the transformation it composes to is returned.

Raises:

Type Description
DomainError

If the chain does not map a space to itself, or if the square root of what it reduces to is not defined.

NotImplementedError

If the chain does not compose to a single transformation.

to
to(
    cls: Type[Transformation] | None = None, **kwargs
) -> Transformation

Convert this chain to a different type or encoding.

See Transformation.to. A chain has no tangent of its own -- the tangent of a composition is not the sum of the tangents -- so log= re-encodes the transformation it reduces to, and anything else is refused before it is computed:

  • a chain that simplifies to one transformation is that one;
  • a change of coordinates [P, *X, P^-1] (see sqrt) keeps its ends, and re-encodes X: the flow of a velocity commutes with the conjugation, so this is exact. A velocity read between a world-to-voxel affine and its inverse (|svf) is turned into its displacement that way;
  • a chain of affines is composed, which is cheap and exact.

Any other chain -- one with a field, between ends that do not undo each other -- raises ConversionError.

MutableSequence magic

MutableSequence(
    _transformations: list[Transformation] | None = None,
)

Bases: MutableSequenceMixin, Sequence

A sequence of transformations.

Note

Transformations in a sequence are listed in the order in which they are applied. It reads as the opposite order to function composition (or matrix multiplication), which may be confusing.

  • Sequence([t1, t2, t3])(x) is equivalent to t3(t2(t1(x))).
  • Sequence([t1, t2, t3]) @ x is equivalent to t3 @ t2 @ t1 @ x.

Methods:

from_dict classmethod
from_dict(other: Mapping, *args, **kwargs) -> Self

Create an instance of the class from a dictionary-like object.

Only keys in the dictionary that match keyword-like fields of this class, or the keywords its constructor takes without storing them (its InitVars, such as the matrix= of an Affine), will be used. Other keys are ignored, but see from_other, which refuses them.

Additional positional and/or keyword arguments can be provided, and will take precedence over the values in the dictionary.

A key naming a field that this class fixes (a field that cannot be passed to its constructor) is checked instead of used: a dictionary that sets it to anything other than None or the value of this class is refused with a ValueError.

from_instance classmethod
from_instance(other: Self, *args, **kwargs) -> Self

Create an instance of the class from an instance of a similar class.

Only attributes of the other instance that match keyword-like fields of this class will be used. An attribute that is None is unset, and leaves the default of this class in place.

Additional positional and/or keyword arguments can be provided, and will take precedence over the attributes in the instance.

Unless the other instance is already an instance of this class, an attribute naming a field that this class fixes (a field that cannot be passed to its constructor) is checked instead of used: an instance that sets it to anything other than None or the value of this class is refused with a ValueError. A generic Axis whose orientation is right-to-left, for example, cannot be read as a LeftToRightAxis.

from_other classmethod
from_other(other: Any, *args, **kwargs) -> Self

Create an instance of the class from any object that can be interpreted as a dictionary, or an instance of a similar class, or an arguments to be passed to the constructor.

A similar class is this class or one of its parents within the data model, or another member of a polymorphic family this class belongs to: calling a polymorphic class such as Axis builds the subclass its arguments select, so a "generic" axis is usually an instance of a sibling (a RightToLeftAxis, a TimeAxis) rather than of a parent. Any other object, including an instance of a parent that is not a data model (such as a plain object), is passed to the constructor.

Unlike from_dict, a dictionary with a key that matches no field of this class is refused with a TypeError naming the keys, so that a misspelt key is not silently dropped.

compute
compute(
    mode: ModeLike = True,
    *,
    simplify: SimplifyLike = "analytic",
    factor: bool = False,
) -> Transformation

Compute the resulting transform of the sequence of transformations.

Assuming that mode=True:

  • If all transformations in the sequence are affine-like transformations, compute() returns an affine-like transform.

  • If the first (= rightmost) transform in the sequence is a coordinate field, compute() returns a coordinate field.

  • If the first (= rightmost) transform in the sequence is an affine-like transform, and the sequence contains at least one non-affine-like transform, compute() returns a sequence of two transformations:

  • the composition of all affine-like transformations that appear before the first non-affine-like transform in the sequence, and

  • the composition of all transformations in the sequence, starting from the first non-affine-like transform in the sequence.
Parameters

mode : [list of] name or type, optional Kinds of transformations to compose. * If True (default): compose every kind in the sequence. * If False: compose nothing (simplify-only). * If a (list of) transformation type(s): compose only pairs of transformations of these kinds. simplify : simplify policy, default="analytic" Whether to simplify sub-transformations prior to composition, and how hard to try to simplify them. * "analytic" (the default) looks at the type structure only; * "numeric" looks at the numeric values of the transformation; * False/"none"/None disables simplification. factor : bool, default=False Whether to rewrite the sequence into its axis-group normal form [grid?, F_1..F_m, Pi_perm?]: a leading grid (if any), one axis-preserving subspace factor per group of axes that transform together, and a trailing reindex permutation. Off by default, so the result is byte-for-byte the plain compute() result. Nothing is ever composed across groups; mode still decides whether the restricted pieces inside a group compose. A chain that creates or drops axes is left unfactored. With mode=False nothing is computed, so factor has nothing to act on and is ignored.

simplify
simplify(
    policy: SimplifyLike = "analytic",
    *,
    compute: ModeLike | bool | None = False,
) -> Self

Simplify this transformation under a per-kind policy.

Convenience sugar for compute: t.simplify(policy, compute=mode) is t.compute(mode, simplify=policy).

By default simplify() does no computation at all: compute=False maps to mode=False, which composes nothing (no matrices multiplied, no fields sampled, no lazy inverse materialized). It only downcasts each leaf under policy (analytic by default). Pass an explicit compute=<mode> to also compose that kind.

Parameters:

Name Type Description Default
policy simplify policy

The simplify policy, in the grammar compute accepts.

"analytic"
compute [list of] name or type

The compose mode. The default, False, composes nothing (mode=False in compute); None would compose every kind. A real mode passes straight through.

False
square
square(compute: bool = False, **kwargs) -> Transformation

Return the square of this transformation, self @ self.

The square is the sequence [self, self], which composes when it is computed. It is defined for a transformation that maps a space to itself.

Parameters:

Name Type Description Default
compute bool

Whether to compute the result now rather than return it lazily.

False
**kwargs

Passed to compute when compute is true.

{}

Raises:

Type Description
DomainError

If the transformation does not map a space to itself.

sqrt
sqrt(compute: bool = False, **kwargs) -> Transformation

Return the principal square root of this chain.

The chain is first simplified, which costs nothing. A chain [P, *X, P^-1], where P^-1 is the lazy inverse of P, or both are affines whose product is exactly the identity, is a change of coordinates around X, and its square root is [P, sqrt(X), P^-1]: a field stored in voxels between a world-to-voxel affine and its lazy inverse keeps that form. Any other chain is composed now, and the square root of the transformation it composes to is returned.

Raises:

Type Description
DomainError

If the chain does not map a space to itself, or if the square root of what it reduces to is not defined.

NotImplementedError

If the chain does not compose to a single transformation.

to
to(
    cls: Type[Transformation] | None = None, **kwargs
) -> Transformation

Convert this chain to a different type or encoding.

See Transformation.to. A chain has no tangent of its own -- the tangent of a composition is not the sum of the tangents -- so log= re-encodes the transformation it reduces to, and anything else is refused before it is computed:

  • a chain that simplifies to one transformation is that one;
  • a change of coordinates [P, *X, P^-1] (see sqrt) keeps its ends, and re-encodes X: the flow of a velocity commutes with the conjugation, so this is exact. A velocity read between a world-to-voxel affine and its inverse (|svf) is turned into its displacement that way;
  • a chain of affines is composed, which is cheap and exact.

Any other chain -- one with a field, between ends that do not undo each other -- raises ConversionError.

Sequence magic

Sequence(
    _transformations: Sequence[Transformation]
    | None = None,
)

Bases: SequenceMixin, Transformation

A sequence of transformations.

This is a base class shared by mutable and immutable sequences.

It can also be used as a factory itself, in which case it returns a MutableSequence.

Note

Transformations in a sequence are listed in the order in which they are applied. It reads as the opposite order to function composition (or matrix multiplication), which may be confusing.

  • Sequence([t1, t2, t3])(x) is equivalent to t3(t2(t1(x))).
  • Sequence([t1, t2, t3]) @ x is equivalent to t3 @ t2 @ t1 @ x.

Methods:

from_dict classmethod
from_dict(other: Mapping, *args, **kwargs) -> Self

Create an instance of the class from a dictionary-like object.

Only keys in the dictionary that match keyword-like fields of this class, or the keywords its constructor takes without storing them (its InitVars, such as the matrix= of an Affine), will be used. Other keys are ignored, but see from_other, which refuses them.

Additional positional and/or keyword arguments can be provided, and will take precedence over the values in the dictionary.

A key naming a field that this class fixes (a field that cannot be passed to its constructor) is checked instead of used: a dictionary that sets it to anything other than None or the value of this class is refused with a ValueError.

from_instance classmethod
from_instance(other: Self, *args, **kwargs) -> Self

Create an instance of the class from an instance of a similar class.

Only attributes of the other instance that match keyword-like fields of this class will be used. An attribute that is None is unset, and leaves the default of this class in place.

Additional positional and/or keyword arguments can be provided, and will take precedence over the attributes in the instance.

Unless the other instance is already an instance of this class, an attribute naming a field that this class fixes (a field that cannot be passed to its constructor) is checked instead of used: an instance that sets it to anything other than None or the value of this class is refused with a ValueError. A generic Axis whose orientation is right-to-left, for example, cannot be read as a LeftToRightAxis.

from_other classmethod
from_other(other: Any, *args, **kwargs) -> Self

Create an instance of the class from any object that can be interpreted as a dictionary, or an instance of a similar class, or an arguments to be passed to the constructor.

A similar class is this class or one of its parents within the data model, or another member of a polymorphic family this class belongs to: calling a polymorphic class such as Axis builds the subclass its arguments select, so a "generic" axis is usually an instance of a sibling (a RightToLeftAxis, a TimeAxis) rather than of a parent. Any other object, including an instance of a parent that is not a data model (such as a plain object), is passed to the constructor.

Unlike from_dict, a dictionary with a key that matches no field of this class is refused with a TypeError naming the keys, so that a misspelt key is not silently dropped.

simplify
simplify(
    policy: SimplifyLike = "analytic",
    *,
    compute: ModeLike | bool | None = False,
) -> Self

Simplify this transformation under a per-kind policy.

Convenience sugar for compute: t.simplify(policy, compute=mode) is t.compute(mode, simplify=policy).

By default simplify() does no computation at all: compute=False maps to mode=False, which composes nothing (no matrices multiplied, no fields sampled, no lazy inverse materialized). It only downcasts each leaf under policy (analytic by default). Pass an explicit compute=<mode> to also compose that kind.

Parameters:

Name Type Description Default
policy simplify policy

The simplify policy, in the grammar compute accepts.

"analytic"
compute [list of] name or type

The compose mode. The default, False, composes nothing (mode=False in compute); None would compose every kind. A real mode passes straight through.

False
square
square(compute: bool = False, **kwargs) -> Transformation

Return the square of this transformation, self @ self.

The square is the sequence [self, self], which composes when it is computed. It is defined for a transformation that maps a space to itself.

Parameters:

Name Type Description Default
compute bool

Whether to compute the result now rather than return it lazily.

False
**kwargs

Passed to compute when compute is true.

{}

Raises:

Type Description
DomainError

If the transformation does not map a space to itself.

sqrt
sqrt(compute: bool = False, **kwargs) -> Transformation

Return the principal square root of this chain.

The chain is first simplified, which costs nothing. A chain [P, *X, P^-1], where P^-1 is the lazy inverse of P, or both are affines whose product is exactly the identity, is a change of coordinates around X, and its square root is [P, sqrt(X), P^-1]: a field stored in voxels between a world-to-voxel affine and its lazy inverse keeps that form. Any other chain is composed now, and the square root of the transformation it composes to is returned.

Raises:

Type Description
DomainError

If the chain does not map a space to itself, or if the square root of what it reduces to is not defined.

NotImplementedError

If the chain does not compose to a single transformation.

to
to(
    cls: Type[Transformation] | None = None, **kwargs
) -> Transformation

Convert this chain to a different type or encoding.

See Transformation.to. A chain has no tangent of its own -- the tangent of a composition is not the sum of the tangents -- so log= re-encodes the transformation it reduces to, and anything else is refused before it is computed:

  • a chain that simplifies to one transformation is that one;
  • a change of coordinates [P, *X, P^-1] (see sqrt) keeps its ends, and re-encodes X: the flow of a velocity commutes with the conjugation, so this is exact. A velocity read between a world-to-voxel affine and its inverse (|svf) is turned into its displacement that way;
  • a chain of affines is composed, which is cheap and exact.

Any other chain -- one with a field, between ends that do not undo each other -- raises ConversionError.

compute
compute(
    mode: ModeLike = True,
    *,
    simplify: SimplifyLike = "analytic",
    factor: bool = False,
) -> Transformation

Compute the resulting transform of the sequence of transformations.

Assuming that mode=True:

  • If all transformations in the sequence are affine-like transformations, compute() returns an affine-like transform.

  • If the first (= rightmost) transform in the sequence is a coordinate field, compute() returns a coordinate field.

  • If the first (= rightmost) transform in the sequence is an affine-like transform, and the sequence contains at least one non-affine-like transform, compute() returns a sequence of two transformations:

  • the composition of all affine-like transformations that appear before the first non-affine-like transform in the sequence, and

  • the composition of all transformations in the sequence, starting from the first non-affine-like transform in the sequence.
Parameters

mode : [list of] name or type, optional Kinds of transformations to compose. * If True (default): compose every kind in the sequence. * If False: compose nothing (simplify-only). * If a (list of) transformation type(s): compose only pairs of transformations of these kinds. simplify : simplify policy, default="analytic" Whether to simplify sub-transformations prior to composition, and how hard to try to simplify them. * "analytic" (the default) looks at the type structure only; * "numeric" looks at the numeric values of the transformation; * False/"none"/None disables simplification. factor : bool, default=False Whether to rewrite the sequence into its axis-group normal form [grid?, F_1..F_m, Pi_perm?]: a leading grid (if any), one axis-preserving subspace factor per group of axes that transform together, and a trailing reindex permutation. Off by default, so the result is byte-for-byte the plain compute() result. Nothing is ever composed across groups; mode still decides whether the restricted pieces inside a group compose. A chain that creates or drops axes is left unfactored. With mode=False nothing is computed, so factor has nothing to act on and is ignored.

SimplifyPolicy

Bases: StrEnum

How hard a transformation may be looked at, and therefore how far it may be simplified.

  • none -- declared type only: nothing is inspected, nothing is rewritten.
  • analytic -- structure only: None parameters, array shapes, axis lists and wrapper contents are read; no value is read and no lazy inverse is materialized. Invertibility, injectivity and surjectivity of a matrix transformation are assumed from its shape at this level (a square matrix is presumed invertible, a wide one surjective, a tall one injective).
  • numeric -- values too: zero tests, diagonality, orthogonality, rank; a typed inverse may be materialized when a leaf is downcast. Rank replaces the analytic shape assumption, so a square singular matrix is not invertible here.

SimplifyTable

Bases: dict

A Dict[TransformationFamily, SimplifyPolicy] mapping.

The None key holds the fallback policy, used for a transform that matches no other entry.

Methods:

from_like classmethod
from_like(value: SimplifyLike) -> Self

Normalize any accepted simplify= input into a simplify table.

Input Output
None {None: none}
False {None: none}
True {None: numeric}
"none" {None: none}
"analytic" {None: analytic}
"numeric" {None: numeric}
a policy: SimplifyPolicy {None: policy}
a key: str &verbar; type {None: none, lowered(key): analytic}
a Iterable[key: str] {None: none, lowered(key): analytic, ...}
a Dict[key: str, policy: SimplifyPolicy} {None: <fallback>, lowered(key): policy, ...}
from_families classmethod
from_families(value: SimplifyLike) -> Self

Build a table from one family key, or an iterable of them.

from_mapping classmethod
from_mapping(value: Mapping) -> Self

Build a table from a {family: policy} mapping.

is_noop
is_noop() -> bool

Whether this table leaves every transform untouched.

resolve
resolve(*transformations: Transformation) -> SimplifyPolicy

Resolve the simplify policy for one transform, or the policy shared by several.

Every entry whose family admits the transform applies, and the safest of them wins; when none does, the None fallback applies. Given several transforms, the safest of their policies wins, so a pair is only rewritten as hard as its most protected member allows.

Parameters:

Name Type Description Default
*transformations Transformation

The transforms to resolve.

()

Returns:

Type Description
SimplifyPolicy

The resolved policy.

Functions:

is_identity

is_identity(
    xform: Transformation, /, compute: bool = False
) -> bool

Return whether a transformation is the identity.

A transformation is recognized as the identity when its parameters are unset, or when it is an instance of Identity. When compute is true, the parameters of a transformation such as Translation, Scaling, Permutation, Linear, Affine, or DisplacementField are also inspected, so that a transformation whose parameters happen to encode the identity is recognized as such even though it is not stored as one.

A CartesianField is a regular grid of coordinates, which is the identity map over its grid by construction. When compute is true, a CartesianField is therefore recognized as the identity. When compute is false, a CartesianField that carries a grid is not recognized as the identity, because its shape parameter is set. A CartesianField with no grid has an unset shape parameter and is recognized as the identity by the parameter check under either value of compute. The shape is read, never the derived field, so the meshgrid is not built by a structural check.

Recognizing a grid as the identity does not mean a grid may be dropped on sight. A grid also defines the sampling domain onto which data is resampled. The decision to factor a grid away is made by the sequence simplifier, which only does so for a grid that sits strictly between two other transformations.

is_linear

is_linear(
    xform: Transformation, /, compute: bool = False
) -> bool

Return whether a transformation is linear, without a translation.

A transformation is recognized as linear when it is an instance of kinds.Linear, or when is_identity recognizes it as the identity, which is itself linear.

When compute is true, the matrix of an Affine transformation is also inspected for a zero translation component.

is_permutation

is_permutation(
    xform: Transformation, /, compute: bool = False
) -> bool

Return whether a transformation is a pure permutation of axes.

A transformation is recognized as a permutation when it is an instance of kinds.Permutation, or when is_identity recognizes it as the identity, which is itself a trivial permutation.

When compute is true, the matrix of a Linear or Affine transformation is also inspected for a binary, one-per-row and one-per-column structure.

is_rotation

is_rotation(
    xform: Transformation, /, compute: bool = False
) -> bool

Return whether a transformation is a pure rotation.

A transformation is recognized as a rotation when it is an instance of kinds.SpecialOrthogonal, or when is_identity recognizes it as the identity, which is itself a rotation by zero.

When compute is true, the matrix of a Linear or Affine transformation is also inspected for orthogonality and a positive determinant.

is_scaling

is_scaling(
    xform: Transformation, /, compute: bool = False
) -> bool

Return whether a transformation is a pure scaling.

A transformation is recognized as a scaling when it is an instance of kinds.Diagonal, or when is_identity recognizes it as the identity, which is itself a scaling by one.

When compute is true, the matrix of a Linear or Affine transformation is also inspected for a diagonal structure.

is_translation

is_translation(
    xform: Transformation, /, compute: bool = False
) -> bool

Return whether a transformation is a pure translation.

A transformation is recognized as a translation when it is an instance of kinds.Translation, or when is_identity recognizes it as the identity, which is itself a translation by zero.

When compute is true, the matrix of an Affine transformation is also inspected for a linear part equal to the identity.