Skip to content

ucon.core

Core types for representing units, quantities, and dimensional constraints.

ucon.core

Core types for the ucon unit system.

This package re-exports all public symbols from its submodules for backward compatibility. from ucon.core import Unit continues to work.

DimensionNotCovered

Bases: Exception

Raised when a BaseUnits mapping doesn't cover a requested dimension.

KindDimensionMismatch

Bases: Exception

Kind's dimension does not match the Number's unit dimension.

Raised at :meth:ucon.Number.__post_init__ when kind is supplied and kind.dimension != unit.dimension. A Number's kind must refine the same dimensional equivalence class its unit lives in.

Attributes

kind : Kind The kind whose dimension did not match. unit : Unit | UnitProduct The unit the Number was constructed with.

KindMismatch

Bases: Exception

Kinded and unkinded Numbers combined under strict mode.

Raised by Number.__add__ / Number.__sub__ / Number.__mul__ / Number.__truediv__ when one operand has kind set and the other does not, and the active context has strict=True.

Attributes

kinded : Kind The kind present on the annotated operand. unkinded_side : str Which operand was unkinded ("left" or "right").

NonScalableError

Bases: UnknownUnitError

Raised when a scale prefix is applied to a unit marked non-scalable.

Subclass of :class:UnknownUnitError so that callers that catch the parent class continue to work. Callers that want the richer diagnostic can catch :class:NonScalableError directly and inspect :attr:base and :attr:prefix.

Attributes

attempted : str The full unit string that failed to parse (e.g. "Pflop"). base : Unit The base unit that was found but is marked non-scalable. prefix : str The prefix shorthand that was attempted (e.g. "P" for peta).

UnitDefinitionMismatch

Bases: Exception

Source unit not in the active conversion graph by identity.

Raised by :meth:ucon.Number.to (and :meth:ucon.NumberArray.to) under strict=True (the v2.0 default) when self.unit is not registered in the resolution graph by object identity. The most common cause is using a :class:Number constructed under one :class:UnitSystem against another. Re-bind via system.adopt(n) if the unit names match across systems, or Bridge(src, dst, ...).apply(n) when names or bases diverge.

Attributes

unit : Unit | UnitProduct The source unit that failed identity-based resolution. graph : ConversionGraph The active conversion graph that did not contain unit by identity.

UnknownUnitError

Bases: Exception

Raised when a unit string cannot be resolved to a known unit.

BaseForm dataclass

Definitional decomposition of a unit into canonical base units of its basis.

A unit's base_form answers: "in terms of the basis's canonical base units, what does 1 of this unit equal?" Mathematically:

1 U  ≡  prefactor × b₁^e₁ × b₂^e₂ × ... × bₙ^eₙ

Examples (SI basis): kilogram: BaseForm(prefactor=1.0, factors=((kilogram, 1.0),)) gram: BaseForm(prefactor=0.001, factors=((kilogram, 1.0),)) newton: BaseForm(prefactor=1.0, factors=((kilogram, 1.0), (meter, 1.0), (second, -2.0))) bar: BaseForm(prefactor=100000.0, factors=((kilogram, 1.0), (meter, -1.0), (second, -2.0))) foot: BaseForm(prefactor=0.3048, factors=((meter, 1.0),))

Invariants
  • prefactor is positive and finite
  • factors references only canonical (SI) base units
  • for SI-basis units, dimensionally consistent with the parent Unit's dimension; purely multiplicative CGS-mechanical units (dyne, erg, poise, stokes, barye, galileo, kayser, langley) carry their exact SI-equivalent factorization even though their own dimension lives in the CGS basis
  • immutable; set at Unit construction; never mutated

base_form = None means no single (prefactor, factors) representation exists, for one of two reasons:

  • chart structure — affine units (celsius, fahrenheit) have an offset no pure scaling can express, and logarithmic units (dB, Np, pH) are levels, not scalings;
  • cross-basis dimensional scoping — electromagnetic CGS units (gauss, maxwell, statvolt, abohm, …) have dimensional exponents that genuinely differ from their SI counterparts', so an SI factorization would be dimensionally ill-typed; conversion routes through RebasedUnit edges instead.

Never infer a unit's chart/scale structure from base_form is None alone — the two causes above are unrelated.

