Skip to content

ucon.basis

Core basis abstractions: Basis, BasisComponent, Vector, and related exceptions.

Basis abstraction for user-definable dimensional coordinate systems.

This package provides the foundation for representing dimensions in arbitrary bases (SI, CGS, CGS-ESU, natural units, custom domains) without hardcoding to a specific set of components.

Submodules

  • types: Core types (Basis, BasisComponent, exceptions including BasisMismatch, LossyProjection, NoTransformPath).
  • vector: Vector dimensional exponent vectors. Arithmetic is strict same-basis; cross-basis arithmetic lives in ops.
  • transforms: Transform types and standard transform instances.
  • graph: BasisGraph registry and standard-graph factory.
  • ops: Explicit cross-basis arithmetic (multiply_via, divide_via, unify).
  • builtin: Standard bases (SI, CGS, CGS-ESU, CGS-EMU, NATURAL, PLANCK, ATOMIC).

BasisGraph

Graph of basis transforms with path-finding and composition.

Nodes are Basis objects (dimensional coordinate systems). Edges are BasisTransform objects. Path-finding composes transforms transitively.

Examples:

>>> graph = BasisGraph()
>>> graph.add_transform(SI_TO_CGS)
>>> graph.add_transform(CGS_TO_CGS_ESU)
>>> # Transitive composition: SI -> CGS -> CGS-ESU
>>> transform = graph.get_transform(SI, CGS_ESU)

add_transform(transform)

Register a transform. Does NOT auto-register inverse.

Parameters:

Name Type Description Default
transform '_Transform'

The transform to register.

required

add_transform_pair(forward, reverse)

Register bidirectional transforms (e.g., projection + embedding).

Parameters:

Name Type Description Default
forward 'BasisTransform'

Transform A -> B.

required
reverse 'BasisTransform'

Transform B -> A.

required

get_transform(source, target)

Find or compose a transform between bases.

Parameters:

Name Type Description Default
source Basis

The source basis.

required
target Basis

The target basis.

required

Returns:

Type Description
'BasisTransform'

A BasisTransform from source to target.

Raises:

Type Description
NoTransformPath

If no path exists between the bases.

are_connected(a, b)

Check if two bases can interoperate.

Parameters:

Name Type Description Default
a Basis

First basis.

required
b Basis

Second basis.

required

Returns:

Type Description
bool

True if a path exists between the bases.

reachable_from(basis)

Return all bases reachable from the given basis.

Parameters:

Name Type Description Default
basis Basis

The starting basis.

required

Returns:

Type Description
set[Basis]

Set of all bases reachable via transforms.

with_transform(transform)

Return a new graph with an additional transform (copy-on-extend).

Parameters:

Name Type Description Default
transform 'BasisTransform'

The transform to add.

required

Returns:

Type Description
'BasisGraph'

A new BasisGraph with the additional transform.

BasisTransform dataclass

Linear map between dimensional bases.

Represents how each component of the source basis expresses in terms of the target basis components via matrix multiplication.

Parameters:

Name Type Description Default
source Basis

The source basis.

required
target Basis

The target basis.

required
matrix tuple[tuple[Fraction, ...], ...]

Transformation matrix as tuple of tuples. Shape is (len(source), len(target)). Entry [i][j] is the coefficient of target component j when transforming source component i.

required

Raises:

Type Description
ValueError

If matrix dimensions don't match basis dimensions.

Examples:

>>> # Identity transform
>>> identity = BasisTransform.identity(some_basis)
>>> identity.is_identity()
True
>>> # SI current in CGS-ESU: I -> L^(3/2) M^(1/2) T^(-2)
>>> transform = BasisTransform(SI, CGS_ESU, matrix)
>>> esu_dim = transform(si_current_vector)

__str__()

Human-readable string with matrix visualization.

__call__(vector, *, allow_projection=False)

Transform a vector from source basis to target basis.

Parameters:

Name Type Description Default
vector Vector

The vector to transform (must be in source basis).

required
allow_projection bool

If False (default), raise LossyProjection when a non-zero component would be discarded. If True, silently project (drop) unrepresentable components.

False

Returns:

Type Description
Vector

A new Vector in the target basis.

Raises:

Type Description
ValueError

If vector is not in the source basis.

LossyProjection

If allow_projection=False and a non-zero component maps entirely to zeros in the target basis.

inverse()

Return the inverse transform (target -> source).

Uses Gaussian elimination with partial pivoting over Fraction for exact arithmetic.

Returns:

Type Description
'BasisTransform'

A new BasisTransform from target to source.

Raises:

Type Description
ValueError

If the matrix is not square or is singular.

embedding()

Return the canonical embedding (target -> source).

For a projection A -> B, the embedding B -> A maps each B component back to its source A component, with zeros for unmapped A components.

