Skip to content

brainhops.io.transformations.itk.tfm

ITK "TFM" transformations are saved in a text format and support a variety of (chained) transformations.

2D rotation encoded by Euler angles

# Insight Transform File V1.0
# Number of parameters = 3
# Transform 0:
# Class name = Euler2DTransform
# Parameters = 0 10 20
Transform: Euler2DTransform_double_2_2
Parameters: 0 10 20
FixedParameters: 50 50

Composite transformation

# Insight Transform File V1.0
# Transform 0
Transform: CompositeTransform_double_3_3
# Transform 1
Transform: TranslationTransform_double_3_3
Parameters: 10.5 -5.0 20.0
FixedParameters:

# Transform 2
Transform: Euler3DTransform_double_3_3
Parameters: 0.1 0.0 -0.2 0.0 0.0 0.0
FixedParameters: 128.0 128.0 64.0

ITK applies the blocks of a composite last to first: this file rotates a point, then translates it. The reader lists the blocks in the order they apply, [Euler3D, Translation].

Composite transformations

ITK writes a CompositeTransform as a header block of class CompositeTransform, which has no parameters, followed by the blocks of its transform queue, front to back. CompositeTransform::TransformPoint applies the queue back to front: a file [Composite, T0, T1] maps x to T0(T1(x)). A brainhops Sequence lists its transformations in the order they apply, so the reader lists the blocks of a composite in reverse file order, [T1, T0].

A file with several blocks but no CompositeTransform header is a list of separate transforms, which ITK does not compose. The reader loads one of them: the first, as SimpleITK's ReadTransform does, with a warning that the file holds several, or the one at position= (TfmTransform.from_file(path, position=1)). A composite file holds a single transform, the composite, at position 0. A CompositeTransform that is not the first block is refused, as ITK never writes one there.

Approximate specification

1. The Header Line

The very first non-blank line of the file must be a strict match for the format version header:

# Insight Transform File V1.0

If this header is missing or altered, the ITK parser will immediately reject the file.

2. The Transform Block

Every transform in the file is parsed sequentially as an object. A block contains exactly three required, case-sensitive tags:

  • Transform: {ClassName}_{Precision}_{InputDim}_{OutputDim}
    • Specifies the RTTI (Run-Time Type Information) class name.
    • Precision must be double or float.
    • Dimensions specify the spatial manipulation (e.g., _3_3 for 3D-to-3D).
  • Parameters: {Space-separated floating-point numbers}
    • The variable, optimizable values.
    • If a transform type does not have variable parameters (like an identity block), this line must still exist but can be left empty.
  • FixedParameters: {Space-separated floating-point numbers}
    • Parameter constants that do not change during registration optimization (typically the center of rotation coordinates).
    • If none exist, this tag must still be explicitly typed out and left blank.

3. Comments and Whitespace

Any line starting with a # is treated as a comment and skipped by the parser.

Empty lines between blocks are ignored.

Implicit Geometrical Specifications

Beyond text formatting, the data inside the file must adhere to ITK's structural physics guidelines:

  • Coordinate System: The numerical values inside a .tfm file are strictly calculated using the LPS (Left-Posterior-Superior) coordinate system. If you export a transform from software that defaults to RAS (Right-Anterior-Superior), like 3D Slicer, the values are automatically matrix-converted to LPS before saving to the .tfm file.

  • Array Ordering: Multi-dimensional matrices (such as the rotation elements in an AffineTransform) are written out in row-major order (linearized row by row).

Transformation types

The text-based .tfm standard is intended only for linear, rigid, or affine transformations.

Transform Class Name Variable Parameters (Optimisable) Length FixedParameters Description / Note
IdentityTransform None 0 None Maps input coordinates completely unaltered.
TranslationTransform [t_x, t_y, ...] D None Standard shifts along spatial axes (e.g., 2 or 3 parameters).
ScaleTransform [s_x, s_y, ...] D [c_x, c_y, ...] Center of scaling Anisotropic scaling along spatial axes.
Euler2DTransform [angle, t_x, t_y] 3 [c_x, c_y] Center of rotation Rigid 2D transform (1 rotation parameter in radians, 2 translations).
Euler3DTransform [angle_x, angle_y, angle_z, t_x, t_y, t_z] 6 [c_x, c_y, c_z] Center of rotation Rigid 3D transform (3 Euler rotation angles in radians, 3 translations).
VersorTransform [v_x, v_y, v_z] 3 [c_x, c_y, c_z] Center of rotation Pure 3D rotation defined using a unit quaternion vector (versor).
VersorRigid3DTransform [v_x, v_y, v_z, t_x, t_y, t_z] 6 [c_x, c_y, c_z] Center of rotation Standard 3D rigid transform. Uses versors for cleaner rotation optimization.
Similarity2DTransform [scale, angle, t_x, t_y] 4 [c_x, c_y] Center of rotation/scale Rigid 2D transformation plus uniform scaling factor.
Similarity3DTransform [v_x, v_y, v_z, t_x, t_y, t_z, scale] 7 [c_x, c_y, c_z] Center of rotation/scale Rigid 3D transformation plus uniform scaling factor.
AffineTransform [Matrix elements (row-major), Translation vector] D² + D [c_x, c_y, ...] Center of rotation Fully unbounded linear mapping (Translation, Rotation, Shearing, and Scale). Example (3D): 9 matrix values + 3 translations = 12 parameters.