DimensionConstraint

Annotation marker: constrains a Number to a specific Dimension.

Used with typing.Annotated to enable Number[TIME] syntax. The decorator @enforce_dimensions introspects this marker at runtime.

Exponent

Represents a base–exponent pair (e.g., 10³ or 2¹⁰).

Provides comparison and division semantics used internally to represent magnitude prefixes (e.g., kilo, mega, micro).

evaluated property

Return the numeric value of base ** power.

parts()

Return (base, power) tuple, used for Scale lookups.

__truediv__(other)

Divide two Exponents. - If bases match, returns a relative Exponent. - If bases differ, returns a numeric ratio (float).

__pow__(exponent)

Raise this Exponent to a numeric power.

Example

Exponent(10, 3) ** 2

→ Exponent(base=10, power=6)

to_base(new_base)

Convert this Exponent to another base representation.

Example

Exponent(2, 10).to_base(10)

→ Exponent(base=10, power=3.010299956639812)

KindConstraint

Annotation marker: constrains a Number to a specific Kind.

Used with typing.Annotated to enable Number[kind] and Number[Dimension.X, kind] syntax. The decorator @enforce_dimensions introspects this marker at runtime.

Number dataclass

Represents a numeric quantity with an associated :class:Unit and :class:Scale.

Combines magnitude, unit, and scale into a single, composable object that supports dimensional arithmetic and conversion:

>>> from ucon.units import meter, second
>>> length = meter(5)
>>> time = second(2)
>>> speed = length / time
>>> speed
<2.5 m/s>

Optionally includes measurement uncertainty for error propagation:

>>> length = meter(1.234, uncertainty=0.005)
>>> length
<1.234 ± 0.005 m>

value property

Return the numeric magnitude as-expressed (no scale folding).

Scale lives in the unit expression (e.g. kJ, mL) and is NOT folded into the returned value. Use unit.fold_scale() on a UnitProduct when you need the base-unit-equivalent magnitude.

canonical_magnitude property

Quantity expressed in coherent base-unit scale, as a plain float.

This is the magnitude you would get from :meth:to_base and then reading .quantity. It is a pure function of (self.quantity, self.unit) and does NOT consult any conversion graph.

Use :attr:canonical_magnitude at interop boundaries where you need a raw float in SI-coherent units (e.g., for a dimensionless formula constant, a JSON payload, or a plotting library). For unit-safe composition, prefer :meth:to_base, which returns a new Number.

Examples

from ucon.units import kilometer, hour kilometer(5).canonical_magnitude 5000.0 (kilometer(90) / hour(1)).canonical_magnitude 25.0

base_signature property

Hashable, sorted base-unit-name projection of this Number's unit.

Delegates to self.unit.base_signature. See :attr:Unit.base_signature for semantics and intended uses.

The signature is invariant under :meth:to_base — that is, n.base_signature == n.to_base().base_signature for every Number n. This makes it a useful dispatch / grouping key for formula inputs expressed in arbitrary scales.

Examples

from ucon.units import kilometer, hour kilometer(5).base_signature (('meter', 1.0),) (kilometer(90) / hour(1)).base_signature (('meter', 1.0), ('second', -1.0))

in_base_form property

True if this Number is already expressed in coherent base units.

A Number is in base form when :meth:to_base would produce an output equivalent to self (up to structural identity of the unit expression). Concretely, this holds when:

  • every factor's scale is :attr:Scale.one,
  • every factor's underlying :class:Unit is a leaf — either base_form is None or a self-referential coherent base (e.g., kilogram, meter), and
  • any residual scale factor from cancelled factors is 1.0.

Use in_base_form as a fast pre-check to avoid a redundant :meth:to_base call in hot paths, or as an invariant assertion at formula boundaries.

Examples

from ucon.units import kilometer, meter, hour, joule meter(5).in_base_form True kilometer(5).in_base_form False kilometer(5).to_base().in_base_form True joule(1).in_base_form # joule has a non-trivial base_form False

__class_getitem__(key)

Enable Number[Dimension], Number[Kind], and Number[Dimension, Kind] syntax for type annotations.

Returns Annotated[Number, ...] with the appropriate constraint markers for runtime introspection by @enforce_dimensions. Tuple subscripts are order-insensitive: Number[dim, kind] and Number[kind, dim] produce the same annotation.