Only valid for clean projections where each target component maps from exactly one source component with coefficient 1.

Returns:

Type Description
'BasisTransform'

A new BasisTransform from target to source.

Raises:

Type Description
ValueError

If the transform is not a clean projection.

__matmul__(other)

Compose transforms: (self @ other)(v) = self(other(v)).

Parameters:

Name Type Description Default
other 'BasisTransform'

Transform to apply first.

required

Returns:

Type Description
'BasisTransform'

A composed transform from other.source to self.target.

Raises:

Type Description
ValueError

If other.target != self.source.

identity(basis) classmethod

Return the identity transform for a basis.

Parameters:

Name Type Description Default
basis Basis

The basis for the identity transform.

required

Returns:

Type Description
'BasisTransform'

An identity transform where source == target == basis.

append_components_embedding(parent, extended) classmethod

Return the zero-pad embedding parent -> extended.

Builds a clean parent -> extended embedding where each parent component maps 1-to-1 to the same-named component in extended, and components present only in extended are zero-padded (i.e., a parent vector lifts into extended with zeros on the added slots).

This is the canonical transform for an "append-only" basis extension (e.g., SI extended with a currency component to form a financial basis). With this transform registered in the active :class:~ucon.basis.graph.BasisGraph, :func:~ucon.basis.ops.unify succeeds when composing parent-basis vectors with extended-basis vectors.

The reverse projection (extended -> parent) is derived via :meth:embedding; it drops the added components and raises :class:~ucon.basis.types.LossyProjection if any of them is non-zero, which is the correct behavior for unification.

Parameters:

Name Type Description Default
parent Basis

The smaller basis (e.g., SI).

required
extended Basis

The larger basis that contains every component of parent (matched by name) plus optionally additional components.

required

Returns:

Type Description
'BasisTransform'

A BasisTransform from parent to extended.

Raises:

Type Description
ValueError

If any parent component is not present (by name) in extended.

Examples:

>>> from ucon.basis.builtin import SI
>>> from ucon.basis import Basis, BasisComponent
>>> fin = Basis("fin", list(SI) + [BasisComponent("currency", "C")])
>>> embedding = BasisTransform.append_components_embedding(SI, fin)
>>> embedding.source.name, embedding.target.name
('SI', 'fin')

is_identity()

Check if this transform is the identity.

Returns:

Type Description
bool

True if source == target and matrix is identity matrix.

ConstantBinding dataclass

Binds a source dimension to a target expression via a physical constant.

Records that source_component in the source basis becomes target_expression in the target basis, with the relationship defined by a physical constant raised to exponent.

Parameters

source_component : BasisComponent The fundamental component being transformed. target_expression : Vector How it expresses in the target basis. constant_symbol : str Symbol of the constant defining this relationship (e.g., "c", "ℏ"). We use a string rather than a Constant object to avoid circular imports between ucon.basis and ucon.constants. exponent : Fraction Power of the constant in the relationship (usually ±1/2 or ±1).

Examples

In natural units: length = ℏc/E, so L → E⁻¹ via ℏc

from fractions import Fraction binding = ConstantBinding( ... source_component=BasisComponent("length", "L"), ... target_expression=Vector(NATURAL, (Fraction(-1),)), ... constant_symbol="ℏc", ... exponent=Fraction(1), ... )

ConstantBoundBasisTransform dataclass

A basis transform with constants that enable inversion of non-square matrices.

Extends BasisTransform with explicit constant bindings that record which constants define each non-trivial mapping. This enables inverse() to work on non-square transforms by providing the information needed to reverse derived mappings.

Parameters

source : Basis Source basis. target : Basis Target basis. matrix : tuple[tuple[Fraction, ...], ...] Dimensional transformation matrix. Shape is (len(source), len(target)). bindings : tuple[ConstantBinding, ...] Constants that define derived relationships.

Examples

SI (8 dimensions) → NATURAL (1 dimension) transform