Classes

TfmTransformParser

Bases: Magic, TextFileParser

Parses an ITK text (.tfm) transform file into a chain of transform blocks.

The blocks of a CompositeTransform are listed in the order they apply to points, which is the reverse of their order in the file (ITK applies the last block of a composite first).

Each block is itself a brainhops transformation, so the parsed blocks are stored straight into the transformations of the sequence that this parser is mixed into.

Attributes

EXTENSIONS class-attribute
EXTENSIONS: tuple[str, ...] = ()

File extensions handled by this parser, e.g. (".nii", ".nii.gz").

Used as a first, cheap dispatch pass. When several parsers match, the longest matching extension wins, so a parser declaring ".nii.gz" takes precedence over one declaring ".gz".

PREFIXES class-attribute
PREFIXES: tuple[str, ...] = ()

Filename prefixes required by this parser, e.g. ("y_", "iy_").

An empty tuple means "no constraint". A parser that constrains the prefix is more specific than one that does not, and wins ties.

Declaring EXTENSIONS and PREFIXES separately states the cross-product implicitly, which is how these conventions actually work: SPM's four names are {y_, iy_} x {.nii, .nii.gz}.

PRIORITY class-attribute
PRIORITY: int = 0

Explicit tie-breaker, consulted only when specificity cannot decide. Higher wins. Leave at 0 unless two parsers genuinely collide.

Methods:

sniff classmethod
sniff(
    file: FileOrContentLike,
    error: bool | Type[Exception] = False,
    **kwargs,
) -> float

Determine if the given file is of the type that this parser can handle.

Parameters:

Name Type Description Default
file FileOrContentLike

The file to sniff.

required
error bool | type[Exception]

If not False, raise an error if the file cannot be sniffed.

False
**kwargs

Parser-specific options.

{}

Returns:

Type Description
float

Confidence that the file is of this type, in [0, 1].

sniff_file classmethod
sniff_file(
    file: FileLike,
    error: bool | Type[Exception] = False,
    **kwargs,
) -> float

Determine if the given file is of the type that this parser can handle.

Parameters:

Name Type Description Default
file FileLike

The file to sniff.

required
error bool | type[Exception]

If not False, raise an error if the file cannot be sniffed.

False
**kwargs

Parser-specific options.

{}

Returns:

Type Description
float

Confidence that the file is of this type, in [0, 1].

sniff_filename classmethod
sniff_filename(
    filename: FilenameLike,
    error: bool | Type[Exception] = False,
    **kwargs,
) -> float

Determine if the given filename is of the type that this parser can handle.

Parameters:

Name Type Description Default
filename FilenameLike

The filename to sniff.

required
error bool | type[Exception]

If not False, raise an error if the filename cannot be sniffed.

False
**kwargs

Parser-specific options.

{}

Returns:

Type Description
float

Confidence that the filename is of this type, in [0, 1].

sniff_fileobj classmethod
sniff_fileobj(
    file: IO,
    error: bool | Type[Exception] = False,
    **kwargs,
) -> float

Determine if the given file-like object is of the type that this parser can handle.

A text stream decodes as it is read, so content that is not text -- a binary file that shares an extension with a text format -- fails there. That is a "no", not a failure to sniff.

Parameters:

Name Type Description Default
file IO

A file object open for reading.

required
error bool | type[Exception]

If not False, raise an error if the file cannot be sniffed.

False
**kwargs

Parser-specific options.

{}

Returns:

Type Description
float

Confidence that the file is of this type, in [0, 1].

sniff_content classmethod
sniff_content(
    content: ContentLike,
    error: bool | Type[Exception] = False,
    **kwargs,
) -> float

