ucon 0.3.3rc1__tar.gz → 0.3.4__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {ucon-0.3.3rc1 → ucon-0.3.4}/.github/workflows/publish.yaml +1 -0
- {ucon-0.3.3rc1 → ucon-0.3.4}/PKG-INFO +6 -5
- {ucon-0.3.3rc1 → ucon-0.3.4}/README.md +5 -4
- {ucon-0.3.3rc1 → ucon-0.3.4}/ROADMAP.md +3 -3
- ucon-0.3.4/docs/decisions/composable-unit-algebra.md +241 -0
- ucon-0.3.4/docs/decisions/composite-units.md +160 -0
- ucon-0.3.4/docs/decisions/unit-algebra-naming.md +169 -0
- ucon-0.3.4/docs/explainers/type-operation-matrix.md +14 -0
- ucon-0.3.4/docs/explainers/why-algebraic-closure-matters.md +175 -0
- ucon-0.3.4/docs/explainers/why-type-safety-matters.md +92 -0
- ucon-0.3.4/docs/proposals/project_unified-algebraic-core.md +171 -0
- ucon-0.3.4/docs/proposals/unified-unit-presentation.md +168 -0
- ucon-0.3.4/tests/ucon/test_algebra.py +237 -0
- ucon-0.3.4/tests/ucon/test_core.py +674 -0
- ucon-0.3.4/tests/ucon/test_quantity.py +363 -0
- {ucon-0.3.3rc1 → ucon-0.3.4}/tests/ucon/test_units.py +5 -3
- {ucon-0.3.3rc1 → ucon-0.3.4}/ucon/__init__.py +3 -3
- ucon-0.3.4/ucon/algebra.py +212 -0
- ucon-0.3.4/ucon/core.py +806 -0
- ucon-0.3.4/ucon/quantity.py +249 -0
- {ucon-0.3.3rc1 → ucon-0.3.4}/ucon/units.py +1 -2
- {ucon-0.3.3rc1 → ucon-0.3.4}/ucon.egg-info/PKG-INFO +6 -5
- {ucon-0.3.3rc1 → ucon-0.3.4}/ucon.egg-info/SOURCES.txt +12 -4
- ucon-0.3.3rc1/tests/ucon/test_core.py +0 -583
- ucon-0.3.3rc1/tests/ucon/test_dimension.py +0 -206
- ucon-0.3.3rc1/tests/ucon/test_unit.py +0 -143
- ucon-0.3.3rc1/ucon/core.py +0 -401
- ucon-0.3.3rc1/ucon/dimension.py +0 -172
- ucon-0.3.3rc1/ucon/unit.py +0 -92
- {ucon-0.3.3rc1 → ucon-0.3.4}/.github/workflows/tests.yaml +0 -0
- {ucon-0.3.3rc1 → ucon-0.3.4}/.gitignore +0 -0
- {ucon-0.3.3rc1 → ucon-0.3.4}/LICENSE +0 -0
- {ucon-0.3.3rc1 → ucon-0.3.4}/docs/decisions/unity-distance-metric-for-nearest-scale.md +0 -0
- {ucon-0.3.3rc1 → ucon-0.3.4}/docs/proposals/interface-unifying-the-value-layer.md +0 -0
- {ucon-0.3.3rc1 → ucon-0.3.4}/docs/proposals/support-for-fractional-exponents.md +0 -0
- {ucon-0.3.3rc1 → ucon-0.3.4}/noxfile.py +0 -0
- {ucon-0.3.3rc1 → ucon-0.3.4}/requirements.txt +0 -0
- {ucon-0.3.3rc1 → ucon-0.3.4}/setup.cfg +0 -0
- {ucon-0.3.3rc1 → ucon-0.3.4}/setup.py +0 -0
- {ucon-0.3.3rc1 → ucon-0.3.4}/tests/__init__.py +0 -0
- {ucon-0.3.3rc1 → ucon-0.3.4}/tests/ucon/__init__.py +0 -0
- {ucon-0.3.3rc1 → ucon-0.3.4}/ucon.egg-info/dependency_links.txt +0 -0
- {ucon-0.3.3rc1 → ucon-0.3.4}/ucon.egg-info/top_level.txt +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: ucon
|
|
3
|
-
Version: 0.3.
|
|
3
|
+
Version: 0.3.4
|
|
4
4
|
Summary: a tool for dimensional analysis: a "Unit CONverter"
|
|
5
5
|
Home-page: https://github.com/withtwoemms/ucon
|
|
6
6
|
Author: Emmanuel I. Obi
|
|
@@ -82,7 +82,7 @@ To best answer this question, we turn to an age-old technique ([dimensional anal
|
|
|
82
82
|
|
|
83
83
|
`ucon` models unit math through a hierarchy where each layer builds on the last:
|
|
84
84
|
|
|
85
|
-
<img src=https://gist.githubusercontent.com/withtwoemms/429d2ca1f979865aa80a2658bf9efa32/raw/
|
|
85
|
+
<img src=https://gist.githubusercontent.com/withtwoemms/429d2ca1f979865aa80a2658bf9efa32/raw/0c704737a52b9e4a87cda5c839e9aa40f7e5bb48/ucon.data-model_v035.png align="center" alt="ucon Data Model" width=600/>
|
|
86
86
|
|
|
87
87
|
## Why `ucon`?
|
|
88
88
|
|
|
@@ -138,12 +138,13 @@ becomes straightforward when you define a measurement:
|
|
|
138
138
|
from ucon import Number, Scale, Units, Ratio
|
|
139
139
|
|
|
140
140
|
# Two milliliters of bromine
|
|
141
|
-
|
|
141
|
+
mL = Scale.milli * units.liter
|
|
142
|
+
two_mL_bromine = Number(quantity=2, unit=mL)
|
|
142
143
|
|
|
143
144
|
# Density of bromine: 3.119 g/mL
|
|
144
145
|
bromine_density = Ratio(
|
|
145
|
-
numerator=Number(unit=
|
|
146
|
-
denominator=Number(unit=
|
|
146
|
+
numerator=Number(unit=units.gram, quantity=3.119),
|
|
147
|
+
denominator=Number(unit=mL),
|
|
147
148
|
)
|
|
148
149
|
|
|
149
150
|
# Multiply to find mass
|
|
@@ -46,7 +46,7 @@ To best answer this question, we turn to an age-old technique ([dimensional anal
|
|
|
46
46
|
|
|
47
47
|
`ucon` models unit math through a hierarchy where each layer builds on the last:
|
|
48
48
|
|
|
49
|
-
<img src=https://gist.githubusercontent.com/withtwoemms/429d2ca1f979865aa80a2658bf9efa32/raw/
|
|
49
|
+
<img src=https://gist.githubusercontent.com/withtwoemms/429d2ca1f979865aa80a2658bf9efa32/raw/0c704737a52b9e4a87cda5c839e9aa40f7e5bb48/ucon.data-model_v035.png align="center" alt="ucon Data Model" width=600/>
|
|
50
50
|
|
|
51
51
|
## Why `ucon`?
|
|
52
52
|
|
|
@@ -102,12 +102,13 @@ becomes straightforward when you define a measurement:
|
|
|
102
102
|
from ucon import Number, Scale, Units, Ratio
|
|
103
103
|
|
|
104
104
|
# Two milliliters of bromine
|
|
105
|
-
|
|
105
|
+
mL = Scale.milli * units.liter
|
|
106
|
+
two_mL_bromine = Number(quantity=2, unit=mL)
|
|
106
107
|
|
|
107
108
|
# Density of bromine: 3.119 g/mL
|
|
108
109
|
bromine_density = Ratio(
|
|
109
|
-
numerator=Number(unit=
|
|
110
|
-
denominator=Number(unit=
|
|
110
|
+
numerator=Number(unit=units.gram, quantity=3.119),
|
|
111
|
+
denominator=Number(unit=mL),
|
|
111
112
|
)
|
|
112
113
|
|
|
113
114
|
# Multiply to find mass
|
|
@@ -23,13 +23,13 @@ Stable baseline for:
|
|
|
23
23
|
- [x] Implement `Vector` and `Dimension` classes
|
|
24
24
|
- [x] Integrate dimensions into `Unit`
|
|
25
25
|
- [x] Refactor `ucon.units` to use dimensional definitions
|
|
26
|
-
- [
|
|
26
|
+
- [x] Publish documentation for dimensional operations
|
|
27
27
|
- [x] Verify uniqueness and hashing correctness across all Dimensions
|
|
28
28
|
- [x] Redesign `Exponent` to support algebraic operations (`__mul__`, `__truediv__`, `to_base`, etc.)
|
|
29
29
|
- [x] Remove redundant evaluated caching in favor of property-based computation
|
|
30
30
|
- [x] Integrate `Scale` with Exponent for consistent prefix arithmetic
|
|
31
31
|
- [ ] Update `Number` and `Ratio` to use Exponent-driven scaling
|
|
32
|
-
- [
|
|
32
|
+
- [x] Add regression tests for prefix math (`kilo / milli → mega`, `2¹⁰ / 10³ → 1.024×`)
|
|
33
33
|
- [ ] Document Exponent/Scale relationship in developer guide
|
|
34
34
|
|
|
35
35
|
### 🧩 Outcomes
|
|
@@ -37,7 +37,7 @@ Stable baseline for:
|
|
|
37
37
|
- Enables composable and type-safe dimensional operations
|
|
38
38
|
- Establishes the mathematical foundation for future conversions
|
|
39
39
|
- Unified algebraic foundation for all scaling and magnitude operations
|
|
40
|
-
- Precise, reversible cross-base math (`2ⁿ ↔ 10ᵐ`)
|
|
40
|
+
- ~Precise, reversible cross-base math (`2ⁿ ↔ 10ᵐ`)~
|
|
41
41
|
- Simplified, consistent `Scale` and `Number` behavior
|
|
42
42
|
- Ready for integration into the conversion engine (`ucon.conversions`)
|
|
43
43
|
|
|
@@ -0,0 +1,241 @@
|
|
|
1
|
+
# UnitFactor — Structure for a Composable Unit Algebra
|
|
2
|
+
|
|
3
|
+
## 1. Overview
|
|
4
|
+
|
|
5
|
+
`UnitFactor` is introduced as a **structural atom** of the unit algebra:
|
|
6
|
+
|
|
7
|
+
```
|
|
8
|
+
UnitFactor = (unit, scale)
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
where:
|
|
12
|
+
- `unit` is a stable, canonical unit identity (e.g., gram, liter, meter),
|
|
13
|
+
- `scale` is a prefix-like symbolic modifier (e.g., milli, kilo, micro).
|
|
14
|
+
|
|
15
|
+
Unlike the legacy `Unit` object—which merged name, dimension, formatting hints, and scale—`UnitFactor` is **atomic**, **unambiguous**, and **hashable**.
|
|
16
|
+
It acts as the _basis element_ of the unit algebra — the analogue of a "BasisDimension" (i.e. Length, Time, etc.) in dimensional algebra.
|
|
17
|
+
|
|
18
|
+
By elevating scale into a first-class algebraic component,
|
|
19
|
+
`UnitFactor` restores clean structural separation and enables unit expressions that are lossless, composable, and reversible.
|
|
20
|
+
|
|
21
|
+
---
|
|
22
|
+
|
|
23
|
+
## 2. The Problem It Solves
|
|
24
|
+
|
|
25
|
+
### 2.1. Scale Entanglement in Legacy Unit Semantics
|
|
26
|
+
|
|
27
|
+
Legacy `Unit` objects encoded scale internally:
|
|
28
|
+
|
|
29
|
+
```
|
|
30
|
+
mg = Unit("mg", dimension=MASS, scale=milli)
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
This resulted in a system where scale and identity were inseparable, leading to:
|
|
34
|
+
|
|
35
|
+
- duplicate definitions (`mg` vs `milli * gram`),
|
|
36
|
+
- unwanted normalization of prefixes,
|
|
37
|
+
- scale leaking into numeric magnitude,
|
|
38
|
+
- loss of provenance during calculations.
|
|
39
|
+
|
|
40
|
+
The system could _represent_ scaled units but could not _reason_ about them consistently.
|
|
41
|
+
|
|
42
|
+
**`UnitFactor` resolves this by making scale a distinct algebraic coordinate.**
|
|
43
|
+
|
|
44
|
+
---
|
|
45
|
+
|
|
46
|
+
### 2.2. Loss of User Intent During Composite Operations
|
|
47
|
+
|
|
48
|
+
`CompositeUnit` formerly stored raw `Unit` instances, which meant that user-intent information, especially regarding prefixes, was immediately lost.
|
|
49
|
+
|
|
50
|
+
Example issues:
|
|
51
|
+
|
|
52
|
+
- `mL` and `L` collapsed unpredictably
|
|
53
|
+
- `(mg/mL) * mL` produced incorrect quantities
|
|
54
|
+
- scale information disappeared inside normalization (absorbed by numeric magnitude)
|
|
55
|
+
- mathematically identical expressions yielded structurally different objects
|
|
56
|
+
|
|
57
|
+
By shifting to:
|
|
58
|
+
|
|
59
|
+
```
|
|
60
|
+
{ UnitFactor(base=gram, scale=milli) → +1,
|
|
61
|
+
UnitFactor(base=liter, scale=milli) → -1 }
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
the algebra becomes **lossless**, **deterministic**, and fully **transparent**.
|
|
65
|
+
|
|
66
|
+
---
|
|
67
|
+
|
|
68
|
+
### 2.3. Embedding Interpretation Inside Algebra
|
|
69
|
+
|
|
70
|
+
Prior to `UnitFactor`, unit multiplication/division required interpretation:
|
|
71
|
+
|
|
72
|
+
- Should prefix scale merge?
|
|
73
|
+
- Should the result canonicalize to SI?
|
|
74
|
+
- Should scale affect numeric magnitude?
|
|
75
|
+
- Should shorthand labels collapse?
|
|
76
|
+
|
|
77
|
+
These semantic choices polluted the algebra layer.
|
|
78
|
+
|
|
79
|
+
**`UnitFactor` restores algebraic purity by keeping scale symbolic rather than interpretive.**
|
|
80
|
+
|
|
81
|
+
---
|
|
82
|
+
|
|
83
|
+
## 3. `UnitFactor` as an Atom in Unit Space
|
|
84
|
+
|
|
85
|
+
`UnitFactor` parallels dimensional algebra:
|
|
86
|
+
|
|
87
|
+
**Dimensional Algebra**
|
|
88
|
+
```
|
|
89
|
+
Vector({ BasisDimension → exponent })
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
**Unit Algebra (with `UnitFactor`)**
|
|
93
|
+
```
|
|
94
|
+
UnitProduct({ UnitFactor → exponent })
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
`UnitProduct` is the successor to `CompositeUnit`: _a free abelian product over `UnitFactor`s._
|
|
98
|
+
|
|
99
|
+
This yields a clean architectural symmetry:
|
|
100
|
+
|
|
101
|
+
| Dimensional Layer | Unit Layer (future) |
|
|
102
|
+
|-------------------|----------------------|
|
|
103
|
+
| BasisDimension | UnitFactor |
|
|
104
|
+
| Vector | UnitProduct |
|
|
105
|
+
| Dimension | UnitForm |
|
|
106
|
+
|
|
107
|
+
`UnitFactor` is the “basis atom” that makes this composite unit space possible.
|
|
108
|
+
|
|
109
|
+
---
|
|
110
|
+
|
|
111
|
+
## 4. What `UnitFactor` Enables
|
|
112
|
+
|
|
113
|
+
### 4.1. Lossless, Predictable Unit Arithmetic
|
|
114
|
+
|
|
115
|
+
- user prefixes remain intact
|
|
116
|
+
- cancellation is structural, not heuristic
|
|
117
|
+
- unit cancellation _before_ scale factor reconciliation
|
|
118
|
+
- algebraic operations preserve user intent
|
|
119
|
+
- scale never leaks into numeric magnitude
|
|
120
|
+
|
|
121
|
+
Examples:
|
|
122
|
+
|
|
123
|
+
```
|
|
124
|
+
(g/mL) * mL → g
|
|
125
|
+
(mg/mL) * mL → mg
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
Correctness is now a mathematical property, not an accidental outcome.
|
|
129
|
+
|
|
130
|
+
---
|
|
131
|
+
|
|
132
|
+
### 4.2. Algebraic Normalization without Canonicalization
|
|
133
|
+
|
|
134
|
+
`UnitFactor` supports strict algebraic behavior:
|
|
135
|
+
|
|
136
|
+
- no forced SI normalization
|
|
137
|
+
- no heuristic prefix adjustments
|
|
138
|
+
- no implicit conversion to base units
|
|
139
|
+
|
|
140
|
+
Canonicalization moves into higher layers (`UnitForm`, `ConversionGraph`).
|
|
141
|
+
|
|
142
|
+
---
|
|
143
|
+
|
|
144
|
+
### 4.3. Foundation for ConversionGraph
|
|
145
|
+
|
|
146
|
+
`UnitFactor` exposes:
|
|
147
|
+
|
|
148
|
+
- base identity
|
|
149
|
+
- scale prefix
|
|
150
|
+
- dimension
|
|
151
|
+
|
|
152
|
+
as independent coordinates, enabling semantic conversions such as:
|
|
153
|
+
|
|
154
|
+
```
|
|
155
|
+
kJ·h/s → J·h/s → W·h
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
`UnitFactor` & `UnitProduct` provide the structural substrate, while `ConversionGraph` handles meaning.
|
|
159
|
+
|
|
160
|
+
---
|
|
161
|
+
|
|
162
|
+
## 5. The Path It Paves
|
|
163
|
+
|
|
164
|
+
### 5.1. Eliminating `Unit.scale`
|
|
165
|
+
|
|
166
|
+
`Unit` becomes purely declarative:
|
|
167
|
+
|
|
168
|
+
```
|
|
169
|
+
Unit(name="gram", dimension=MASS)
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
All scaling semantics shift into `FactoredUnit`.
|
|
173
|
+
Once scale is removed, `Unit` no longer participates in algebraic operations.
|
|
174
|
+
It becomes a **canonical identity object**, analogous to a basis `Dimension` (e.g. time, length, mass, etc.):
|
|
175
|
+
a stable nameable anchor used by registries, `UnitForm`, and `ConversionGraph`.
|
|
176
|
+
|
|
177
|
+
A Unit carries only semantic information (name, aliases, dimension) and does _not_ combine multiplicatively.
|
|
178
|
+
All algebraic behavior moves exclusively into `UnitFactor` and `UnitProduct`, allowing `Unit` to remain a pure symbolic identity within the broader type ecosystem.
|
|
179
|
+
|
|
180
|
+
---
|
|
181
|
+
|
|
182
|
+
### 5.2. CompositeUnit Evolves into UnitProduct
|
|
183
|
+
|
|
184
|
+
`CompositeUnit` is ultimately replaced by:
|
|
185
|
+
|
|
186
|
+
```
|
|
187
|
+
UnitProduct = { UnitFactor → exponent }
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
This yields a principled free abelian structure paralleling dimensional vectors.
|
|
191
|
+
|
|
192
|
+
---
|
|
193
|
+
|
|
194
|
+
### 5.3. User-Facing Layer Becomes UnitForm
|
|
195
|
+
|
|
196
|
+
**UnitForm** becomes the user-visible representation layer:
|
|
197
|
+
|
|
198
|
+
- parses expressions (`"g/mL"`)
|
|
199
|
+
- prints canonical or preferred forms
|
|
200
|
+
- integrates with registries
|
|
201
|
+
- applies prefix or display policies
|
|
202
|
+
- guarantees round-trip stability
|
|
203
|
+
|
|
204
|
+
`UnitProduct` becomes the algebra;
|
|
205
|
+
`UnitForm` becomes the language.
|
|
206
|
+
|
|
207
|
+
---
|
|
208
|
+
|
|
209
|
+
### 5.4. Integration with ConversionGraph
|
|
210
|
+
|
|
211
|
+
`UnitFactor` and `UnitProduct` act as the structural substrate for semantic conversions:
|
|
212
|
+
|
|
213
|
+
- J ↔ W·s
|
|
214
|
+
- cal ↔ J
|
|
215
|
+
- mL ↔ L
|
|
216
|
+
- h ↔ 3600 s
|
|
217
|
+
|
|
218
|
+
`ConversionGraph` operates on meaning; `UnitProduct` ensures consistent structure.
|
|
219
|
+
|
|
220
|
+
---
|
|
221
|
+
|
|
222
|
+
## 6. Architectural Summary
|
|
223
|
+
|
|
224
|
+
| Layer | Role | Value |
|
|
225
|
+
|-------|------|--------|
|
|
226
|
+
| **Unit** | atomic, canonical identity | base symbol for units |
|
|
227
|
+
| **UnitFactor** | algebraic atom | scale-inclusive symbolic factor |
|
|
228
|
+
| **UnitProduct** | formal product | composable, invertible algebra |
|
|
229
|
+
| **UnitForm** | user-facing interface | formatting, parsing, canonicalization |
|
|
230
|
+
| **ConversionGraph** | semantic layer | derived-unit conversions |
|
|
231
|
+
|
|
232
|
+
For a deep dive into the new naming conventions check [this](./unit-algebra-naming.md) out
|
|
233
|
+
|
|
234
|
+
---
|
|
235
|
+
|
|
236
|
+
## 7. Philosophical Note
|
|
237
|
+
|
|
238
|
+
> A unit is not a label.
|
|
239
|
+
> It is a structural atom in an algebra whose interactions encode physical meaning.
|
|
240
|
+
|
|
241
|
+
`UnitFactor` restores this foundation, revealing the future shape of `ucon`’s unit algebra.
|
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
# Unit Combination and Algebraic Closure in `ucon`
|
|
2
|
+
|
|
3
|
+
## 1. Composite Units
|
|
4
|
+
|
|
5
|
+
Composite dimensions (e.g., velocity, acceleration, density) arise as products or quotients of base dimensions.
|
|
6
|
+
In the continuous model, these combine algebraically in exponent space.
|
|
7
|
+
|
|
8
|
+
Example: velocity = length / time
|
|
9
|
+
|
|
10
|
+
$$
|
|
11
|
+
V = \frac{L}{T} = a^{x_L - x_T}
|
|
12
|
+
$$
|
|
13
|
+
|
|
14
|
+
If the length and time graphs are independent CCGs, their exponents combine by **subtraction of vectors**.
|
|
15
|
+
This allows multi-dimensional conversion to be expressed purely algebraically.
|
|
16
|
+
|
|
17
|
+
| Quantity | Formula | Exponent Form |
|
|
18
|
+
|-----------|----------|---------------|
|
|
19
|
+
| Velocity | L/T | \( $x_L - x_T$ \) |
|
|
20
|
+
| Acceleration | L/T² | \( $x_L - 2x_T$ \) |
|
|
21
|
+
| Force | M·L/T² | \( $x_M + x_L - 2x_T$ \) |
|
|
22
|
+
| Density | M/L³ | \( $x_M - 3x_L$ \) |
|
|
23
|
+
|
|
24
|
+
Each component dimension (L, T, M, etc.) maintains its own graph — conversions for composite units are vector sums.
|
|
25
|
+
|
|
26
|
+
---
|
|
27
|
+
|
|
28
|
+
## 2. What Would Be Impossible Without `CompositeUnit`
|
|
29
|
+
|
|
30
|
+
Without `CompositeUnit`, **ucon would be descriptive, not algebraic.**
|
|
31
|
+
It could *store* conversions but not *derive* them.
|
|
32
|
+
|
|
33
|
+
| Capability | Without `CompositeUnit` | With `CompositeUnit` |
|
|
34
|
+
|-------------|------------------------|-----------------------|
|
|
35
|
+
| Unit algebra | Flat mapping of names | Free abelian group of composable morphisms |
|
|
36
|
+
| Derived dimensions | Pre-registered only | Algebraically inferred |
|
|
37
|
+
| Simplification | Manual or string-based | Symbolic, lossless cancellation |
|
|
38
|
+
| Conversion chaining | Requires graph heuristics | Structural traversal via decomposition |
|
|
39
|
+
| Reasoning | String pattern matching | Category-theoretic functor between symbolic and numeric domains |
|
|
40
|
+
| Expressiveness | Lookup tables | Algebraic system of morphisms |
|
|
41
|
+
| Extensibility | Must predefine all derived units | Derived units emerge from composition |
|
|
42
|
+
|
|
43
|
+
> `CompositeUnit` transforms ucon from a **registry of facts** into an **engine of derivation.**
|
|
44
|
+
|
|
45
|
+
---
|
|
46
|
+
|
|
47
|
+
## 3. CompositeUnit, Exponent, and Scale: Cohesive Closure
|
|
48
|
+
|
|
49
|
+
| Role | Domain | Operation | Closure Guarantee |
|
|
50
|
+
|------|---------|------------|------------------|
|
|
51
|
+
| **Exponent** | Algebra | Powers of numeric bases (10, 2, etc.) | Defines magnitude algebra |
|
|
52
|
+
| **Scale** | Ontology | Named prefixes for exponents | Names exponent values |
|
|
53
|
+
| **Unit** | Ontology | Typed measure symbol | Couples dimension + scale |
|
|
54
|
+
| **CompositeUnit** | Algebra on units | Product, quotient, powers | Closes the group |
|
|
55
|
+
|
|
56
|
+
This creates the **closure chain**:
|
|
57
|
+
|
|
58
|
+
$$
|
|
59
|
+
\text{Exponent} \Rightarrow \text{Scale} \Rightarrow \text{Unit} \Rightarrow \text{CompositeUnit}
|
|
60
|
+
$$
|
|
61
|
+
|
|
62
|
+
Each layer embeds the previous one, while adding new semantics (naming, dimension, composability).
|
|
63
|
+
|
|
64
|
+
---
|
|
65
|
+
|
|
66
|
+
## 4. CompositeUnit as Morphism
|
|
67
|
+
|
|
68
|
+
`CompositeUnit` is both an **element** and a **morphism** in the unit group:
|
|
69
|
+
|
|
70
|
+
$$
|
|
71
|
+
f: U_1 \to U_2, \quad f(a \cdot b) = f(a) \cdot f(b)
|
|
72
|
+
$$
|
|
73
|
+
|
|
74
|
+
This gives the unit algebra:
|
|
75
|
+
|
|
76
|
+
- **Associativity** (composition)
|
|
77
|
+
- **Identity** (`dimensionless`)
|
|
78
|
+
- **Inverses** (`u⁻¹`)
|
|
79
|
+
- **Closure** (`U × U → CompositeUnit ⊂ Unit`)
|
|
80
|
+
|
|
81
|
+
It forms a **monoidal category** of units where:
|
|
82
|
+
- objects = base units,
|
|
83
|
+
- morphisms = composite transformations,
|
|
84
|
+
- functors = conversions between systems (SI, CGS, Imperial).
|
|
85
|
+
|
|
86
|
+
---
|
|
87
|
+
|
|
88
|
+
## 5. Why the ConversionGraph Depends on It
|
|
89
|
+
|
|
90
|
+
The ConversionGraph functor acts over this unit algebra:
|
|
91
|
+
|
|
92
|
+
$$
|
|
93
|
+
F: (\text{Unit Algebra}) \to (\text{Numeric Transformations})
|
|
94
|
+
$$
|
|
95
|
+
|
|
96
|
+
`CompositeUnit` guarantees totality — all symbolic unit expressions can be decomposed and recomposed in graph traversal.
|
|
97
|
+
|
|
98
|
+
Example:
|
|
99
|
+
```python
|
|
100
|
+
force = units.kilogram * units.meter / (units.second ** 2)
|
|
101
|
+
graph.convert(force, "N") # Converts via decomposed path
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
Without `CompositeUnit`, such a conversion is not possible,
|
|
105
|
+
since the graph would have no way to represent composite relationships between base units.
|
|
106
|
+
|
|
107
|
+
---
|
|
108
|
+
|
|
109
|
+
## 6. How Competitors Handle This (or Don’t)
|
|
110
|
+
|
|
111
|
+
| Library | Composite Concept | Mechanism | Limitations |
|
|
112
|
+
|----------|------------------|------------|--------------|
|
|
113
|
+
| **Pint** | Implicit composite via `Quantity` + registry | Tuple of (unit, exponent) pairs parsed from strings | Composite logic is hidden, not a first-class algebraic type; no symbolic morphisms |
|
|
114
|
+
| **SymPy.physics.units** | Composition through symbolic `Mul(Unit, Unit)` trees | Full symbolic representation | Algebraic but non-canonical; requires tree simplification and lacks registry consistency |
|
|
115
|
+
| **Unyt** | `UnitRegistry` + array wrapper | Exponents over strings | Conversion graph is registry-based only; no morphic algebra |
|
|
116
|
+
| **Astropy.units** | `UnitBase` and compound units via operator overloads | Functional for end users | No first-class algebra for composition; context-dependent simplification |
|
|
117
|
+
| **Unum** | Explicit *universal number* with lazy dimension algebra | Arithmetic objects track dimension exponents | Symbolic but not categorical: lacks conversion composition semantics and no functorial conversion; operations can lose context |
|
|
118
|
+
| **ucon** | **`CompositeUnit` as morphism in a composable unit group** | Explicit algebraic closure; conversion is a functor | Symbolic reasoning, compositional simplification, direct ConversionGraph integration |
|
|
119
|
+
|
|
120
|
+
### 🔍 Commentary on *Unum*
|
|
121
|
+
- **Strength:** Unum pioneered embedding dimensional arithmetic directly into number objects (`Unum(3, 'm/s²')`).
|
|
122
|
+
- **Weakness:** Its algebra is _monolithic_, coupling value, dimension, and conversion rules in one type.
|
|
123
|
+
- There’s no separation of concerns — no morphism layer between symbolic representation and numeric transformation.
|
|
124
|
+
- Conversions are _eager_ rather than structural, meaning they cannot be composed functorially.
|
|
125
|
+
- **Contrast with ucon:**
|
|
126
|
+
ucon’s `CompositeUnit` isolates the symbolic structure from numeric evaluation.
|
|
127
|
+
This allows deferred evaluation, symbolic simplification, and graph-based reasoning across systems of units.
|
|
128
|
+
Thus, ucon’s algebra is **refactorable and extensible**, while unum’s is **monolithic and eager**.
|
|
129
|
+
|
|
130
|
+
---
|
|
131
|
+
|
|
132
|
+
## 7. Philosophical Summary
|
|
133
|
+
|
|
134
|
+
> In most libraries, a “unit” is a label.
|
|
135
|
+
> In ucon, a unit is a **morphism** in a composable algebra.
|
|
136
|
+
|
|
137
|
+
`CompositeUnit` makes ucon a **structural model** of physics:
|
|
138
|
+
|
|
139
|
+
$$
|
|
140
|
+
\frac{L}{T^2} \Rightarrow \text{Acceleration}
|
|
141
|
+
$$
|
|
142
|
+
|
|
143
|
+
not as a string or a heuristic, but as a typed algebraic expression.
|
|
144
|
+
|
|
145
|
+
It allows ucon to:
|
|
146
|
+
- **derive** (not just define) relationships,
|
|
147
|
+
- **normalize** representations,
|
|
148
|
+
- **reason** about systems symbolically and numerically.
|
|
149
|
+
|
|
150
|
+
Thus:
|
|
151
|
+
> ucon is not merely a _unit-aware computation library_ — it is a **dimensional reasoning framework.**
|
|
152
|
+
|
|
153
|
+
---
|
|
154
|
+
|
|
155
|
+
## 7. Next Steps (Implementation Implications)
|
|
156
|
+
|
|
157
|
+
1. Keep `CompositeUnit` algebraically pure (no conversion logic).
|
|
158
|
+
1. Allow `Unit` and `Scale` to compose naturally.
|
|
159
|
+
1. Ensure simplification of reciprocal terms (`g·mL/mL → g`).
|
|
160
|
+
1. Use canonical hashing for composite signatures.
|
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
# Future Naming Scheme for the `Unit` Algebra
|
|
2
|
+
*(UnitFactor, UnitProduct, UnitForm)*
|
|
3
|
+
|
|
4
|
+
## 1. Context
|
|
5
|
+
|
|
6
|
+
ucon’s evolving unit system is transitioning toward a more explicit algebraic foundation.
|
|
7
|
+
Recent advances—particularly the introduction of `FactoredUnit`—have clarified the need for:
|
|
8
|
+
|
|
9
|
+
- cleaner separation between *atomic unit components*
|
|
10
|
+
- purely algebraic composite unit structures
|
|
11
|
+
- a stable, user-facing layer for rendering, parsing, and canonicalization
|
|
12
|
+
|
|
13
|
+
As ucon’s unit semantics converge toward a **free abelian group** model (mirroring the dimensional algebra), the existing naming (`CompositeUnit`, `FactoredUnit`, `Unit`) no longer captures the distinctions between:
|
|
14
|
+
|
|
15
|
+
- the algebraic substrate
|
|
16
|
+
- the atomic symbolic components
|
|
17
|
+
- the user interface layer
|
|
18
|
+
|
|
19
|
+
This document outlines a naming scheme aligned with that architecture.
|
|
20
|
+
|
|
21
|
+
---
|
|
22
|
+
|
|
23
|
+
## 2. Decision
|
|
24
|
+
|
|
25
|
+
Adopt the following naming triad for a future ucon unit algebra:
|
|
26
|
+
|
|
27
|
+
### **1. UnitFactor**
|
|
28
|
+
The atomic building block of unit expressions.
|
|
29
|
+
|
|
30
|
+
- Represents a pair: _(canonical unit identity, scale)_
|
|
31
|
+
- Corresponds structurally to a “coordinate” or “basis element” of the unit algebra
|
|
32
|
+
- Replaces and generalizes the existing `FactoredUnit`
|
|
33
|
+
- Holds no formatting, registry, or canonicalization responsibilities
|
|
34
|
+
- Exists solely for algebraic manipulation
|
|
35
|
+
|
|
36
|
+
### **2. UnitProduct**
|
|
37
|
+
The algebraic combination of UnitFactors.
|
|
38
|
+
|
|
39
|
+
- A mapping `{UnitFactor → exponent}`
|
|
40
|
+
- Represents a formal multiplicative product
|
|
41
|
+
- Free abelian group structure (addition/subtraction of exponents)
|
|
42
|
+
- Replaces the current `CompositeUnit`
|
|
43
|
+
- Pure algebraic core: no interpretation, no formatting, no normalization
|
|
44
|
+
- Positionally analogous to the dimensional `Vector` type, but specialized to units
|
|
45
|
+
|
|
46
|
+
### **3. UnitForm**
|
|
47
|
+
The user-facing representation of units.
|
|
48
|
+
|
|
49
|
+
- Provides formatting, parsing, canonicalization rules, alias handling, and registry integration
|
|
50
|
+
- Wraps a `UnitProduct` internally
|
|
51
|
+
- Represents what users write and see (`"g/mL"`, `"kW·h"`, `"psi"`)
|
|
52
|
+
- Cleanly decouples UI semantics from algebraic mechanics
|
|
53
|
+
- Replaces the conceptual role of “Unit” as the object users interact with
|
|
54
|
+
|
|
55
|
+
---
|
|
56
|
+
|
|
57
|
+
## 3. Rationale
|
|
58
|
+
|
|
59
|
+
### 3.1. Why **UnitFactor**
|
|
60
|
+
“Factor” is:
|
|
61
|
+
|
|
62
|
+
- algebraically accurate
|
|
63
|
+
- readable and intuitive
|
|
64
|
+
- directly compatible with the term “product”
|
|
65
|
+
- expressive of the role: a scaled, atomic unit element that participates in multiplication
|
|
66
|
+
|
|
67
|
+
Compared to alternatives (“Term”, “BasisUnit”, “Atom”, “Coordinate”),
|
|
68
|
+
**UnitFactor** strikes the ideal balance between mathematical precision and everyday usability.
|
|
69
|
+
|
|
70
|
+
---
|
|
71
|
+
|
|
72
|
+
### 3.2. Why **UnitProduct**
|
|
73
|
+
The algebra underlying ucon unit combinations is not vector algebra
|
|
74
|
+
(in the sense of magnitude-1 unit vectors), but **formal multiplicative algebra**.
|
|
75
|
+
|
|
76
|
+
A UnitProduct is:
|
|
77
|
+
|
|
78
|
+
- a product of UnitFactors
|
|
79
|
+
- a free abelian group element
|
|
80
|
+
- the natural analogue of a symbolic monomial
|
|
81
|
+
|
|
82
|
+
“Product” is accessible to users without sacrificing correctness.
|
|
83
|
+
It avoids the misleading connotation of “vector” and is friendlier than “monomial.”
|
|
84
|
+
|
|
85
|
+
---
|
|
86
|
+
|
|
87
|
+
### 3.3. Why **UnitForm**
|
|
88
|
+
The system needs a distinct layer that:
|
|
89
|
+
|
|
90
|
+
- users interact with
|
|
91
|
+
- ties into the registry
|
|
92
|
+
- controls printing and parsing
|
|
93
|
+
- decides when/how to reflect prefixes
|
|
94
|
+
- chooses canonical representations
|
|
95
|
+
- remains stable across refactors
|
|
96
|
+
|
|
97
|
+
“UnitExpression” was serviceable but generic.
|
|
98
|
+
“UnitForm” is:
|
|
99
|
+
|
|
100
|
+
- concise
|
|
101
|
+
- semantically clean
|
|
102
|
+
- visually and conceptually distinct from algebraic layers
|
|
103
|
+
- evocative of representation rather than structure
|
|
104
|
+
|
|
105
|
+
It completes the tiered architecture:
|
|
106
|
+
|
|
107
|
+
```
|
|
108
|
+
UnitFactor → structural atom
|
|
109
|
+
UnitProduct → algebraic composite
|
|
110
|
+
UnitForm → user-facing representation
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
---
|
|
114
|
+
|
|
115
|
+
## 4. Consequences
|
|
116
|
+
|
|
117
|
+
### Positive
|
|
118
|
+
|
|
119
|
+
- Clear conceptual separation between algebra and user semantics
|
|
120
|
+
- Naming aligns with physical intuition and mathematical structure
|
|
121
|
+
- Improves API clarity and documentation readability
|
|
122
|
+
- Prepares the codebase for future features:
|
|
123
|
+
- ConversionGraph
|
|
124
|
+
- Semantic canonicalization
|
|
125
|
+
- Unit registry enhancements
|
|
126
|
+
- Parsing/formatting improvements
|
|
127
|
+
|
|
128
|
+
### Neutral/Deferred
|
|
129
|
+
|
|
130
|
+
- No immediate refactor is required; this ADR guides future work
|
|
131
|
+
- CompositeUnit and FactoredUnit can coexist temporarily during transition
|
|
132
|
+
- Existing APIs remain intact until migration pathways are established
|
|
133
|
+
|
|
134
|
+
### Negative
|
|
135
|
+
|
|
136
|
+
- Some renaming churn is expected during adoption
|
|
137
|
+
- Downstream references to “CompositeUnit” and “FactoredUnit” will need updating
|
|
138
|
+
|
|
139
|
+
---
|
|
140
|
+
|
|
141
|
+
## 5. Alternatives Considered
|
|
142
|
+
|
|
143
|
+
- **UnitMonomial / UnitTerm**
|
|
144
|
+
- Mathematically elegant but feels overly academic
|
|
145
|
+
- **UnitCoordinate / UnitVector**
|
|
146
|
+
- Accurate but too abstract, and “unit vector” is overloaded in linear algebra
|
|
147
|
+
- **UnitExpression**
|
|
148
|
+
- Adequate, but less crisp than “UnitForm” as a representation-layer concept
|
|
149
|
+
- **Retaining existing names**
|
|
150
|
+
- Would perpetuate conceptual muddiness as the system grows
|
|
151
|
+
|
|
152
|
+
---
|
|
153
|
+
|
|
154
|
+
## 6. Future Work (Nonbinding)
|
|
155
|
+
|
|
156
|
+
- Introduce `UnitFactor` and `UnitProduct` in parallel with existing structures
|
|
157
|
+
- Evolve `UnitForm` as the primary user-facing unit API
|
|
158
|
+
- Gradually refactor internal algebra toward the new architecture
|
|
159
|
+
- Propose complementary ADRs covering:
|
|
160
|
+
- CanonicalUnit identity objects
|
|
161
|
+
- Registry architecture
|
|
162
|
+
- ConversionGraph integration
|
|
163
|
+
- Unit parsing and pretty-printing models
|
|
164
|
+
|
|
165
|
+
---
|
|
166
|
+
|
|
167
|
+
## 7. Acknowledgements
|
|
168
|
+
|
|
169
|
+
This naming scheme emerged from design discussions surrounding the FactoredUnit refactor, the need for scale-preserving operations, and the broader goal of unifying unit algebra with dimensional algebra in ucon’s long-term architecture.
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
# Type × Operation Matrix
|
|
2
|
+
|
|
3
|
+
| Type | + | - | * | / | ** | Neg | == | Category |
|
|
4
|
+
|---------------|-----|-----|-----|-----|-----|-----|--------|-------------------------|
|
|
5
|
+
| Vector | ✓ | ✓ | ✓ | — | — | ✓ | ✓ | Algebraic |
|
|
6
|
+
| Exponent | — | — | ✓ | ✓ | ✓ | — | ✓ | Algebraic |
|
|
7
|
+
| Dimension | — | — | ✓ | ✓ | ✓ | — | ✓ | Algebraic |
|
|
8
|
+
| CompositeUnit | — | — | ✓ | ✓ | ✓ | — | ✓ | Algebraic |
|
|
9
|
+
| Number | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | structural | Algebraic |
|
|
10
|
+
| Ratio | — | — | ✓ | ✓ | — | — | — | Partial Algebra |
|
|
11
|
+
| Unit | — | — | — | — | — | — | ✓ | Semantic |
|
|
12
|
+
| Scale | — | — | ✓ | — | — | — | — | Semantic |
|
|
13
|
+
| ScaleDescriptor | — | — | — | — | — | — | — | Semantic |
|
|
14
|
+
| FactoredUnit | — | — | — | — | — | — | ✓ | Semantic |
|