SI_TO_NATURAL = ConstantBoundBasisTransform( ... source=SI, ... target=NATURAL, ... matrix=(...), # 8×1 matrix ... bindings=(...), # Bindings for L, T, M, Θ → E ... )

This works because bindings record how to reverse!

NATURAL_TO_SI = SI_TO_NATURAL.inverse()

__call__(vector, *, allow_projection=False)

Transform a vector from source basis to target basis.

Parameters:

Name Type Description Default
vector Vector

The vector to transform (must be in source basis).

required
allow_projection bool

If False (default), raise LossyProjection when a non-zero component would be discarded. If True, silently project (drop) unrepresentable components.

False

Returns:

Type Description
Vector

A new Vector in the target basis.

Raises:

Type Description
ValueError

If vector is not in the source basis.

LossyProjection

If allow_projection=False and a non-zero component maps entirely to zeros in the target basis.

inverse()

Compute the inverse transform using constant bindings.

For each binding (src_component → target_expression via constant): - The inverse maps target_expression → src_component - The constant exponent is negated (constant^(-exponent))

Returns

ConstantBoundBasisTransform The inverse transform from target to source.

Raises

ValueError If a source component has no binding and cannot be inverted.

Notes

Components that map to zero (truly dropped) cannot be recovered and will map to zero in the inverse. Only components with bindings are invertible for non-square matrices.

as_basis_transform()

Return as plain BasisTransform (loses binding information).

Useful for interoperability with code expecting BasisTransform.

Basis

An ordered collection of basis components defining a coordinate system.

A Basis defines the dimensional coordinate system for a set of units. Components are indexed by both name and symbol for flexible lookup.

Parameters:

Name Type Description Default
name str

A descriptive name for the basis (e.g., "SI", "CGS", "Mechanics").

required
components Sequence[str | BasisComponent]

Sequence of component names (str) or BasisComponent objects.

required

Raises:

Type Description
ValueError

If component names or symbols collide.

Examples:

>>> mechanics = Basis("Mechanics", ["length", "mass", "time"])
>>> len(mechanics)
3
>>> "length" in mechanics
True
>>> mechanics.index("length")
0
>>> si = Basis("SI", [
...     BasisComponent("length", "L"),
...     BasisComponent("mass", "M"),
...     BasisComponent("time", "T"),
... ])
>>> "L" in si
True
>>> si.index("L")
0

name property

The descriptive name of this basis.

component_names property

Tuple of component names in order.

index(name)

Return the index of a component by name or symbol.

Parameters:

Name Type Description Default
name str

Component name or symbol to look up.

required

Returns:

Type Description
int

The zero-based index of the component.

Raises:

Type Description
KeyError

If name/symbol is not found in this basis.

BasisComponent dataclass

An atomic generator of a dimensional basis.

A BasisComponent represents a single independent dimension in a basis, such as "length", "mass", or "time" in SI, or custom dimensions like "mana" or "gold" in a game domain.

Parameters:

Name Type Description Default
name str

The canonical name of the component (e.g., "length").

required
symbol str | None

Optional short symbol (e.g., "L"). If None, name is used.

None

Examples:

>>> length = BasisComponent("length", "L")
>>> str(length)
'L'
>>> mass = BasisComponent("mass")
>>> str(mass)
'mass'

BasisMismatch

Bases: ValueError

Raised when a same-basis Vector operation receives operands in different bases.

Vector arithmetic is strict same-basis. Cross-basis arithmetic must go through :mod:ucon.basis.ops, which consults a BasisGraph for a clean (non-lossy) projection.

Subclasses :class:ValueError so legacy except ValueError and regex-matched pytest.raises(ValueError, ...) sites continue to catch it.

Parameters

message : str Human-readable description. left, right : Basis, optional The two bases that failed to unify. op : str, optional The operation that triggered the mismatch (e.g., "multiply", "divide", "unify").

LossyProjection

Bases: Exception

Raised when a basis transform would discard dimensional information.

This occurs when a source component has a non-zero exponent but maps entirely to zeros in the target basis (e.g., SI current -> CGS).

NoTransformPath

Bases: Exception

Raised when no path exists between two bases in a BasisGraph.

Vector dataclass

A dimensional exponent vector tied to a specific basis.

Vector represents a point in dimensional space, where each component is the exponent of the corresponding basis component. For example, velocity (length/time) in SI would be Vector(SI, (1, 0, -1, 0, 0, 0, 0, 0)).

Parameters:

Name Type Description Default
basis Basis

The Basis this vector belongs to.

required
components tuple[int | Fraction, ...]

Tuple of Fraction exponents, one per basis component.

required

Raises:

Type Description
ValueError

If components length doesn't match basis length.

zero(basis) classmethod

Create a zero (dimensionless) vector in the given basis.

Parameters:

Name Type Description Default
basis Basis

The basis to create the zero vector against.

required

Returns:

Type Description
'Vector'

A Vector with all components set to 0.

__getitem__(key)

Get a component by name, symbol, or index.

Parameters:

Name Type Description Default
key str | int

Component name, symbol, or integer index.

required

Returns:

Type Description
Fraction

The Fraction exponent for that component.

is_dimensionless()

Return True if all exponents are zero.

__mul__(other)

Multiply dimensions (add exponents). Strict same-basis.

Raises

BasisMismatch If self and other are in different bases. Use :func:ucon.basis.ops.multiply_via for cross-basis multiplication.

__truediv__(other)

Divide dimensions (subtract exponents). Strict same-basis.

Raises

BasisMismatch If self and other are in different bases. Use :func:ucon.basis.ops.divide_via for cross-basis division.

__pow__(exponent)

Raise dimension to a power (multiply all exponents).

__neg__()

Negate all exponents (reciprocal dimension).