Determine if the given content is of the type that this parser can handle.

Parameters:

Name Type Description Default
content ContentLike

The content to sniff.

required
error bool | type[Exception]

If not False, raise an error if the content cannot be sniffed.

False
**kwargs

Parser-specific options.

{}

Returns:

Type Description
float

Confidence that the content is of this type, in [0, 1].

sniff_bytes classmethod
sniff_bytes(
    content: BinaryContentLike,
    error: bool | Type[Exception] = False,
    **kwargs,
) -> float

Determine if the given bytes are of the type that this parser can handle, by decoding them to text and delegating to sniff_text. Bytes that do not decode are not text, so they score NO.

Parameters:

Name Type Description Default
content BinaryContentLike

The content to sniff.

required
error bool | type[Exception]

If not False, raise an error if the content cannot be sniffed.

False
**kwargs

Parser-specific options, plus encoding (default "utf-8") for decoding content.

{}

Returns:

Type Description
float

Confidence that the content is of this type, in [0, 1].

sniff_text classmethod
sniff_text(
    text: str,
    error: bool | Type[Exception] = False,
    **kwargs,
) -> float

Determine if the given text is of the type that this parser can handle.

Parameters:

Name Type Description Default
text str

The text to sniff.

required
error bool | type[Exception]

If not False, raise an error if the content cannot be sniffed.

False
**kwargs

Parser-specific options.

{}

Returns:

Type Description
float

Confidence that the text is of this type, in [0, 1].

sniff_lines classmethod
sniff_lines(
    lines: Iterable[str],
    error: bool | Type[Exception] = False,
    **kwargs,
) -> float

Determine if the given lines are of the type that this parser can handle.

Parameters:

Name Type Description Default
lines Iterable[str]

The lines to sniff.

required
error bool | type[Exception]

If not False, raise an error if the content cannot be sniffed.

False
**kwargs

Parser-specific options.

{}

Returns:

Type Description
float

Confidence that the lines is of this type, in [0, 1].

load classmethod
load(other: FileOrContentLike, **kwargs) -> Self

Build an object from a file (path, file-like object or iterable of lines).

This is the generic front door to the from_* family: it looks at what it was handed and calls the right one.

A str is always a path, whether or not the file exists, so a missing file raises FileNotFoundError whichever way its path was spelled. Text held in memory is read with from_text or from_content.

Parameters:

Name Type Description Default
other FileOrContentLike

Input file, or its content.

required
**kwargs

Parser-specific options.

{}

Returns:

Type Description
obj

The parsed object.

Raises:

Type Description
ParserExistsError

If other is a path to a file that does not exist. It is a FileNotFoundError.

from_spec classmethod
from_spec(spec: SourceSpec, **kwargs) -> Self

Build an object from an unqualified structured source.

from_file classmethod
from_file(file: FileLike, **kwargs) -> Self

Build an object from a file (path or file-like object).

Parameters:

Name Type Description Default
file FileLike

The file to parse.

required
**kwargs

Parser-specific options.

{}

Returns:

Type Description
obj

The parsed object.

from_filename classmethod
from_filename(filename: FilenameLike, **kwargs) -> Self

Build an object from a filename.

Parameters:

Name Type Description Default
filename FilenameLike

The filename to parse.

required
**kwargs

Parser-specific options.

{}

Returns:

Type Description
obj

The parsed object.

from_fileobj classmethod
from_fileobj(file: IO, **kwargs) -> Self

Build an object from a file-like object.

The default implementation reads the whole stream and hands its content to from_content (hence to from_bytes for binary streams). Parsers that only need part of the stream (e.g., a header) should override this method; from_bytes then falls back to it.

Parameters:

Name Type Description Default
file IO

A file object open for reading.

required
**kwargs

Parser-specific options.

{}

Returns:

Type Description
obj

The parsed object.

from_content classmethod
from_content(content: ContentLike, **kwargs) -> Self

Build an object from a file content (bytes, str, or iterable of lines).

Parameters:

Name Type Description Default
content ContentLike

The content to parse.

required
**kwargs

Parser-specific options.

{}

Returns:

Type Description
obj

The parsed object.

from_bytes classmethod
from_bytes(content: BinaryContentLike, **kwargs) -> Self

Build an object from bytes, by decoding them to text and delegating to from_text.

Parameters:

Name Type Description Default
content BinaryContentLike

The content to parse.

required
**kwargs

Parser-specific options, plus encoding (default "utf-8") for decoding content.