to_base()

Return a new Number expressed in coherent base-unit scale.

Walks self.unit and decomposes each factor through its :attr:~Unit.base_form (when available) to produce a quantity in the basis's canonical base units (e.g., SI: kg, m, s, A, K, cd, mol).

This is a pure algebraic operation; no :class:~ucon.graph.ConversionGraph is consulted. Units that lack a base_form (affine temperature units, logarithmic units, or units whose definition is graph-only) are preserved as-is at Scale.one.

Returns

Number A new Number whose unit is either a plain base Unit (when the decomposition collapses to a single factor at exponent 1) or a :class:UnitProduct of base units. Uncertainty is scaled by the same multiplier as the quantity.

Examples

from ucon.units import kilometer, hour, joule kilometer(5).to_base() <5000 m> (kilometer(90) / hour(1)).to_base() <25 m/s> joule(1).to_base() <1 kg·m²/s²>

Notes

to_base() is the unit-safe counterpart to :attr:canonical_magnitude. The identity n.to_base().quantity == n.canonical_magnitude holds for every Number n.

same_dimension_as(other)

Return True if self and other share a dimension.

Accepts another :class:Number, :class:Unit, or :class:UnitProduct. Compares on :attr:Dimension equality — the fundamental invariant of unit compatibility — which is basis-aware and scale-agnostic.

This is a lightweight compatibility check for the common case "can I add / compare / feed these into the same formula slot?" without the overhead of constructing a conversion or walking the graph.

Parameters

other : Number, Unit, or UnitProduct The quantity or unit expression to compare dimensions with.

Returns

bool True if the dimensions match, False otherwise.

Raises

TypeError If other is not a Number, Unit, or UnitProduct.

Examples

from ucon.units import kilometer, mile, hour, second, joule kilometer(5).same_dimension_as(mile(3)) True kilometer(5).same_dimension_as(hour(2)) False (kilometer(90) / hour(1)).same_dimension_as( ... kilometer(1) / second(1) ... ) True

simplify()

Return a new Number expressed in base scale (Scale.one).

This normalizes the unit expression by removing all scale prefixes and adjusting the quantity accordingly. No conversion graph is needed since this is purely a scale transformation.

Examples

from ucon import Scale, units km = Scale.kilo * units.meter km(5).simplify() <5000 m> mg = Scale.milli * units.gram mg(500).simplify() <0.5 g>

to(target, graph=None, propagate_factor_uncertainty=False, *, system=None)

Convert this Number to a different unit expression.

Parameters

target : Unit, UnitProduct, or str The target unit to convert to. Strings are resolved via :func:~ucon.resolver.parse_unit, which supports bare names ("foot"), aliases ("ft"), scale prefixes ("km"), and composite expressions ("m/s²"). graph : ConversionGraph, optional The conversion graph to use. If not provided, uses the default graph. propagate_factor_uncertainty : bool, optional When True, include the relative uncertainty of the conversion factor (from measured physical constants) in the result uncertainty via GUM quadrature. Default False preserves backward compatibility — only measurement uncertainty is propagated. system : UnitSystem, optional When provided, routes through system.conversion_graph for graph lookups and system.units for string-target parsing. Takes precedence over graph= when both are given.

Returns

Number A new Number with the converted quantity and target unit.

Examples

from ucon.units import meter, foot length = meter(100) length.to(foot) <328.084 ft> length.to("ft") <328.084 ft> length.to("km") <0.1 km>

__pow__(power)

Raise Number to a power.

Examples

from ucon import units v = units.meter(3) / units.second(1) v ** 2 <9 m²/s²>

NumberArray

A collection of quantities with a shared unit.

Combines a numpy array of magnitudes with a unit, enabling vectorized arithmetic and conversion.

Parameters

quantities : array-like The numeric values (will be converted to numpy array). unit : Unit or UnitProduct, optional The unit for all quantities. Defaults to dimensionless. uncertainty : float or array-like, optional Uncertainty value(s). If scalar, applies uniformly to all elements. If array-like, must match the shape of quantities.

Examples

from ucon import units from ucon.numpy import NumberArray

Create from list:

heights = NumberArray([1.7, 1.8, 1.9], unit=units.meter) len(heights) 3

Vectorized conversion:

heights_ft = heights.to(units.foot) heights_ft[0].quantity # doctest: +ELLIPSIS 5.577...

With uniform uncertainty:

temps = NumberArray([20, 21, 22], unit=units.celsius, uncertainty=0.5)

With per-element uncertainty:

measurements = NumberArray([1.0, 2.0, 3.0], unit=units.meter, ... uncertainty=[0.01, 0.02, 0.015])

quantities property

The array of numeric values.

unit property

The unit shared by all quantities.

uncertainty property

The uncertainty (scalar or per-element array).

shape property

Shape of the quantities array.

ndim property

Number of dimensions.

dtype property

Data type of the quantities array.

dimension property

The physical dimension of the quantities.

__len__()

Return the number of elements.

__getitem__(key)

Index or slice the array.

Returns Number for scalar index, NumberArray for slice.

__iter__()

Iterate as Number instances.

__repr__()

String representation with truncation for large arrays.

__mul__(other)

Multiply by scalar, Number, or NumberArray.

__rmul__(other)

Right multiplication.

__truediv__(other)

Divide by scalar, Number, or NumberArray.

__rtruediv__(other)

Right division (other / self).

__add__(other)

Add NumberArray or Number (same unit required).

__radd__(other)

Right addition.

__sub__(other)

Subtract NumberArray or Number (same unit required).

__rsub__(other)

Right subtraction (other - self).

__neg__()

Negation.

__pos__()

Unary positive (returns copy).

__abs__()

Absolute value.

__eq__(other)

Element-wise equality comparison. Returns boolean array.

__ne__(other)

Element-wise inequality comparison. Returns boolean array.

__lt__(other)

Element-wise less-than comparison. Returns boolean array.

__le__(other)

Element-wise less-than-or-equal comparison. Returns boolean array.

__gt__(other)

Element-wise greater-than comparison. Returns boolean array.

__ge__(other)

Element-wise greater-than-or-equal comparison. Returns boolean array.

to(target, graph=None)

Convert all quantities to a different unit.

Parameters

target : Unit or UnitProduct The target unit to convert to. graph : ConversionGraph, optional The conversion graph to use. Defaults to the global default graph.

Returns

NumberArray A new NumberArray with converted quantities.

Examples

from ucon import units heights = NumberArray([1, 2, 3], unit=units.meter) heights_ft = heights.to(units.foot)

__array__(dtype=None)

Support np.asarray(number_array).

sum()

Sum all quantities.

mean()

Compute the mean.

std(ddof=0)

Compute the standard deviation.

min()

Return the minimum value.

max()

Return the maximum value.

Ratio

Represents a ratio of two Numbers, preserving their unit semantics.

Useful for expressing physical relationships like efficiency, density, or dimensionless comparisons:

>>> ratio = Ratio(length, time)
>>> ratio.evaluate()
<2.5 m/s>

evaluate()

Evaluate the ratio to a Number.

Uses Exponent-derived arithmetic for scale handling: - If the result is dimensionless (units cancel), scales are folded into the magnitude using _canonical_magnitude. - If the result is dimensionful, raw quantities are divided and unit scales are preserved symbolically.

This matches the behavior of Number.truediv for consistency.

RebasedUnit dataclass

A unit whose dimension was transformed by a BasisTransform.

Lives in the destination partition but preserves provenance to the original unit and the transform that created it.

Parameters

original : Unit The original unit before transformation. rebased_dimension : Dimension The dimension in the destination system. basis_transform : ucon.basis.BasisTransform or ucon.basis.transforms.ConstantBoundBasisTransform The transform that rebased this unit (from ucon.basis module).

Examples

rebased = RebasedUnit( ... original=statcoulomb, ... rebased_dimension=Dimension.charge, ... basis_transform=esu_to_si, ... ) rebased.dimension rebased.name 'statcoulomb'

dimension property

Return the rebased dimension (in the destination system).

name property

Return the name of the original unit.

Scale

Bases: Enum

by_value() cached staticmethod

Return a map from evaluated numeric value → Scale name. Cached after first access.

Unit dataclass

Represents a unit of measure associated with a :class:Dimension.

