The Kind-of-Quantity Problem¶
Core conceptual foundation for understanding dimensional ambiguity and how ucon addresses it.
The Problem¶
When working with physical quantities, a fundamental limitation of dimensional analysis becomes apparent: units and dimensions do not uniquely identify the kind of quantity being measured.
Examples of Ambiguity¶
| Unit | Possible Quantities |
|---|---|
kg·m²·s⁻² |
Energy, Torque, Work, Heat |
s⁻¹ |
Frequency, Angular velocity, Radioactive activity |
1 (dimensionless) |
Angle, Refractive index, Efficiency, Count |
This is known as the Kind-of-Quantity (KOQ) problem in metrology literature.
Why It Matters¶
- Silent errors: Adding energy to torque produces nonsense but passes dimensional checks
- Ambiguous conversions:
s⁻¹ → Hzis valid for frequency but not for activity - Lost semantics: Dimensionless quantities lose all physical meaning
ucon's Two Solutions¶
ucon addresses KOQ through two complementary mechanisms:
- Pseudo-dimensions — Semantic tags for quantities dimensionless within a basis
- Basis abstraction — Coordinate transforms across dimensional systems
Both solutions build on the relationship between BasisVector and Dimension.
BasisVector and Dimension¶
Before diving into solutions, it's important to understand how ucon represents dimensions internally.
BasisVector: The Coordinate Representation¶
A BasisVector is the raw numerical representation of a dimension—a tuple of
exponents over a basis. Think of it as coordinates in dimensional space:
from ucon import BasisVector, SI
from fractions import Fraction
# Velocity = L/T = L¹·T⁻¹ in SI
# SI order: (T, L, M, I, Θ, J, N, B)
velocity_vector = BasisVector(SI, (
Fraction(-1), # T⁻¹
Fraction(1), # L¹
Fraction(0), # M⁰
Fraction(0), # I⁰
Fraction(0), # Θ⁰
Fraction(0), # J⁰
Fraction(0), # N⁰
Fraction(0), # B⁰
))
velocity_vector.is_dimensionless() # False
BasisVector supports algebraic operations (multiplication, division, exponentiation)
that add, subtract, or scale exponents:
# length_vec * length_vec = area_vec (exponents add)
# length_vec / time_vec = velocity_vec (exponents subtract)
Dimension: The Named, Semantic Wrapper¶
A Dimension wraps a BasisVector with additional metadata:
- name: Human-readable identifier (e.g., "velocity", "energy")
- symbol: Short notation (e.g., "L", "T")
- tag: For pseudo-dimensions (e.g., "angle", "count")
from ucon import Dimension
# Access predefined dimensions
Dimension.velocity.name # "velocity"
Dimension.velocity.vector # The underlying BasisVector
# Dimensions resolve from vectors automatically
from ucon import resolve_dimension
resolved = resolve_dimension(velocity_vector)
resolved == Dimension.velocity # True
The Key Relationship¶
flowchart LR
subgraph BasisVector["BasisVector"]
bv_basis["basis"]
bv_components["components"]
bv_algebra["algebra"]
end
subgraph Dimension["Dimension"]
d_vector["vector"]
d_name["name"]
d_symbol["symbol"]
d_tag["tag (pseudo)"]
end
Dimension -- "wraps" --> BasisVector
BasisVector --> coords["(−1, 1, 0, 0, 0, 0, 0, 0)<br/><i>raw coordinates in dimensional space</i>"]
Dimension --> semantic["Dimension(velocity)<br/><i>semantic identity for human reasoning</i>"]
Why does this matter for KOQ?
BasisVectorhandles the algebra—it knows nothing about "torque" vs "energy"Dimensionprovides the semantic layer—it can distinguish quantities via names or tags- The KOQ problem arises when the same
BasisVectormaps to multiple physical meanings - ucon's solutions work by either:
- Adding a tag to the
Dimension(pseudo-dimensions) - Choosing a different basis so the
BasisVectordiffers (basis abstraction)
Solution 1: Pseudo-Dimensions¶
For quantities that are mathematically dimensionless but physically distinct, ucon provides pseudo-dimensions:
from ucon import Dimension, units
# These are all dimensionless (zero vector) but semantically isolated
Dimension.angle # radians, degrees
Dimension.solid_angle # steradians
Dimension.ratio # percent, ppm, ppb
Dimension.count # discrete items
# Semantic isolation prevents nonsensical operations
angle = units.radian(3.14)
count = units.each(5)
# This raises TypeError — incompatible pseudo-dimensions
result = angle + count # Error!
# But algebra within the same pseudo-dimension works
total_angle = units.radian(1.57) + units.radian(1.57) # OK
How Pseudo-Dimensions Work¶
| Aspect | Behavior |
|---|---|
| Algebraic | Zero vector — behaves as dimensionless in multiplication |
| Semantic | Tagged — prevents mixing incompatible types |
| Cancellation | angle / angle = dimensionless (not angle) |
When to Use¶
- Angles (radian, degree, steradian)
- Counts of discrete items
- Ratios and proportions (percent, ppm)
- Any quantity dimensionless in all reasonable unit systems
Solution 2: Basis Abstraction¶
The key insight is that dimensional ambiguity is basis-dependent. Two quantities that share the same dimension in one basis may be distinguished in another.
Example: Torque vs Energy¶
In standard SI, torque and energy are dimensionally identical:
| Quantity | SI Dimension | Problem |
|---|---|---|
| Energy | M·L²·T⁻² | Same as torque! |
| Torque | M·L²·T⁻² | Same as energy! |
But physically, torque = force × lever arm × angle. If we choose a basis where angle is NOT dimensionless, the ambiguity resolves:
from ucon import Basis, BasisComponent, BasisVector
from fractions import Fraction
# Define a basis where angle (θ) is a base dimension
MECHANICAL_WITH_ANGLE = Basis(
"mechanical_angle",
[
BasisComponent("time", "T"),
BasisComponent("length", "L"),
BasisComponent("mass", "M"),
BasisComponent("angle", "θ"), # Angle as base dimension!
],
)
# In this basis:
# Energy = M·L²·T⁻²·θ⁰ (no angle dependence)
# Torque = M·L²·T⁻²·θ¹ (depends on angle!)
energy_vec = BasisVector(MECHANICAL_WITH_ANGLE, (
Fraction(-2), Fraction(2), Fraction(1), Fraction(0) # T⁻² L² M¹ θ⁰
))
torque_vec = BasisVector(MECHANICAL_WITH_ANGLE, (
Fraction(-2), Fraction(2), Fraction(1), Fraction(1) # T⁻² L² M¹ θ¹
))
energy_vec == torque_vec # False! Now distinguishable
Example: Gray (Gy) vs Sievert (Sv)¶
In radiation dosimetry, absorbed dose (Gy) and dose equivalent (Sv) have the same SI dimension (m²·s⁻²) but measure different things:
- Gray: Physical energy absorbed per unit mass
- Sievert: Biological effect (weighted by radiation type)
A domain-specific basis can distinguish them:
from ucon import Basis, BasisComponent, BasisVector
from fractions import Fraction
DOSIMETRY = Basis(
"dosimetry",
[
BasisComponent("time", "T"),
BasisComponent("length", "L"),
BasisComponent("mass", "M"),
BasisComponent("biological_weight", "Q"), # Quality factor dimension
],
)
# Absorbed dose (Gy): L²·T⁻²·Q⁰
# Dose equivalent (Sv): L²·T⁻²·Q¹
absorbed_dose = BasisVector(DOSIMETRY, (
Fraction(-2), Fraction(2), Fraction(0), Fraction(0)
))
dose_equivalent = BasisVector(DOSIMETRY, (
Fraction(-2), Fraction(2), Fraction(0), Fraction(1) # Q¹ factor!
))
# Now they're dimensionally distinct
absorbed_dose == dose_equivalent # False
Natural Units (Advanced)¶
For particle physics, where c = ℏ = k_B = 1, dimensions collapse further:
| Quantity | SI Dimension | Natural Units |
|---|---|---|
| Velocity | L·T⁻¹ | E⁰ (dimensionless!) |
| Length | L | E⁻¹ |
| Mass | M | E |
from ucon import SI, NATURAL, SI_TO_NATURAL, BasisVector
from fractions import Fraction
# Velocity becomes dimensionless in natural units
si_velocity = BasisVector(SI, (
Fraction(-1), Fraction(1), Fraction(0), Fraction(0),
Fraction(0), Fraction(0), Fraction(0), Fraction(0),
))
natural_velocity = SI_TO_NATURAL(si_velocity)
natural_velocity.is_dimensionless() # True! (c = 1)
When to Use Basis Abstraction¶
| Scenario | Basis Strategy |
|---|---|
| Torque vs Energy | Add angle as base dimension |
| Gy vs Sv | Add biological weighting dimension |
| SI ↔ CGS | Standard basis transforms |
| Particle physics | Natural units (E only) |
| Electromagnetism | CGS-ESU (charge as base) |
Comparing the Two Approaches¶
| Aspect | Pseudo-Dimensions | Basis Abstraction |
|---|---|---|
| Problem solved | Dimensionless quantities that differ semantically | Quantities with same dimension that differ physically |
| Mechanism | Semantic tag on zero-vector | Choose a basis where dimensions differ |
| Scope | Works within any single basis | Requires defining/choosing appropriate basis |
| Examples | angle vs count vs ratio | torque vs energy, Gy vs Sv |
| Declaration | Dimension.pseudo("tag") |
Basis(name, components) |
| Trade-off | Simple but limited to "truly" dimensionless | Powerful but requires domain modeling |
The Unified Picture¶
Both solutions preserve kind-of-quantity information that pure dimensional analysis loses. The choice depends on the nature of the ambiguity:
flowchart TB
KOQ["KOQ Ambiguity"]
KOQ --> dimensionless["Dimensionless but<br/>semantically distinct"]
KOQ --> same_dim["Same dimension but<br/>physically distinct"]
dimensionless --> pseudo["<b>PSEUDO-DIMENSION</b><br/><br/>angle<br/>count<br/>ratio"]
same_dim --> basis["<b>BASIS ABSTRACTION</b><br/><br/>Expand basis to<br/>include hidden<br/>dimension"]
pseudo --> tag["Tag on zero-vector<br/><code>(0,0,0,...,'angle')</code>"]
basis --> vectors["Different vectors<br/>in richer basis"]
Key insight: The SI's 7-dimensional basis is a pragmatic choice, not a physical necessity. Some KOQ problems arise because the SI basis is too coarse to distinguish certain quantities. ucon lets you:
- Add semantic tags for quantities the SI treats as dimensionless
- Define richer bases for quantities the SI conflates
Further Reading¶
- Hall, B.D. (2022). "Representing quantities and units in digital systems." Measurement: Sensors
- Hall, B.D. (2023). "Modelling expressions of physical quantities." IC3K 2023
- Hall, B.D. (2025). "Interpreting SI notation for units and dimensions." Measurement: Sensors