{}

Returns:

Type Description
obj

The parsed object.

from_text classmethod
from_text(text: str, **kwargs) -> Self

Build an object from a text representation of a file.

Parameters:

Name Type Description Default
text str

The text to parse.

required
**kwargs

Parser-specific options.

{}

Returns:

Type Description
obj

The parsed object.

from_line classmethod
from_line(line: str, **kwargs) -> Self

Build an object from a single line of text.

Parameters:

Name Type Description Default
line str

The line to parse.

required
**kwargs

Parser-specific options.

{}

Returns:

Type Description
obj

The parsed object.

sniff_line classmethod
sniff_line(
    line: str,
    error: bool | Type[Exception] = False,
    **kwargs,
) -> float

Score how confident the parser is that a line starts a .tfm transform block.

from_lines classmethod
from_lines(
    lines: Iterable[str],
    position: int | None = None,
    **kwargs,
) -> Self

Build the transform chain from an iterable over lines of a .tfm file.

Parameters:

Name Type Description Default
lines iterable of str

Lines of the file.

required
position int

Which top-level transform of the file to read: the composite, if the file starts with a CompositeTransform header, else one of its blocks. By default, the first one, with a warning if the file holds several.

None

TfmTransform

TfmTransform(
    _transformations: Sequence[Transformation]
    | None = None,
)

Bases: TfmTransformParser, ItkTransform

A transformation stored in an ITK text (.tfm) file.

Attributes

PREFIXES class-attribute
PREFIXES: tuple[str, ...] = ()

Filename prefixes required by this parser, e.g. ("y_", "iy_").

An empty tuple means "no constraint". A parser that constrains the prefix is more specific than one that does not, and wins ties.

Declaring EXTENSIONS and PREFIXES separately states the cross-product implicitly, which is how these conventions actually work: SPM's four names are {y_, iy_} x {.nii, .nii.gz}.

PRIORITY class-attribute
PRIORITY: int = 0

Explicit tie-breaker, consulted only when specificity cannot decide. Higher wins. Leave at 0 unless two parsers genuinely collide.

Methods:

sniff classmethod
sniff(
    file: FileOrContentLike,
    error: bool | Type[Exception] = False,
    **kwargs,
) -> type | None

On a dispatcher, identify which registered format would read file. On a concrete format, score how confident it is that file, in any supported form, is its own.

sniff_file classmethod
sniff_file(
    file: FileLike,
    error: bool | Type[Exception] = False,
    **kwargs,
) -> type | None

On a dispatcher, identify which registered format would read the file (path or file-like object). On a concrete format, score how confident it is that the file is its own.

sniff_filename classmethod
sniff_filename(
    filename: FilenameLike,
    error: bool | Type[Exception] = False,
    **kwargs,
) -> float

Determine if the given filename is of the type that this parser can handle.

Parameters:

Name Type Description Default
filename FilenameLike

The filename to sniff.

required
error bool | type[Exception]

If not False, raise an error if the filename cannot be sniffed.

False
**kwargs

Parser-specific options.

{}

Returns:

Type Description
float

Confidence that the filename is of this type, in [0, 1].

sniff_fileobj classmethod
sniff_fileobj(
    file: IO,
    error: bool | Type[Exception] = False,
    **kwargs,
) -> float

Determine if the given file-like object is of the type that this parser can handle.

A text stream decodes as it is read, so content that is not text -- a binary file that shares an extension with a text format -- fails there. That is a "no", not a failure to sniff.

Parameters:

Name Type Description Default
file IO

A file object open for reading.

required
error bool | type[Exception]

If not False, raise an error if the file cannot be sniffed.

False
**kwargs

Parser-specific options.

{}

Returns:

Type Description
float

Confidence that the file is of this type, in [0, 1].

sniff_content classmethod
sniff_content(
    content: ContentLike,
    error: bool | Type[Exception] = False,
    **kwargs,
) -> type | None

On a dispatcher, identify which registered format would read the content (text or bytes). On a concrete format, score how confident it is that the content is its own.

sniff_bytes classmethod
sniff_bytes(
    content: BinaryContentLike,
    error: bool | Type[Exception] = False,
    **kwargs,
) -> float

Determine if the given bytes are of the type that this parser can handle, by decoding them to text and delegating to sniff_text. Bytes that do not decode are not text, so they score NO.

Parameters:

Name Type Description Default
content BinaryContentLike

The content to sniff.

required
error bool | type[Exception]

If not False, raise an error if the content cannot be sniffed.

