unitx 0.8.2__tar.gz → 0.8.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.
- {unitx-0.8.2 → unitx-0.8.4}/CHANGELOG.md +37 -0
- {unitx-0.8.2 → unitx-0.8.4}/PKG-INFO +45 -22
- {unitx-0.8.2 → unitx-0.8.4}/README.md +43 -20
- {unitx-0.8.2 → unitx-0.8.4}/docs/numpy.md +105 -17
- unitx-0.8.4/examples/README.md +52 -0
- unitx-0.8.4/examples/blackbody.ipynb +143 -0
- unitx-0.8.4/examples/damped_oscillator.ipynb +153 -0
- unitx-0.8.4/examples/gaussian_wavepacket.ipynb +149 -0
- unitx-0.8.4/examples/optical_attenuation.ipynb +176 -0
- unitx-0.8.4/examples/pendulum_uncertainty.ipynb +188 -0
- {unitx-0.8.2 → unitx-0.8.4}/pyproject.toml +2 -2
- {unitx-0.8.2 → unitx-0.8.4}/pyrightconfig.json +3 -1
- {unitx-0.8.2 → unitx-0.8.4}/src/unitx/_numpy.py +155 -41
- {unitx-0.8.2 → unitx-0.8.4}/src/unitx/quantity.py +9 -22
- unitx-0.8.4/tests/_notebooks.py +11 -0
- {unitx-0.8.2 → unitx-0.8.4}/tests/numpy_typing/check_numpy.py +17 -0
- unitx-0.8.4/tests/test_examples.py +42 -0
- {unitx-0.8.2 → unitx-0.8.4}/tests/test_numpy.py +17 -13
- unitx-0.8.4/tests/test_numpy_integration.py +93 -0
- unitx-0.8.4/tests/test_numpy_outputs.py +229 -0
- unitx-0.8.4/tests/test_numpy_products.py +296 -0
- {unitx-0.8.2 → unitx-0.8.4}/tests/test_typing.py +17 -9
- unitx-0.8.2/examples/blackbody.py +0 -20
- unitx-0.8.2/pyrightconfig.asarray.json +0 -5
- unitx-0.8.2/pyrightconfig.examples.json +0 -5
- unitx-0.8.2/pyrightconfig.numpy.json +0 -5
- unitx-0.8.2/pyrightconfig.scalar.json +0 -5
- {unitx-0.8.2 → unitx-0.8.4}/.github/workflows/ci.yml +0 -0
- {unitx-0.8.2 → unitx-0.8.4}/.github/workflows/release.yml +0 -0
- {unitx-0.8.2 → unitx-0.8.4}/.gitignore +0 -0
- {unitx-0.8.2 → unitx-0.8.4}/LICENSE +0 -0
- {unitx-0.8.2 → unitx-0.8.4}/conftest.py +0 -0
- {unitx-0.8.2 → unitx-0.8.4}/docs/images/blackbody.png +0 -0
- {unitx-0.8.2 → unitx-0.8.4}/docs/migration.md +0 -0
- {unitx-0.8.2 → unitx-0.8.4}/docs/scalars.md +0 -0
- {unitx-0.8.2 → unitx-0.8.4}/docs/units.md +0 -0
- {unitx-0.8.2 → unitx-0.8.4}/src/unitx/__init__.py +0 -0
- {unitx-0.8.2 → unitx-0.8.4}/src/unitx/_constnamespace.py +0 -0
- {unitx-0.8.2 → unitx-0.8.4}/src/unitx/_numerics.py +0 -0
- {unitx-0.8.2 → unitx-0.8.4}/src/unitx/_numpy_typing.py +0 -0
- {unitx-0.8.2 → unitx-0.8.4}/src/unitx/_unicode.py +0 -0
- {unitx-0.8.2 → unitx-0.8.4}/src/unitx/dimension.py +0 -0
- {unitx-0.8.2 → unitx-0.8.4}/src/unitx/exceptions.py +0 -0
- {unitx-0.8.2 → unitx-0.8.4}/src/unitx/factor.py +0 -0
- {unitx-0.8.2 → unitx-0.8.4}/src/unitx/monomial.py +0 -0
- {unitx-0.8.2 → unitx-0.8.4}/src/unitx/py.typed +0 -0
- {unitx-0.8.2 → unitx-0.8.4}/src/unitx/si/__init__.py +0 -0
- {unitx-0.8.2 → unitx-0.8.4}/src/unitx/si/bases.py +0 -0
- {unitx-0.8.2 → unitx-0.8.4}/src/unitx/si/constants.py +0 -0
- {unitx-0.8.2 → unitx-0.8.4}/src/unitx/si/units.py +0 -0
- {unitx-0.8.2 → unitx-0.8.4}/src/unitx/singleunit.py +0 -0
- {unitx-0.8.2 → unitx-0.8.4}/src/unitx/unit.py +0 -0
- {unitx-0.8.2 → unitx-0.8.4}/src/unitx/unitparser.py +0 -0
- {unitx-0.8.2 → unitx-0.8.4}/src/unitx/unitregistry.py +0 -0
- {unitx-0.8.2 → unitx-0.8.4}/tests/__init__.py +0 -0
- {unitx-0.8.2 → unitx-0.8.4}/tests/example_typing/check_blackbody.py +0 -0
- {unitx-0.8.2 → unitx-0.8.4}/tests/test_builtin_definitions.py +0 -0
- {unitx-0.8.2 → unitx-0.8.4}/tests/test_dimension.py +0 -0
- {unitx-0.8.2 → unitx-0.8.4}/tests/test_factor.py +0 -0
- {unitx-0.8.2 → unitx-0.8.4}/tests/test_import.py +0 -0
- {unitx-0.8.2 → unitx-0.8.4}/tests/test_monomial.py +0 -0
- {unitx-0.8.2 → unitx-0.8.4}/tests/test_numeric.py +0 -0
- {unitx-0.8.2 → unitx-0.8.4}/tests/test_quantity.py +0 -0
- {unitx-0.8.2 → unitx-0.8.4}/tests/test_si.py +0 -0
- {unitx-0.8.2 → unitx-0.8.4}/tests/test_singleunit.py +0 -0
- {unitx-0.8.2 → unitx-0.8.4}/tests/test_unicode.py +0 -0
- {unitx-0.8.2 → unitx-0.8.4}/tests/test_unit.py +0 -0
- {unitx-0.8.2 → unitx-0.8.4}/tests/test_unit_definition.py +0 -0
- {unitx-0.8.2 → unitx-0.8.4}/tests/test_unitparser.py +0 -0
- {unitx-0.8.2 → unitx-0.8.4}/tests/test_unitregistry.py +0 -0
- {unitx-0.8.2 → unitx-0.8.4}/tests/test_warnings.py +0 -0
- {unitx-0.8.2 → unitx-0.8.4}/tests/typing/check_quantity.py +0 -0
- {unitx-0.8.2 → unitx-0.8.4}/tests/typing/check_si.py +0 -0
|
@@ -1,5 +1,42 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [0.8.4] - 2026-10-20
|
|
4
|
+
|
|
5
|
+
### Added
|
|
6
|
+
|
|
7
|
+
- Support prod and multiply.reduce with exact product units, scalar initial
|
|
8
|
+
values (including Quantities), boolean input masks, and staged output writes.
|
|
9
|
+
Require equal selected counts for dimensional outputs; normalize dimensionless
|
|
10
|
+
inputs before reduction. Document empty products and accumulator dtype rules.
|
|
11
|
+
- Support trapezoid integration with Quantity ordinates, coordinates, or scalar
|
|
12
|
+
spacing. Combine their units directly, preserving native coordinate order
|
|
13
|
+
and axis behavior without manual value extraction or unit reconstruction.
|
|
14
|
+
|
|
15
|
+
### Improved
|
|
16
|
+
|
|
17
|
+
- Keep Python-comparison-to-ufunc mapping in the optional NumPy adapter and
|
|
18
|
+
replace redundant Fractionable type guards with direct isinstance checks.
|
|
19
|
+
|
|
20
|
+
### Examples
|
|
21
|
+
|
|
22
|
+
- Replace the blackbody script with a notebook and add damped motion, free
|
|
23
|
+
Gaussian wave-packet propagation, optical attenuation, and correlated
|
|
24
|
+
measurement-uncertainty notebooks. Keep calculations as Quantities and derive
|
|
25
|
+
plot labels from their units. Check execution, typing, and output-free notebook
|
|
26
|
+
files without adding Jupyter as a library or test dependency.
|
|
27
|
+
|
|
28
|
+
## [0.8.3] - 2026-10-20
|
|
29
|
+
|
|
30
|
+
### Added
|
|
31
|
+
|
|
32
|
+
- Support unit-aware `out` for sum, mean, median, std, var, cumsum,
|
|
33
|
+
concatenate, stack, and add.reduce/accumulate. Require the exact result shape,
|
|
34
|
+
preserve target identity, unit, and dtype, and stage computation, conversion,
|
|
35
|
+
and casting before writing. Argmin/argmax accept bare integer ndarray outputs.
|
|
36
|
+
- Document function/reduction output casting and add regressions for scaled
|
|
37
|
+
units, positional outputs, overlapping/strided buffers, and unchanged outputs
|
|
38
|
+
on failure, plus installed-consumer type checks.
|
|
39
|
+
|
|
3
40
|
## [0.8.2] - 2026-10-20
|
|
4
41
|
|
|
5
42
|
### Fixed
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: unitx
|
|
3
|
-
Version: 0.8.
|
|
4
|
-
Summary: A modern, intuitive
|
|
3
|
+
Version: 0.8.4
|
|
4
|
+
Summary: A modern, intuitive unit library, with exact unit algebra, expressive type hints, and NumPy integration.
|
|
5
5
|
Project-URL: Homepage, https://github.com/DaitTHU/unitx
|
|
6
6
|
Project-URL: Issues, https://github.com/DaitTHU/unitx/issues
|
|
7
7
|
Author: Dait
|
|
@@ -28,31 +28,37 @@ Description-Content-Type: text/markdown
|
|
|
28
28
|
[](https://pypi.org/project/unitx/)
|
|
29
29
|
[](LICENSE)
|
|
30
30
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
31
|
+
A modern, intuitive unit library for Python 3.12+.
|
|
32
|
+
Exact unit algebra, expressive type hints, and NumPy integration.
|
|
33
|
+
|
|
34
|
+
Write physical formulas with units and constants in Python. `unitx` provides
|
|
35
|
+
unit conversion and dimensional analysis for Python scalars and integrates
|
|
36
|
+
with NumPy array arithmetic, broadcasting, and supported functions.
|
|
37
|
+
Unit scales and rational exponents retain their exact structure.
|
|
34
38
|
|
|
35
39
|
The library is in early development; public APIs may change during the 0.x series.
|
|
36
40
|
|
|
37
41
|
## Install
|
|
38
42
|
|
|
39
|
-
Python **3.12 or later** is required.
|
|
40
|
-
runtime dependencies:
|
|
43
|
+
Python **3.12 or later** is required. Install unitx with:
|
|
41
44
|
|
|
42
45
|
```sh
|
|
43
|
-
|
|
46
|
+
pip install unitx
|
|
44
47
|
```
|
|
45
48
|
|
|
46
|
-
|
|
49
|
+
There are no mandatory runtime dependencies. If you already use NumPy **2.1
|
|
50
|
+
or later**, this installation also lets you use units in your NumPy calculations.
|
|
51
|
+
For NumPy work in a new environment or with an older NumPy version, use the
|
|
52
|
+
following command to install unitx and a compatible NumPy version:
|
|
47
53
|
|
|
48
54
|
```sh
|
|
49
|
-
|
|
55
|
+
pip install 'unitx[numpy]'
|
|
50
56
|
```
|
|
51
57
|
|
|
52
|
-
For development, install into
|
|
58
|
+
For development, install into your active Python environment:
|
|
53
59
|
|
|
54
60
|
```sh
|
|
55
|
-
|
|
61
|
+
pip install -e '.[test,numpy]'
|
|
56
62
|
```
|
|
57
63
|
|
|
58
64
|
This README describes the current source tree. For an older release, consult
|
|
@@ -60,8 +66,17 @@ its matching Git tag.
|
|
|
60
66
|
|
|
61
67
|
## Start with units and constants
|
|
62
68
|
|
|
63
|
-
`si` provides units
|
|
64
|
-
|
|
69
|
+
The `unitx.si` submodule provides ready-to-use units and physical constants
|
|
70
|
+
based on the International System of Units (SI), through two read-only
|
|
71
|
+
namespaces:
|
|
72
|
+
|
|
73
|
+
- `si` contains units such as `si.m`, `si.s`, and `si.MeV`, including common
|
|
74
|
+
prefixes and non-SI units.
|
|
75
|
+
- `SI` contains physical constants expressed in SI units, such as the speed
|
|
76
|
+
of light `SI.c` and the Planck constant `SI.h`.
|
|
77
|
+
|
|
78
|
+
In the import below, `unitx.si` is the module path; the imported `si` and `SI`
|
|
79
|
+
are the namespaces you use directly in formulas:
|
|
65
80
|
|
|
66
81
|
```pycon
|
|
67
82
|
>>> from unitx.si import SI, si
|
|
@@ -85,10 +100,13 @@ division combine units; addition and subtraction align compatible quantities
|
|
|
85
100
|
to the left operand's unit. Incompatible conversions and arithmetic raise
|
|
86
101
|
`DimensionError`.
|
|
87
102
|
|
|
88
|
-
## NumPy
|
|
103
|
+
## Units in NumPy: blackbody radiation
|
|
89
104
|
|
|
90
|
-
|
|
91
|
-
|
|
105
|
+
Attach units to NumPy arrays, then use broadcasting and NumPy functions to
|
|
106
|
+
evaluate a physical formula. Here, a column of wavelengths and three
|
|
107
|
+
temperatures broadcast to give Planck's spectral radiance.
|
|
108
|
+
|
|
109
|
+
Add `matplotlib` to your environment to plot the result:
|
|
92
110
|
|
|
93
111
|
```python
|
|
94
112
|
import numpy as np
|
|
@@ -121,7 +139,7 @@ values in the catalogue and enter NumPy calculations as floats.
|
|
|
121
139
|
`.value_in(unit)` also converts it to a chosen unit. Implicit unit removal with
|
|
122
140
|
`np.asarray(quantity)` or `np.array(quantity)` raises TypeError.
|
|
123
141
|
|
|
124
|
-
The [
|
|
142
|
+
The [blackbody notebook](examples/blackbody.ipynb) uses `np.asarray([...]) * unit`
|
|
125
143
|
without an explicit dtype. This automatic construction inference is checked
|
|
126
144
|
with NumPy 2.5 stubs and Pyright; the example also runs on NumPy 2.1. Older
|
|
127
145
|
NumPy stubs may still infer Any for this expression. NumPy's own stubs can
|
|
@@ -131,6 +149,11 @@ infer different types for `np.array` and `np.asarray`;
|
|
|
131
149
|
shape/dtype inference and wrapped return types for every NumPy function are not
|
|
132
150
|
promised. See the [supported operations, storage rules, and typing limits](docs/numpy.md).
|
|
133
151
|
|
|
152
|
+
The [physics notebooks](examples/README.md) also cover damped motion, Gaussian
|
|
153
|
+
wave-packet spreading, optical attenuation, and correlated measurement uncertainty.
|
|
154
|
+
They include explanations and numerical checks; plots are generated when run,
|
|
155
|
+
keeping saved notebooks small.
|
|
156
|
+
|
|
134
157
|
## Values and conversion
|
|
135
158
|
|
|
136
159
|
Use `Quantity` and `Unit` directly when constructing values from strings:
|
|
@@ -219,7 +242,7 @@ copying, and serialization.
|
|
|
219
242
|
|
|
220
243
|
## Scope and types
|
|
221
244
|
|
|
222
|
-
- Supported magnitudes are Python scalars and
|
|
245
|
+
- Supported magnitudes are Python scalars and plain numeric NumPy
|
|
223
246
|
arrays/scalars. Other array backends, ndarray subclasses, object arrays,
|
|
224
247
|
and implicit list/tuple magnitudes are unsupported.
|
|
225
248
|
- Conversion uses multiplication by a scale. Offset temperature scales such
|
|
@@ -250,9 +273,9 @@ with `_` are internal.
|
|
|
250
273
|
Run the checks from the repository root:
|
|
251
274
|
|
|
252
275
|
```sh
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
276
|
+
pytest -q
|
|
277
|
+
ruff check .
|
|
278
|
+
ruff format --check .
|
|
256
279
|
python -m doctest README.md docs/units.md docs/scalars.md
|
|
257
280
|
```
|
|
258
281
|
|
|
@@ -4,31 +4,37 @@
|
|
|
4
4
|
[](https://pypi.org/project/unitx/)
|
|
5
5
|
[](LICENSE)
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
7
|
+
A modern, intuitive unit library for Python 3.12+.
|
|
8
|
+
Exact unit algebra, expressive type hints, and NumPy integration.
|
|
9
|
+
|
|
10
|
+
Write physical formulas with units and constants in Python. `unitx` provides
|
|
11
|
+
unit conversion and dimensional analysis for Python scalars and integrates
|
|
12
|
+
with NumPy array arithmetic, broadcasting, and supported functions.
|
|
13
|
+
Unit scales and rational exponents retain their exact structure.
|
|
10
14
|
|
|
11
15
|
The library is in early development; public APIs may change during the 0.x series.
|
|
12
16
|
|
|
13
17
|
## Install
|
|
14
18
|
|
|
15
|
-
Python **3.12 or later** is required.
|
|
16
|
-
runtime dependencies:
|
|
19
|
+
Python **3.12 or later** is required. Install unitx with:
|
|
17
20
|
|
|
18
21
|
```sh
|
|
19
|
-
|
|
22
|
+
pip install unitx
|
|
20
23
|
```
|
|
21
24
|
|
|
22
|
-
|
|
25
|
+
There are no mandatory runtime dependencies. If you already use NumPy **2.1
|
|
26
|
+
or later**, this installation also lets you use units in your NumPy calculations.
|
|
27
|
+
For NumPy work in a new environment or with an older NumPy version, use the
|
|
28
|
+
following command to install unitx and a compatible NumPy version:
|
|
23
29
|
|
|
24
30
|
```sh
|
|
25
|
-
|
|
31
|
+
pip install 'unitx[numpy]'
|
|
26
32
|
```
|
|
27
33
|
|
|
28
|
-
For development, install into
|
|
34
|
+
For development, install into your active Python environment:
|
|
29
35
|
|
|
30
36
|
```sh
|
|
31
|
-
|
|
37
|
+
pip install -e '.[test,numpy]'
|
|
32
38
|
```
|
|
33
39
|
|
|
34
40
|
This README describes the current source tree. For an older release, consult
|
|
@@ -36,8 +42,17 @@ its matching Git tag.
|
|
|
36
42
|
|
|
37
43
|
## Start with units and constants
|
|
38
44
|
|
|
39
|
-
`si` provides units
|
|
40
|
-
|
|
45
|
+
The `unitx.si` submodule provides ready-to-use units and physical constants
|
|
46
|
+
based on the International System of Units (SI), through two read-only
|
|
47
|
+
namespaces:
|
|
48
|
+
|
|
49
|
+
- `si` contains units such as `si.m`, `si.s`, and `si.MeV`, including common
|
|
50
|
+
prefixes and non-SI units.
|
|
51
|
+
- `SI` contains physical constants expressed in SI units, such as the speed
|
|
52
|
+
of light `SI.c` and the Planck constant `SI.h`.
|
|
53
|
+
|
|
54
|
+
In the import below, `unitx.si` is the module path; the imported `si` and `SI`
|
|
55
|
+
are the namespaces you use directly in formulas:
|
|
41
56
|
|
|
42
57
|
```pycon
|
|
43
58
|
>>> from unitx.si import SI, si
|
|
@@ -61,10 +76,13 @@ division combine units; addition and subtraction align compatible quantities
|
|
|
61
76
|
to the left operand's unit. Incompatible conversions and arithmetic raise
|
|
62
77
|
`DimensionError`.
|
|
63
78
|
|
|
64
|
-
## NumPy
|
|
79
|
+
## Units in NumPy: blackbody radiation
|
|
65
80
|
|
|
66
|
-
|
|
67
|
-
|
|
81
|
+
Attach units to NumPy arrays, then use broadcasting and NumPy functions to
|
|
82
|
+
evaluate a physical formula. Here, a column of wavelengths and three
|
|
83
|
+
temperatures broadcast to give Planck's spectral radiance.
|
|
84
|
+
|
|
85
|
+
Add `matplotlib` to your environment to plot the result:
|
|
68
86
|
|
|
69
87
|
```python
|
|
70
88
|
import numpy as np
|
|
@@ -97,7 +115,7 @@ values in the catalogue and enter NumPy calculations as floats.
|
|
|
97
115
|
`.value_in(unit)` also converts it to a chosen unit. Implicit unit removal with
|
|
98
116
|
`np.asarray(quantity)` or `np.array(quantity)` raises TypeError.
|
|
99
117
|
|
|
100
|
-
The [
|
|
118
|
+
The [blackbody notebook](examples/blackbody.ipynb) uses `np.asarray([...]) * unit`
|
|
101
119
|
without an explicit dtype. This automatic construction inference is checked
|
|
102
120
|
with NumPy 2.5 stubs and Pyright; the example also runs on NumPy 2.1. Older
|
|
103
121
|
NumPy stubs may still infer Any for this expression. NumPy's own stubs can
|
|
@@ -107,6 +125,11 @@ infer different types for `np.array` and `np.asarray`;
|
|
|
107
125
|
shape/dtype inference and wrapped return types for every NumPy function are not
|
|
108
126
|
promised. See the [supported operations, storage rules, and typing limits](docs/numpy.md).
|
|
109
127
|
|
|
128
|
+
The [physics notebooks](examples/README.md) also cover damped motion, Gaussian
|
|
129
|
+
wave-packet spreading, optical attenuation, and correlated measurement uncertainty.
|
|
130
|
+
They include explanations and numerical checks; plots are generated when run,
|
|
131
|
+
keeping saved notebooks small.
|
|
132
|
+
|
|
110
133
|
## Values and conversion
|
|
111
134
|
|
|
112
135
|
Use `Quantity` and `Unit` directly when constructing values from strings:
|
|
@@ -195,7 +218,7 @@ copying, and serialization.
|
|
|
195
218
|
|
|
196
219
|
## Scope and types
|
|
197
220
|
|
|
198
|
-
- Supported magnitudes are Python scalars and
|
|
221
|
+
- Supported magnitudes are Python scalars and plain numeric NumPy
|
|
199
222
|
arrays/scalars. Other array backends, ndarray subclasses, object arrays,
|
|
200
223
|
and implicit list/tuple magnitudes are unsupported.
|
|
201
224
|
- Conversion uses multiplication by a scale. Offset temperature scales such
|
|
@@ -226,9 +249,9 @@ with `_` are internal.
|
|
|
226
249
|
Run the checks from the repository root:
|
|
227
250
|
|
|
228
251
|
```sh
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
252
|
+
pytest -q
|
|
253
|
+
ruff check .
|
|
254
|
+
ruff format --check .
|
|
232
255
|
python -m doctest README.md docs/units.md docs/scalars.md
|
|
233
256
|
```
|
|
234
257
|
|
|
@@ -79,14 +79,15 @@ methods, mixed array types, and keywords fail explicitly.
|
|
|
79
79
|
| power, float_power / `**` | Dimensional bases require a finite real scalar exponent; dimensionless bases/exponents normalize their scales |
|
|
80
80
|
| sin, cos, tan, exp, expm1, log, log2, log10, log1p | Require coherent dimensionless values; return dimensionless Quantity |
|
|
81
81
|
| isfinite, isnan, isinf, signbit | Bare boolean results |
|
|
82
|
-
| add.reduce, add.accumulate | Preserve unit; accept axis
|
|
82
|
+
| add.reduce, add.accumulate | Preserve unit; accept axis, dtype, out, plus keepdims for reduce |
|
|
83
|
+
| multiply.reduce | Product unit rules below; accepts axis, dtype, keepdims, initial, where, out |
|
|
83
84
|
|
|
84
85
|
Ufunc `__call__` accepts `where`, `dtype`, `casting`, `order`, `subok`, and
|
|
85
86
|
single-output `out` as described below. Each kernel validates its own options.
|
|
86
87
|
`where` is a bare boolean scalar
|
|
87
88
|
or plain boolean ndarray; masked-out positions without an output buffer follow
|
|
88
89
|
NumPy's uninitialized-result behavior. Numeric outputs must stay in the
|
|
89
|
-
supported dtype domain. Product
|
|
90
|
+
supported dtype domain. Product accumulation, at, outer, and reduceat are
|
|
90
91
|
unsupported. Python `**` also accepts Fraction/Decimal exponents, retaining
|
|
91
92
|
exact unit exponents while passing a float exponent to the NumPy kernel.
|
|
92
93
|
Angles retain unitx's dimensionless model: deg/rad normalize before these
|
|
@@ -95,25 +96,89 @@ functions, including exp/log. Python scalar numerical semantics remain native.
|
|
|
95
96
|
| NumPy function | Unit/result rule | Supported options |
|
|
96
97
|
| --- | --- | --- |
|
|
97
98
|
| reshape, transpose | Preserve unit | shape/order/copy; axes |
|
|
98
|
-
| concatenate, stack | Convert to first Quantity's unit; bare arrays remain dimensionless | axis, dtype, casting |
|
|
99
|
-
| sum, mean | Preserve unit | axis, dtype, keepdims |
|
|
100
|
-
|
|
|
101
|
-
|
|
|
102
|
-
|
|
|
103
|
-
|
|
|
99
|
+
| concatenate, stack | Convert to first Quantity's unit; bare arrays remain dimensionless | axis, dtype, casting, out; dtype and out are mutually exclusive |
|
|
100
|
+
| sum, mean | Preserve unit | axis, dtype, keepdims, out |
|
|
101
|
+
| prod | Product unit rules below | axis, dtype, keepdims, initial, where, out |
|
|
102
|
+
| median | Preserve unit | axis, keepdims, out; overwrite_input=False |
|
|
103
|
+
| std, var | Preserve unit / square unit | axis, dtype, ddof, keepdims, out |
|
|
104
|
+
| cumsum | Preserve unit | axis, dtype, out |
|
|
105
|
+
| argmin, argmax | Bare indices | axis, keepdims, out |
|
|
106
|
+
| trapezoid | Multiply ordinate and coordinate units | x, scalar dx, axis; no out |
|
|
104
107
|
| isclose, allclose | Bare mask / Python bool | rtol, atol, equal_nan |
|
|
105
108
|
|
|
106
109
|
Supply the first magnitude argument positionally; concatenate/stack take a
|
|
107
110
|
sequence. Options follow each supported signature, including positional out
|
|
108
|
-
checks. Function and reduction
|
|
109
|
-
|
|
111
|
+
checks. Function and reduction outputs follow the rules below;
|
|
112
|
+
overwrite_input=True is rejected. Reduction/statistical `where` and `initial`
|
|
113
|
+
are supported only for prod/multiply.reduce. Unsupported mean, correction,
|
|
114
|
+
and other keywords raise TypeError.
|
|
110
115
|
There is no `__setitem__`; `q += other` creates a result and rebinds q.
|
|
111
116
|
|
|
112
|
-
|
|
117
|
+
`np.trapezoid(y, x=x)` accepts a Quantity for y, x, or both and returns a
|
|
118
|
+
Quantity with unit `y.unit * x.unit`; bare inputs are dimensionless. With
|
|
119
|
+
`x=None`, scalar `dx` supplies the coordinate unit instead (default: dimensionless
|
|
120
|
+
1). NumPy dispatches this function on y and x, so at least one of those must be
|
|
121
|
+
a Quantity to enter unitx; a Quantity supplied only as dx is insufficient.
|
|
122
|
+
Explicit x makes dx irrelevant. Numeric arrays, scalar spacing, axis handling,
|
|
123
|
+
coordinate order (including reversed or nonmonotonic x), broadcasting, and
|
|
124
|
+
empty intervals follow [NumPy trapezoid](https://numpy.org/doc/stable/reference/generated/numpy.trapezoid.html).
|
|
125
|
+
No coordinate sorting, interpolation, dtype option, or output buffer is added.
|
|
126
|
+
|
|
127
|
+
## Product reductions
|
|
128
|
+
|
|
129
|
+
`np.prod(q)` reduces all axes by default; `np.multiply.reduce(q)` defaults to
|
|
130
|
+
axis 0, following NumPy. Both accept scalar, negative, or tuple axes, `axis=None`,
|
|
131
|
+
`axis=()`, and `keepdims`. For dimensional input with unit U, each result has
|
|
132
|
+
unit `U**N`, where N is the number of selected input elements in that slice.
|
|
133
|
+
Zero-valued elements still count. All output slices must have the same N;
|
|
134
|
+
otherwise unitx raises DimensionError because a single Quantity cannot hold
|
|
135
|
+
different dimensions. `where` accepts the same bare boolean masks as ufunc
|
|
136
|
+
calls and broadcasts to the input shape. It selects input elements; every
|
|
137
|
+
output position is written when an output buffer is supplied.
|
|
138
|
+
|
|
139
|
+
An empty or fully masked product has value 1 and unit `U**0`, before applying
|
|
140
|
+
`initial`. If the output itself has no elements, the unit uses the nominal
|
|
141
|
+
reduced-axis extent; scalar `where=False` sets that extent to zero.
|
|
142
|
+
Dimensionless inputs, including deg and km/m, first convert to coherent
|
|
143
|
+
dimensionless values and produce unit `Unit()`. Their masked slices may have
|
|
144
|
+
different counts because the result still has a single coherent unit.
|
|
145
|
+
|
|
146
|
+
`initial` is a bare numeric scalar or a scalar Quantity, including NumPy
|
|
147
|
+
scalars and zero-dimensional arrays. A bare initial is dimensionless; a
|
|
148
|
+
Quantity initial contributes its own unit once, so the result unit is
|
|
149
|
+
`U**N * initial.unit`. An explicit zero still contributes its declared unit.
|
|
150
|
+
The default is dimensionless 1. `initial=None` uses NumPy's first-element
|
|
151
|
+
semantics and fails for empty reductions. NumPy controls the accumulator dtype,
|
|
152
|
+
including casting the initial value to that dtype; initial does not select
|
|
153
|
+
a wider numerical domain. Decimal/Fraction initial values enter NumPy as floats.
|
|
113
154
|
|
|
114
|
-
|
|
155
|
+
```python
|
|
156
|
+
lengths = Quantity(np.array([[2.0, 3, 4], [5, 6, 7]]), 'm')
|
|
157
|
+
selected = np.array([True, False, True])
|
|
158
|
+
areas = np.prod(lengths, axis=1, where=selected)
|
|
159
|
+
assert areas.unit == Unit('m2')
|
|
160
|
+
np.testing.assert_array_equal(areas.value, [8, 35])
|
|
161
|
+
weighted = np.multiply.reduce(lengths, axis=1, where=selected, initial=Quantity(2, 's'))
|
|
162
|
+
assert weighted.unit == Unit('m2 s')
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
Both entry points support the output rules below, including exact result
|
|
166
|
+
shape and unchanged targets on computation, unit, shape, or casting errors.
|
|
167
|
+
`cumprod` and `multiply.accumulate` remain unsupported: partial products
|
|
168
|
+
generally require different units at different positions. The supported
|
|
169
|
+
axis, empty-product, initial, and mask behavior follows
|
|
170
|
+
[NumPy prod](https://numpy.org/doc/stable/reference/generated/numpy.prod.html)
|
|
171
|
+
and [ufunc.reduce](https://numpy.org/doc/stable/reference/generated/numpy.ufunc.reduce.html),
|
|
172
|
+
with the additional single-unit and explicit-output rules described here.
|
|
173
|
+
|
|
174
|
+
## Output buffers
|
|
175
|
+
|
|
176
|
+
Supported single-output ufunc calls, add.reduce/accumulate, multiply.reduce, and the numeric
|
|
177
|
+
functions listed with `out` above accept a Quantity whose magnitude is a
|
|
115
178
|
writable plain numeric ndarray. `out=target`, `out=(target,)`, and positional
|
|
116
|
-
outputs return that same target
|
|
179
|
+
outputs for ufuncs return that same target; functions accept `out=target` or
|
|
180
|
+
the positional output argument in their NumPy signature, without a tuple.
|
|
181
|
+
The target's magnitude object, dtype, and unit stay
|
|
117
182
|
fixed. Zero-dimensional, empty, and noncontiguous output arrays are supported.
|
|
118
183
|
NumPy scalars and Python scalars cannot serve as output buffers.
|
|
119
184
|
|
|
@@ -127,7 +192,10 @@ converts that result to the target unit and casts it into a staging buffer.
|
|
|
127
192
|
The numerical kernel uses the input dtypes and any explicit `dtype`; the
|
|
128
193
|
target dtype is used for the final cast. This is not a promise of NumPy's
|
|
129
194
|
output-dependent kernel selection or allocation-free execution. Both the
|
|
130
|
-
result and `where` mask must broadcast to the target shape
|
|
195
|
+
result and `where` mask must broadcast to the target shape for ufunc calls.
|
|
196
|
+
Function and reduction outputs must have exactly the ordinary result's shape,
|
|
197
|
+
including axes retained by `keepdims`; they do not broadcast into a larger
|
|
198
|
+
target. Only true mask
|
|
131
199
|
positions are written; false positions retain their original target values.
|
|
132
200
|
Unit conversion also skips false positions. Input/output overlap and shared
|
|
133
201
|
slices are handled through temporaries; a mask sharing output storage is copied.
|
|
@@ -138,6 +206,8 @@ length target. `ScaledUnit` factors participate in the conversion. Every numeric
|
|
|
138
206
|
result, including a coherent or scaled dimensionless result, requires a Quantity
|
|
139
207
|
target; writing it to a bare ndarray would discard its unit. Boolean predicates
|
|
140
208
|
and comparisons instead accept only a bare boolean ndarray output.
|
|
209
|
+
`argmin` and `argmax` accept only a bare integer ndarray output, with the
|
|
210
|
+
same exact shape requirement as other function outputs.
|
|
141
211
|
|
|
142
212
|
Final casting uses `casting='same_kind'` by default, or the explicitly requested
|
|
143
213
|
NumPy casting policy. It does not silently enable `unsafe`; nonintegral unit
|
|
@@ -148,8 +218,24 @@ The final copy is not a general transaction against concurrent changes or
|
|
|
148
218
|
external buffer failures. Temporaries cost memory proportional to the result
|
|
149
219
|
and target; `out` provides controlled writes, not a zero-allocation guarantee.
|
|
150
220
|
|
|
151
|
-
|
|
152
|
-
|
|
221
|
+
Functions and supported reductions/accumulations use `same_kind` for the final cast and do
|
|
222
|
+
not accept a new `casting` keyword. Concatenate and stack use their existing
|
|
223
|
+
`casting` option for the final write as well as the kernel; their `dtype` and
|
|
224
|
+
`out` options cannot be combined. Index outputs also use `same_kind`, including
|
|
225
|
+
its allowance for integer narrowing. These policies intentionally do not
|
|
226
|
+
reproduce every function's native output casting rule. An explicit `dtype`
|
|
227
|
+
controls the temporary numerical computation for supported reductions; the
|
|
228
|
+
target dtype does not select the accumulator or kernel dtype.
|
|
229
|
+
|
|
230
|
+
```python
|
|
231
|
+
totals = Quantity(np.empty(3), 'cm')
|
|
232
|
+
assert np.sum(q, axis=0, out=totals) is totals
|
|
233
|
+
indices = np.empty(3, dtype=np.intp)
|
|
234
|
+
assert np.argmax(q, axis=0, out=indices) is indices
|
|
235
|
+
```
|
|
236
|
+
|
|
237
|
+
`out=None` and ufunc `out=(None,)` allocate ordinary results.
|
|
238
|
+
Multiple-output ufuncs and product accumulations remain unsupported.
|
|
153
239
|
Output writes preserve the magnitude's type and dtype, so the covariant
|
|
154
240
|
`Quantity[T]` contract remains valid; no setter or arbitrary replacement of T
|
|
155
241
|
is introduced. NumPy's own stubs do not accept Quantity outputs or infer wrapped
|
|
@@ -196,7 +282,9 @@ NumPy's many arithmetic overloads against Scalar's own return protocol.
|
|
|
196
282
|
`_numpy_typing.py` imports concrete NumPy types only for static analysis; core
|
|
197
283
|
runtime imports still do not load NumPy. Strict scalar-consumer checks also
|
|
198
284
|
run with NumPy absent. Checking the full library's optional NumPy annotations
|
|
199
|
-
requires NumPy; `
|
|
285
|
+
requires NumPy; `pyright tests/typing` checks scalar consumers without it.
|
|
286
|
+
All checks share `pyrightconfig.json`; the test runner selects the input
|
|
287
|
+
directories and skips optional cases when their dependencies are unavailable.
|
|
200
288
|
|
|
201
289
|
NumPy's left-operand and function stubs do not generally describe every
|
|
202
290
|
unit-aware dispatch. With NumPy 2.5 stubs and Pyright 1.1.414, the documented
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
# Physics notebooks
|
|
2
|
+
|
|
3
|
+
These notebooks use unitx for dimensional calculations and NumPy for numerical
|
|
4
|
+
work. Each contains a model, assumptions, plots, and numerical checks. The
|
|
5
|
+
material parameters and measurement draws are illustrative, not experimental data.
|
|
6
|
+
|
|
7
|
+
| Notebook | Topic | unitx features |
|
|
8
|
+
| --- | --- | --- |
|
|
9
|
+
| [Blackbody radiation](blackbody.ipynb) | Planck spectra and Wien peak checks | Constants, broadcasting, spectral-density conversion |
|
|
10
|
+
| [Damped oscillator](damped_oscillator.ipynb) | Release from rest and energy loss | Dimensionless ufunc arguments, energy units, comparisons |
|
|
11
|
+
| [Gaussian wave packet](gaussian_wavepacket.ipynb) | Free electron propagation and uncertainty | Probability-density units, quantum constants, unit-aware integration |
|
|
12
|
+
| [Optical attenuation](optical_attenuation.ipynb) | Transmission through absorbing layers | prod/multiply.reduce, input masks, Quantity initial, fixed-unit out |
|
|
13
|
+
| [Pendulum uncertainty](pendulum_uncertainty.ipynb) | Correlated input uncertainties and Monte Carlo propagation | Mean/std/var units, mixed measurement units, explicit quantiles |
|
|
14
|
+
|
|
15
|
+
## Run
|
|
16
|
+
|
|
17
|
+
Use Python 3.12 or newer. From the repository root, install the current checkout
|
|
18
|
+
and notebook tools in the environment you will select as the Jupyter kernel:
|
|
19
|
+
|
|
20
|
+
```sh
|
|
21
|
+
python -m pip install -e '.[numpy]' matplotlib jupyterlab
|
|
22
|
+
jupyter lab examples/
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
Open a notebook and run all cells from the beginning. These notebooks require
|
|
26
|
+
unitx 0.8.4 or newer for product reductions and unit-aware integration.
|
|
27
|
+
The examples do not download datasets or write files. Keep physical quantities in calculations;
|
|
28
|
+
plot their `.value` and derive labels from their `.unit`. Convert only to choose
|
|
29
|
+
a useful display scale or to align units at a numerical boundary. Quantiles use
|
|
30
|
+
an explicit numerical boundary and reattach the input unit, without naming a
|
|
31
|
+
variable after its unit. Display equations use `$$...$$`.
|
|
32
|
+
|
|
33
|
+
## Keep Git history small
|
|
34
|
+
|
|
35
|
+
Commit only notebook source and minimal kernel metadata. Clear all outputs and
|
|
36
|
+
execution counts before committing; do not embed figures, widget state, or
|
|
37
|
+
attachments. Figures are regenerated when cells run. The test suite checks this
|
|
38
|
+
policy and executes the numerical examples when NumPy and Matplotlib are present.
|
|
39
|
+
|
|
40
|
+
To clear a notebook after running it, use JupyterLab's **Clear Outputs of All
|
|
41
|
+
Cells**, then save it. For a command-line cleanup using nbconvert:
|
|
42
|
+
|
|
43
|
+
```sh
|
|
44
|
+
python -m pip install nbconvert
|
|
45
|
+
jupyter nbconvert --clear-output --inplace examples/*.ipynb
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
The notebooks use ordinary Python code cells. Their code is also extracted for
|
|
49
|
+
the existing Pyright example check, without committing duplicate `.py` exports.
|
|
50
|
+
Assertions on NumPy results also check that dispatch retains the Quantity
|
|
51
|
+
wrapper. NumPy's stubs cannot describe every wrapped result; the optical
|
|
52
|
+
example documents local suppressions for its Quantity `initial` and `out` call.
|