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
prefactoris positive and finitefactorsreferences 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 owndimensionlives 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
RebasedUnitedges 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.
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:
Unitis a leaf — eitherbase_form is Noneor 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>
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'
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_signatureto check they are all the same kind of thing before a calculation. - Dispatch keys: a hashable, basis-locked fingerprint suitable for
dict/setlookups (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__()
¶
__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.
unitis a plain Unit (no extra meaning beyond dimension + aliases + name).scaleis 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)
¶
is_base()
¶
True if this is a base dimension (single component with exponent 1).
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.