False
**kwargs

Parser-specific options, plus encoding (default "utf-8") for decoding content.

{}

Returns:

Type Description
float

Confidence that the content is of this type, in [0, 1].

sniff_text classmethod
sniff_text(
    text: str,
    error: bool | Type[Exception] = False,
    **kwargs,
) -> type | None

On a dispatcher, identify which registered format would read the text. On a concrete format, score how confident it is that the text is its own.

sniff_lines classmethod
sniff_lines(
    lines: Iterable[str],
    error: bool | Type[Exception] = False,
    **kwargs,
) -> type | None

On a dispatcher, identify which registered format would read the lines. On a concrete format, score how confident it is that the lines are its own.

sniff_line classmethod
sniff_line(
    line: str,
    error: bool | Type[Exception] = False,
    **kwargs,
) -> float

Score how confident the parser is that a line starts a .tfm transform block.

load classmethod
load(other: FileOrContentLike, **kwargs) -> Self

On a dispatcher, pick the best-matching registered format and build an instance of it from other. On a concrete format, build an instance of this class from other, in any supported form.

from_spec classmethod
from_spec(spec: SourceSpec, **kwargs) -> Self

Load a structured source specification through this dispatcher.

from_file classmethod
from_file(file: FileLike, **kwargs) -> Self

On a dispatcher, pick the best-matching registered format and build an instance of it from the file (path or file-like object). On a concrete format, build an instance of this class from the file.

from_filename classmethod
from_filename(filename: FilenameLike, **kwargs) -> Self

Build an object from a filename.

Parameters:

Name Type Description Default
filename FilenameLike

The filename to parse.

required
**kwargs

Parser-specific options.

{}

Returns:

Type Description
obj

The parsed object.

from_fileobj classmethod
from_fileobj(file: IO, **kwargs) -> Self

On a dispatcher, pick the best-matching registered format and build an instance of it from the open file object. On a concrete format, build an instance of this class from the file object.

from_content classmethod
from_content(content: ContentLike, **kwargs) -> Self

On a dispatcher, pick the best-matching registered format and build an instance of it from the content (text or bytes). On a concrete format, build an instance of this class from the content.

from_bytes classmethod
from_bytes(content: BinaryContentLike, **kwargs) -> Self

Build an object from bytes, by decoding them to text and delegating to from_text.

Parameters:

Name Type Description Default
content BinaryContentLike

The content to parse.

required
**kwargs

Parser-specific options, plus encoding (default "utf-8") for decoding content.

{}

Returns:

Type Description
obj

The parsed object.

from_text classmethod
from_text(text: str, **kwargs) -> Self

On a dispatcher, pick the best-matching registered format and build an instance of it from the text. On a concrete format, build an instance of this class from the text.

from_lines classmethod
from_lines(
    lines: Iterable[str],
    position: int | None = None,
    **kwargs,
) -> Self

Build the transform chain from an iterable over lines of a .tfm file.

Parameters:

Name Type Description Default
lines iterable of str

Lines of the file.

required
position int

Which top-level transform of the file to read: the composite, if the file starts with a CompositeTransform header, else one of its blocks. By default, the first one, with a warning if the file holds several.

None
from_line classmethod
from_line(line: str, **kwargs) -> Self

On a dispatcher, pick the best-matching registered format and build an instance of it from the line. On a concrete format, build an instance of this class from the line.

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.

The data model copies the fields both classes share, by name. A field that a file format declares for its own use -- such as the nibabel image and header of the NIfTI and MGH formats -- is only copied from an object of that same format: from any other object, a field of the same name holds something else (a NIfTI image is no MGH image), so this class's default is kept instead. Saving a NIfTI image to MGH, or the converse, therefore converts the data model only, and the format-specific state is rebuilt by the writer.

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

Create an instance from a file, or from anything the data model reads.

A path (str or os.PathLike), an open file, bytes or a structured source (SourceSpec) is read with load: on a dispatcher such as FileBasedImage, the best-matching registered format reads it, and on a concrete format, that format does. Any other value is handed to the data model's own from_other, which reads a mapping field by field, copies an instance of a similar class, and passes anything else to the constructor.

Parameters:

Name Type Description Default
other Any

A file, its content, a mapping, or an instance of a similar class.

required
*args

Constructor arguments. A file is read with keyword options only.

()
**kwargs

Format-specific options when reading a file, and field values otherwise.

{}

Returns:

Type Description
obj

The object that was built.

Raises:

Type Description
TypeError

If positional arguments come with a file to read.

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.