unitx 0.17.2__tar.gz → 0.17.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.17.2 → unitx-0.17.4}/.github/consumers/arrays.py +100 -6
- {unitx-0.17.2 → unitx-0.17.4}/.github/consumers/scalars.py +15 -0
- {unitx-0.17.2 → unitx-0.17.4}/CHANGELOG.md +50 -0
- {unitx-0.17.2 → unitx-0.17.4}/CONTRIBUTING.md +7 -4
- {unitx-0.17.2 → unitx-0.17.4}/PKG-INFO +1 -1
- {unitx-0.17.2 → unitx-0.17.4}/docs/architecture.md +6 -0
- {unitx-0.17.2 → unitx-0.17.4}/docs/numpy/calculus.md +39 -4
- {unitx-0.17.2 → unitx-0.17.4}/docs/numpy/methods.md +12 -2
- {unitx-0.17.2 → unitx-0.17.4}/docs/numpy.md +7 -6
- {unitx-0.17.2 → unitx-0.17.4}/docs/stdlib.md +33 -6
- {unitx-0.17.2 → unitx-0.17.4}/docs/typing.md +122 -14
- {unitx-0.17.2 → unitx-0.17.4}/docs/units.md +17 -0
- {unitx-0.17.2 → unitx-0.17.4}/pyproject.toml +1 -1
- {unitx-0.17.2 → unitx-0.17.4}/src/unitx/_coordinates/points.py +4 -4
- unitx-0.17.4/src/unitx/_numerics/methods.py +31 -0
- {unitx-0.17.2 → unitx-0.17.4}/src/unitx/_numerics/numpy.py +36 -17
- {unitx-0.17.2 → unitx-0.17.4}/src/unitx/_numerics/numpy_typing.py +40 -3
- {unitx-0.17.2 → unitx-0.17.4}/src/unitx/affinequantity.py +60 -38
- {unitx-0.17.2 → unitx-0.17.4}/src/unitx/exceptions.py +11 -1
- {unitx-0.17.2 → unitx-0.17.4}/src/unitx/logquantity.py +60 -38
- {unitx-0.17.2 → unitx-0.17.4}/src/unitx/math.py +142 -61
- {unitx-0.17.2 → unitx-0.17.4}/src/unitx/quantity.py +40 -62
- {unitx-0.17.2 → unitx-0.17.4}/src/unitx/quantity.pyi +647 -5
- {unitx-0.17.2 → unitx-0.17.4}/src/unitx/unitregistry.py +2 -2
- {unitx-0.17.2 → unitx-0.17.4}/tests/numpy/test_array_methods.py +69 -1
- unitx-0.17.4/tests/numpy/test_dtype_contracts.py +74 -0
- unitx-0.17.4/tests/numpy/test_inference_contracts.py +69 -0
- {unitx-0.17.2 → unitx-0.17.4}/tests/numpy/test_math_numpy.py +20 -0
- {unitx-0.17.2 → unitx-0.17.4}/tests/numpy/test_numpy_scientific.py +1 -1
- unitx-0.17.4/tests/numpy/test_point_calculus.py +110 -0
- {unitx-0.17.2 → unitx-0.17.4}/tests/numpy_typing/check_array_methods.py +19 -2
- unitx-0.17.4/tests/numpy_typing/check_lm_inference.py +109 -0
- unitx-0.17.4/tests/numpy_typing/check_math.py +35 -0
- {unitx-0.17.2 → unitx-0.17.4}/tests/numpy_typing/check_numpy.py +19 -13
- unitx-0.17.4/tests/numpy_typing/check_precision.py +48 -0
- {unitx-0.17.2 → unitx-0.17.4}/tests/numpy_typing/check_representation.py +4 -5
- {unitx-0.17.2 → unitx-0.17.4}/tests/quantities/test_representation.py +7 -1
- {unitx-0.17.2 → unitx-0.17.4}/tests/stdlib/test_math.py +22 -0
- unitx-0.17.4/tests/test_exceptions.py +36 -0
- {unitx-0.17.2 → unitx-0.17.4}/tests/test_typing.py +1 -1
- {unitx-0.17.2 → unitx-0.17.4}/tests/typing/check_impedance_example.py +3 -3
- {unitx-0.17.2 → unitx-0.17.4}/tests/typing/check_math_time.py +4 -0
- {unitx-0.17.2 → unitx-0.17.4}/tests/typing/check_quantity.py +2 -2
- {unitx-0.17.2 → unitx-0.17.4}/tests/typing/check_representation.py +31 -4
- unitx-0.17.2/tests/numpy_typing/check_math.py +0 -14
- {unitx-0.17.2 → unitx-0.17.4}/.github/consumers/plots.py +0 -0
- {unitx-0.17.2 → unitx-0.17.4}/.github/consumers/pyrightconfig.json +0 -0
- {unitx-0.17.2 → unitx-0.17.4}/.github/consumers/scipy_support.py +0 -0
- {unitx-0.17.2 → unitx-0.17.4}/.github/workflows/ci.yml +0 -0
- {unitx-0.17.2 → unitx-0.17.4}/.github/workflows/pages.yml +0 -0
- {unitx-0.17.2 → unitx-0.17.4}/.github/workflows/release.yml +0 -0
- {unitx-0.17.2 → unitx-0.17.4}/.gitignore +0 -0
- {unitx-0.17.2 → unitx-0.17.4}/.readthedocs.yaml +0 -0
- {unitx-0.17.2 → unitx-0.17.4}/LICENSE +0 -0
- {unitx-0.17.2 → unitx-0.17.4}/README.md +0 -0
- {unitx-0.17.2 → unitx-0.17.4}/benchmarks/README.md +0 -0
- {unitx-0.17.2 → unitx-0.17.4}/benchmarks/numpy_writes.py +0 -0
- {unitx-0.17.2 → unitx-0.17.4}/benchmarks/scalars.py +0 -0
- {unitx-0.17.2 → unitx-0.17.4}/conftest.py +0 -0
- {unitx-0.17.2 → unitx-0.17.4}/docs/README.md +0 -0
- {unitx-0.17.2 → unitx-0.17.4}/docs/affine.md +0 -0
- {unitx-0.17.2 → unitx-0.17.4}/docs/catalogues/README.md +0 -0
- {unitx-0.17.2 → unitx-0.17.4}/docs/catalogues/cgs.md +0 -0
- {unitx-0.17.2 → unitx-0.17.4}/docs/catalogues/imperial.md +0 -0
- {unitx-0.17.2 → unitx-0.17.4}/docs/catalogues/si.md +0 -0
- {unitx-0.17.2 → unitx-0.17.4}/docs/custom-units.md +0 -0
- {unitx-0.17.2 → unitx-0.17.4}/docs/display.md +0 -0
- {unitx-0.17.2 → unitx-0.17.4}/docs/images/blackbody.svg +0 -0
- {unitx-0.17.2 → unitx-0.17.4}/docs/javascripts/mermaid.mjs +0 -0
- {unitx-0.17.2 → unitx-0.17.4}/docs/logarithmic.md +0 -0
- {unitx-0.17.2 → unitx-0.17.4}/docs/matplotlib.md +0 -0
- {unitx-0.17.2 → unitx-0.17.4}/docs/migration.md +0 -0
- {unitx-0.17.2 → unitx-0.17.4}/docs/numpy/compatibility.md +0 -0
- {unitx-0.17.2 → unitx-0.17.4}/docs/numpy/contractions.md +0 -0
- {unitx-0.17.2 → unitx-0.17.4}/docs/numpy/creation.md +0 -0
- {unitx-0.17.2 → unitx-0.17.4}/docs/numpy/fft.md +0 -0
- {unitx-0.17.2 → unitx-0.17.4}/docs/numpy/histograms.md +0 -0
- {unitx-0.17.2 → unitx-0.17.4}/docs/numpy/indexing.md +0 -0
- {unitx-0.17.2 → unitx-0.17.4}/docs/numpy/linalg.md +0 -0
- {unitx-0.17.2 → unitx-0.17.4}/docs/numpy/selection.md +0 -0
- {unitx-0.17.2 → unitx-0.17.4}/docs/numpy/statistics.md +0 -0
- {unitx-0.17.2 → unitx-0.17.4}/docs/numpy/writes.md +0 -0
- {unitx-0.17.2 → unitx-0.17.4}/docs/representation.md +0 -0
- {unitx-0.17.2 → unitx-0.17.4}/docs/requirements.txt +0 -0
- {unitx-0.17.2 → unitx-0.17.4}/docs/scalars.md +0 -0
- {unitx-0.17.2 → unitx-0.17.4}/docs/scipy.md +0 -0
- {unitx-0.17.2 → unitx-0.17.4}/docs/serialization.md +0 -0
- {unitx-0.17.2 → unitx-0.17.4}/docs/statistics.md +0 -0
- {unitx-0.17.2 → unitx-0.17.4}/examples/README.md +0 -0
- {unitx-0.17.2 → unitx-0.17.4}/examples/arrhenius_fit.ipynb +0 -0
- {unitx-0.17.2 → unitx-0.17.4}/examples/blackbody.ipynb +0 -0
- {unitx-0.17.2 → unitx-0.17.4}/examples/damped_oscillator.ipynb +0 -0
- {unitx-0.17.2 → unitx-0.17.4}/examples/gaussian_wavepacket.ipynb +0 -0
- {unitx-0.17.2 → unitx-0.17.4}/examples/impedance.md +0 -0
- {unitx-0.17.2 → unitx-0.17.4}/examples/impedance.py +0 -0
- {unitx-0.17.2 → unitx-0.17.4}/examples/optical_attenuation.ipynb +0 -0
- {unitx-0.17.2 → unitx-0.17.4}/examples/pendulum_uncertainty.ipynb +0 -0
- {unitx-0.17.2 → unitx-0.17.4}/examples/smith_chart.ipynb +0 -0
- {unitx-0.17.2 → unitx-0.17.4}/mkdocs.yml +0 -0
- {unitx-0.17.2 → unitx-0.17.4}/pyrightconfig.json +0 -0
- {unitx-0.17.2 → unitx-0.17.4}/src/unitx/__init__.py +0 -0
- {unitx-0.17.2 → unitx-0.17.4}/src/unitx/_constnamespace.py +0 -0
- {unitx-0.17.2 → unitx-0.17.4}/src/unitx/_coordinates/__init__.py +0 -0
- {unitx-0.17.2 → unitx-0.17.4}/src/unitx/_coordinates/affine.py +0 -0
- {unitx-0.17.2 → unitx-0.17.4}/src/unitx/_coordinates/definition.py +0 -0
- {unitx-0.17.2 → unitx-0.17.4}/src/unitx/_coordinates/logarithmic.py +0 -0
- {unitx-0.17.2 → unitx-0.17.4}/src/unitx/_coordinates/logarithms.py +0 -0
- {unitx-0.17.2 → unitx-0.17.4}/src/unitx/_coordinates/resolve.py +0 -0
- {unitx-0.17.2 → unitx-0.17.4}/src/unitx/_electromagnetism/__init__.py +0 -0
- {unitx-0.17.2 → unitx-0.17.4}/src/unitx/_electromagnetism/coefficients.py +0 -0
- {unitx-0.17.2 → unitx-0.17.4}/src/unitx/_electromagnetism/conversion.py +0 -0
- {unitx-0.17.2 → unitx-0.17.4}/src/unitx/_formatting/__init__.py +0 -0
- {unitx-0.17.2 → unitx-0.17.4}/src/unitx/_formatting/render.py +0 -0
- {unitx-0.17.2 → unitx-0.17.4}/src/unitx/_formatting/unicode.py +0 -0
- {unitx-0.17.2 → unitx-0.17.4}/src/unitx/_immutable.py +0 -0
- {unitx-0.17.2 → unitx-0.17.4}/src/unitx/_numerics/__init__.py +0 -0
- {unitx-0.17.2 → unitx-0.17.4}/src/unitx/_numerics/conversion.py +0 -0
- {unitx-0.17.2 → unitx-0.17.4}/src/unitx/_numerics/numpy_creation.py +0 -0
- {unitx-0.17.2 → unitx-0.17.4}/src/unitx/_numerics/numpy_histograms.py +0 -0
- {unitx-0.17.2 → unitx-0.17.4}/src/unitx/_numerics/numpy_misc.py +0 -0
- {unitx-0.17.2 → unitx-0.17.4}/src/unitx/_numerics/numpy_writes.py +0 -0
- {unitx-0.17.2 → unitx-0.17.4}/src/unitx/_numerics/scaling.py +0 -0
- {unitx-0.17.2 → unitx-0.17.4}/src/unitx/_operands.py +0 -0
- {unitx-0.17.2 → unitx-0.17.4}/src/unitx/_registry/__init__.py +0 -0
- {unitx-0.17.2 → unitx-0.17.4}/src/unitx/_registry/builtin_units.py +0 -0
- {unitx-0.17.2 → unitx-0.17.4}/src/unitx/_registry/prefixes.py +0 -0
- {unitx-0.17.2 → unitx-0.17.4}/src/unitx/_registry/reconstruction.py +0 -0
- {unitx-0.17.2 → unitx-0.17.4}/src/unitx/_representation.py +0 -0
- {unitx-0.17.2 → unitx-0.17.4}/src/unitx/affineunit.py +0 -0
- {unitx-0.17.2 → unitx-0.17.4}/src/unitx/cgs/__init__.py +0 -0
- {unitx-0.17.2 → unitx-0.17.4}/src/unitx/cgs/units.py +0 -0
- {unitx-0.17.2 → unitx-0.17.4}/src/unitx/dimension.py +0 -0
- {unitx-0.17.2 → unitx-0.17.4}/src/unitx/factor.py +0 -0
- {unitx-0.17.2 → unitx-0.17.4}/src/unitx/imperial/__init__.py +0 -0
- {unitx-0.17.2 → unitx-0.17.4}/src/unitx/imperial/units.py +0 -0
- {unitx-0.17.2 → unitx-0.17.4}/src/unitx/logunit.py +0 -0
- {unitx-0.17.2 → unitx-0.17.4}/src/unitx/matplotlib.py +0 -0
- {unitx-0.17.2 → unitx-0.17.4}/src/unitx/monomial.py +0 -0
- {unitx-0.17.2 → unitx-0.17.4}/src/unitx/py.typed +0 -0
- {unitx-0.17.2 → unitx-0.17.4}/src/unitx/scipy.py +0 -0
- {unitx-0.17.2 → unitx-0.17.4}/src/unitx/serialization.py +0 -0
- {unitx-0.17.2 → unitx-0.17.4}/src/unitx/si/__init__.py +0 -0
- {unitx-0.17.2 → unitx-0.17.4}/src/unitx/si/bases.py +0 -0
- {unitx-0.17.2 → unitx-0.17.4}/src/unitx/si/constants.py +0 -0
- {unitx-0.17.2 → unitx-0.17.4}/src/unitx/si/units.py +0 -0
- {unitx-0.17.2 → unitx-0.17.4}/src/unitx/singleunit.py +0 -0
- {unitx-0.17.2 → unitx-0.17.4}/src/unitx/statistics.py +0 -0
- {unitx-0.17.2 → unitx-0.17.4}/src/unitx/time.py +0 -0
- {unitx-0.17.2 → unitx-0.17.4}/src/unitx/unit.py +0 -0
- {unitx-0.17.2 → unitx-0.17.4}/src/unitx/unitcatalog.py +0 -0
- {unitx-0.17.2 → unitx-0.17.4}/src/unitx/unitdefinition.py +0 -0
- {unitx-0.17.2 → unitx-0.17.4}/src/unitx/unitparser.py +0 -0
- {unitx-0.17.2 → unitx-0.17.4}/tests/README.md +0 -0
- {unitx-0.17.2 → unitx-0.17.4}/tests/__init__.py +0 -0
- {unitx-0.17.2 → unitx-0.17.4}/tests/_notebooks.py +0 -0
- {unitx-0.17.2 → unitx-0.17.4}/tests/algebra/__init__.py +0 -0
- {unitx-0.17.2 → unitx-0.17.4}/tests/algebra/test_dimension.py +0 -0
- {unitx-0.17.2 → unitx-0.17.4}/tests/algebra/test_factor.py +0 -0
- {unitx-0.17.2 → unitx-0.17.4}/tests/algebra/test_monomial.py +0 -0
- {unitx-0.17.2 → unitx-0.17.4}/tests/algebra/test_numeric.py +0 -0
- {unitx-0.17.2 → unitx-0.17.4}/tests/catalogues/__init__.py +0 -0
- {unitx-0.17.2 → unitx-0.17.4}/tests/catalogues/test_cgs.py +0 -0
- {unitx-0.17.2 → unitx-0.17.4}/tests/catalogues/test_cgs_systems.py +0 -0
- {unitx-0.17.2 → unitx-0.17.4}/tests/catalogues/test_imperial.py +0 -0
- {unitx-0.17.2 → unitx-0.17.4}/tests/catalogues/test_si.py +0 -0
- {unitx-0.17.2 → unitx-0.17.4}/tests/catalogues/test_unicode_units.py +0 -0
- {unitx-0.17.2 → unitx-0.17.4}/tests/display/__init__.py +0 -0
- {unitx-0.17.2 → unitx-0.17.4}/tests/display/test_display.py +0 -0
- {unitx-0.17.2 → unitx-0.17.4}/tests/display/test_siunitx_display.py +0 -0
- {unitx-0.17.2 → unitx-0.17.4}/tests/display/test_unicode.py +0 -0
- {unitx-0.17.2 → unitx-0.17.4}/tests/numpy/__init__.py +0 -0
- {unitx-0.17.2 → unitx-0.17.4}/tests/numpy/conftest.py +0 -0
- {unitx-0.17.2 → unitx-0.17.4}/tests/numpy/test_cgs_numpy.py +0 -0
- {unitx-0.17.2 → unitx-0.17.4}/tests/numpy/test_numpy.py +0 -0
- {unitx-0.17.2 → unitx-0.17.4}/tests/numpy/test_numpy_affine.py +0 -0
- {unitx-0.17.2 → unitx-0.17.4}/tests/numpy/test_numpy_array_manipulation.py +0 -0
- {unitx-0.17.2 → unitx-0.17.4}/tests/numpy/test_numpy_compatibility.py +0 -0
- {unitx-0.17.2 → unitx-0.17.4}/tests/numpy/test_numpy_contractions.py +0 -0
- {unitx-0.17.2 → unitx-0.17.4}/tests/numpy/test_numpy_covariance.py +0 -0
- {unitx-0.17.2 → unitx-0.17.4}/tests/numpy/test_numpy_creation.py +0 -0
- {unitx-0.17.2 → unitx-0.17.4}/tests/numpy/test_numpy_differentiation.py +0 -0
- {unitx-0.17.2 → unitx-0.17.4}/tests/numpy/test_numpy_factorizations.py +0 -0
- {unitx-0.17.2 → unitx-0.17.4}/tests/numpy/test_numpy_fft.py +0 -0
- {unitx-0.17.2 → unitx-0.17.4}/tests/numpy/test_numpy_histograms.py +0 -0
- {unitx-0.17.2 → unitx-0.17.4}/tests/numpy/test_numpy_indexing.py +0 -0
- {unitx-0.17.2 → unitx-0.17.4}/tests/numpy/test_numpy_integration.py +0 -0
- {unitx-0.17.2 → unitx-0.17.4}/tests/numpy/test_numpy_interpolation.py +0 -0
- {unitx-0.17.2 → unitx-0.17.4}/tests/numpy/test_numpy_joining.py +0 -0
- {unitx-0.17.2 → unitx-0.17.4}/tests/numpy/test_numpy_linalg.py +0 -0
- {unitx-0.17.2 → unitx-0.17.4}/tests/numpy/test_numpy_math.py +0 -0
- {unitx-0.17.2 → unitx-0.17.4}/tests/numpy/test_numpy_multi_outputs.py +0 -0
- {unitx-0.17.2 → unitx-0.17.4}/tests/numpy/test_numpy_mutation.py +0 -0
- {unitx-0.17.2 → unitx-0.17.4}/tests/numpy/test_numpy_nan_reductions.py +0 -0
- {unitx-0.17.2 → unitx-0.17.4}/tests/numpy/test_numpy_nan_statistics.py +0 -0
- {unitx-0.17.2 → unitx-0.17.4}/tests/numpy/test_numpy_norm.py +0 -0
- {unitx-0.17.2 → unitx-0.17.4}/tests/numpy/test_numpy_ordering.py +0 -0
- {unitx-0.17.2 → unitx-0.17.4}/tests/numpy/test_numpy_outputs.py +0 -0
- {unitx-0.17.2 → unitx-0.17.4}/tests/numpy/test_numpy_products.py +0 -0
- {unitx-0.17.2 → unitx-0.17.4}/tests/numpy/test_numpy_selection.py +0 -0
- {unitx-0.17.2 → unitx-0.17.4}/tests/numpy/test_numpy_shapes.py +0 -0
- {unitx-0.17.2 → unitx-0.17.4}/tests/numpy/test_numpy_statistics.py +0 -0
- {unitx-0.17.2 → unitx-0.17.4}/tests/numpy/test_numpy_ufunc_methods.py +0 -0
- {unitx-0.17.2 → unitx-0.17.4}/tests/numpy/test_numpy_weighted_statistics.py +0 -0
- {unitx-0.17.2 → unitx-0.17.4}/tests/numpy/test_numpy_workflows.py +0 -0
- {unitx-0.17.2 → unitx-0.17.4}/tests/numpy/test_numpy_write_functions.py +0 -0
- {unitx-0.17.2 → unitx-0.17.4}/tests/numpy_typing/check_asarray.py +0 -0
- {unitx-0.17.2 → unitx-0.17.4}/tests/numpy_typing/check_cgs.py +0 -0
- {unitx-0.17.2 → unitx-0.17.4}/tests/numpy_typing/check_components.py +0 -0
- {unitx-0.17.2 → unitx-0.17.4}/tests/numpy_typing/check_indexing.py +0 -0
- {unitx-0.17.2 → unitx-0.17.4}/tests/numpy_typing/check_logarithmic.py +0 -0
- {unitx-0.17.2 → unitx-0.17.4}/tests/numpy_typing/check_scipy.py +0 -0
- {unitx-0.17.2 → unitx-0.17.4}/tests/quantities/__init__.py +0 -0
- {unitx-0.17.2 → unitx-0.17.4}/tests/quantities/test_affine.py +0 -0
- {unitx-0.17.2 → unitx-0.17.4}/tests/quantities/test_affinequantity.py +0 -0
- {unitx-0.17.2 → unitx-0.17.4}/tests/quantities/test_decibel_call.py +0 -0
- {unitx-0.17.2 → unitx-0.17.4}/tests/quantities/test_float_decimal.py +0 -0
- {unitx-0.17.2 → unitx-0.17.4}/tests/quantities/test_linear_boundaries.py +0 -0
- {unitx-0.17.2 → unitx-0.17.4}/tests/quantities/test_logarithmic_model.py +0 -0
- {unitx-0.17.2 → unitx-0.17.4}/tests/quantities/test_quantity.py +0 -0
- {unitx-0.17.2 → unitx-0.17.4}/tests/quantities/test_quantity_astype.py +0 -0
- {unitx-0.17.2 → unitx-0.17.4}/tests/quantities/test_scalar_protocols.py +0 -0
- {unitx-0.17.2 → unitx-0.17.4}/tests/stdlib/__init__.py +0 -0
- {unitx-0.17.2 → unitx-0.17.4}/tests/stdlib/test_scipy.py +0 -0
- {unitx-0.17.2 → unitx-0.17.4}/tests/stdlib/test_statistics.py +0 -0
- {unitx-0.17.2 → unitx-0.17.4}/tests/stdlib/test_time.py +0 -0
- {unitx-0.17.2 → unitx-0.17.4}/tests/test_examples.py +0 -0
- {unitx-0.17.2 → unitx-0.17.4}/tests/test_immutable.py +0 -0
- {unitx-0.17.2 → unitx-0.17.4}/tests/test_impedance_example.py +0 -0
- {unitx-0.17.2 → unitx-0.17.4}/tests/test_import.py +0 -0
- {unitx-0.17.2 → unitx-0.17.4}/tests/test_matplotlib.py +0 -0
- {unitx-0.17.2 → unitx-0.17.4}/tests/test_serialization.py +0 -0
- {unitx-0.17.2 → unitx-0.17.4}/tests/test_warnings.py +0 -0
- {unitx-0.17.2 → unitx-0.17.4}/tests/typing/check_affine.py +0 -0
- {unitx-0.17.2 → unitx-0.17.4}/tests/typing/check_cgs.py +0 -0
- {unitx-0.17.2 → unitx-0.17.4}/tests/typing/check_float.py +0 -0
- {unitx-0.17.2 → unitx-0.17.4}/tests/typing/check_imperial.py +0 -0
- {unitx-0.17.2 → unitx-0.17.4}/tests/typing/check_logarithmic.py +0 -0
- {unitx-0.17.2 → unitx-0.17.4}/tests/typing/check_registry.py +0 -0
- {unitx-0.17.2 → unitx-0.17.4}/tests/typing/check_serialization.py +0 -0
- {unitx-0.17.2 → unitx-0.17.4}/tests/typing/check_si.py +0 -0
- {unitx-0.17.2 → unitx-0.17.4}/tests/typing/check_statistics.py +0 -0
- {unitx-0.17.2 → unitx-0.17.4}/tests/units/__init__.py +0 -0
- {unitx-0.17.2 → unitx-0.17.4}/tests/units/test_builtin_definitions.py +0 -0
- {unitx-0.17.2 → unitx-0.17.4}/tests/units/test_catalog_collection.py +0 -0
- {unitx-0.17.2 → unitx-0.17.4}/tests/units/test_definition_scope.py +0 -0
- {unitx-0.17.2 → unitx-0.17.4}/tests/units/test_registry.py +0 -0
- {unitx-0.17.2 → unitx-0.17.4}/tests/units/test_registry_scope.py +0 -0
- {unitx-0.17.2 → unitx-0.17.4}/tests/units/test_singleunit.py +0 -0
- {unitx-0.17.2 → unitx-0.17.4}/tests/units/test_unit.py +0 -0
- {unitx-0.17.2 → unitx-0.17.4}/tests/units/test_unit_definition.py +0 -0
- {unitx-0.17.2 → unitx-0.17.4}/tests/units/test_unitparser.py +0 -0
- {unitx-0.17.2 → unitx-0.17.4}/tests/units/test_unitregistry.py +0 -0
|
@@ -6,10 +6,11 @@ import numpy as np
|
|
|
6
6
|
from numpy.typing import NDArray
|
|
7
7
|
|
|
8
8
|
from unitx import AffineQuantity, LogQuantity, LogUnit, Quantity, Unit
|
|
9
|
+
from unitx import math as unitx_math
|
|
9
10
|
from unitx._numerics import Array
|
|
10
11
|
from unitx._numerics.numpy_typing import NumpyValue
|
|
11
12
|
from unitx.cgs import emu, esu, gaussian, hl
|
|
12
|
-
from unitx.exceptions import DimensionError
|
|
13
|
+
from unitx.exceptions import DimensionError, ImplicitConversionError, UnitOperationError
|
|
13
14
|
from unitx.si import si
|
|
14
15
|
|
|
15
16
|
type ArrayQuantity = Quantity[Array] | AffineQuantity[Array] | LogQuantity[Array]
|
|
@@ -29,13 +30,13 @@ def check_components(signal: Quantity[NDArray[np.complex128]]) -> None:
|
|
|
29
30
|
|
|
30
31
|
def check_arrays(values: NDArray[np.float64]) -> None:
|
|
31
32
|
ratio = Quantity(values, si.percent)
|
|
32
|
-
assert_type(ratio.n,
|
|
33
|
+
assert_type(ratio.n, NDArray[np.float64] | np.float64)
|
|
33
34
|
np.testing.assert_allclose(ratio.n, values / 100)
|
|
34
35
|
assert_type(ratio.as_pair(), tuple[NDArray[np.float64], Unit])
|
|
35
36
|
assert ratio.as_pair()[0] is values
|
|
36
|
-
assert_type(ratio.to_base(), Quantity[
|
|
37
|
-
assert_type(ratio.simplify(), Quantity[
|
|
38
|
-
assert_type(Quantity(values, si.m).compact(), Quantity[
|
|
37
|
+
assert_type(ratio.to_base(), Quantity[NDArray[np.float64] | np.float64])
|
|
38
|
+
assert_type(ratio.simplify(), Quantity[NDArray[np.float64] | np.float64])
|
|
39
|
+
assert_type(Quantity(values, si.m).compact(), Quantity[NDArray[np.float64] | np.float64])
|
|
39
40
|
assert Quantity(values, si.cm * si.m).simplify().unit == si.m**2
|
|
40
41
|
signal = Quantity(np.asarray([3 + 4j], dtype=np.complex128), si.V)
|
|
41
42
|
check_components(signal)
|
|
@@ -555,7 +556,7 @@ def check_array_methods(target: NDArray[np.float64]) -> None:
|
|
|
555
556
|
assert_type(columns, Quantity[NDArray[np.float32]])
|
|
556
557
|
assert_type(columns.ravel(), Quantity[NDArray[np.float32]])
|
|
557
558
|
assert_type(columns.copy(), Quantity[NDArray[np.float32]])
|
|
558
|
-
assert_type(columns.mean(axis=0), Quantity[
|
|
559
|
+
assert_type(columns.mean(axis=0), Quantity[NDArray[np.float32] | np.float32])
|
|
559
560
|
assert np.shares_memory(columns.value, values)
|
|
560
561
|
assert not np.shares_memory(columns.copy().value, values)
|
|
561
562
|
out = Quantity(target, si.cm)
|
|
@@ -578,3 +579,96 @@ def check_array_methods(target: NDArray[np.float64]) -> None:
|
|
|
578
579
|
|
|
579
580
|
|
|
580
581
|
check_array_methods(np.zeros(2, dtype=np.float64))
|
|
582
|
+
|
|
583
|
+
|
|
584
|
+
def check_calculus_types(values: NDArray[np.float64]) -> None:
|
|
585
|
+
coordinate = Quantity(values, si.s)
|
|
586
|
+
signal = 2 * Quantity(values, si.A)
|
|
587
|
+
assert_type(coordinate.to(si.ms), Quantity[NDArray[np.float64] | np.float64])
|
|
588
|
+
assert_type(signal * coordinate, Quantity[NDArray[np.float64] | np.float64])
|
|
589
|
+
weights = cast(Quantity[Array], np.gradient(coordinate, axis=0))
|
|
590
|
+
weights[[0, -1]] /= 2
|
|
591
|
+
integral = cast(Quantity[Array], np.trapezoid(signal, coordinate))
|
|
592
|
+
assert np.sum(signal * weights).isclose(integral)
|
|
593
|
+
points = AffineQuantity(values, si.degC)
|
|
594
|
+
increments = cast(Quantity[Array], np.diff(points))
|
|
595
|
+
assert increments.unit == si.degC.delta_unit
|
|
596
|
+
assert np.diff(points, n=0) is points
|
|
597
|
+
rate = cast(Quantity[Array], np.gradient(points, coordinate, axis=0))
|
|
598
|
+
np.testing.assert_allclose(rate.value, 1)
|
|
599
|
+
levels = LogQuantity(values, si.dBm)
|
|
600
|
+
differences = cast(Quantity[Array], np.diff(levels))
|
|
601
|
+
assert differences.unit == si.dBm.delta_unit
|
|
602
|
+
try:
|
|
603
|
+
np.asarray(coordinate)
|
|
604
|
+
except ImplicitConversionError as error:
|
|
605
|
+
assert isinstance(error, TypeError)
|
|
606
|
+
else:
|
|
607
|
+
error_message = 'Array coercion must preserve the explicit numerical boundary.'
|
|
608
|
+
raise AssertionError(error_message)
|
|
609
|
+
try:
|
|
610
|
+
np.add(points, points)
|
|
611
|
+
except UnitOperationError as error:
|
|
612
|
+
assert isinstance(error, TypeError)
|
|
613
|
+
else:
|
|
614
|
+
error_message = 'Adding two points must fail.'
|
|
615
|
+
raise AssertionError(error_message)
|
|
616
|
+
|
|
617
|
+
|
|
618
|
+
check_calculus_types(np.array([0.0, 1, 3, 6]))
|
|
619
|
+
|
|
620
|
+
|
|
621
|
+
def check_scientific_inference(values: NDArray[np.float64]) -> None:
|
|
622
|
+
spectrum = Quantity(values.reshape(2, 2, 2), si.J)
|
|
623
|
+
mask = np.array([True, False])
|
|
624
|
+
selected = spectrum[mask, 0, 0]
|
|
625
|
+
assert_type(selected, Quantity[NDArray[np.float64]])
|
|
626
|
+
assert_type(spectrum[:, 0, 0], Quantity[NDArray[np.float64]])
|
|
627
|
+
phase = 1j * selected
|
|
628
|
+
assert_type(phase, Quantity[NDArray[np.complex128] | np.complex128])
|
|
629
|
+
assert_type(spectrum.sum(), Quantity[np.float64])
|
|
630
|
+
assert_type(spectrum.sum().value_in(si.J), np.float64)
|
|
631
|
+
assert_type(selected.astype(float), Quantity[NDArray[np.float64]])
|
|
632
|
+
assert_type(Quantity(np.float32(2), si.percent).n, np.float32)
|
|
633
|
+
np.testing.assert_array_equal(selected.value, [values[0]])
|
|
634
|
+
np.testing.assert_array_equal(phase.value, 1j * selected.value)
|
|
635
|
+
assert spectrum.sum().value_in(si.J) == np.sum(values)
|
|
636
|
+
|
|
637
|
+
|
|
638
|
+
check_scientific_inference(np.arange(8, dtype=np.float64))
|
|
639
|
+
|
|
640
|
+
|
|
641
|
+
def check_complex_field(values: NDArray[np.float64]) -> None:
|
|
642
|
+
z = values * si.m
|
|
643
|
+
gouy = unitx_math.atan(z / (0.5 * si.m))
|
|
644
|
+
geometry = unitx_math.hypot(1, z / (0.5 * si.m))
|
|
645
|
+
field = unitx_math.conj(unitx_math.exp(1j * gouy) / geometry)
|
|
646
|
+
assert_type(field, Quantity[NDArray[np.complex128] | np.complex128])
|
|
647
|
+
for _ in range(3):
|
|
648
|
+
field *= unitx_math.exp(-1j * gouy)
|
|
649
|
+
assert_type(field, Quantity[NDArray[np.complex128] | np.complex128])
|
|
650
|
+
angle = np.arctan(np.linspace(-1, 1, 5) / 0.5)
|
|
651
|
+
expected = np.exp(-4j * angle) / np.hypot(1, np.linspace(-1, 1, 5) / 0.5)
|
|
652
|
+
np.testing.assert_allclose(field.n, expected, rtol=1e-14)
|
|
653
|
+
|
|
654
|
+
|
|
655
|
+
check_complex_field(np.linspace(-1, 1, 5))
|
|
656
|
+
|
|
657
|
+
|
|
658
|
+
def check_shape_axes(values: NDArray[np.float64]) -> None:
|
|
659
|
+
q = Quantity(values.reshape(2, 1, 4), si.m)
|
|
660
|
+
permuted = q.transpose(2, 0, 1).squeeze(-1)
|
|
661
|
+
assert_type(permuted, Quantity[NDArray[np.float64]])
|
|
662
|
+
assert np.shares_memory(permuted.value, values)
|
|
663
|
+
np.testing.assert_array_equal(permuted.value, values.reshape(2, 4).T)
|
|
664
|
+
assert_type(Quantity(np.float32(2), si.m).squeeze(), Quantity[np.float32])
|
|
665
|
+
for point in (
|
|
666
|
+
AffineQuantity(values.reshape(2, 1, 4), si.degC),
|
|
667
|
+
LogQuantity(values.reshape(2, 1, 4), si.dBm),
|
|
668
|
+
):
|
|
669
|
+
transformed = point.transpose((2, 0, 1)).squeeze(axis=-1)
|
|
670
|
+
assert type(transformed) is type(point) and transformed.unit is point.unit
|
|
671
|
+
np.testing.assert_array_equal(transformed.value, values.reshape(2, 4).T)
|
|
672
|
+
|
|
673
|
+
|
|
674
|
+
check_shape_axes(np.arange(8.0))
|
|
@@ -26,6 +26,7 @@ from unitx import (
|
|
|
26
26
|
time,
|
|
27
27
|
)
|
|
28
28
|
from unitx.cgs import cgs, emu, esu, gaussian, hl
|
|
29
|
+
from unitx.exceptions import ImplicitConversionError, UnitOperationError, UnitxError
|
|
29
30
|
from unitx.factor import Factor
|
|
30
31
|
from unitx.imperial import imperial
|
|
31
32
|
from unitx.quantity import quantity as decimal_quantity
|
|
@@ -120,6 +121,9 @@ assert_type(root, Quantity[float])
|
|
|
120
121
|
assert root == 3 * si.m
|
|
121
122
|
assert math.sin(90 * si.deg).value == 1.0
|
|
122
123
|
assert math.hypot(3 * si.m, 400 * si.cm) == 5 * si.m
|
|
124
|
+
assert_type(math.exp(1j), Quantity[complex])
|
|
125
|
+
assert_type(math.conj(2 + 3j), Quantity[complex])
|
|
126
|
+
assert math.conj(Quantity(2 + 3j, si.m)).value == 2 - 3j
|
|
123
127
|
|
|
124
128
|
stamp = time.time()
|
|
125
129
|
start = time.perf_counter()
|
|
@@ -185,3 +189,14 @@ assert 'matplotlib' not in sys.modules
|
|
|
185
189
|
# The sibling stub must retain the module-level Decimal factory.
|
|
186
190
|
assert_type(decimal_quantity(1.25, si.m), Quantity[Decimal])
|
|
187
191
|
assert decimal_quantity(1.25, si.m).value == Decimal('1.25')
|
|
192
|
+
|
|
193
|
+
assert issubclass(UnitOperationError, TypeError)
|
|
194
|
+
assert issubclass(UnitOperationError, UnitxError)
|
|
195
|
+
assert issubclass(ImplicitConversionError, UnitOperationError)
|
|
196
|
+
try:
|
|
197
|
+
_ = (20 @ si.degC) * 2
|
|
198
|
+
except UnitOperationError as error:
|
|
199
|
+
assert isinstance(error, TypeError)
|
|
200
|
+
else:
|
|
201
|
+
error_message = 'Multiplying a coordinate point must fail.'
|
|
202
|
+
raise AssertionError(error_message)
|
|
@@ -1,5 +1,55 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [0.17.4] - 2026-10-28
|
|
4
|
+
|
|
5
|
+
### Added
|
|
6
|
+
|
|
7
|
+
- Add typed `transpose` and `squeeze` methods for Quantity, AffineQuantity and
|
|
8
|
+
LogQuantity, preserving full units, coordinate families and NumPy views.
|
|
9
|
+
- Add `unitx.math.conj` and complex inputs to `unitx.math.exp` for typed complex
|
|
10
|
+
phases, preserving complete units and the existing NumPy dispatch rules.
|
|
11
|
+
|
|
12
|
+
### Changed
|
|
13
|
+
|
|
14
|
+
- Expose `n` as an ordinary read-only property and retain float inference for
|
|
15
|
+
scientific scalar formulas, with exact runtime conversion rules unchanged.
|
|
16
|
+
- Preserve known NumPy dtypes through the supported `unitx.math` phase functions,
|
|
17
|
+
mixed real/complex algebra, absolute values and same-dtype augmented products.
|
|
18
|
+
- Retain ndarray results and numeric dtypes for slices, boolean indices,
|
|
19
|
+
ellipses, new axes and tuples starting with one of these indices.
|
|
20
|
+
- Infer complex64/complex128 for float32/float64 multiplication and division
|
|
21
|
+
with Python complex scalars, including reflected operations.
|
|
22
|
+
- Infer concrete NumPy dtype and container types for explicit `astype` calls,
|
|
23
|
+
and NumPy scalar types for complete sum/mean reductions and their numerical
|
|
24
|
+
exits, reducing the need for consumer casts and numerical conversions.
|
|
25
|
+
|
|
26
|
+
## [0.17.3] - 2026-10-27
|
|
27
|
+
|
|
28
|
+
### Added
|
|
29
|
+
|
|
30
|
+
- Support `diff` and `gradient` on affine/logarithmic point arrays, returning
|
|
31
|
+
differences and using coordinate difference units for derivatives. Align
|
|
32
|
+
point boundaries explicitly; retain the original object for `diff(n=0)`.
|
|
33
|
+
- Document reusable trapezoidal weights using `np.gradient` and an endpoint
|
|
34
|
+
correction.
|
|
35
|
+
- Add `UnitOperationError` for point/difference semantic violations and its
|
|
36
|
+
`ImplicitConversionError` subclass for silent array unit removal. Both remain
|
|
37
|
+
catchable as TypeError and UnitxError; native numerical errors stay native.
|
|
38
|
+
|
|
39
|
+
### Changed
|
|
40
|
+
|
|
41
|
+
- Delegate direct array methods through a private lazy decorator, retaining
|
|
42
|
+
explicit signatures, method defaults and the existing NumPy unit/output rules.
|
|
43
|
+
- Retain known floating/complex NumPy dtypes in linear conversions, supported
|
|
44
|
+
arithmetic and default sum/mean results, including possible NumPy scalars.
|
|
45
|
+
Preserve numeric dtypes in indexing/iteration; narrow exact Fraction
|
|
46
|
+
arithmetic and complex scalar result domains.
|
|
47
|
+
|
|
48
|
+
### Fixed
|
|
49
|
+
|
|
50
|
+
- Update the generator annotation on registry definition scopes to avoid the
|
|
51
|
+
deprecated Iterator overload of `contextmanager` in current type stubs.
|
|
52
|
+
|
|
3
53
|
## [0.17.2] - 2026-10-27
|
|
4
54
|
|
|
5
55
|
### Added
|
|
@@ -112,10 +112,13 @@ python -m build
|
|
|
112
112
|
python -m twine check --strict dist/*
|
|
113
113
|
```
|
|
114
114
|
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
115
|
+
Build release artifacts from a clean checkout or Git export of the intended
|
|
116
|
+
commit. Git's local `.git/info/exclude` is not a distribution manifest:
|
|
117
|
+
building a shared working tree can include locally ignored notes in an sdist.
|
|
118
|
+
Check wheel/sdist contents, version metadata, `py.typed`, and installed
|
|
119
|
+
consumers outside the checkout. Source-tree success alone does not verify
|
|
120
|
+
packaging. When separating changes, also validate the actual committed
|
|
121
|
+
snapshots rather than only the final working tree.
|
|
119
122
|
|
|
120
123
|
The [release workflow](.github/workflows/release.yml) validates distributions
|
|
121
124
|
and uploads them to PyPI after a published GitHub Release. The tag must match
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: unitx
|
|
3
|
-
Version: 0.17.
|
|
3
|
+
Version: 0.17.4
|
|
4
4
|
Summary: Physical units, quantities, and unit conversion with exact unit algebra, type hints, and NumPy integration.
|
|
5
5
|
Project-URL: Homepage, https://github.com/DaitTHU/unitx
|
|
6
6
|
Project-URL: Documentation, https://daitthu.github.io/unitx/
|
|
@@ -165,6 +165,12 @@ enumerate their own reference/difference dependencies. Display, NumPy and
|
|
|
165
165
|
serialization remain explicit integration boundaries. Numeric caches, parser
|
|
166
166
|
state and reconstruction indexes remain separate from mathematical identity.
|
|
167
167
|
|
|
168
|
+
Direct array methods declare their public signatures explicitly. A private
|
|
169
|
+
decorator in `_numerics/methods.py` binds their defaults and lazily delegates to
|
|
170
|
+
the same NumPy dispatch used by function calls. It adds no dynamic method lookup
|
|
171
|
+
or separate unit rules; coordinate and linear result construction stays in the
|
|
172
|
+
existing handlers. Reshape keeps its explicit positional-shape normalization.
|
|
173
|
+
|
|
168
174
|
The point marker's type parameter describes the result of adding a difference,
|
|
169
175
|
not the original magnitude type. This prevents the open scalar protocol from
|
|
170
176
|
claiming point operands and preserves concrete result types without naming the
|
|
@@ -69,13 +69,18 @@ No coordinate sorting, interpolation, dtype option, or output buffer is added.
|
|
|
69
69
|
|
|
70
70
|
## Differences and gradients
|
|
71
71
|
|
|
72
|
-
`np.diff(q, n=1, axis=-1)` computes differences in q's stored coordinates
|
|
73
|
-
|
|
72
|
+
`np.diff(q, n=1, axis=-1)` computes differences in q's stored coordinates.
|
|
73
|
+
Linear quantities retain their unit; AffineQuantity and LogQuantity points
|
|
74
|
+
return ordinary Quantities in their complete difference unit for every positive
|
|
75
|
+
order n. Logarithmic differences describe changes in readings, without an
|
|
76
|
+
implicit conversion to physical power or amplitude. `prepend` and `append` may be numeric
|
|
74
77
|
scalars/arrays or Quantities; their dimensions must match the input, and their
|
|
75
78
|
values convert to the input unit before differencing. Bare boundaries are
|
|
76
79
|
dimensionless, including bare zero. A bare input with a Quantity boundary is
|
|
77
80
|
also dimensionless. Scaled dimensionless boundaries therefore normalize to the
|
|
78
81
|
input's coordinates. Explicit list inputs/boundaries remain unsupported.
|
|
82
|
+
For points, boundaries must be compatible points and convert to the input
|
|
83
|
+
coordinate first; a difference or bare zero cannot stand in for a point.
|
|
79
84
|
|
|
80
85
|
With `n=0`, diff returns its input object unchanged and ignores axis and
|
|
81
86
|
boundaries. Other orders follow [NumPy diff](https://numpy.org/doc/stable/reference/generated/numpy.diff.html)
|
|
@@ -83,12 +88,15 @@ for shapes, scalar-boundary expansion, dtype promotion, unsigned wraparound,
|
|
|
83
88
|
and empty results. A difference is not a derivative: its unit is not divided
|
|
84
89
|
by a coordinate unit or raised to n.
|
|
85
90
|
|
|
86
|
-
`np.gradient(f, *spacing, axis=None, edge_order=1)` accepts numeric
|
|
87
|
-
|
|
91
|
+
`np.gradient(f, *spacing, axis=None, edge_order=1)` accepts numeric values,
|
|
92
|
+
Quantities and coordinate points. Each spacing is a scalar difference step or one-dimensional coordinate
|
|
88
93
|
array; bare inputs and spacings are dimensionless. A single scalar step applies
|
|
89
94
|
to every selected axis. Otherwise supply one spacing per selected axis, in
|
|
90
95
|
the order given by axis. Each component has unit `f.unit / spacing.unit`,
|
|
91
96
|
including exact Unit factors. No spacing means dimensionless unit steps.
|
|
97
|
+
For point-valued f, use its difference unit in the numerator. A point coordinate
|
|
98
|
+
array contributes its difference unit in the denominator; a scalar point is
|
|
99
|
+
not a step. Changing a coordinate origin does not change the derivative.
|
|
92
100
|
The kernels use stored numerical coordinates; no implicit SI conversion is
|
|
93
101
|
needed because each result retains the corresponding unit ratio.
|
|
94
102
|
|
|
@@ -112,4 +120,31 @@ np.testing.assert_allclose(velocity.value, 2)
|
|
|
112
120
|
assert np.trapezoid(velocity, time).isclose(distance[-1] - distance[0])
|
|
113
121
|
```
|
|
114
122
|
|
|
123
|
+
## Reusable trapezoidal weights
|
|
124
|
+
|
|
125
|
+
For repeated weighted sums or contractions on a real one-dimensional grid of
|
|
126
|
+
at least two samples, compute weights with gradient and halve the endpoints:
|
|
127
|
+
|
|
128
|
+
```python
|
|
129
|
+
time = Quantity(np.array([0.0, 1, 3, 6]), 's')
|
|
130
|
+
current = Quantity(np.array([0.0, 2, 6, 12]), 'A')
|
|
131
|
+
weights = np.gradient(time, axis=0)
|
|
132
|
+
weights[[0, -1]] /= 2
|
|
133
|
+
np.testing.assert_allclose(weights.value, [0.5, 1.5, 2.5, 1.5])
|
|
134
|
+
assert np.sum(current * weights).isclose(np.trapezoid(current, time))
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
With no spacing argument and the default `edge_order=1`, interior gradient
|
|
138
|
+
entries are `(x[i+1] - x[i-1]) / 2`, half the sum of adjacent intervals.
|
|
139
|
+
Endpoints are full one-sided intervals, so their halving is essential.
|
|
140
|
+
This is mathematically equivalent to trapezoidal weights; floating-point
|
|
141
|
+
rounding order can differ from interval-by-interval integration.
|
|
142
|
+
Decreasing and nonmonotonic coordinates retain their interval signs.
|
|
143
|
+
Gradient needs at least two samples; handle empty/singleton grids locally
|
|
144
|
+
only when the calculation requires them. Point coordinates return difference
|
|
145
|
+
weights; logarithmic readings are not implicitly mapped to physical values.
|
|
146
|
+
|
|
147
|
+
For a single integral, use `np.trapezoid`, following the linear integration
|
|
148
|
+
contract above. NumPy function stubs retain the [documented typing limits](../typing.md#numpy-magnitude-types).
|
|
149
|
+
|
|
115
150
|
[NumPy overview and support matrix](../numpy.md) · [Documentation index](../README.md)
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# Direct array methods
|
|
2
2
|
|
|
3
|
-
For NumPy magnitudes, Quantity provides `reshape`, `ravel`, `copy`, `
|
|
4
|
-
`mean` and `std`. AffineQuantity and LogQuantity provide the same methods
|
|
3
|
+
For NumPy magnitudes, Quantity provides `reshape`, `ravel`, `copy`, `transpose`,
|
|
4
|
+
`squeeze`, `sum`, `mean` and `std`. AffineQuantity and LogQuantity provide the same methods
|
|
5
5
|
except `sum`. Mean preserves a point's coordinate; standard deviation returns
|
|
6
6
|
its difference unit. Logarithmic statistics operate on readings; convert to
|
|
7
7
|
physical values explicitly before averaging power or amplitude.
|
|
@@ -15,6 +15,14 @@ ndarray storage, including for a NumPy scalar. Its C default follows
|
|
|
15
15
|
can remain a NumPy scalar; ndarray input remains ndarray with the same dtype.
|
|
16
16
|
Python scalar magnitudes require the scalar APIs or explicit array construction.
|
|
17
17
|
|
|
18
|
+
`transpose()` reverses the axes; `transpose((2, 0, 1))` and
|
|
19
|
+
`transpose(2, 0, 1)` select a permutation. Axis inputs are positional.
|
|
20
|
+
`squeeze(axis=None)` removes all length-one axes, or only the selected integer
|
|
21
|
+
or tuple of axes. Both retain the complete unit, coordinate family and dtype,
|
|
22
|
+
and share storage for ndarray inputs. A fully squeezed ndarray remains a
|
|
23
|
+
zero-dimensional ndarray; a NumPy scalar remains a NumPy scalar. Invalid
|
|
24
|
+
axes raise native NumPy errors without changing the input.
|
|
25
|
+
|
|
18
26
|
Reductions accept `axis`, `dtype`, `out`, `keepdims` and `where`. Sum also
|
|
19
27
|
accepts a compatible `initial` (bare zero is the additive identity); std
|
|
20
28
|
supports `ddof`, `correction` and a compatible precomputed `mean`. These use
|
|
@@ -34,6 +42,8 @@ np.testing.assert_allclose(samples.mean(axis=1).value, [1, 4])
|
|
|
34
42
|
assert samples.sum(initial=Quantity(100, 'cm')) == Quantity(16, 'm')
|
|
35
43
|
assert np.shares_memory(samples.ravel().value, samples.value)
|
|
36
44
|
assert not np.shares_memory(samples.copy().value, samples.value)
|
|
45
|
+
channels = samples.reshape(2, 1, 3).transpose(2, 0, 1).squeeze(-1)
|
|
46
|
+
np.testing.assert_array_equal(channels.value, samples.value.T)
|
|
37
47
|
assert np.trapezoid(np.array([1.0, 2, 3]), dx=Quantity(2, 's')) == Quantity(8, 's')
|
|
38
48
|
```
|
|
39
49
|
|
|
@@ -33,7 +33,8 @@ differences, and point sums/products are rejected.
|
|
|
33
33
|
## Values, storage, and precision
|
|
34
34
|
|
|
35
35
|
`.value`, `.value_in(unit)`, and `.to(unit).value` are explicit numerical exits.
|
|
36
|
-
`np.asarray(q)` and `np.array(q)` raise
|
|
36
|
+
`np.asarray(q)` and `np.array(q)` raise `ImplicitConversionError` (a TypeError)
|
|
37
|
+
even for dimensionless q;
|
|
37
38
|
use `np.asarray(q.value_in(target_unit))`.
|
|
38
39
|
|
|
39
40
|
Construction, unit-only multiplication/division, and an identity conversion
|
|
@@ -71,7 +72,7 @@ produce unhashable Quantities. `bool(q)` delegates to `bool(q.value)`.
|
|
|
71
72
|
|
|
72
73
|
## Direct array methods
|
|
73
74
|
|
|
74
|
-
Quantity provides `reshape`, `ravel`, `copy`, `sum`, `mean` and `std` for NumPy
|
|
75
|
+
Quantity provides `reshape`, `ravel`, `copy`, `transpose`, `squeeze`, `sum`, `mean` and `std` for NumPy
|
|
75
76
|
magnitudes. Two coordinate families provide the same methods except `sum`;
|
|
76
77
|
mean preserves a point and std returns a difference. These methods preserve
|
|
77
78
|
the wrapper in static types. See [array methods](numpy/methods.md) for shape,
|
|
@@ -212,8 +213,8 @@ functions, including exp/log. Python scalar arithmetic follows the separate [sca
|
|
|
212
213
|
| argmin/nanargmin, argmax/nanargmax | Bare indices | axis, keepdims, out |
|
|
213
214
|
| interp | Align x to xp's unit; retain fp's unit | finite strictly increasing 1-D xp; scalar left/right, period=None; no out |
|
|
214
215
|
| trapezoid | Multiply ordinate and coordinate units | x, scalar dx, axis; no out |
|
|
215
|
-
| diff | Preserve
|
|
216
|
-
| gradient | Divide input unit by each coordinate unit | scalar spacings or coordinate arrays, axis, edge_order; no out |
|
|
216
|
+
| diff | Preserve linear unit; point inputs return differences for n > 0 | n, axis, compatible point/value prepend and append; no out |
|
|
217
|
+
| gradient | Divide input difference unit by each coordinate difference unit | scalar difference spacings or coordinate arrays, axis, edge_order; no out |
|
|
217
218
|
| isclose, allclose | Bare mask / Python bool | rtol, atol, equal_nan |
|
|
218
219
|
|
|
219
220
|
Supply the first magnitude argument positionally; concatenate/stack take a
|
|
@@ -235,8 +236,8 @@ behavior for augmented arithmetic.
|
|
|
235
236
|
`squeeze`, `expand_dims`, `moveaxis`, `swapaxes`, `rollaxis`, and `ravel`
|
|
236
237
|
operate on magnitudes without conversion. Like reshape and transpose, they
|
|
237
238
|
retain the complete unit or point coordinate and return the same family:
|
|
238
|
-
Quantity, AffineQuantity, or LogQuantity.
|
|
239
|
-
|
|
239
|
+
Quantity, AffineQuantity, or LogQuantity. Ravel also has a direct method;
|
|
240
|
+
these functions have no `out` option.
|
|
240
241
|
|
|
241
242
|
Axis rules and errors follow NumPy, including negative and tuple axes where
|
|
242
243
|
supported. Squeezing an ndarray whose axes all have length one produces a
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Standard-library enhancements
|
|
2
2
|
|
|
3
|
-
`unitx.math` provides a finite set of unit-aware
|
|
3
|
+
`unitx.math` provides a finite set of unit-aware functions. `unitx.time`
|
|
4
4
|
provides integer nanosecond clock readings and explicit duration adapters.
|
|
5
5
|
`unitx.statistics` provides scalar means, dispersion and paired statistics.
|
|
6
6
|
These modules work without NumPy installed.
|
|
@@ -9,7 +9,7 @@ These modules work without NumPy installed.
|
|
|
9
9
|
|
|
10
10
|
| Module | Use |
|
|
11
11
|
| --- | --- |
|
|
12
|
-
| `unitx.math` | Unit-aware
|
|
12
|
+
| `unitx.math` | Unit-aware mathematical functions with scalar and optional NumPy backends |
|
|
13
13
|
| `unitx.time` | Integer ns clocks, scalar sleep, timedelta and aware datetime conversion |
|
|
14
14
|
| `unitx.statistics` | [Scalar means, dispersion, covariance and correlation](statistics.md) |
|
|
15
15
|
|
|
@@ -46,6 +46,7 @@ identities or arbitrary-precision evaluation.
|
|
|
46
46
|
| `sin(x)`, `cos(x)`, `tan(x)` | Dimensionless input, including deg/rad; coherent dimensionless result |
|
|
47
47
|
| `asin(x)`, `acos(x)`, `atan(x)` | Dimensionless input; result in rad |
|
|
48
48
|
| `exp(x)`, `expm1(x)` | Dimensionless input; coherent dimensionless result |
|
|
49
|
+
| `conj(x)` | Complex conjugate in the complete input unit |
|
|
49
50
|
| `log(x)`, `log1p(x)`, `log2(x)`, `log10(x)` | Dimensionless input; coherent dimensionless result |
|
|
50
51
|
| `hypot(*coordinates)` | Compatible input dimensions; first coordinate's unit |
|
|
51
52
|
| `atan2(y, x)` | Compatible input dimensions; result in rad |
|
|
@@ -58,11 +59,15 @@ Use `log(x) / log(base)` for a different base. `hypot()` returns dimensionless
|
|
|
58
59
|
zero; `hypot(x)` returns the absolute value in x's unit. For a bare first
|
|
59
60
|
coordinate, the result unit is coherent dimensionless.
|
|
60
61
|
|
|
61
|
-
Python int, float, Fraction and Decimal
|
|
62
|
+
Real transcendental calls on Python int, float, Fraction and Decimal use the standard-library math
|
|
62
63
|
backend, returning `Quantity[float]`. Decimal/Fraction input does not imply
|
|
63
64
|
arbitrary-precision output. Standard math domain, overflow, NaN and infinity
|
|
64
65
|
behavior applies. In particular, negative `sqrt` raises ValueError; negative
|
|
65
|
-
`cbrt` returns a real cube root.
|
|
66
|
+
`cbrt` returns a real cube root. `exp` also accepts complex inputs: Python
|
|
67
|
+
complex values use `cmath.exp`, and NumPy complex magnitudes use `np.exp`.
|
|
68
|
+
`conj` preserves the native scalar type or delegates to NumPy conjugation;
|
|
69
|
+
it preserves the complete input unit. Other functions retain their real domain.
|
|
70
|
+
Bools, custom scalar backends,
|
|
66
71
|
implicit list/tuple arrays, affine points and logarithmic units are unsupported.
|
|
67
72
|
Explicitly convert a logarithmic quantity to a physical ratio first.
|
|
68
73
|
|
|
@@ -74,13 +79,35 @@ may differ from the standard library's multi-coordinate implementation.
|
|
|
74
79
|
The wrappers accept positional inputs only, without `out` or `where`.
|
|
75
80
|
Use the supported NumPy ufuncs directly for those options.
|
|
76
81
|
|
|
77
|
-
|
|
78
|
-
|
|
82
|
+
The `sqrt`, `sin`, `cos`, `atan` and `exp` overloads retain known NumPy floating
|
|
83
|
+
dtypes; `exp` and `conj` also retain known complex dtypes. Two-coordinate
|
|
84
|
+
float64 `hypot` calls with float64 or Python real inputs retain float64.
|
|
85
|
+
The result includes a possible NumPy scalar, since zero-dimensional array
|
|
86
|
+
operations can remove the array container. Other array overloads return
|
|
87
|
+
`Quantity[Array]`, using the NumPy-independent magnitude protocol.
|
|
88
|
+
Strict scalar users have complete annotations without NumPy.
|
|
79
89
|
At runtime, magnitudes are native NumPy arrays/scalars. The protocol exposes
|
|
80
90
|
shape/ndim/size/dtype and explicit array conversion, without promising a
|
|
81
91
|
particular result shape or dtype. For additional native array methods in
|
|
82
92
|
static analysis, use `np.asarray(result.value)`.
|
|
83
93
|
|
|
94
|
+
For a typed complex phase, use this existing mathematical entry point directly:
|
|
95
|
+
|
|
96
|
+
```python
|
|
97
|
+
import numpy as np
|
|
98
|
+
from unitx import math
|
|
99
|
+
from unitx.si import si
|
|
100
|
+
|
|
101
|
+
z = np.linspace(-1, 1, 5) * si.m
|
|
102
|
+
gouy = math.atan(z / (0.5 * si.m))
|
|
103
|
+
field = math.conj(math.exp(1j * gouy) / math.hypot(1, z / (0.5 * si.m)))
|
|
104
|
+
field *= math.exp(-1j * gouy)
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
The phase formula needs no dtype argument or cast. Ordinary `np.exp(q)` and
|
|
108
|
+
`np.conj(q)` still work at runtime, but their NumPy function signatures may
|
|
109
|
+
infer a bare ndarray or an incomplete dtype. unitx does not alter those stubs.
|
|
110
|
+
|
|
84
111
|
## Clock readings
|
|
85
112
|
|
|
86
113
|
```python
|