ucon 0.5.0__tar.gz → 0.5.2__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.5.0 → ucon-0.5.2}/PKG-INFO +105 -3
- {ucon-0.5.0 → ucon-0.5.2}/README.md +104 -2
- {ucon-0.5.0 → ucon-0.5.2}/ROADMAP.md +51 -40
- ucon-0.5.2/tests/ucon/test_basis_transform.py +521 -0
- ucon-0.5.2/tests/ucon/test_graph_basis_transform.py +263 -0
- ucon-0.5.2/tests/ucon/test_rebased_unit.py +184 -0
- ucon-0.5.2/tests/ucon/test_uncertainty.py +264 -0
- ucon-0.5.2/tests/ucon/test_unit_system.py +174 -0
- ucon-0.5.2/tests/ucon/test_vector_fraction.py +185 -0
- {ucon-0.5.0 → ucon-0.5.2}/ucon/__init__.py +20 -2
- {ucon-0.5.0 → ucon-0.5.2}/ucon/algebra.py +36 -14
- {ucon-0.5.0 → ucon-0.5.2}/ucon/core.py +558 -12
- {ucon-0.5.0 → ucon-0.5.2}/ucon/graph.py +167 -10
- {ucon-0.5.0 → ucon-0.5.2}/ucon/maps.py +22 -1
- {ucon-0.5.0 → ucon-0.5.2}/ucon/units.py +28 -1
- {ucon-0.5.0 → ucon-0.5.2}/ucon.egg-info/PKG-INFO +105 -3
- {ucon-0.5.0 → ucon-0.5.2}/ucon.egg-info/SOURCES.txt +6 -0
- {ucon-0.5.0 → ucon-0.5.2}/.github/workflows/publish.yaml +0 -0
- {ucon-0.5.0 → ucon-0.5.2}/.github/workflows/tests.yaml +0 -0
- {ucon-0.5.0 → ucon-0.5.2}/.gitignore +0 -0
- {ucon-0.5.0 → ucon-0.5.2}/LICENSE +0 -0
- {ucon-0.5.0 → ucon-0.5.2}/NOTICE +0 -0
- {ucon-0.5.0 → ucon-0.5.2}/docs/decisions/composable-unit-algebra.md +0 -0
- {ucon-0.5.0 → ucon-0.5.2}/docs/decisions/composite-units.md +0 -0
- {ucon-0.5.0 → ucon-0.5.2}/docs/decisions/pseudo-dimension-tuple-values.md +0 -0
- {ucon-0.5.0 → ucon-0.5.2}/docs/decisions/unit-algebra-naming.md +0 -0
- {ucon-0.5.0 → ucon-0.5.2}/docs/decisions/unity-distance-metric-for-nearest-scale.md +0 -0
- {ucon-0.5.0 → ucon-0.5.2}/docs/explainers/exponent-scale-relationship.md +0 -0
- {ucon-0.5.0 → ucon-0.5.2}/docs/explainers/type-operation-matrix.md +0 -0
- {ucon-0.5.0 → ucon-0.5.2}/docs/explainers/why-algebraic-closure-matters.md +0 -0
- {ucon-0.5.0 → ucon-0.5.2}/docs/explainers/why-type-safety-matters.md +0 -0
- {ucon-0.5.0 → ucon-0.5.2}/docs/proposals/interface-unifying-the-value-layer.md +0 -0
- {ucon-0.5.0 → ucon-0.5.2}/docs/proposals/project_unified-algebraic-core.md +0 -0
- {ucon-0.5.0 → ucon-0.5.2}/docs/proposals/support-for-fractional-exponents.md +0 -0
- {ucon-0.5.0 → ucon-0.5.2}/docs/proposals/unified-unit-presentation.md +0 -0
- {ucon-0.5.0 → ucon-0.5.2}/noxfile.py +0 -0
- {ucon-0.5.0 → ucon-0.5.2}/requirements.txt +0 -0
- {ucon-0.5.0 → ucon-0.5.2}/setup.cfg +0 -0
- {ucon-0.5.0 → ucon-0.5.2}/setup.py +0 -0
- {ucon-0.5.0 → ucon-0.5.2}/tests/__init__.py +0 -0
- {ucon-0.5.0 → ucon-0.5.2}/tests/ucon/__init__.py +0 -0
- {ucon-0.5.0 → ucon-0.5.2}/tests/ucon/conversion/__init__.py +0 -0
- {ucon-0.5.0 → ucon-0.5.2}/tests/ucon/conversion/test_graph.py +0 -0
- {ucon-0.5.0 → ucon-0.5.2}/tests/ucon/conversion/test_map.py +0 -0
- {ucon-0.5.0 → ucon-0.5.2}/tests/ucon/test_algebra.py +0 -0
- {ucon-0.5.0 → ucon-0.5.2}/tests/ucon/test_core.py +0 -0
- {ucon-0.5.0 → ucon-0.5.2}/tests/ucon/test_default_graph_conversions.py +0 -0
- {ucon-0.5.0 → ucon-0.5.2}/tests/ucon/test_dimensionless_units.py +0 -0
- {ucon-0.5.0 → ucon-0.5.2}/tests/ucon/test_quantity.py +0 -0
- {ucon-0.5.0 → ucon-0.5.2}/tests/ucon/test_units.py +0 -0
- {ucon-0.5.0 → ucon-0.5.2}/ucon/quantity.py +0 -0
- {ucon-0.5.0 → ucon-0.5.2}/ucon.egg-info/dependency_links.txt +0 -0
- {ucon-0.5.0 → ucon-0.5.2}/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.5.
|
|
3
|
+
Version: 0.5.2
|
|
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
|
|
@@ -67,6 +67,7 @@ It combines **units**, **scales**, and **dimensions** into a composable algebra
|
|
|
67
67
|
- Scale-aware arithmetic via `UnitFactor` and `UnitProduct`
|
|
68
68
|
- Metric and binary prefixes (`kilo`, `kibi`, `micro`, `mebi`, etc.)
|
|
69
69
|
- Pseudo-dimensions for angles, solid angles, and ratios with semantic isolation
|
|
70
|
+
- Uncertainty propagation through arithmetic and conversions
|
|
70
71
|
- A clean foundation for physics, chemistry, data modeling, and beyond
|
|
71
72
|
|
|
72
73
|
Think of it as **`decimal.Decimal` for the physical world** — precise, predictable, and type-safe.
|
|
@@ -91,6 +92,9 @@ To best answer this question, we turn to an age-old technique ([dimensional anal
|
|
|
91
92
|
| **`Ratio`** | `ucon.core` | Represents the division of two `Number` objects; captures relationships between quantities. | Expressing rates, densities, efficiencies (e.g., energy / time = power, length / time = velocity). |
|
|
92
93
|
| **`Map`** hierarchy | `ucon.maps` | Composable conversion morphisms: `LinearMap`, `AffineMap`, `ComposedMap`. | Defining conversion functions between units (e.g., meter→foot, celsius→kelvin). |
|
|
93
94
|
| **`ConversionGraph`** | `ucon.graph` | Registry of unit conversion edges with BFS path composition. | Converting between units via `Number.to(target)`; managing default and custom graphs. |
|
|
95
|
+
| **`UnitSystem`** | `ucon.core` | Named mapping from dimensions to base units (e.g., SI, Imperial). | Defining coherent unit systems; grouping base units by dimension. |
|
|
96
|
+
| **`BasisTransform`** | `ucon.core` | Matrix-based transformation between dimensional exponent spaces. | Converting between incompatible dimensional structures; exact arithmetic with `Fraction`. |
|
|
97
|
+
| **`RebasedUnit`** | `ucon.core` | A unit rebased to another system's dimension, preserving provenance. | Cross-basis conversions; tracking original unit through basis changes. |
|
|
94
98
|
| **`units` module** | `ucon.units` | Defines canonical unit instances (SI, imperial, information, and derived units). | Quick access to standard physical units (`units.meter`, `units.foot`, `units.byte`, etc.). |
|
|
95
99
|
|
|
96
100
|
### Under the Hood
|
|
@@ -215,6 +219,102 @@ print(ratio.to(units.ppm)) # <500000.0 ppm>
|
|
|
215
219
|
units.radian(1).to(units.percent) # raises ConversionNotFound
|
|
216
220
|
```
|
|
217
221
|
|
|
222
|
+
Uncertainty propagates through arithmetic and conversions:
|
|
223
|
+
```python
|
|
224
|
+
from ucon import units
|
|
225
|
+
|
|
226
|
+
# Measurements with uncertainty
|
|
227
|
+
length = units.meter(1.234, uncertainty=0.005)
|
|
228
|
+
width = units.meter(0.567, uncertainty=0.003)
|
|
229
|
+
|
|
230
|
+
print(length) # <1.234 ± 0.005 m>
|
|
231
|
+
|
|
232
|
+
# Uncertainty propagates through arithmetic (quadrature)
|
|
233
|
+
area = length * width
|
|
234
|
+
print(area) # <0.699678 ± 0.00424... m²>
|
|
235
|
+
|
|
236
|
+
# Uncertainty propagates through conversion
|
|
237
|
+
length_ft = length.to(units.foot)
|
|
238
|
+
print(length_ft) # <4.048... ± 0.0164... ft>
|
|
239
|
+
```
|
|
240
|
+
|
|
241
|
+
Unit systems and basis transforms enable conversions between incompatible dimensional structures.
|
|
242
|
+
This goes beyond simple unit conversion (meter → foot) into structural transformation:
|
|
243
|
+
|
|
244
|
+
```python
|
|
245
|
+
from fractions import Fraction
|
|
246
|
+
from ucon import BasisTransform, Dimension, Unit, UnitSystem, units
|
|
247
|
+
from ucon.graph import ConversionGraph
|
|
248
|
+
from ucon.maps import LinearMap
|
|
249
|
+
|
|
250
|
+
# The realm of Valdris has three fundamental dimensions:
|
|
251
|
+
# - Aether (A): magical energy substrate
|
|
252
|
+
# - Resonance (R): vibrational frequency of magic
|
|
253
|
+
# - Substance (S): physical matter
|
|
254
|
+
#
|
|
255
|
+
# These combine into SI dimensions via a transformation matrix:
|
|
256
|
+
#
|
|
257
|
+
# | L | | 2 0 0 | | A |
|
|
258
|
+
# | M | = | 1 0 1 | × | R |
|
|
259
|
+
# | T | |-2 -1 0 | | S |
|
|
260
|
+
#
|
|
261
|
+
# Reading the columns:
|
|
262
|
+
# - 1 aether contributes: L², M, T⁻² (energy-like)
|
|
263
|
+
# - 1 resonance contributes: T⁻¹ (frequency-like)
|
|
264
|
+
# - 1 substance contributes: M (mass-like)
|
|
265
|
+
|
|
266
|
+
# Fantasy base units
|
|
267
|
+
mote = Unit(name='mote', dimension=Dimension.energy, aliases=('mt',))
|
|
268
|
+
chime = Unit(name='chime', dimension=Dimension.frequency, aliases=('ch',))
|
|
269
|
+
ite = Unit(name='ite', dimension=Dimension.mass, aliases=('it',))
|
|
270
|
+
|
|
271
|
+
valdris = UnitSystem(
|
|
272
|
+
name="Valdris",
|
|
273
|
+
bases={
|
|
274
|
+
Dimension.energy: mote,
|
|
275
|
+
Dimension.frequency: chime,
|
|
276
|
+
Dimension.mass: ite,
|
|
277
|
+
}
|
|
278
|
+
)
|
|
279
|
+
|
|
280
|
+
# The basis transform encodes how Valdris dimensions compose into SI
|
|
281
|
+
valdris_to_si = BasisTransform(
|
|
282
|
+
src=valdris,
|
|
283
|
+
dst=units.si,
|
|
284
|
+
src_dimensions=(Dimension.energy, Dimension.frequency, Dimension.mass),
|
|
285
|
+
dst_dimensions=(Dimension.energy, Dimension.frequency, Dimension.mass),
|
|
286
|
+
matrix=(
|
|
287
|
+
(2, 0, 0), # energy: 2 × aether
|
|
288
|
+
(1, 0, 1), # frequency: aether + substance
|
|
289
|
+
(-2, -1, 0), # mass: -2×aether - resonance
|
|
290
|
+
),
|
|
291
|
+
)
|
|
292
|
+
|
|
293
|
+
# Physical calibration: how many SI units per fantasy unit
|
|
294
|
+
graph = ConversionGraph()
|
|
295
|
+
graph.connect_systems(
|
|
296
|
+
basis_transform=valdris_to_si,
|
|
297
|
+
edges={
|
|
298
|
+
(mote, units.joule): LinearMap(42), # 1 mote = 42 J
|
|
299
|
+
(chime, units.hertz): LinearMap(7), # 1 chime = 7 Hz
|
|
300
|
+
(ite, units.kilogram): LinearMap(Fraction(1, 2)), # 1 ite = 0.5 kg
|
|
301
|
+
}
|
|
302
|
+
)
|
|
303
|
+
|
|
304
|
+
# Game engine converts between physics systems
|
|
305
|
+
energy_map = graph.convert(src=mote, dst=units.joule)
|
|
306
|
+
energy_map(10) # 420 joules from 10 motes
|
|
307
|
+
|
|
308
|
+
# Inverse: display real-world values in game units
|
|
309
|
+
joule_to_mote = graph.convert(src=units.joule, dst=mote)
|
|
310
|
+
joule_to_mote(420) # 10 motes
|
|
311
|
+
|
|
312
|
+
# The transform is invertible with exact Fraction arithmetic
|
|
313
|
+
valdris_to_si.is_invertible # True
|
|
314
|
+
```
|
|
315
|
+
|
|
316
|
+
This enables fantasy game physics, or any field where the dimensional structure differs from SI.
|
|
317
|
+
|
|
218
318
|
---
|
|
219
319
|
|
|
220
320
|
## Roadmap Highlights
|
|
@@ -224,8 +324,10 @@ units.radian(1).to(units.percent) # raises ConversionNotFound
|
|
|
224
324
|
| **0.3.x** | Dimensional Algebra | Unit/Scale separation, `UnitFactor`, `UnitProduct` | ✅ Complete |
|
|
225
325
|
| **0.4.x** | Conversion System | `ConversionGraph`, `Number.to()`, callable units | ✅ Complete |
|
|
226
326
|
| **0.5.0** | Dimensionless Units | Pseudo-dimensions for angle, solid angle, ratio | ✅ Complete |
|
|
227
|
-
| **0.5.x** |
|
|
228
|
-
| **0.
|
|
327
|
+
| **0.5.x** | Uncertainty | Propagation through arithmetic and conversions | ✅ Complete |
|
|
328
|
+
| **0.5.x** | Unit Systems | `BasisTransform`, `UnitSystem`, cross-basis conversion | ✅ Complete |
|
|
329
|
+
| **0.6.x** | Pydantic Integration | Type-safe quantity validation | ⏳ Planned |
|
|
330
|
+
| **0.7.x** | NumPy Arrays | Vectorized conversion and arithmetic | ⏳ Planned |
|
|
229
331
|
|
|
230
332
|
See full roadmap: [ROADMAP.md](./ROADMAP.md)
|
|
231
333
|
|
|
@@ -30,6 +30,7 @@ It combines **units**, **scales**, and **dimensions** into a composable algebra
|
|
|
30
30
|
- Scale-aware arithmetic via `UnitFactor` and `UnitProduct`
|
|
31
31
|
- Metric and binary prefixes (`kilo`, `kibi`, `micro`, `mebi`, etc.)
|
|
32
32
|
- Pseudo-dimensions for angles, solid angles, and ratios with semantic isolation
|
|
33
|
+
- Uncertainty propagation through arithmetic and conversions
|
|
33
34
|
- A clean foundation for physics, chemistry, data modeling, and beyond
|
|
34
35
|
|
|
35
36
|
Think of it as **`decimal.Decimal` for the physical world** — precise, predictable, and type-safe.
|
|
@@ -54,6 +55,9 @@ To best answer this question, we turn to an age-old technique ([dimensional anal
|
|
|
54
55
|
| **`Ratio`** | `ucon.core` | Represents the division of two `Number` objects; captures relationships between quantities. | Expressing rates, densities, efficiencies (e.g., energy / time = power, length / time = velocity). |
|
|
55
56
|
| **`Map`** hierarchy | `ucon.maps` | Composable conversion morphisms: `LinearMap`, `AffineMap`, `ComposedMap`. | Defining conversion functions between units (e.g., meter→foot, celsius→kelvin). |
|
|
56
57
|
| **`ConversionGraph`** | `ucon.graph` | Registry of unit conversion edges with BFS path composition. | Converting between units via `Number.to(target)`; managing default and custom graphs. |
|
|
58
|
+
| **`UnitSystem`** | `ucon.core` | Named mapping from dimensions to base units (e.g., SI, Imperial). | Defining coherent unit systems; grouping base units by dimension. |
|
|
59
|
+
| **`BasisTransform`** | `ucon.core` | Matrix-based transformation between dimensional exponent spaces. | Converting between incompatible dimensional structures; exact arithmetic with `Fraction`. |
|
|
60
|
+
| **`RebasedUnit`** | `ucon.core` | A unit rebased to another system's dimension, preserving provenance. | Cross-basis conversions; tracking original unit through basis changes. |
|
|
57
61
|
| **`units` module** | `ucon.units` | Defines canonical unit instances (SI, imperial, information, and derived units). | Quick access to standard physical units (`units.meter`, `units.foot`, `units.byte`, etc.). |
|
|
58
62
|
|
|
59
63
|
### Under the Hood
|
|
@@ -178,6 +182,102 @@ print(ratio.to(units.ppm)) # <500000.0 ppm>
|
|
|
178
182
|
units.radian(1).to(units.percent) # raises ConversionNotFound
|
|
179
183
|
```
|
|
180
184
|
|
|
185
|
+
Uncertainty propagates through arithmetic and conversions:
|
|
186
|
+
```python
|
|
187
|
+
from ucon import units
|
|
188
|
+
|
|
189
|
+
# Measurements with uncertainty
|
|
190
|
+
length = units.meter(1.234, uncertainty=0.005)
|
|
191
|
+
width = units.meter(0.567, uncertainty=0.003)
|
|
192
|
+
|
|
193
|
+
print(length) # <1.234 ± 0.005 m>
|
|
194
|
+
|
|
195
|
+
# Uncertainty propagates through arithmetic (quadrature)
|
|
196
|
+
area = length * width
|
|
197
|
+
print(area) # <0.699678 ± 0.00424... m²>
|
|
198
|
+
|
|
199
|
+
# Uncertainty propagates through conversion
|
|
200
|
+
length_ft = length.to(units.foot)
|
|
201
|
+
print(length_ft) # <4.048... ± 0.0164... ft>
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
Unit systems and basis transforms enable conversions between incompatible dimensional structures.
|
|
205
|
+
This goes beyond simple unit conversion (meter → foot) into structural transformation:
|
|
206
|
+
|
|
207
|
+
```python
|
|
208
|
+
from fractions import Fraction
|
|
209
|
+
from ucon import BasisTransform, Dimension, Unit, UnitSystem, units
|
|
210
|
+
from ucon.graph import ConversionGraph
|
|
211
|
+
from ucon.maps import LinearMap
|
|
212
|
+
|
|
213
|
+
# The realm of Valdris has three fundamental dimensions:
|
|
214
|
+
# - Aether (A): magical energy substrate
|
|
215
|
+
# - Resonance (R): vibrational frequency of magic
|
|
216
|
+
# - Substance (S): physical matter
|
|
217
|
+
#
|
|
218
|
+
# These combine into SI dimensions via a transformation matrix:
|
|
219
|
+
#
|
|
220
|
+
# | L | | 2 0 0 | | A |
|
|
221
|
+
# | M | = | 1 0 1 | × | R |
|
|
222
|
+
# | T | |-2 -1 0 | | S |
|
|
223
|
+
#
|
|
224
|
+
# Reading the columns:
|
|
225
|
+
# - 1 aether contributes: L², M, T⁻² (energy-like)
|
|
226
|
+
# - 1 resonance contributes: T⁻¹ (frequency-like)
|
|
227
|
+
# - 1 substance contributes: M (mass-like)
|
|
228
|
+
|
|
229
|
+
# Fantasy base units
|
|
230
|
+
mote = Unit(name='mote', dimension=Dimension.energy, aliases=('mt',))
|
|
231
|
+
chime = Unit(name='chime', dimension=Dimension.frequency, aliases=('ch',))
|
|
232
|
+
ite = Unit(name='ite', dimension=Dimension.mass, aliases=('it',))
|
|
233
|
+
|
|
234
|
+
valdris = UnitSystem(
|
|
235
|
+
name="Valdris",
|
|
236
|
+
bases={
|
|
237
|
+
Dimension.energy: mote,
|
|
238
|
+
Dimension.frequency: chime,
|
|
239
|
+
Dimension.mass: ite,
|
|
240
|
+
}
|
|
241
|
+
)
|
|
242
|
+
|
|
243
|
+
# The basis transform encodes how Valdris dimensions compose into SI
|
|
244
|
+
valdris_to_si = BasisTransform(
|
|
245
|
+
src=valdris,
|
|
246
|
+
dst=units.si,
|
|
247
|
+
src_dimensions=(Dimension.energy, Dimension.frequency, Dimension.mass),
|
|
248
|
+
dst_dimensions=(Dimension.energy, Dimension.frequency, Dimension.mass),
|
|
249
|
+
matrix=(
|
|
250
|
+
(2, 0, 0), # energy: 2 × aether
|
|
251
|
+
(1, 0, 1), # frequency: aether + substance
|
|
252
|
+
(-2, -1, 0), # mass: -2×aether - resonance
|
|
253
|
+
),
|
|
254
|
+
)
|
|
255
|
+
|
|
256
|
+
# Physical calibration: how many SI units per fantasy unit
|
|
257
|
+
graph = ConversionGraph()
|
|
258
|
+
graph.connect_systems(
|
|
259
|
+
basis_transform=valdris_to_si,
|
|
260
|
+
edges={
|
|
261
|
+
(mote, units.joule): LinearMap(42), # 1 mote = 42 J
|
|
262
|
+
(chime, units.hertz): LinearMap(7), # 1 chime = 7 Hz
|
|
263
|
+
(ite, units.kilogram): LinearMap(Fraction(1, 2)), # 1 ite = 0.5 kg
|
|
264
|
+
}
|
|
265
|
+
)
|
|
266
|
+
|
|
267
|
+
# Game engine converts between physics systems
|
|
268
|
+
energy_map = graph.convert(src=mote, dst=units.joule)
|
|
269
|
+
energy_map(10) # 420 joules from 10 motes
|
|
270
|
+
|
|
271
|
+
# Inverse: display real-world values in game units
|
|
272
|
+
joule_to_mote = graph.convert(src=units.joule, dst=mote)
|
|
273
|
+
joule_to_mote(420) # 10 motes
|
|
274
|
+
|
|
275
|
+
# The transform is invertible with exact Fraction arithmetic
|
|
276
|
+
valdris_to_si.is_invertible # True
|
|
277
|
+
```
|
|
278
|
+
|
|
279
|
+
This enables fantasy game physics, or any field where the dimensional structure differs from SI.
|
|
280
|
+
|
|
181
281
|
---
|
|
182
282
|
|
|
183
283
|
## Roadmap Highlights
|
|
@@ -187,8 +287,10 @@ units.radian(1).to(units.percent) # raises ConversionNotFound
|
|
|
187
287
|
| **0.3.x** | Dimensional Algebra | Unit/Scale separation, `UnitFactor`, `UnitProduct` | ✅ Complete |
|
|
188
288
|
| **0.4.x** | Conversion System | `ConversionGraph`, `Number.to()`, callable units | ✅ Complete |
|
|
189
289
|
| **0.5.0** | Dimensionless Units | Pseudo-dimensions for angle, solid angle, ratio | ✅ Complete |
|
|
190
|
-
| **0.5.x** |
|
|
191
|
-
| **0.
|
|
290
|
+
| **0.5.x** | Uncertainty | Propagation through arithmetic and conversions | ✅ Complete |
|
|
291
|
+
| **0.5.x** | Unit Systems | `BasisTransform`, `UnitSystem`, cross-basis conversion | ✅ Complete |
|
|
292
|
+
| **0.6.x** | Pydantic Integration | Type-safe quantity validation | ⏳ Planned |
|
|
293
|
+
| **0.7.x** | NumPy Arrays | Vectorized conversion and arithmetic | ⏳ Planned |
|
|
192
294
|
|
|
193
295
|
See full roadmap: [ROADMAP.md](./ROADMAP.md)
|
|
194
296
|
|
|
@@ -23,10 +23,10 @@ ucon is a dimensional analysis library for engineers building systems where unit
|
|
|
23
23
|
| v0.3.x | Dimensional Algebra | Complete |
|
|
24
24
|
| v0.4.x | Core Conversion + Information | Complete |
|
|
25
25
|
| v0.5.0 | Dimensionless Units | Complete |
|
|
26
|
-
| v0.5.x | Uncertainty Propagation |
|
|
27
|
-
| v0.5.x |
|
|
28
|
-
| v0.6.0 |
|
|
29
|
-
| v0.7.0 |
|
|
26
|
+
| v0.5.x | Uncertainty Propagation | Complete |
|
|
27
|
+
| v0.5.x | BasisTransform + UnitSystem | Complete |
|
|
28
|
+
| v0.6.0 | Pydantic + Serialization | Planned |
|
|
29
|
+
| v0.7.0 | NumPy Array Support | Planned |
|
|
30
30
|
| v0.8.0 | String Parsing | Planned |
|
|
31
31
|
| v0.9.0 | Constants + Logarithmic Units | Planned |
|
|
32
32
|
| v0.10.0 | DataFrame Integration | Planned |
|
|
@@ -34,17 +34,21 @@ ucon is a dimensional analysis library for engineers building systems where unit
|
|
|
34
34
|
|
|
35
35
|
---
|
|
36
36
|
|
|
37
|
-
## Current Version: **v0.5.x** (
|
|
37
|
+
## Current Version: **v0.5.x** (complete)
|
|
38
38
|
|
|
39
39
|
Building on v0.5.0 baseline:
|
|
40
|
-
- `ucon.core` (`Dimension`, `Scale`, `Unit`, `UnitFactor`, `UnitProduct`, `Number`, `Ratio`)
|
|
41
|
-
- `ucon.maps` (`Map`, `LinearMap`, `AffineMap`, `ComposedMap`)
|
|
42
|
-
- `ucon.graph` (`ConversionGraph`, default graph, `get_default_graph()`, `using_graph()
|
|
43
|
-
- `ucon.units` (SI + imperial + information + angle + ratio units, callable syntax)
|
|
40
|
+
- `ucon.core` (`Dimension`, `Scale`, `Unit`, `UnitFactor`, `UnitProduct`, `Number`, `Ratio`, `UnitSystem`, `BasisTransform`, `RebasedUnit`)
|
|
41
|
+
- `ucon.maps` (`Map`, `LinearMap`, `AffineMap`, `ComposedMap` with `derivative()`)
|
|
42
|
+
- `ucon.graph` (`ConversionGraph`, default graph, `get_default_graph()`, `using_graph()`, cross-basis conversion)
|
|
43
|
+
- `ucon.units` (SI + imperial + information + angle + ratio units, callable syntax, `si` and `imperial` systems)
|
|
44
|
+
- `ucon.algebra` (`Vector` with `Fraction` exponents, `Exponent`)
|
|
44
45
|
- Callable unit API: `meter(5)`, `(mile / hour)(60)`
|
|
45
46
|
- `Number.simplify()` for base-scale normalization
|
|
46
47
|
- `Dimension.information` with `units.bit`, `units.byte`
|
|
47
48
|
- Pseudo-dimensions: `angle`, `solid_angle`, `ratio` with semantic isolation
|
|
49
|
+
- Uncertainty propagation: `meter(1.234, uncertainty=0.005)` with quadrature arithmetic
|
|
50
|
+
- `BasisTransform` for cross-system dimensional mapping with exact matrix arithmetic
|
|
51
|
+
- `UnitSystem` for named dimension-to-unit groupings
|
|
48
52
|
|
|
49
53
|
---
|
|
50
54
|
|
|
@@ -116,15 +120,15 @@ Building on v0.5.0 baseline:
|
|
|
116
120
|
|
|
117
121
|
---
|
|
118
122
|
|
|
119
|
-
## v0.5.x — Uncertainty Propagation
|
|
123
|
+
## v0.5.x — Uncertainty Propagation (Complete)
|
|
120
124
|
|
|
121
125
|
**Theme:** Metrology foundation.
|
|
122
126
|
|
|
123
|
-
- [
|
|
124
|
-
- [
|
|
125
|
-
- [
|
|
126
|
-
- [
|
|
127
|
-
- [
|
|
127
|
+
- [x] `Number.uncertainty: float | None`
|
|
128
|
+
- [x] Propagation through arithmetic (uncorrelated, quadrature)
|
|
129
|
+
- [x] Propagation through conversion via `Map.derivative()`
|
|
130
|
+
- [x] Construction: `meter(1.234, uncertainty=0.005)`
|
|
131
|
+
- [x] Display: `1.234 ± 0.005 meter`
|
|
128
132
|
|
|
129
133
|
**Outcomes:**
|
|
130
134
|
- First-class uncertainty support for scientific and engineering workflows
|
|
@@ -133,40 +137,31 @@ Building on v0.5.0 baseline:
|
|
|
133
137
|
|
|
134
138
|
---
|
|
135
139
|
|
|
136
|
-
## v0.5.x —
|
|
140
|
+
## v0.5.x — BasisTransform + UnitSystem (Complete)
|
|
137
141
|
|
|
138
142
|
**Theme:** Cross-system architecture.
|
|
139
143
|
|
|
140
|
-
- [
|
|
141
|
-
- [
|
|
142
|
-
- [
|
|
143
|
-
- [
|
|
144
|
-
- [
|
|
144
|
+
- [x] `Vector` with `Fraction` exponents for exact arithmetic
|
|
145
|
+
- [x] `UnitSystem` class (named dimension-to-unit mapping)
|
|
146
|
+
- [x] `BasisTransform` class (matrix-based dimensional basis transformation)
|
|
147
|
+
- [x] `RebasedUnit` class (provenance-preserving cross-basis unit)
|
|
148
|
+
- [x] `NonInvertibleTransform` exception for surjective transforms
|
|
149
|
+
- [x] Prebuilt systems: `units.si`, `units.imperial`
|
|
150
|
+
- [x] `graph.add_edge()` with `basis_transform` parameter
|
|
151
|
+
- [x] `graph.connect_systems()` for bulk edge creation
|
|
152
|
+
- [x] Cross-basis conversion via rebased paths
|
|
153
|
+
- [x] Introspection: `list_transforms()`, `list_rebased_units()`, `edges_for_transform()`
|
|
145
154
|
|
|
146
155
|
**Outcomes:**
|
|
147
|
-
- `
|
|
156
|
+
- `BasisTransform` enables conversions between incompatible dimensional structures
|
|
157
|
+
- Matrix operations with exact `Fraction` arithmetic (no floating-point drift)
|
|
158
|
+
- Invertibility detection with clear error messages for surjective transforms
|
|
148
159
|
- Named unit systems for domain-specific workflows
|
|
149
|
-
- Foundation for
|
|
160
|
+
- Foundation for custom dimension domains
|
|
150
161
|
|
|
151
162
|
---
|
|
152
163
|
|
|
153
|
-
## v0.6.0 —
|
|
154
|
-
|
|
155
|
-
**Theme:** Scientific computing integration.
|
|
156
|
-
|
|
157
|
-
- [ ] `Number` wraps `np.ndarray` values
|
|
158
|
-
- [ ] Vectorized conversion
|
|
159
|
-
- [ ] Vectorized arithmetic with uncertainty propagation
|
|
160
|
-
- [ ] Performance benchmarks
|
|
161
|
-
|
|
162
|
-
**Outcomes:**
|
|
163
|
-
- Seamless integration with NumPy-based scientific workflows
|
|
164
|
-
- Efficient batch conversions for large datasets
|
|
165
|
-
- Performance characteristics documented and optimized
|
|
166
|
-
|
|
167
|
-
---
|
|
168
|
-
|
|
169
|
-
## v0.7.0 — Pydantic + Serialization
|
|
164
|
+
## v0.6.0 — Pydantic + Serialization
|
|
170
165
|
|
|
171
166
|
**Theme:** API and persistence integration.
|
|
172
167
|
|
|
@@ -182,6 +177,22 @@ Building on v0.5.0 baseline:
|
|
|
182
177
|
|
|
183
178
|
---
|
|
184
179
|
|
|
180
|
+
## v0.7.0 — NumPy Array Support
|
|
181
|
+
|
|
182
|
+
**Theme:** Scientific computing integration.
|
|
183
|
+
|
|
184
|
+
- [ ] `Number` wraps `np.ndarray` values
|
|
185
|
+
- [ ] Vectorized conversion
|
|
186
|
+
- [ ] Vectorized arithmetic with uncertainty propagation
|
|
187
|
+
- [ ] Performance benchmarks
|
|
188
|
+
|
|
189
|
+
**Outcomes:**
|
|
190
|
+
- Seamless integration with NumPy-based scientific workflows
|
|
191
|
+
- Efficient batch conversions for large datasets
|
|
192
|
+
- Performance characteristics documented and optimized
|
|
193
|
+
|
|
194
|
+
---
|
|
195
|
+
|
|
185
196
|
## v0.8.0 — String Parsing
|
|
186
197
|
|
|
187
198
|
**Theme:** Ergonomic input.
|