A Unit is an atomic symbol with no scale information. Scale is handled separately by UnitFactor, which pairs a Unit with a Scale.

Parameters

name : str Canonical name of the unit (e.g., "meter"). dimension : Dimension The physical dimension this unit represents. aliases : tuple[str, ...] Optional shorthand symbols (e.g., ("m", "M")). scalable : bool Whether SI scale prefixes (k, M, G, …) may be applied to this unit at parse time. Defaults to True. Set to False for units that do not compose with prefixes (e.g. affine temperature scales like celsius, or domain conventions like radian where prefixed forms are not idiomatic). When False, parsing "Pflop" for a non-scalable "flop" raises :class:NonScalableError rather than a generic :class:UnknownUnitError, giving callers a precise signal that the base is registered but does not accept prefix decomposition.

Like :attr:`base_form`, ``scalable`` is metadata about parsing
behavior, not an identity attribute — two Units that differ only in
``scalable`` compare equal and hash identically. This keeps the
registry consistent if the flag is flipped on an existing unit.

shorthand property

Symbol used in expressions (e.g., 'm', 's'). For dimensionless units, returns ''.

Note: Scale prefixes are handled by UnitFactor.shorthand, not here.

basis property

The dimensional basis this unit belongs to.

base_signature property

Hashable, sorted projection of this unit's base_form to base-unit names.

Returns a tuple of (base_unit_name, exponent) pairs, sorted by name. The prefactor from :attr:base_form is intentionally dropped — base_signature identifies the shape of the decomposition (which base units participate and with what exponents), not its scale.

Units without a base_form (e.g., affine temperature, logarithmic, or graph-only units) report themselves as a self-leaf, so base_signature is always defined and the identity n.to_base().unit.base_signature == n.unit.base_signature holds for every Number n.

Intended uses
  • Formula pre-validation: group inputs by base_signature to check they are all the same kind of thing before a calculation.
  • Dispatch keys: a hashable, basis-locked fingerprint suitable for dict / set lookups (e.g., memoizing formulas by input kind).
  • Round-trip equivalence checks in serialization / drift detection.

base_signature is basis-locked (compares CGS and SI forms on their own base-unit vocabularies) and does not disambiguate kinds of quantity that share dimensions (e.g., energy vs torque).

Examples

from ucon import units units.meter.base_signature (('meter', 1.0),) units.joule.base_signature (('kilogram', 1.0), ('meter', 2.0), ('second', -2.0))

is_compatible(other, basis_graph=None)

Check if this unit is compatible with another for conversion.

Two units are compatible if: 1. They have the same dimension, OR 2. Their bases are connected via the BasisGraph (cross-basis conversion)

Parameters

other : Unit The other unit to check compatibility with. basis_graph : BasisGraph, optional The basis graph to use for cross-basis compatibility checks. If None, only same-dimension compatibility is checked.

Returns

bool True if the units can be converted between each other.

Examples

from ucon import units, BasisGraph units.meter.is_compatible(units.foot) True units.meter.is_compatible(units.second) False

__mul__(other)

Unit * Unit -> UnitProduct Unit * UnitProduct -> UnitProduct

__truediv__(other)

Unit / Unit or Unit / UnitProduct => UnitProduct

__pow__(power)

Unit ** n => UnitProduct with that exponent.

__repr__()

, , , , etc.

__call__(quantity, uncertainty=None)

Create a Number or NumberArray with this unit.

Parameters

quantity : int, float, list, tuple, or numpy.ndarray The numeric value(s). If array-like, returns NumberArray. uncertainty : float, array-like, or None The measurement uncertainty.

Returns

Number or NumberArray Number for scalar inputs, NumberArray for array inputs.

Example

meter(5) <5 m> meter(1.234, uncertainty=0.005) <1.234 ± 0.005 m> meter([1, 2, 3]) # requires numpy

UnitFactor dataclass

A structural pair (unit, scale) used as the key inside UnitProduct.

  • unit is a plain Unit (no extra meaning beyond dimension + aliases + name).
  • scale is the expression-level Scale attached by the user (e.g. milli in mL).

Two UnitFactors are equal iff both unit and scale are equal, so components with the same base unit and same scale truly merge.

NOTE: We also implement equality / hashing in a way that allows lookups by the underlying Unit to keep working:

m in product.factors
product.factors[m]

still work even though the actual keys are UnitFactor instances.

shorthand property

Render something like 'mg' for UnitFactor(gram, milli), or 'L' for UnitFactor(liter, one).

UnitProduct

Represents a product or quotient of Units.

Key properties: - factors is a dict[UnitFactor, float] mapping (unit, scale) pairs to exponents. - Nested UnitProduct instances are flattened. - Identical UnitFactors (same underlying unit and same scale) merge exponents. - Units with net exponent ~0 are dropped. - Dimensionless units (NONE) are dropped. - Scaled variants of the same base unit (e.g. L and mL) are grouped by (name, dimension, aliases) and their exponents combined; if the net exponent is ~0, the whole group is cancelled.

shorthand property

Human-readable composite unit string, e.g. 'kg·m/s²'.

base_signature property

Hashable, sorted projection of this product's base-unit decomposition.

Returns a tuple of (base_unit_name, exponent) pairs, sorted by name. Composes each factor's Unit.base_signature contribution with the product's exponents, collapsing duplicates and dropping zero-exponent terms. The prefactor accumulated during base-form expansion is intentionally dropped.

Leverages the same walk as :meth:to_base_form but discards the cumulative scalar, returning only the basis-identity fingerprint.

Examples

from ucon.units import meter, second (meter / second).base_signature (('meter', 1.0), ('second', -1.0)) (meter * meter / (second * second)).base_signature (('meter', 2.0), ('second', -2.0))

__init__(factors, canonical_scale=1.0)

Build a canonical UnitProduct with UnitFactor keys, preserving user-provided scales.

Parameters

factors Mapping of Unit / UnitFactor / nested UnitProduct keys to exponents. Canonicalized in place: dimensionless factors are absorbed into canonical_scale, zero-exponent factors are dropped, same-scale variants collapse per the Step 4 rules below. Cross-scale variants (e.g. mg and kg) are distinct UnitFactors and both survive. canonical_scale Seed value composed into the final canonical_scale. Defaults to 1.0 so existing single-argument call sites are unaffected. Passing the canonical_scale of an already-built product (UnitProduct(u.factors, u.canonical_scale)) yields a structurally equal product (idempotence).

Canonical form (per-UnitFactor grain)

On return, factors contains at most one entry per distinct UnitFactor — i.e. per (unit_name, dimension, aliases, scale) tuple. No dimensionless factor survives (absorbed into canonical_scale), no zero-exponent factor survives. The canonical_scale field is 1.0 whenever factors is non-empty; a non-1.0 value is permitted only on fully-cancelled dimensionless products.

Cross-scale variants of the same base unit (e.g. mg and kg) are distinct UnitFactors and both survive. This preserves downstream composition (mg/kg * kg == mg) and display fidelity (shorthand renders "mg/kg"). The numeric ratio is recoverable via fold_scale().

Key principles: - Never canonicalize scale (no implicit preference for Scale.one). - Same-scale duplicates collapse; cross-scale variants survive. - Scale is part of the identity of a UnitFactor, not metadata.

fold_scale()

Compute the overall numeric scale factor of this UnitProduct by folding together the scales of each UnitFactor raised to its exponent, plus any residual scale factor from cancelled units.

Returns

float The combined numeric scale factor.

to_base_form()

Expand all factors to SI base units algebraically.

Returns

(base_factors, prefactor) base_factors: dict mapping base Unit → net exponent prefactor: cumulative scalar (product of all scale, decomposition prefactors)

from_unit(unit) classmethod

Wrap a plain Unit as a UnitProduct with Scale.one (cached).

as_unit()

Extract the underlying Unit if this is a trivial single-factor product.

Returns the Unit when this UnitProduct wraps exactly one factor with exponent 1 and Scale.one, otherwise None.

factors_by_dimension()

Group factors by dimension.

Returns a dict mapping each Dimension to (UnitFactor, exponent). Raises ValueError if multiple factors share the same Dimension.

__pow__(power)

UnitProduct ** n => new UnitProduct with scaled exponents.

__call__(quantity, uncertainty=None)

Create a Number or NumberArray with this unit product.

Parameters

quantity : int, float, list, tuple, or numpy.ndarray The numeric value(s). If array-like, returns NumberArray. uncertainty : float, array-like, or None The measurement uncertainty.

Returns

Number or NumberArray Number for scalar inputs, NumberArray for array inputs.

Example

(meter / second)(10) <10 m/s> (meter / second)(10, uncertainty=0.5) <10 ± 0.5 m/s> (meter / second)([10, 20, 30]) # requires numpy

Dimension dataclass

A physical dimension represented by an exponent vector over a basis.

Parameters

vector : Vector The dimensional exponent vector. name : str | None Optional human-readable name (e.g., "length", "velocity"). symbol : str | None Optional short symbol (e.g., "L", "T"). tag : str | None Tag for pseudo-dimensions. Pseudo-dimensions share the zero vector but are semantically isolated (e.g., "angle", "ratio", "count").

Examples

from ucon.dimension import LENGTH, TIME velocity = LENGTH / TIME velocity == VELOCITY True

basis property

The basis this dimension is expressed in.

value property

Backward compatibility: the dimensional vector.

This is equivalent to .vector but matches the old Enum API.

is_pseudo property

True if this is a pseudo-dimension (tagged, dimensionless vector).

is_dimensionless property

True if the underlying vector is dimensionless.

from_components(basis=None, *, name=None, symbol=None, **components) classmethod

Create a dimension from named component exponents.

Parameters

basis : Basis The basis to use. Defaults to SI. name : str | None Optional name for the dimension. symbol : str | None Optional symbol for the dimension. **components Named exponents (e.g., L=1, T=-1 for velocity).

Returns

Dimension A new dimension with the specified components.

Examples

velocity = Dimension.from_components(L=1, T=-1, name="velocity") velocity == LENGTH / TIME True

pseudo(tag, *, name=None, symbol=None, basis=None) classmethod

Create a pseudo-dimension with a semantic tag.

Pseudo-dimensions share the zero vector (dimensionless) but are semantically isolated from each other and from NONE.

Parameters

tag : str Semantic tag for isolation (e.g., "angle", "ratio", "count"). name : str | None Optional name. Defaults to tag. symbol : str | None Optional symbol. basis : Basis The basis to use. Defaults to SI.

Returns

Dimension A pseudo-dimension with the specified tag.

Examples

ANGLE = Dimension.pseudo("angle", name="angle") ANGLE.is_pseudo True ANGLE == NONE False

in_basis(transform)

Transform this dimension to a different basis.

Parameters

transform : BasisTransform The transform to apply.

Returns

Dimension A new dimension in the target basis.

Raises

ValueError If this dimension's basis doesn't match the transform source.

is_base()

True if this is a base dimension (single component with exponent 1).

base_expansion()

Express this dimension as a product of base dimensions.

Returns

dict[Dimension, Fraction] Mapping from base dimensions to their exponents.

Examples

VELOCITY.base_expansion()

__mul__(other)

Multiply dimensions (add exponent vectors).

NONE acts as identity: NONE * X = X and X * NONE = X. Pseudo-dimensions behave like NONE in algebraic combinations: - MASS * COUNT = MASS (count adds zero to the vector) - ANGLE * LENGTH = LENGTH But pseudo-dimensions preserve themselves when alone: - ANGLE * NONE = ANGLE

__truediv__(other)

Divide dimensions (subtract exponent vectors).

NONE acts as identity: X / NONE = X. Pseudo-dimensions behave like NONE in algebraic combinations: - MASS / COUNT = MASS (count subtracts zero from the vector) - LENGTH / ANGLE = LENGTH But self-division returns NONE: - ANGLE / ANGLE = NONE (not ANGLE, since exponent becomes 0)

__pow__(power)

Raise dimension to a power (multiply exponent vector by scalar).

Pseudo-dimensions behave like dimensionless for exponentiation: - ANGLE ** 2 = ANGLE (angle^2 is still angle semantically) - COUNT ** -1 = COUNT (per-count is still count semantically)

__eq__(other)

Compare dimensions for equality.

Pseudo-dimensions compare by tag, not just vector. Regular dimensions compare by vector.

__hash__()

Hash based on vector and tag for pseudo-dimensions.

__bool__()

False for NONE (dimensionless with no tag), True otherwise.