From 428bb785425490b83b3f018a43c484f1c76184f5 Mon Sep 17 00:00:00 2001 From: shivasankar Date: Sat, 4 Apr 2026 01:05:32 +0900 Subject: [PATCH 01/11] update mojo to 26.2 --- pixi.lock | 934 ++++++++++++++++++++++++++++++------------------------ pixi.toml | 4 +- 2 files changed, 520 insertions(+), 418 deletions(-) diff --git a/pixi.lock b/pixi.lock index b488cfc..f9431c4 100644 --- a/pixi.lock +++ b/pixi.lock @@ -3,229 +3,230 @@ environments: default: channels: - url: https://repo.prefix.dev/modular-community/ - - url: https://conda.modular.com/max-nightly/ - url: https://conda.modular.com/max/ - url: https://conda.anaconda.org/conda-forge/ + - url: https://conda.modular.com/max-nightly/ + options: + pypi-prerelease-mode: if-necessary-or-explicit packages: linux-64: - conda: https://conda.anaconda.org/conda-forge/linux-64/_openmp_mutex-4.5-20_gnu.conda - conda: https://conda.anaconda.org/conda-forge/noarch/_python_abi3_support-1.0-hd8ed1ab_2.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/bzip2-1.0.8-hda65f42_9.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/ca-certificates-2026.1.4-hbd8a1cb_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/ca-certificates-2026.2.25-hbd8a1cb_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/click-8.3.1-pyh8f84b5b_1.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/cpython-3.13.12-py313hd8ed1ab_100.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/icu-78.2-h33c6efd_0.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/importlib-metadata-8.7.0-pyhe01879c_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/cpython-3.14.3-py314hd8ed1ab_101.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/icu-78.3-h33c6efd_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/importlib-metadata-8.8.0-pyhcf101f3_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/jupyter_client-8.6.3-pyhd8ed1ab_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/jupyter_core-5.9.1-pyhc90fa1f_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/keyutils-1.6.3-hb9d3cd8_0.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/krb5-1.21.3-h659f571_0.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/ld_impl_linux-64-2.45.1-default_hbd61a6d_101.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/krb5-1.22.2-ha1258a1_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/ld_impl_linux-64-2.45.1-default_hbd61a6d_102.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libedit-3.1.20250104-pl5321h7949ede_0.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/libexpat-2.7.4-hecca717_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libexpat-2.7.5-hecca717_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libffi-3.5.2-h3435931_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libgcc-15.2.0-he0feb66_18.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/libgcc-ng-15.2.0-h69a702a_18.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libgomp-15.2.0-he0feb66_18.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/liblzma-5.8.2-hb03c661_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libmpdec-4.0.0-hb03c661_1.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/libsodium-1.0.20-h4ab18f5_0.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/libsqlite-3.51.2-hf4e2dac_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libsodium-1.0.21-h280c20c_3.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libsqlite-3.52.0-hf4e2dac_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libstdcxx-15.2.0-h934c35e_18.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/libstdcxx-ng-15.2.0-hdf11a46_18.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/libuuid-2.41.3-h5347b49_0.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/libzlib-1.3.1-hb9d3cd8_2.conda - - conda: https://conda.modular.com/max-nightly/noarch/mblack-26.1.0-release.conda - - conda: https://conda.modular.com/max-nightly/linux-64/mojo-0.26.1.0-release.conda - - conda: https://conda.modular.com/max-nightly/linux-64/mojo-compiler-0.26.1.0-release.conda - - conda: https://conda.modular.com/max-nightly/noarch/mojo-python-0.26.1.0-release.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libuuid-2.42-h5347b49_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libzlib-1.3.2-h25fd6f3_2.conda + - conda: https://conda.modular.com/max/noarch/mblack-26.2.0-release.conda + - conda: https://conda.modular.com/max/linux-64/mojo-0.26.2.0-release.conda + - conda: https://conda.modular.com/max/linux-64/mojo-compiler-0.26.2.0-release.conda + - conda: https://conda.modular.com/max/noarch/mojo-python-0.26.2.0-release.conda - conda: https://conda.anaconda.org/conda-forge/noarch/mypy_extensions-1.1.0-pyha770c72_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/ncurses-6.5-h2d0b736_3.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/openssl-3.6.1-h35e630c_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/packaging-26.0-pyhcf101f3_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pathspec-1.0.4-pyhd8ed1ab_0.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/platformdirs-4.9.2-pyhcf101f3_0.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/python-3.13.12-hc97d973_100_cp313.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/platformdirs-4.9.4-pyhcf101f3_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/python-3.14.3-h32b2ec7_101_cp314.conda - conda: https://conda.anaconda.org/conda-forge/noarch/python-dateutil-2.9.0.post0-pyhe01879c_2.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/python-gil-3.13.12-h4df99d1_100.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/python_abi-3.13-8_cp313.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/pyzmq-27.1.0-py312hfb55c3c_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/python-gil-3.14.3-h4df99d1_101.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/python_abi-3.14-8_cp314.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/pyzmq-27.1.0-py312hda471dd_2.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/readline-8.3-h853b02a_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/six-1.17.0-pyhe01879c_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/tk-8.6.13-noxft_h366c992_103.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/tomli-2.4.0-pyhcf101f3_0.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/tornado-6.5.3-py313h07c4f96_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/tomli-2.4.1-pyhcf101f3_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/tornado-6.5.5-py314h5bd0f2a_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/traitlets-5.14.3-pyhd8ed1ab_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/tzdata-2025c-hc9c84f9_1.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/zeromq-4.3.5-h387f397_9.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/zeromq-4.3.5-h41580af_10.conda - conda: https://conda.anaconda.org/conda-forge/noarch/zipp-3.23.0-pyhcf101f3_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/zstd-1.5.7-hb78ec9c_6.conda osx-arm64: - conda: https://conda.anaconda.org/conda-forge/noarch/_python_abi3_support-1.0-hd8ed1ab_2.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/bzip2-1.0.8-hd037594_9.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/ca-certificates-2026.1.4-hbd8a1cb_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/ca-certificates-2026.2.25-hbd8a1cb_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/click-8.3.1-pyh8f84b5b_1.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/cpython-3.13.12-py313hd8ed1ab_100.conda - - conda: https://conda.anaconda.org/conda-forge/osx-arm64/icu-78.2-h38cb7af_0.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/importlib-metadata-8.7.0-pyhe01879c_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/cpython-3.14.3-py314hd8ed1ab_101.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/icu-78.3-hef89b57_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/importlib-metadata-8.8.0-pyhcf101f3_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/jupyter_client-8.6.3-pyhd8ed1ab_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/jupyter_core-5.9.1-pyhc90fa1f_0.conda - - conda: https://conda.anaconda.org/conda-forge/osx-arm64/krb5-1.21.3-h237132a_0.conda - - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libcxx-21.1.8-h55c6f16_2.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/krb5-1.22.2-h385eeb1_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libcxx-22.1.2-h55c6f16_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libedit-3.1.20250104-pl5321hafb1f1b_0.conda - - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libexpat-2.7.4-hf6b4638_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libexpat-2.7.5-hf6b4638_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libffi-3.5.2-hcf2aa1b_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/liblzma-5.8.2-h8088a28_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libmpdec-4.0.0-h84a0fba_1.conda - - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libsodium-1.0.20-h99b78c6_0.conda - - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libsqlite-3.51.2-h1ae2325_0.conda - - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libzlib-1.3.1-h8359307_2.conda - - conda: https://conda.modular.com/max-nightly/noarch/mblack-26.1.0-release.conda - - conda: https://conda.modular.com/max-nightly/osx-arm64/mojo-0.26.1.0-release.conda - - conda: https://conda.modular.com/max-nightly/osx-arm64/mojo-compiler-0.26.1.0-release.conda - - conda: https://conda.modular.com/max-nightly/noarch/mojo-python-0.26.1.0-release.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libsodium-1.0.21-h1a92334_3.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libsqlite-3.52.0-h1ae2325_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libzlib-1.3.2-h8088a28_2.conda + - conda: https://conda.modular.com/max/noarch/mblack-26.2.0-release.conda + - conda: https://conda.modular.com/max/osx-arm64/mojo-0.26.2.0-release.conda + - conda: https://conda.modular.com/max/osx-arm64/mojo-compiler-0.26.2.0-release.conda + - conda: https://conda.modular.com/max/noarch/mojo-python-0.26.2.0-release.conda - conda: https://conda.anaconda.org/conda-forge/noarch/mypy_extensions-1.1.0-pyha770c72_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/ncurses-6.5-h5e97a16_3.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/openssl-3.6.1-hd24854e_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/packaging-26.0-pyhcf101f3_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pathspec-1.0.4-pyhd8ed1ab_0.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/platformdirs-4.9.2-pyhcf101f3_0.conda - - conda: https://conda.anaconda.org/conda-forge/osx-arm64/python-3.13.12-h20e6be0_100_cp313.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/platformdirs-4.9.4-pyhcf101f3_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/python-3.14.3-h4c637c5_101_cp314.conda - conda: https://conda.anaconda.org/conda-forge/noarch/python-dateutil-2.9.0.post0-pyhe01879c_2.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/python-gil-3.13.12-h4df99d1_100.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/python_abi-3.13-8_cp313.conda - - conda: https://conda.anaconda.org/conda-forge/osx-arm64/pyzmq-27.1.0-py312hd65ceae_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/python-gil-3.14.3-h4df99d1_101.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/python_abi-3.14-8_cp314.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/pyzmq-27.1.0-py312h022ad19_2.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/readline-8.3-h46df422_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/six-1.17.0-pyhe01879c_1.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/tk-8.6.13-h010d191_3.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/tomli-2.4.0-pyhcf101f3_0.conda - - conda: https://conda.anaconda.org/conda-forge/osx-arm64/tornado-6.5.4-py313h6535dbc_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/tomli-2.4.1-pyhcf101f3_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/tornado-6.5.5-py314h6c2aa35_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/traitlets-5.14.3-pyhd8ed1ab_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/tzdata-2025c-hc9c84f9_1.conda - - conda: https://conda.anaconda.org/conda-forge/osx-arm64/zeromq-4.3.5-h888dc83_9.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/zeromq-4.3.5-h4818236_10.conda - conda: https://conda.anaconda.org/conda-forge/noarch/zipp-3.23.0-pyhcf101f3_1.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/zstd-1.5.7-hbf9d68e_6.conda test: channels: - url: https://repo.prefix.dev/modular-community/ - - url: https://conda.modular.com/max-nightly/ - url: https://conda.modular.com/max/ - url: https://conda.anaconda.org/conda-forge/ + - url: https://conda.modular.com/max-nightly/ + options: + pypi-prerelease-mode: if-necessary-or-explicit packages: linux-64: - conda: https://conda.anaconda.org/conda-forge/linux-64/_openmp_mutex-4.5-20_gnu.conda - conda: https://conda.anaconda.org/conda-forge/noarch/_python_abi3_support-1.0-hd8ed1ab_2.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/bzip2-1.0.8-hda65f42_9.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/ca-certificates-2026.1.4-hbd8a1cb_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/ca-certificates-2026.2.25-hbd8a1cb_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/click-8.3.1-pyh8f84b5b_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/cpython-3.13.12-py313hd8ed1ab_100.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/icu-78.2-h33c6efd_0.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/importlib-metadata-8.7.0-pyhe01879c_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/icu-78.3-h33c6efd_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/importlib-metadata-8.8.0-pyhcf101f3_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/jupyter_client-8.6.3-pyhd8ed1ab_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/jupyter_core-5.9.1-pyhc90fa1f_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/keyutils-1.6.3-hb9d3cd8_0.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/krb5-1.21.3-h659f571_0.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/ld_impl_linux-64-2.45.1-default_hbd61a6d_101.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/libblas-3.11.0-5_h4a7cf45_openblas.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/libcblas-3.11.0-5_h0358290_openblas.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/krb5-1.22.2-ha1258a1_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/ld_impl_linux-64-2.45.1-default_hbd61a6d_102.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libblas-3.11.0-6_h4a7cf45_openblas.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libcblas-3.11.0-6_h0358290_openblas.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libedit-3.1.20250104-pl5321h7949ede_0.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/libexpat-2.7.4-hecca717_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libexpat-2.7.5-hecca717_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libffi-3.5.2-h3435931_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libgcc-15.2.0-he0feb66_18.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/libgcc-ng-15.2.0-h69a702a_18.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libgfortran-15.2.0-h69a702a_18.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libgfortran5-15.2.0-h68bc16d_18.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libgomp-15.2.0-he0feb66_18.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/liblapack-3.11.0-5_h47877c9_openblas.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/liblapack-3.11.0-6_h47877c9_openblas.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/liblzma-5.8.2-hb03c661_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libmpdec-4.0.0-hb03c661_1.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/libopenblas-0.3.30-pthreads_h94d23a6_4.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/libsodium-1.0.20-h4ab18f5_0.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/libsqlite-3.51.2-hf4e2dac_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libopenblas-0.3.32-pthreads_h94d23a6_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libsodium-1.0.21-h280c20c_3.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libsqlite-3.52.0-hf4e2dac_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libstdcxx-15.2.0-h934c35e_18.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/libstdcxx-ng-15.2.0-hdf11a46_18.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/libuuid-2.41.3-h5347b49_0.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/libzlib-1.3.1-hb9d3cd8_2.conda - - conda: https://conda.modular.com/max-nightly/noarch/mblack-26.1.0-release.conda - - conda: https://conda.modular.com/max-nightly/linux-64/mojo-0.26.1.0-release.conda - - conda: https://conda.modular.com/max-nightly/linux-64/mojo-compiler-0.26.1.0-release.conda - - conda: https://conda.modular.com/max-nightly/noarch/mojo-python-0.26.1.0-release.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libuuid-2.42-h5347b49_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libzlib-1.3.2-h25fd6f3_2.conda + - conda: https://conda.modular.com/max/noarch/mblack-26.2.0-release.conda + - conda: https://conda.modular.com/max/linux-64/mojo-0.26.2.0-release.conda + - conda: https://conda.modular.com/max/linux-64/mojo-compiler-0.26.2.0-release.conda + - conda: https://conda.modular.com/max/noarch/mojo-python-0.26.2.0-release.conda - conda: https://conda.anaconda.org/conda-forge/noarch/mypy_extensions-1.1.0-pyha770c72_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/ncurses-6.5-h2d0b736_3.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/numpy-2.4.2-py313hf6604e3_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/numpy-2.4.3-py313hf6604e3_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/openssl-3.6.1-h35e630c_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/packaging-26.0-pyhcf101f3_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pathspec-1.0.4-pyhd8ed1ab_0.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/platformdirs-4.9.2-pyhcf101f3_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/platformdirs-4.9.4-pyhcf101f3_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/python-3.13.12-hc97d973_100_cp313.conda - conda: https://conda.anaconda.org/conda-forge/noarch/python-dateutil-2.9.0.post0-pyhe01879c_2.conda - conda: https://conda.anaconda.org/conda-forge/noarch/python-gil-3.13.12-h4df99d1_100.conda - conda: https://conda.anaconda.org/conda-forge/noarch/python_abi-3.13-8_cp313.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/pyzmq-27.1.0-py312hfb55c3c_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/pyzmq-27.1.0-py312hda471dd_2.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/readline-8.3-h853b02a_0.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/scipy-1.17.0-py313h4b8bb8b_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/scipy-1.17.1-py313h4b8bb8b_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/six-1.17.0-pyhe01879c_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/tk-8.6.13-noxft_h366c992_103.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/tomli-2.4.0-pyhcf101f3_0.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/tornado-6.5.3-py313h07c4f96_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/tomli-2.4.1-pyhcf101f3_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/tornado-6.5.5-py313h07c4f96_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/traitlets-5.14.3-pyhd8ed1ab_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/tzdata-2025c-hc9c84f9_1.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/zeromq-4.3.5-h387f397_9.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/zeromq-4.3.5-h41580af_10.conda - conda: https://conda.anaconda.org/conda-forge/noarch/zipp-3.23.0-pyhcf101f3_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/zstd-1.5.7-hb78ec9c_6.conda osx-arm64: - conda: https://conda.anaconda.org/conda-forge/osx-arm64/_openmp_mutex-4.5-7_kmp_llvm.conda - conda: https://conda.anaconda.org/conda-forge/noarch/_python_abi3_support-1.0-hd8ed1ab_2.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/bzip2-1.0.8-hd037594_9.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/ca-certificates-2026.1.4-hbd8a1cb_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/ca-certificates-2026.2.25-hbd8a1cb_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/click-8.3.1-pyh8f84b5b_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/cpython-3.13.12-py313hd8ed1ab_100.conda - - conda: https://conda.anaconda.org/conda-forge/osx-arm64/icu-78.2-h38cb7af_0.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/importlib-metadata-8.7.0-pyhe01879c_1.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/icu-78.3-hef89b57_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/importlib-metadata-8.8.0-pyhcf101f3_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/jupyter_client-8.6.3-pyhd8ed1ab_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/jupyter_core-5.9.1-pyhc90fa1f_0.conda - - conda: https://conda.anaconda.org/conda-forge/osx-arm64/krb5-1.21.3-h237132a_0.conda - - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libblas-3.11.0-5_h51639a9_openblas.conda - - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libcblas-3.11.0-5_hb0561ab_openblas.conda - - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libcxx-21.1.8-h55c6f16_2.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/krb5-1.22.2-h385eeb1_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libblas-3.11.0-6_h51639a9_openblas.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libcblas-3.11.0-6_hb0561ab_openblas.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libcxx-22.1.2-h55c6f16_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libedit-3.1.20250104-pl5321hafb1f1b_0.conda - - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libexpat-2.7.4-hf6b4638_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libexpat-2.7.5-hf6b4638_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libffi-3.5.2-hcf2aa1b_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libgcc-15.2.0-hcbb3090_18.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libgfortran-15.2.0-h07b0088_18.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libgfortran5-15.2.0-hdae7583_18.conda - - conda: https://conda.anaconda.org/conda-forge/osx-arm64/liblapack-3.11.0-5_hd9741b5_openblas.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/liblapack-3.11.0-6_hd9741b5_openblas.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/liblzma-5.8.2-h8088a28_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libmpdec-4.0.0-h84a0fba_1.conda - - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libopenblas-0.3.30-openmp_ha158390_4.conda - - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libsodium-1.0.20-h99b78c6_0.conda - - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libsqlite-3.51.2-h1ae2325_0.conda - - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libzlib-1.3.1-h8359307_2.conda - - conda: https://conda.anaconda.org/conda-forge/osx-arm64/llvm-openmp-21.1.8-h4a912ad_0.conda - - conda: https://conda.modular.com/max-nightly/noarch/mblack-26.1.0-release.conda - - conda: https://conda.modular.com/max-nightly/osx-arm64/mojo-0.26.1.0-release.conda - - conda: https://conda.modular.com/max-nightly/osx-arm64/mojo-compiler-0.26.1.0-release.conda - - conda: https://conda.modular.com/max-nightly/noarch/mojo-python-0.26.1.0-release.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libopenblas-0.3.32-openmp_he657e61_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libsodium-1.0.21-h1a92334_3.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libsqlite-3.52.0-h1ae2325_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libzlib-1.3.2-h8088a28_2.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/llvm-openmp-22.1.2-hc7d1edf_0.conda + - conda: https://conda.modular.com/max/noarch/mblack-26.2.0-release.conda + - conda: https://conda.modular.com/max/osx-arm64/mojo-0.26.2.0-release.conda + - conda: https://conda.modular.com/max/osx-arm64/mojo-compiler-0.26.2.0-release.conda + - conda: https://conda.modular.com/max/noarch/mojo-python-0.26.2.0-release.conda - conda: https://conda.anaconda.org/conda-forge/noarch/mypy_extensions-1.1.0-pyha770c72_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/ncurses-6.5-h5e97a16_3.conda - - conda: https://conda.anaconda.org/conda-forge/osx-arm64/numpy-2.4.2-py313h16eae64_1.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/numpy-2.4.3-py313he4a34aa_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/openssl-3.6.1-hd24854e_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/packaging-26.0-pyhcf101f3_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pathspec-1.0.4-pyhd8ed1ab_0.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/platformdirs-4.9.2-pyhcf101f3_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/platformdirs-4.9.4-pyhcf101f3_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/python-3.13.12-h20e6be0_100_cp313.conda - conda: https://conda.anaconda.org/conda-forge/noarch/python-dateutil-2.9.0.post0-pyhe01879c_2.conda - conda: https://conda.anaconda.org/conda-forge/noarch/python-gil-3.13.12-h4df99d1_100.conda - conda: https://conda.anaconda.org/conda-forge/noarch/python_abi-3.13-8_cp313.conda - - conda: https://conda.anaconda.org/conda-forge/osx-arm64/pyzmq-27.1.0-py312hd65ceae_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/pyzmq-27.1.0-py312h022ad19_2.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/readline-8.3-h46df422_0.conda - - conda: https://conda.anaconda.org/conda-forge/osx-arm64/scipy-1.17.0-py313hc753a45_1.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/scipy-1.17.1-py313hc753a45_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/six-1.17.0-pyhe01879c_1.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/tk-8.6.13-h010d191_3.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/tomli-2.4.0-pyhcf101f3_0.conda - - conda: https://conda.anaconda.org/conda-forge/osx-arm64/tornado-6.5.4-py313h6535dbc_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/tomli-2.4.1-pyhcf101f3_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/tornado-6.5.5-py313h0997733_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/traitlets-5.14.3-pyhd8ed1ab_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/tzdata-2025c-hc9c84f9_1.conda - - conda: https://conda.anaconda.org/conda-forge/osx-arm64/zeromq-4.3.5-h888dc83_9.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/zeromq-4.3.5-h4818236_10.conda - conda: https://conda.anaconda.org/conda-forge/noarch/zipp-3.23.0-pyhcf101f3_1.conda packages: - conda: https://conda.anaconda.org/conda-forge/linux-64/_openmp_mutex-4.5-20_gnu.conda @@ -280,14 +281,14 @@ packages: license_family: BSD size: 124834 timestamp: 1771350416561 -- conda: https://conda.anaconda.org/conda-forge/noarch/ca-certificates-2026.1.4-hbd8a1cb_0.conda - sha256: b5974ec9b50e3c514a382335efa81ed02b05906849827a34061c496f4defa0b2 - md5: bddacf101bb4dd0e51811cb69c7790e2 +- conda: https://conda.anaconda.org/conda-forge/noarch/ca-certificates-2026.2.25-hbd8a1cb_0.conda + sha256: 67cc7101b36421c5913a1687ef1b99f85b5d6868da3abbf6ec1a4181e79782fc + md5: 4492fd26db29495f0ba23f146cd5638d depends: - __unix license: ISC - size: 146519 - timestamp: 1767500828366 + size: 147413 + timestamp: 1772006283803 - conda: https://conda.anaconda.org/conda-forge/noarch/click-8.3.1-pyh8f84b5b_1.conda sha256: 38cfe1ee75b21a8361c8824f5544c3866f303af1762693a178266d7f198e8715 md5: ea8a6c3256897cc31263de9f455e25d9 @@ -309,37 +310,47 @@ packages: license: Python-2.0 size: 48648 timestamp: 1770270374831 -- conda: https://conda.anaconda.org/conda-forge/linux-64/icu-78.2-h33c6efd_0.conda - sha256: 142a722072fa96cf16ff98eaaf641f54ab84744af81754c292cb81e0881c0329 - md5: 186a18e3ba246eccfc7cff00cd19a870 +- conda: https://conda.anaconda.org/conda-forge/noarch/cpython-3.14.3-py314hd8ed1ab_101.conda + noarch: generic + sha256: 91b06300879df746214f7363d6c27c2489c80732e46a369eb2afc234bcafb44c + md5: 3bb89e4f795e5414addaa531d6b1500a + depends: + - python >=3.14,<3.15.0a0 + - python_abi * *_cp314 + license: Python-2.0 + size: 50078 + timestamp: 1770674447292 +- conda: https://conda.anaconda.org/conda-forge/linux-64/icu-78.3-h33c6efd_0.conda + sha256: fbf86c4a59c2ed05bbffb2ba25c7ed94f6185ec30ecb691615d42342baa1a16a + md5: c80d8a3b84358cb967fa81e7075fbc8a depends: - __glibc >=2.17,<3.0.a0 - libgcc >=14 - libstdcxx >=14 license: MIT license_family: MIT - size: 12728445 - timestamp: 1767969922681 -- conda: https://conda.anaconda.org/conda-forge/osx-arm64/icu-78.2-h38cb7af_0.conda - sha256: d4cefbca587429d1192509edc52c88de52bc96c2447771ddc1f8bee928aed5ef - md5: 1e93aca311da0210e660d2247812fa02 + size: 12723451 + timestamp: 1773822285671 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/icu-78.3-hef89b57_0.conda + sha256: 3a7907a17e9937d3a46dfd41cffaf815abad59a569440d1e25177c15fd0684e5 + md5: f1182c91c0de31a7abd40cedf6a5ebef depends: - __osx >=11.0 license: MIT license_family: MIT - size: 12358010 - timestamp: 1767970350308 -- conda: https://conda.anaconda.org/conda-forge/noarch/importlib-metadata-8.7.0-pyhe01879c_1.conda - sha256: c18ab120a0613ada4391b15981d86ff777b5690ca461ea7e9e49531e8f374745 - md5: 63ccfdc3a3ce25b027b8767eb722fca8 + size: 12361647 + timestamp: 1773822915649 +- conda: https://conda.anaconda.org/conda-forge/noarch/importlib-metadata-8.8.0-pyhcf101f3_0.conda + sha256: 82ab2a0d91ca1e7e63ab6a4939356667ef683905dea631bc2121aa534d347b16 + md5: 080594bf4493e6bae2607e65390c520a depends: - - python >=3.9 + - python >=3.10 - zipp >=3.20 - python license: Apache-2.0 license_family: APACHE - size: 34641 - timestamp: 1747934053147 + size: 34387 + timestamp: 1773931568510 - conda: https://conda.anaconda.org/conda-forge/noarch/jupyter_client-8.6.3-pyhd8ed1ab_1.conda sha256: 19d8bd5bb2fde910ec59e081eeb59529491995ce0d653a5209366611023a0b3a md5: 4ebae00eae9705b0c3d6d1018a81d047 @@ -380,36 +391,37 @@ packages: license: LGPL-2.1-or-later size: 134088 timestamp: 1754905959823 -- conda: https://conda.anaconda.org/conda-forge/linux-64/krb5-1.21.3-h659f571_0.conda - sha256: 99df692f7a8a5c27cd14b5fb1374ee55e756631b9c3d659ed3ee60830249b238 - md5: 3f43953b7d3fb3aaa1d0d0723d91e368 - depends: - - keyutils >=1.6.1,<2.0a0 - - libedit >=3.1.20191231,<3.2.0a0 - - libedit >=3.1.20191231,<4.0a0 - - libgcc-ng >=12 - - libstdcxx-ng >=12 - - openssl >=3.3.1,<4.0a0 +- conda: https://conda.anaconda.org/conda-forge/linux-64/krb5-1.22.2-ha1258a1_0.conda + sha256: 3e307628ca3527448dd1cb14ad7bb9d04d1d28c7d4c5f97ba196ae984571dd25 + md5: fb53fb07ce46a575c5d004bbc96032c2 + depends: + - __glibc >=2.17,<3.0.a0 + - keyutils >=1.6.3,<2.0a0 + - libedit >=3.1.20250104,<3.2.0a0 + - libedit >=3.1.20250104,<4.0a0 + - libgcc >=14 + - libstdcxx >=14 + - openssl >=3.5.5,<4.0a0 license: MIT license_family: MIT - size: 1370023 - timestamp: 1719463201255 -- conda: https://conda.anaconda.org/conda-forge/osx-arm64/krb5-1.21.3-h237132a_0.conda - sha256: 4442f957c3c77d69d9da3521268cad5d54c9033f1a73f99cde0a3658937b159b - md5: c6dc8a0fdec13a0565936655c33069a1 + size: 1386730 + timestamp: 1769769569681 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/krb5-1.22.2-h385eeb1_0.conda + sha256: c0a0bf028fe7f3defcdcaa464e536cf1b202d07451e18ad83fdd169d15bef6ed + md5: e446e1822f4da8e5080a9de93474184d depends: - __osx >=11.0 - - libcxx >=16 - - libedit >=3.1.20191231,<3.2.0a0 - - libedit >=3.1.20191231,<4.0a0 - - openssl >=3.3.1,<4.0a0 + - libcxx >=19 + - libedit >=3.1.20250104,<3.2.0a0 + - libedit >=3.1.20250104,<4.0a0 + - openssl >=3.5.5,<4.0a0 license: MIT license_family: MIT - size: 1155530 - timestamp: 1719463474401 -- conda: https://conda.anaconda.org/conda-forge/linux-64/ld_impl_linux-64-2.45.1-default_hbd61a6d_101.conda - sha256: 565941ac1f8b0d2f2e8f02827cbca648f4d18cd461afc31f15604cd291b5c5f3 - md5: 12bd9a3f089ee6c9266a37dab82afabd + size: 1160828 + timestamp: 1769770119811 +- conda: https://conda.anaconda.org/conda-forge/linux-64/ld_impl_linux-64-2.45.1-default_hbd61a6d_102.conda + sha256: 3d584956604909ff5df353767f3a2a2f60e07d070b328d109f30ac40cd62df6c + md5: 18335a698559cdbcd86150a48bf54ba6 depends: - __glibc >=2.17,<3.0.a0 - zstd >=1.5.7,<1.6.0a0 @@ -417,79 +429,79 @@ packages: - binutils_impl_linux-64 2.45.1 license: GPL-3.0-only license_family: GPL - size: 725507 - timestamp: 1770267139900 -- conda: https://conda.anaconda.org/conda-forge/linux-64/libblas-3.11.0-5_h4a7cf45_openblas.conda - build_number: 5 - sha256: 18c72545080b86739352482ba14ba2c4815e19e26a7417ca21a95b76ec8da24c - md5: c160954f7418d7b6e87eaf05a8913fa9 - depends: - - libopenblas >=0.3.30,<0.3.31.0a0 - - libopenblas >=0.3.30,<1.0a0 + size: 728002 + timestamp: 1774197446916 +- conda: https://conda.anaconda.org/conda-forge/linux-64/libblas-3.11.0-6_h4a7cf45_openblas.conda + build_number: 6 + sha256: 7bfe936dbb5db04820cf300a9cc1f5ee8d5302fc896c2d66e30f1ee2f20fbfd6 + md5: 6d6d225559bfa6e2f3c90ee9c03d4e2e + depends: + - libopenblas >=0.3.32,<0.3.33.0a0 + - libopenblas >=0.3.32,<1.0a0 constrains: + - blas 2.306 openblas + - liblapack 3.11.0 6*_openblas + - liblapacke 3.11.0 6*_openblas + - libcblas 3.11.0 6*_openblas - mkl <2026 - - liblapack 3.11.0 5*_openblas - - libcblas 3.11.0 5*_openblas - - blas 2.305 openblas - - liblapacke 3.11.0 5*_openblas license: BSD-3-Clause license_family: BSD - size: 18213 - timestamp: 1765818813880 -- conda: https://conda.anaconda.org/conda-forge/osx-arm64/libblas-3.11.0-5_h51639a9_openblas.conda - build_number: 5 - sha256: 620a6278f194dcabc7962277da6835b1e968e46ad0c8e757736255f5ddbfca8d - md5: bcc025e2bbaf8a92982d20863fe1fb69 - depends: - - libopenblas >=0.3.30,<0.3.31.0a0 - - libopenblas >=0.3.30,<1.0a0 + size: 18621 + timestamp: 1774503034895 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/libblas-3.11.0-6_h51639a9_openblas.conda + build_number: 6 + sha256: 979227fc03628925037ab2dfda008eb7b5592644d9c2c21dd285cefe8c42553d + md5: e551103471911260488a02155cef9c94 + depends: + - libopenblas >=0.3.32,<0.3.33.0a0 + - libopenblas >=0.3.32,<1.0a0 constrains: - - libcblas 3.11.0 5*_openblas - - liblapack 3.11.0 5*_openblas - - liblapacke 3.11.0 5*_openblas - - blas 2.305 openblas + - liblapacke 3.11.0 6*_openblas + - liblapack 3.11.0 6*_openblas + - blas 2.306 openblas + - libcblas 3.11.0 6*_openblas - mkl <2026 license: BSD-3-Clause license_family: BSD - size: 18546 - timestamp: 1765819094137 -- conda: https://conda.anaconda.org/conda-forge/linux-64/libcblas-3.11.0-5_h0358290_openblas.conda - build_number: 5 - sha256: 0cbdcc67901e02dc17f1d19e1f9170610bd828100dc207de4d5b6b8ad1ae7ad8 - md5: 6636a2b6f1a87572df2970d3ebc87cc0 - depends: - - libblas 3.11.0 5_h4a7cf45_openblas + size: 18859 + timestamp: 1774504387211 +- conda: https://conda.anaconda.org/conda-forge/linux-64/libcblas-3.11.0-6_h0358290_openblas.conda + build_number: 6 + sha256: 57edafa7796f6fa3ebbd5367692dd4c7f552be42109c2dd1a7c89b55089bf374 + md5: 36ae340a916635b97ac8a0655ace2a35 + depends: + - libblas 3.11.0 6_h4a7cf45_openblas constrains: - - liblapacke 3.11.0 5*_openblas - - blas 2.305 openblas - - liblapack 3.11.0 5*_openblas + - blas 2.306 openblas + - liblapack 3.11.0 6*_openblas + - liblapacke 3.11.0 6*_openblas license: BSD-3-Clause license_family: BSD - size: 18194 - timestamp: 1765818837135 -- conda: https://conda.anaconda.org/conda-forge/osx-arm64/libcblas-3.11.0-5_hb0561ab_openblas.conda - build_number: 5 - sha256: 38809c361bbd165ecf83f7f05fae9b791e1baa11e4447367f38ae1327f402fc0 - md5: efd8bd15ca56e9d01748a3beab8404eb - depends: - - libblas 3.11.0 5_h51639a9_openblas + size: 18622 + timestamp: 1774503050205 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/libcblas-3.11.0-6_hb0561ab_openblas.conda + build_number: 6 + sha256: 2e6b3e9b1ab672133b70fc6730e42290e952793f132cb5e72eee22835463eba0 + md5: 805c6d31c5621fd75e53dfcf21fb243a + depends: + - libblas 3.11.0 6_h51639a9_openblas constrains: - - liblapacke 3.11.0 5*_openblas - - liblapack 3.11.0 5*_openblas - - blas 2.305 openblas + - liblapacke 3.11.0 6*_openblas + - blas 2.306 openblas + - liblapack 3.11.0 6*_openblas license: BSD-3-Clause license_family: BSD - size: 18548 - timestamp: 1765819108956 -- conda: https://conda.anaconda.org/conda-forge/osx-arm64/libcxx-21.1.8-h55c6f16_2.conda - sha256: 5fbeb2fc2673f0455af6079abf93faaf27f11a92574ad51565fa1ecac9a4e2aa - md5: 4cb5878bdb9ebfa65b7cdff5445087c5 + size: 18863 + timestamp: 1774504433388 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/libcxx-22.1.2-h55c6f16_0.conda + sha256: d1402087c8792461bfc081629e8aa97e6e577a31ae0b84e6b9cc144a18f48067 + md5: 4280e0a7fd613b271e022e60dea0138c depends: - __osx >=11.0 license: Apache-2.0 WITH LLVM-exception license_family: Apache - size: 570068 - timestamp: 1770238262922 + size: 568094 + timestamp: 1774439202359 - conda: https://conda.anaconda.org/conda-forge/linux-64/libedit-3.1.20250104-pl5321h7949ede_0.conda sha256: d789471216e7aba3c184cd054ed61ce3f6dac6f87a50ec69291b9297f8c18724 md5: c277e0a4d549b03ac1e9d6cbbe3d017b @@ -513,29 +525,29 @@ packages: license_family: BSD size: 107691 timestamp: 1738479560845 -- conda: https://conda.anaconda.org/conda-forge/linux-64/libexpat-2.7.4-hecca717_0.conda - sha256: d78f1d3bea8c031d2f032b760f36676d87929b18146351c4464c66b0869df3f5 - md5: e7f7ce06ec24cfcfb9e36d28cf82ba57 +- conda: https://conda.anaconda.org/conda-forge/linux-64/libexpat-2.7.5-hecca717_0.conda + sha256: e8c2b57f6aacabdf2f1b0924bd4831ce5071ba080baa4a9e8c0d720588b6794c + md5: 49f570f3bc4c874a06ea69b7225753af depends: - __glibc >=2.17,<3.0.a0 - libgcc >=14 constrains: - - expat 2.7.4.* + - expat 2.7.5.* license: MIT license_family: MIT - size: 76798 - timestamp: 1771259418166 -- conda: https://conda.anaconda.org/conda-forge/osx-arm64/libexpat-2.7.4-hf6b4638_0.conda - sha256: 03887d8080d6a8fe02d75b80929271b39697ecca7628f0657d7afaea87761edf - md5: a92e310ae8dfc206ff449f362fc4217f + size: 76624 + timestamp: 1774719175983 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/libexpat-2.7.5-hf6b4638_0.conda + sha256: 06780dec91dd25770c8cf01e158e1062fbf7c576b1406427475ce69a8af75b7e + md5: a32123f93e168eaa4080d87b0fb5da8a depends: - __osx >=11.0 constrains: - - expat 2.7.4.* + - expat 2.7.5.* license: MIT license_family: MIT - size: 68199 - timestamp: 1771260020767 + size: 68192 + timestamp: 1774719211725 - conda: https://conda.anaconda.org/conda-forge/linux-64/libffi-3.5.2-h3435931_0.conda sha256: 31f19b6a88ce40ebc0d5a992c131f57d919f73c0b92cd1617a5bec83f6e961e6 md5: a360c33a5abe61c07959e449fa1453eb @@ -580,15 +592,6 @@ packages: license_family: GPL size: 401974 timestamp: 1771378877463 -- conda: https://conda.anaconda.org/conda-forge/linux-64/libgcc-ng-15.2.0-h69a702a_18.conda - sha256: e318a711400f536c81123e753d4c797a821021fb38970cebfb3f454126016893 - md5: d5e96b1ed75ca01906b3d2469b4ce493 - depends: - - libgcc 15.2.0 he0feb66_18 - license: GPL-3.0-only WITH GCC-exception-3.1 - license_family: GPL - size: 27526 - timestamp: 1771378224552 - conda: https://conda.anaconda.org/conda-forge/linux-64/libgfortran-15.2.0-h69a702a_18.conda sha256: d2c9fad338fd85e4487424865da8e74006ab2e2475bd788f624d7a39b2a72aee md5: 9063115da5bc35fdc3e1002e69b9ef6e @@ -643,34 +646,34 @@ packages: license_family: GPL size: 603262 timestamp: 1771378117851 -- conda: https://conda.anaconda.org/conda-forge/linux-64/liblapack-3.11.0-5_h47877c9_openblas.conda - build_number: 5 - sha256: c723b6599fcd4c6c75dee728359ef418307280fa3e2ee376e14e85e5bbdda053 - md5: b38076eb5c8e40d0106beda6f95d7609 +- conda: https://conda.anaconda.org/conda-forge/linux-64/liblapack-3.11.0-6_h47877c9_openblas.conda + build_number: 6 + sha256: 371f517eb7010b21c6cc882c7606daccebb943307cb9a3bf2c70456a5c024f7d + md5: 881d801569b201c2e753f03c84b85e15 depends: - - libblas 3.11.0 5_h4a7cf45_openblas + - libblas 3.11.0 6_h4a7cf45_openblas constrains: - - blas 2.305 openblas - - liblapacke 3.11.0 5*_openblas - - libcblas 3.11.0 5*_openblas + - blas 2.306 openblas + - liblapacke 3.11.0 6*_openblas + - libcblas 3.11.0 6*_openblas license: BSD-3-Clause license_family: BSD - size: 18200 - timestamp: 1765818857876 -- conda: https://conda.anaconda.org/conda-forge/osx-arm64/liblapack-3.11.0-5_hd9741b5_openblas.conda - build_number: 5 - sha256: 735a6e6f7d7da6f718b6690b7c0a8ae4815afb89138aa5793abe78128e951dbb - md5: ca9d752201b7fa1225bca036ee300f2b - depends: - - libblas 3.11.0 5_h51639a9_openblas + size: 18624 + timestamp: 1774503065378 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/liblapack-3.11.0-6_hd9741b5_openblas.conda + build_number: 6 + sha256: 21606b7346810559e259807497b86f438950cf19e71838e44ebaf4bd2b35b549 + md5: ee33d2d05a7c5ea1f67653b37eb74db1 + depends: + - libblas 3.11.0 6_h51639a9_openblas constrains: - - libcblas 3.11.0 5*_openblas - - blas 2.305 openblas - - liblapacke 3.11.0 5*_openblas + - liblapacke 3.11.0 6*_openblas + - libcblas 3.11.0 6*_openblas + - blas 2.306 openblas license: BSD-3-Clause license_family: BSD - size: 18551 - timestamp: 1765819121855 + size: 18863 + timestamp: 1774504467905 - conda: https://conda.anaconda.org/conda-forge/linux-64/liblzma-5.8.2-hb03c661_0.conda sha256: 755c55ebab181d678c12e49cced893598f2bab22d582fbbf4d8b83c18be207eb md5: c7c83eecbb72d88b940c249af56c8b17 @@ -711,71 +714,72 @@ packages: license_family: BSD size: 73690 timestamp: 1769482560514 -- conda: https://conda.anaconda.org/conda-forge/linux-64/libopenblas-0.3.30-pthreads_h94d23a6_4.conda - sha256: 199d79c237afb0d4780ccd2fbf829cea80743df60df4705202558675e07dd2c5 - md5: be43915efc66345cccb3c310b6ed0374 +- conda: https://conda.anaconda.org/conda-forge/linux-64/libopenblas-0.3.32-pthreads_h94d23a6_0.conda + sha256: 6dc30b28f32737a1c52dada10c8f3a41bc9e021854215efca04a7f00487d09d9 + md5: 89d61bc91d3f39fda0ca10fcd3c68594 depends: - __glibc >=2.17,<3.0.a0 - libgcc >=14 - libgfortran - libgfortran5 >=14.3.0 constrains: - - openblas >=0.3.30,<0.3.31.0a0 + - openblas >=0.3.32,<0.3.33.0a0 license: BSD-3-Clause license_family: BSD - size: 5927939 - timestamp: 1763114673331 -- conda: https://conda.anaconda.org/conda-forge/osx-arm64/libopenblas-0.3.30-openmp_ha158390_4.conda - sha256: ebbbc089b70bcde87c4121a083c724330f02a690fb9d7c6cd18c30f1b12504fa - md5: a6f6d3a31bb29e48d37ce65de54e2df0 + size: 5928890 + timestamp: 1774471724897 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/libopenblas-0.3.32-openmp_he657e61_0.conda + sha256: 713e453bde3531c22a660577e59bf91ef578dcdfd5edb1253a399fa23514949a + md5: 3a1111a4b6626abebe8b978bb5a323bf depends: - __osx >=11.0 - libgfortran - libgfortran5 >=14.3.0 - llvm-openmp >=19.1.7 constrains: - - openblas >=0.3.30,<0.3.31.0a0 + - openblas >=0.3.32,<0.3.33.0a0 license: BSD-3-Clause license_family: BSD - size: 4284132 - timestamp: 1768547079205 -- conda: https://conda.anaconda.org/conda-forge/linux-64/libsodium-1.0.20-h4ab18f5_0.conda - sha256: 0105bd108f19ea8e6a78d2d994a6d4a8db16d19a41212070d2d1d48a63c34161 - md5: a587892d3c13b6621a6091be690dbca2 + size: 4308797 + timestamp: 1774472508546 +- conda: https://conda.anaconda.org/conda-forge/linux-64/libsodium-1.0.21-h280c20c_3.conda + sha256: 64e5c80cbce4680a2d25179949739a6def695d72c40ca28f010711764e372d97 + md5: 7af961ef4aa2c1136e11dd43ded245ab depends: - - libgcc-ng >=12 + - libgcc >=14 + - __glibc >=2.17,<3.0.a0 license: ISC - size: 205978 - timestamp: 1716828628198 -- conda: https://conda.anaconda.org/conda-forge/osx-arm64/libsodium-1.0.20-h99b78c6_0.conda - sha256: fade8223e1e1004367d7101dd17261003b60aa576df6d7802191f8972f7470b1 - md5: a7ce36e284c5faaf93c220dfc39e3abd + size: 277661 + timestamp: 1772479381288 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/libsodium-1.0.21-h1a92334_3.conda + sha256: df603472ea1ebd8e7d4fb71e4360fe48d10b11c240df51c129de1da2ff9e8227 + md5: 7cc5247987e6d115134ebab15186bc13 depends: - __osx >=11.0 license: ISC - size: 164972 - timestamp: 1716828607917 -- conda: https://conda.anaconda.org/conda-forge/linux-64/libsqlite-3.51.2-hf4e2dac_0.conda - sha256: 04596fcee262a870e4b7c9807224680ff48d4d0cc0dac076a602503d3dc6d217 - md5: da5be73701eecd0e8454423fd6ffcf30 + size: 248039 + timestamp: 1772479570912 +- conda: https://conda.anaconda.org/conda-forge/linux-64/libsqlite-3.52.0-hf4e2dac_0.conda + sha256: d716847b7deca293d2e49ed1c8ab9e4b9e04b9d780aea49a97c26925b28a7993 + md5: fd893f6a3002a635b5e50ceb9dd2c0f4 depends: - __glibc >=2.17,<3.0.a0 - icu >=78.2,<79.0a0 - libgcc >=14 - libzlib >=1.3.1,<2.0a0 license: blessing - size: 942808 - timestamp: 1768147973361 -- conda: https://conda.anaconda.org/conda-forge/osx-arm64/libsqlite-3.51.2-h1ae2325_0.conda - sha256: 6e9b9f269732cbc4698c7984aa5b9682c168e2a8d1e0406e1ff10091ca046167 - md5: 4b0bf313c53c3e89692f020fb55d5f2c + size: 951405 + timestamp: 1772818874251 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/libsqlite-3.52.0-h1ae2325_0.conda + sha256: beb0fd5594d6d7c7cd42c992b6bb4d66cbb39d6c94a8234f15956da99a04306c + md5: f6233a3fddc35a2ec9f617f79d6f3d71 depends: - __osx >=11.0 - icu >=78.2,<79.0a0 - libzlib >=1.3.1,<2.0a0 license: blessing - size: 909777 - timestamp: 1768148320535 + size: 918420 + timestamp: 1772819478684 - conda: https://conda.anaconda.org/conda-forge/linux-64/libstdcxx-15.2.0-h934c35e_18.conda sha256: 78668020064fdaa27e9ab65cd2997e2c837b564ab26ce3bf0e58a2ce1a525c6e md5: 1b08cd684f34175e4514474793d44bcb @@ -788,63 +792,54 @@ packages: license_family: GPL size: 5852330 timestamp: 1771378262446 -- conda: https://conda.anaconda.org/conda-forge/linux-64/libstdcxx-ng-15.2.0-hdf11a46_18.conda - sha256: 3c902ffd673cb3c6ddde624cdb80f870b6c835f8bf28384b0016e7d444dd0145 - md5: 6235adb93d064ecdf3d44faee6f468de - depends: - - libstdcxx 15.2.0 h934c35e_18 - license: GPL-3.0-only WITH GCC-exception-3.1 - license_family: GPL - size: 27575 - timestamp: 1771378314494 -- conda: https://conda.anaconda.org/conda-forge/linux-64/libuuid-2.41.3-h5347b49_0.conda - sha256: 1a7539cfa7df00714e8943e18de0b06cceef6778e420a5ee3a2a145773758aee - md5: db409b7c1720428638e7c0d509d3e1b5 +- conda: https://conda.anaconda.org/conda-forge/linux-64/libuuid-2.42-h5347b49_0.conda + sha256: bc1b08c92626c91500fd9f26f2c797f3eb153b627d53e9c13cd167f1e12b2829 + md5: 38ffe67b78c9d4de527be8315e5ada2c depends: - __glibc >=2.17,<3.0.a0 - libgcc >=14 license: BSD-3-Clause license_family: BSD - size: 40311 - timestamp: 1766271528534 -- conda: https://conda.anaconda.org/conda-forge/linux-64/libzlib-1.3.1-hb9d3cd8_2.conda - sha256: d4bfe88d7cb447768e31650f06257995601f89076080e76df55e3112d4e47dc4 - md5: edb0dca6bc32e4f4789199455a1dbeb8 + size: 40297 + timestamp: 1775052476770 +- conda: https://conda.anaconda.org/conda-forge/linux-64/libzlib-1.3.2-h25fd6f3_2.conda + sha256: 55044c403570f0dc26e6364de4dc5368e5f3fc7ff103e867c487e2b5ab2bcda9 + md5: d87ff7921124eccd67248aa483c23fec depends: - __glibc >=2.17,<3.0.a0 - - libgcc >=13 constrains: - - zlib 1.3.1 *_2 + - zlib 1.3.2 *_2 license: Zlib license_family: Other - size: 60963 - timestamp: 1727963148474 -- conda: https://conda.anaconda.org/conda-forge/osx-arm64/libzlib-1.3.1-h8359307_2.conda - sha256: ce34669eadaba351cd54910743e6a2261b67009624dbc7daeeafdef93616711b - md5: 369964e85dc26bfe78f41399b366c435 + size: 63629 + timestamp: 1774072609062 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/libzlib-1.3.2-h8088a28_2.conda + sha256: 361415a698514b19a852f5d1123c5da746d4642139904156ddfca7c922d23a05 + md5: bc5a5721b6439f2f62a84f2548136082 depends: - __osx >=11.0 constrains: - - zlib 1.3.1 *_2 + - zlib 1.3.2 *_2 license: Zlib license_family: Other - size: 46438 - timestamp: 1727963202283 -- conda: https://conda.anaconda.org/conda-forge/osx-arm64/llvm-openmp-21.1.8-h4a912ad_0.conda - sha256: 56bcd20a0a44ddd143b6ce605700fdf876bcf5c509adc50bf27e76673407a070 - md5: 206ad2df1b5550526e386087bef543c7 + size: 47759 + timestamp: 1774072956767 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/llvm-openmp-22.1.2-hc7d1edf_0.conda + sha256: d8acb8e790312346a286f7168380ca3ce86d5982fb073df6e0fbec1e51fa47a1 + md5: 9c162044093d8d689836dafe3c27fe06 depends: - __osx >=11.0 constrains: - - openmp 21.1.8|21.1.8.* - intel-openmp <0.0a0 + - openmp 22.1.2|22.1.2.* license: Apache-2.0 WITH LLVM-exception license_family: APACHE - size: 285974 - timestamp: 1765964756583 -- conda: https://conda.modular.com/max-nightly/noarch/mblack-26.1.0-release.conda + size: 285695 + timestamp: 1774733561929 +- conda: https://conda.modular.com/max/noarch/mblack-26.2.0-release.conda noarch: python - sha256: 6ccec52fe7354f44be93a41a122d2214ecdb030e6362afe8e7876eab35472e62 + sha256: 3c2fceb89cefca899dcd7c8f26a6202acacb2a073e4cb2ef365514a465d01dcd + md5: dd13667299b9b66b8b314dc8d95b54a3 depends: - python >=3.10 - click >=8.0.0 @@ -853,52 +848,56 @@ packages: - pathspec >=0.9.0 - platformdirs >=2 - tomli >=1.1.0 - - python - license: MIT - size: 135743 - timestamp: 1769478151312 -- conda: https://conda.modular.com/max-nightly/linux-64/mojo-0.26.1.0-release.conda - sha256: e945e8fbff0fdd2064ea193b26fb4ba95ab782367cfd2a2c4522350066434494 + license: LicenseRef-Modular-Proprietary + size: 133798 + timestamp: 1773780198354 +- conda: https://conda.modular.com/max/linux-64/mojo-0.26.2.0-release.conda + sha256: 4d7047466c13d92b1c8eb19c6d203a8503afbd2b1ad63eb5289a8f4bbf4d2945 + md5: 61318988733a695066b39704f6e08bd2 depends: - python >=3.10 - - mojo-compiler ==0.26.1.0 release - - mblack ==26.1.0 release + - mojo-compiler ==0.26.2.0 + - mblack ==26.2.0 - jupyter_client >=8.6.2,<8.7 license: LicenseRef-Modular-Proprietary - size: 89061870 - timestamp: 1769478151312 -- conda: https://conda.modular.com/max-nightly/osx-arm64/mojo-0.26.1.0-release.conda - sha256: ba205a5bb4fafc47abee5db87fd58dee091b104d20651363f3dc1e6ca60e1d21 + size: 89753715 + timestamp: 1773797215278 +- conda: https://conda.modular.com/max/osx-arm64/mojo-0.26.2.0-release.conda + sha256: e35b8d34564b30189c5a985990466b4283f9e1d897baf23fe9ddbcbc9283459c + md5: 12e4d8397c451b7c8a55ff5a759ce00b depends: - python >=3.10 - - mojo-compiler ==0.26.1.0 release - - mblack ==26.1.0 release + - mojo-compiler ==0.26.2.0 + - mblack ==26.2.0 - jupyter_client >=8.6.2,<8.7 license: LicenseRef-Modular-Proprietary - size: 75217574 - timestamp: 1769480882531 -- conda: https://conda.modular.com/max-nightly/linux-64/mojo-compiler-0.26.1.0-release.conda - sha256: aad6cf9e55824ada1147acaee8b37c68ef1973b208a4a4182f7ac85bc20e690c + size: 81534498 + timestamp: 1773797099755 +- conda: https://conda.modular.com/max/linux-64/mojo-compiler-0.26.2.0-release.conda + sha256: e53f30d72a65e6b0a67745e6988f978d8f6ecc14531420631c9719eb9c7b9c2b + md5: e3a673daa0ddf3ca6af297daee4ceab5 depends: - - mojo-python ==0.26.1.0 release + - mojo-python ==0.26.2.0 license: LicenseRef-Modular-Proprietary - size: 85722183 - timestamp: 1769478151311 -- conda: https://conda.modular.com/max-nightly/osx-arm64/mojo-compiler-0.26.1.0-release.conda - sha256: 335323a29c632adaf75958366a93352082f2e6a8bee43353269e86eefa86a2cf + size: 89091679 + timestamp: 1773797216619 +- conda: https://conda.modular.com/max/osx-arm64/mojo-compiler-0.26.2.0-release.conda + sha256: e82cb7ce1a756876a233d364d5397adca5ad7e20fff5204c1c7e93aefe4549b5 + md5: 96e3ec50a2ea4abdb9fc4f3f89dc874b depends: - - mojo-python ==0.26.1.0 release + - mojo-python ==0.26.2.0 license: LicenseRef-Modular-Proprietary - size: 65952232 - timestamp: 1769480882531 -- conda: https://conda.modular.com/max-nightly/noarch/mojo-python-0.26.1.0-release.conda + size: 67499721 + timestamp: 1773797103208 +- conda: https://conda.modular.com/max/noarch/mojo-python-0.26.2.0-release.conda noarch: python - sha256: 9bccbc9045984961426038832c8657198f8ef238d95e00d9bdcff2dd139b7fdf + sha256: 2d9e350cfe7a0ae5d96dea13c082b09f21aac8ac4caa3e5def6b075930348fa1 + md5: 67a4fc0d47e84d3a91c4f12cc912c7ac depends: - - python + - python >=3.10 license: LicenseRef-Modular-Proprietary - size: 24169 - timestamp: 1769478151311 + size: 22936 + timestamp: 1773780198161 - conda: https://conda.anaconda.org/conda-forge/noarch/mypy_extensions-1.1.0-pyha770c72_0.conda sha256: 6ed158e4e5dd8f6a10ad9e525631e35cee8557718f83de7a4e3966b1f772c4b1 md5: e9c622e0d00fa24a6292279af3ab6d06 @@ -925,31 +924,31 @@ packages: license: X11 AND BSD-3-Clause size: 797030 timestamp: 1738196177597 -- conda: https://conda.anaconda.org/conda-forge/linux-64/numpy-2.4.2-py313hf6604e3_1.conda - sha256: 2eb8be25a7504f058a153a84be70471e0ebbf6bd0411ae2b6d34904b89d86fe3 - md5: ca9c6ba4beac38cb3d0a85afde27f94c +- conda: https://conda.anaconda.org/conda-forge/linux-64/numpy-2.4.3-py313hf6604e3_0.conda + sha256: bcf75998ea3ae133df3580fb427d1054b006b093799430f499fd7ce8207d34c7 + md5: c4a9d2e77eb9fee983a70cf5f047c202 depends: - python + - libstdcxx >=14 - libgcc >=14 - __glibc >=2.17,<3.0.a0 - - libstdcxx >=14 - - liblapack >=3.9.0,<4.0a0 - - libcblas >=3.9.0,<4.0a0 - python_abi 3.13.* *_cp313 + - libcblas >=3.9.0,<4.0a0 + - liblapack >=3.9.0,<4.0a0 - libblas >=3.9.0,<4.0a0 constrains: - numpy-base <0a0 license: BSD-3-Clause license_family: BSD - size: 8857152 - timestamp: 1770098515258 -- conda: https://conda.anaconda.org/conda-forge/osx-arm64/numpy-2.4.2-py313h16eae64_1.conda - sha256: 3e23ed9eb63d9ce4dc585aad6b65e0197d7e9f28877acf7114cc64f33763a420 - md5: e34e9c58a0ee3eca3def3bb477797621 + size: 8857056 + timestamp: 1773839226294 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/numpy-2.4.3-py313he4a34aa_0.conda + sha256: d55c3f4b13486bf8e3cadaf731a5d9b67aa9deb51f7c30e381b948a9ada20ef0 + md5: 03b99caf1270c27febfcceb4f1090af7 depends: - python - - __osx >=11.0 - python 3.13.* *_cp313 + - __osx >=11.0 - libcxx >=19 - liblapack >=3.9.0,<4.0a0 - libblas >=3.9.0,<4.0a0 @@ -959,8 +958,8 @@ packages: - numpy-base <0a0 license: BSD-3-Clause license_family: BSD - size: 6925963 - timestamp: 1770098439599 + size: 6924384 + timestamp: 1773839167287 - conda: https://conda.anaconda.org/conda-forge/linux-64/openssl-3.6.1-h35e630c_1.conda sha256: 44c877f8af015332a5d12f5ff0fb20ca32f896526a7d0cdb30c769df1144fb5c md5: f61eb8cd60ff9057122a3d338b99c00f @@ -1001,16 +1000,16 @@ packages: license_family: MOZILLA size: 53739 timestamp: 1769677743677 -- conda: https://conda.anaconda.org/conda-forge/noarch/platformdirs-4.9.2-pyhcf101f3_0.conda - sha256: 7f263219cecf0ba6d74c751efa60c4676ce823157ca90aa43ebba5ac615ca0fa - md5: 4fefefb892ce9cc1539405bec2f1a6cd +- conda: https://conda.anaconda.org/conda-forge/noarch/platformdirs-4.9.4-pyhcf101f3_0.conda + sha256: 0289f0a38337ee201d984f8f31f11f6ef076cfbbfd0ab9181d12d9d1d099bf46 + md5: 82c1787f2a65c0155ef9652466ee98d6 depends: - python >=3.10 - python license: MIT license_family: MIT - size: 25643 - timestamp: 1771233827084 + size: 25646 + timestamp: 1773199142345 - conda: https://conda.anaconda.org/conda-forge/linux-64/python-3.13.12-hc97d973_100_cp313.conda build_number: 100 sha256: 8a08fe5b7cb5a28aa44e2994d18dbf77f443956990753a4ca8173153ffb6eb56 @@ -1037,6 +1036,33 @@ packages: size: 37364553 timestamp: 1770272309861 python_site_packages_path: lib/python3.13/site-packages +- conda: https://conda.anaconda.org/conda-forge/linux-64/python-3.14.3-h32b2ec7_101_cp314.conda + build_number: 101 + sha256: cb0628c5f1732f889f53a877484da98f5a0e0f47326622671396fb4f2b0cd6bd + md5: c014ad06e60441661737121d3eae8a60 + depends: + - __glibc >=2.17,<3.0.a0 + - bzip2 >=1.0.8,<2.0a0 + - ld_impl_linux-64 >=2.36.1 + - libexpat >=2.7.3,<3.0a0 + - libffi >=3.5.2,<3.6.0a0 + - libgcc >=14 + - liblzma >=5.8.2,<6.0a0 + - libmpdec >=4.0.0,<5.0a0 + - libsqlite >=3.51.2,<4.0a0 + - libuuid >=2.41.3,<3.0a0 + - libzlib >=1.3.1,<2.0a0 + - ncurses >=6.5,<7.0a0 + - openssl >=3.5.5,<4.0a0 + - python_abi 3.14.* *_cp314 + - readline >=8.3,<9.0a0 + - tk >=8.6.13,<8.7.0a0 + - tzdata + - zstd >=1.5.7,<1.6.0a0 + license: Python-2.0 + size: 36702440 + timestamp: 1770675584356 + python_site_packages_path: lib/python3.14/site-packages - conda: https://conda.anaconda.org/conda-forge/osx-arm64/python-3.13.12-h20e6be0_100_cp313.conda build_number: 100 sha256: 9a4f16a64def0853f0a7b6a7beb40d498fd6b09bee10b90c3d6069b664156817 @@ -1060,6 +1086,30 @@ packages: size: 12770674 timestamp: 1770272314517 python_site_packages_path: lib/python3.13/site-packages +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/python-3.14.3-h4c637c5_101_cp314.conda + build_number: 101 + sha256: fccce2af62d11328d232df9f6bbf63464fd45f81f718c661757f9c628c4378ce + md5: 753c8d0447677acb7ddbcc6e03e82661 + depends: + - __osx >=11.0 + - bzip2 >=1.0.8,<2.0a0 + - libexpat >=2.7.3,<3.0a0 + - libffi >=3.5.2,<3.6.0a0 + - liblzma >=5.8.2,<6.0a0 + - libmpdec >=4.0.0,<5.0a0 + - libsqlite >=3.51.2,<4.0a0 + - libzlib >=1.3.1,<2.0a0 + - ncurses >=6.5,<7.0a0 + - openssl >=3.5.5,<4.0a0 + - python_abi 3.14.* *_cp314 + - readline >=8.3,<9.0a0 + - tk >=8.6.13,<8.7.0a0 + - tzdata + - zstd >=1.5.7,<1.6.0a0 + license: Python-2.0 + size: 13522698 + timestamp: 1770675365241 + python_site_packages_path: lib/python3.14/site-packages - conda: https://conda.anaconda.org/conda-forge/noarch/python-dateutil-2.9.0.post0-pyhe01879c_2.conda sha256: d6a17ece93bbd5139e02d2bd7dbfa80bee1a4261dced63f65f679121686bf664 md5: 5b8d21249ff20967101ffa321cab24e8 @@ -1080,6 +1130,15 @@ packages: license: Python-2.0 size: 48618 timestamp: 1770270436560 +- conda: https://conda.anaconda.org/conda-forge/noarch/python-gil-3.14.3-h4df99d1_101.conda + sha256: 233aebd94c704ac112afefbb29cf4170b7bc606e22958906f2672081bc50638a + md5: 235765e4ea0d0301c75965985163b5a1 + depends: + - cpython 3.14.3.* + - python_abi * *_cp314 + license: Python-2.0 + size: 50062 + timestamp: 1770674497152 - conda: https://conda.anaconda.org/conda-forge/noarch/python_abi-3.13-8_cp313.conda build_number: 8 sha256: 210bffe7b121e651419cb196a2a63687b087497595c9be9d20ebe97dd06060a7 @@ -1090,37 +1149,47 @@ packages: license_family: BSD size: 7002 timestamp: 1752805902938 -- conda: https://conda.anaconda.org/conda-forge/linux-64/pyzmq-27.1.0-py312hfb55c3c_0.conda +- conda: https://conda.anaconda.org/conda-forge/noarch/python_abi-3.14-8_cp314.conda + build_number: 8 + sha256: ad6d2e9ac39751cc0529dd1566a26751a0bf2542adb0c232533d32e176e21db5 + md5: 0539938c55b6b1a59b560e843ad864a4 + constrains: + - python 3.14.* *_cp314 + license: BSD-3-Clause + license_family: BSD + size: 6989 + timestamp: 1752805904792 +- conda: https://conda.anaconda.org/conda-forge/linux-64/pyzmq-27.1.0-py312hda471dd_2.conda noarch: python - sha256: a00a41b66c12d9c60e66b391e9a4832b7e28743348cf4b48b410b91927cd7819 - md5: 3399d43f564c905250c1aea268ebb935 + sha256: be66c1f85c3b48137200d62c12d918f4f8ad329423daef04fed292818efd3c28 + md5: 082985717303dab433c976986c674b35 depends: - python - - __glibc >=2.17,<3.0.a0 - - libstdcxx >=14 - libgcc >=14 + - libstdcxx >=14 + - __glibc >=2.17,<3.0.a0 + - zeromq >=4.3.5,<4.4.0a0 - _python_abi3_support 1.* - cpython >=3.12 - - zeromq >=4.3.5,<4.4.0a0 license: BSD-3-Clause license_family: BSD - size: 212218 - timestamp: 1757387023399 -- conda: https://conda.anaconda.org/conda-forge/osx-arm64/pyzmq-27.1.0-py312hd65ceae_0.conda + size: 211567 + timestamp: 1771716961404 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/pyzmq-27.1.0-py312h022ad19_2.conda noarch: python - sha256: ef33812c71eccf62ea171906c3e7fc1c8921f31e9cc1fbc3f079f3f074702061 - md5: bbd22b0f0454a5972f68a5f200643050 + sha256: 2f31f799a46ed75518fae0be75ecc8a1b84360dbfd55096bc2fe8bd9c797e772 + md5: 2f6b79700452ef1e91f45a99ab8ffe5a depends: - python - - __osx >=11.0 - libcxx >=19 + - __osx >=11.0 - _python_abi3_support 1.* - cpython >=3.12 - zeromq >=4.3.5,<4.4.0a0 license: BSD-3-Clause license_family: BSD - size: 191115 - timestamp: 1757387128258 + size: 191641 + timestamp: 1771717073430 - conda: https://conda.anaconda.org/conda-forge/linux-64/readline-8.3-h853b02a_0.conda sha256: 12ffde5a6f958e285aa22c191ca01bbd3d6e710aa852e00618fa6ddc59149002 md5: d7d95fc8287ea7bf33e0e7116d2b95ec @@ -1142,9 +1211,9 @@ packages: license_family: GPL size: 313930 timestamp: 1765813902568 -- conda: https://conda.anaconda.org/conda-forge/linux-64/scipy-1.17.0-py313h4b8bb8b_1.conda - sha256: e812ebe8115f8daf005f5788ed8f05a0fdabe47eeb4c30bf0a190f2d1d1da0b6 - md5: 2b18fe5b4b2d1611ddf8c2f080a46563 +- conda: https://conda.anaconda.org/conda-forge/linux-64/scipy-1.17.1-py313h4b8bb8b_0.conda + sha256: fdd92a119a2a5f89d6e549a326adcb008f5046ea5034a9af409e97b7e20e6f06 + md5: ec81bc03787968decae6765c7f61b7cf depends: - __glibc >=2.17,<3.0.a0 - libblas >=3.9.0,<4.0a0 @@ -1161,11 +1230,11 @@ packages: - python_abi 3.13.* *_cp313 license: BSD-3-Clause license_family: BSD - size: 16857028 - timestamp: 1768801011489 -- conda: https://conda.anaconda.org/conda-forge/osx-arm64/scipy-1.17.0-py313hc753a45_1.conda - sha256: 2ea17fc46533e8789881732f42265e32c7ae376344cc3d53683e7b2179d947bb - md5: 5b73b1e6d191aac48960c50d65372f19 + size: 17121940 + timestamp: 1771880708672 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/scipy-1.17.1-py313hc753a45_0.conda + sha256: d22bf4791d1fc96b35374de0dd904745c3b54282ba23c3d435a994b4ff384719 + md5: 6f3a898962bdea87c076108bc336df2e depends: - __osx >=11.0 - libblas >=3.9.0,<4.0a0 @@ -1182,8 +1251,8 @@ packages: - python_abi 3.13.* *_cp313 license: BSD-3-Clause license_family: BSD - size: 13888560 - timestamp: 1768801587965 + size: 14038926 + timestamp: 1771880554132 - conda: https://conda.anaconda.org/conda-forge/noarch/six-1.17.0-pyhe01879c_1.conda sha256: 458227f759d5e3fcec5d9b7acce54e10c9e1f4f4b7ec978f3bfd54ce4ee9853d md5: 3339e3b65d58accf4ca4fb8748ab16b3 @@ -1217,19 +1286,19 @@ packages: license_family: BSD size: 3127137 timestamp: 1769460817696 -- conda: https://conda.anaconda.org/conda-forge/noarch/tomli-2.4.0-pyhcf101f3_0.conda - sha256: 62940c563de45790ba0f076b9f2085a842a65662268b02dd136a8e9b1eaf47a8 - md5: 72e780e9aa2d0a3295f59b1874e3768b +- conda: https://conda.anaconda.org/conda-forge/noarch/tomli-2.4.1-pyhcf101f3_0.conda + sha256: 91cafdb64268e43e0e10d30bd1bef5af392e69f00edd34dfaf909f69ab2da6bd + md5: b5325cf06a000c5b14970462ff5e4d58 depends: - python >=3.10 - python license: MIT license_family: MIT - size: 21453 - timestamp: 1768146676791 -- conda: https://conda.anaconda.org/conda-forge/linux-64/tornado-6.5.3-py313h07c4f96_0.conda - sha256: 6006d4e5a6ff99be052c939e43adee844a38f2dc148f44a7c11aa0011fd3d811 - md5: 82da2dcf1ea3e298f2557b50459809e0 + size: 21561 + timestamp: 1774492402955 +- conda: https://conda.anaconda.org/conda-forge/linux-64/tornado-6.5.5-py313h07c4f96_0.conda + sha256: 9e8497e1ecca77d03c6be2d3b5f901dfe0ab99686af4fb94ab418b7d449ac547 + md5: 6c0b0ae017b5bfd9c8d718217efd8f14 depends: - __glibc >=2.17,<3.0.a0 - libgcc >=14 @@ -1237,11 +1306,23 @@ packages: - python_abi 3.13.* *_cp313 license: Apache-2.0 license_family: Apache - size: 878109 - timestamp: 1765458900582 -- conda: https://conda.anaconda.org/conda-forge/osx-arm64/tornado-6.5.4-py313h6535dbc_0.conda - sha256: a8130a361b7bc21190836ba8889276cc263fcb09f52bf22efcaed1de98179948 - md5: 67a85c1b5c17124eaf9194206afd5159 + size: 882996 + timestamp: 1774358035145 +- conda: https://conda.anaconda.org/conda-forge/linux-64/tornado-6.5.5-py314h5bd0f2a_0.conda + sha256: ed8d06093ff530a2dae9ed1e51eb6f908fbfd171e8b62f4eae782d67b420be5a + md5: dc1ff1e915ab35a06b6fa61efae73ab5 + depends: + - __glibc >=2.17,<3.0.a0 + - libgcc >=14 + - python >=3.14,<3.15.0a0 + - python_abi 3.14.* *_cp314 + license: Apache-2.0 + license_family: Apache + size: 912476 + timestamp: 1774358032579 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/tornado-6.5.5-py313h0997733_0.conda + sha256: c5b0ee042d8a0b88a3823226dc95b794c042c498aee330aa9b4d78bfad01d099 + md5: 303333dd882dfeb303cc8bfac178464b depends: - __osx >=11.0 - python >=3.13,<3.14.0a0 @@ -1249,8 +1330,20 @@ packages: - python_abi 3.13.* *_cp313 license: Apache-2.0 license_family: Apache - size: 877647 - timestamp: 1765836696426 + size: 883472 + timestamp: 1774358832451 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/tornado-6.5.5-py314h6c2aa35_0.conda + sha256: 4ccc4a20d676c0ba85adee9c99015bec7f5b685df0cf8006e34573f1d6c2ce75 + md5: 3f81f8b2fe2c26a82c0abf57ab2b9610 + depends: + - __osx >=11.0 + - python >=3.14,<3.15.0a0 + - python >=3.14,<3.15.0a0 *_cp314 + - python_abi 3.14.* *_cp314 + license: Apache-2.0 + license_family: Apache + size: 910845 + timestamp: 1774358965067 - conda: https://conda.anaconda.org/conda-forge/noarch/traitlets-5.14.3-pyhd8ed1ab_1.conda sha256: f39a5620c6e8e9e98357507262a7869de2ae8cc07da8b7f84e517c9fd6c2b959 md5: 019a7385be9af33791c989871317e1ed @@ -1266,32 +1359,31 @@ packages: license: LicenseRef-Public-Domain size: 119135 timestamp: 1767016325805 -- conda: https://conda.anaconda.org/conda-forge/linux-64/zeromq-4.3.5-h387f397_9.conda - sha256: 47cfe31255b91b4a6fa0e9dbaf26baa60ac97e033402dbc8b90ba5fee5ffe184 - md5: 8035e5b54c08429354d5d64027041cad +- conda: https://conda.anaconda.org/conda-forge/linux-64/zeromq-4.3.5-h41580af_10.conda + sha256: 325d370b28e2b9cc1f765c5b4cdb394c91a5d958fbd15da1a14607a28fee09f6 + md5: 755b096086851e1193f3b10347415d7c depends: - - libstdcxx >=14 - libgcc >=14 - __glibc >=2.17,<3.0.a0 - - libgcc >=14 - - libsodium >=1.0.20,<1.0.21.0a0 - - krb5 >=1.21.3,<1.22.0a0 + - libstdcxx >=14 + - krb5 >=1.22.2,<1.23.0a0 + - libsodium >=1.0.21,<1.0.22.0a0 license: MPL-2.0 license_family: MOZILLA - size: 310648 - timestamp: 1757370847287 -- conda: https://conda.anaconda.org/conda-forge/osx-arm64/zeromq-4.3.5-h888dc83_9.conda - sha256: b6f9c130646e5971f6cad708e1eee278f5c7eea3ca97ec2fdd36e7abb764a7b8 - md5: 26f39dfe38a2a65437c29d69906a0f68 + size: 311150 + timestamp: 1772476812121 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/zeromq-4.3.5-h4818236_10.conda + sha256: 2705360c72d4db8de34291493379ffd13b09fd594d0af20c9eefa8a3f060d868 + md5: e85dcd3bde2b10081cdcaeae15797506 depends: - __osx >=11.0 - libcxx >=19 - - libsodium >=1.0.20,<1.0.21.0a0 - - krb5 >=1.21.3,<1.22.0a0 + - krb5 >=1.22.2,<1.23.0a0 + - libsodium >=1.0.21,<1.0.22.0a0 license: MPL-2.0 license_family: MOZILLA - size: 244772 - timestamp: 1757371008525 + size: 245246 + timestamp: 1772476886668 - conda: https://conda.anaconda.org/conda-forge/noarch/zipp-3.23.0-pyhcf101f3_1.conda sha256: b4533f7d9efc976511a73ef7d4a2473406d7f4c750884be8e8620b0ce70f4dae md5: 30cd29cb87d819caead4d55184c1d115 @@ -1312,3 +1404,13 @@ packages: license_family: BSD size: 601375 timestamp: 1764777111296 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/zstd-1.5.7-hbf9d68e_6.conda + sha256: 9485ba49e8f47d2b597dd399e88f4802e100851b27c21d7525625b0b4025a5d9 + md5: ab136e4c34e97f34fb621d2592a393d8 + depends: + - __osx >=11.0 + - libzlib >=1.3.1,<2.0a0 + license: BSD-3-Clause + license_family: BSD + size: 433413 + timestamp: 1764777166076 diff --git a/pixi.toml b/pixi.toml index d880187..38e9123 100644 --- a/pixi.toml +++ b/pixi.toml @@ -1,6 +1,6 @@ [workspace] authors = ["MojoMath "] -channels = ["https://repo.prefix.dev/modular-community", "https://conda.modular.com/max-nightly", "https://conda.modular.com/max", "conda-forge"] +channels = ["https://repo.prefix.dev/modular-community", "https://conda.modular.com/max", "conda-forge", "https://conda.modular.com/max-nightly"] description = "A statistical computing library for Mojo, inspired by scipy.stats and statsmodels" license = "Apache-2.0" name = "stamojo" @@ -9,7 +9,7 @@ readme = "README.md" version = "0.1.0" [dependencies] -mojo = "==0.26.1" +mojo = ">=0.26.2.0,<0.27" # ── Feature: test (adds scipy for reference-value benchmarks) ──────────────── [feature.test.dependencies] From 11710b185acf63f5be996efb83ea0a0e44a4a5cd Mon Sep 17 00:00:00 2001 From: shivasankar Date: Sat, 4 Apr 2026 01:06:01 +0900 Subject: [PATCH 02/11] change std to stddev because of conflict with mojo's std --- src/stamojo/stats/__init__.mojo | 2 +- src/stamojo/stats/descriptive.mojo | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/stamojo/stats/__init__.mojo b/src/stamojo/stats/__init__.mojo index 77e64b7..c36faf3 100644 --- a/src/stamojo/stats/__init__.mojo +++ b/src/stamojo/stats/__init__.mojo @@ -13,7 +13,7 @@ This subpackage provides: from .descriptive import ( mean, variance, - std, + stddev, median, quantile, skewness, diff --git a/src/stamojo/stats/descriptive.mojo b/src/stamojo/stats/descriptive.mojo index 7a84883..c84a0c2 100644 --- a/src/stamojo/stats/descriptive.mojo +++ b/src/stamojo/stats/descriptive.mojo @@ -86,7 +86,7 @@ fn variance(data: List[Float64], ddof: Int = 0) -> Float64: return ss / Float64(n - ddof) -fn std(data: List[Float64], ddof: Int = 0) -> Float64: +fn stddev(data: List[Float64], ddof: Int = 0) -> Float64: """Standard deviation of *data*. Args: @@ -170,7 +170,7 @@ fn skewness(data: List[Float64]) -> Float64: return nan[DType.float64]() var m = mean(data) - var s = std(data, ddof=1) + var s = stddev(data, ddof=1) if s == 0.0: return 0.0 From aed90b01eaf1f06b590134832c62b198be18b9c4 Mon Sep 17 00:00:00 2001 From: shivasankar Date: Sat, 4 Apr 2026 01:49:31 +0900 Subject: [PATCH 03/11] add add beta, gamma, poission distributions. --- src/stamojo/distributions/beta.mojo | 223 +++++++++++++++++++++++++ src/stamojo/distributions/gamma.mojo | 215 ++++++++++++++++++++++++ src/stamojo/distributions/poisson.mojo | 220 ++++++++++++++++++++++++ 3 files changed, 658 insertions(+) create mode 100644 src/stamojo/distributions/beta.mojo create mode 100644 src/stamojo/distributions/gamma.mojo create mode 100644 src/stamojo/distributions/poisson.mojo diff --git a/src/stamojo/distributions/beta.mojo b/src/stamojo/distributions/beta.mojo new file mode 100644 index 0000000..3ab85a6 --- /dev/null +++ b/src/stamojo/distributions/beta.mojo @@ -0,0 +1,223 @@ +# ===----------------------------------------------------------------------=== # +# Stamojo - Distributions - Beta distribution +# Licensed under Apache 2.0 +# ===----------------------------------------------------------------------=== # +"""Beta distribution. + +Provides the `Beta` distribution struct with PDF, log-PDF, CDF, +survival function, and percent-point function (PPF / quantile). + +The beta distribution with shape parameters *a* and *b* has PDF:: + + f(x; a, b) = x^{a-1} (1-x)^{b-1} / B(a, b), 0 < x < 1 +""" + +from math import sqrt, log, lgamma, exp, nan, inf + +from stamojo.special import betainc, lbeta, ndtri + + +# ===----------------------------------------------------------------------=== # +# Constants +# ===----------------------------------------------------------------------=== # + +comptime _EPS = 1.0e-12 +comptime _MAX_ITER = 100 + + +# ===----------------------------------------------------------------------=== # +# Beta distribution +# ===----------------------------------------------------------------------=== # + + +@fieldwise_init +struct Beta(Copyable, Movable): + """Beta distribution with shape parameters `a` and `b`. + + Fields: + a: First shape parameter. Must be positive. + b: Second shape parameter. Must be positive. + """ + + var a: Float64 + var b: Float64 + + # --- Density functions --------------------------------------------------- + + fn pdf(self, x: Float64) -> Float64: + """Probability density function at *x*.""" + if x <= 0.0 or x >= 1.0: + return 0.0 + return exp(self.logpdf(x)) + + fn logpdf(self, x: Float64) -> Float64: + """Natural logarithm of the probability density function at *x*.""" + if x <= 0.0 or x >= 1.0: + return -inf[DType.float64]() + return ( + (self.a - 1.0) * log(x) + + (self.b - 1.0) * log(1.0 - x) + - lbeta(self.a, self.b) + ) + + # --- Distribution functions ---------------------------------------------- + + fn cdf(self, x: Float64) -> Float64: + """Cumulative distribution function P(X ≤ x). + + CDF(x; a, b) = I_x(a, b) (regularized incomplete beta). + """ + if x <= 0.0: + return 0.0 + if x >= 1.0: + return 1.0 + return betainc(self.a, self.b, x) + + fn logcdf(self, x: Float64) -> Float64: + """Natural logarithm of the CDF at *x*.""" + if x <= 0.0: + return -inf[DType.float64]() + if x >= 1.0: + return 0.0 + var c = self.cdf(x) + if c <= 0.0: + return -inf[DType.float64]() + return log(c) + + fn sf(self, x: Float64) -> Float64: + """Survival function (1 − CDF) at *x*.""" + if x <= 0.0: + return 1.0 + if x >= 1.0: + return 0.0 + return 1.0 - self.cdf(x) + + fn logsf(self, x: Float64) -> Float64: + """Natural logarithm of the survival function at *x*.""" + if x <= 0.0: + return 0.0 + if x >= 1.0: + return -inf[DType.float64]() + var s = self.sf(x) + if s <= 0.0: + return -inf[DType.float64]() + return log(s) + + fn ppf(self, p: Float64) -> Float64: + """Percent-point function (quantile / inverse CDF). + + Uses Newton-Raphson with bisection fallback. + + Args: + p: Probability value in [0, 1]. + + Returns: + The quantile corresponding to *p*. + """ + if p < 0.0 or p > 1.0: + return nan[DType.float64]() + if p == 0.0: + return 0.0 + if p == 1.0: + return 1.0 + + var mu = self.a / (self.a + self.b) + var x: Float64 + if self.a > 1.0 and self.b > 1.0: + var sigma = sqrt( + self.a + * self.b + / ((self.a + self.b) ** 2 * (self.a + self.b + 1.0)) + ) + x = mu + sigma * ndtri(p) + if x <= 0.0: + x = 0.01 + if x >= 1.0: + x = 0.99 + else: + x = mu + + # Newton-Raphson with bisection fallback. + var lo = 0.0 + var hi = 1.0 + + for _ in range(_MAX_ITER): + var f = self.cdf(x) - p + if abs(f) < _EPS: + return x + + var fp = self.pdf(x) + if fp > 1.0e-300: + var x_new = x - f / fp + if f > 0.0: + hi = x + else: + lo = x + if x_new <= lo or x_new >= hi: + x = (lo + hi) / 2.0 + else: + x = x_new + else: + if f > 0.0: + hi = x + else: + lo = x + x = (lo + hi) / 2.0 + + return x + + fn isf(self, q: Float64) -> Float64: + """Inverse survival function (inverse SF). + + Args: + q: Probability in [0, 1]. + + Returns: + The value *x* such that SF(x) = *q*. + """ + return self.ppf(1.0 - q) + + # --- Summary statistics -------------------------------------------------- + + fn median(self) -> Float64: + """Median of the distribution (approximation). + + Uses the approximation: (a - 1/3) / (a + b - 2/3) for a, b >= 1. + """ + if self.a >= 1.0 and self.b >= 1.0: + return (self.a - 1.0 / 3.0) / (self.a + self.b - 2.0 / 3.0) + return self.a / (self.a + self.b) + + fn mean(self) -> Float64: + """Distribution mean = a / (a + b).""" + return self.a / (self.a + self.b) + + fn variance(self) -> Float64: + """Distribution variance = ab / ((a+b)²(a+b+1)).""" + var ab = self.a + self.b + return self.a * self.b / (ab * ab * (ab + 1.0)) + + fn std(self) -> Float64: + """Distribution standard deviation.""" + return sqrt(self.variance()) + + fn entropy(self) -> Float64: + """Differential entropy of the distribution. + + H = ln(B(a,b)) - (a-1)ψ(a) - (b-1)ψ(b) + (a+b-2)ψ(a+b) + Using digamma approximation: ψ(x) ≈ ln(x) - 1/(2x) - 1/(12x²) + """ + var digamma_a = ( + log(self.a) - 1.0 / (2.0 * self.a) - 1.0 / (12.0 * self.a * self.a) + ) + var digamma_b = ( + log(self.b) - 1.0 / (2.0 * self.b) - 1.0 / (12.0 * self.b * self.b) + ) + var ab = self.a + self.b + var digamma_ab = log(ab) - 1.0 / (2.0 * ab) - 1.0 / (12.0 * ab * ab) + return ( + lbeta(self.a, self.b) + - (self.a - 1.0) * digamma_a + - (self.b - 1.0) * digamma_b + + (self.a + self.b - 2.0) * digamma_ab + ) diff --git a/src/stamojo/distributions/gamma.mojo b/src/stamojo/distributions/gamma.mojo new file mode 100644 index 0000000..fd68c1c --- /dev/null +++ b/src/stamojo/distributions/gamma.mojo @@ -0,0 +1,215 @@ +# ===----------------------------------------------------------------------=== # +# Stamojo - Distributions - Gamma distribution +# Licensed under Apache 2.0 +# ===----------------------------------------------------------------------=== # +"""Gamma distribution. + +Provides the `Gamma` distribution struct with PDF, log-PDF, CDF, +survival function, and percent-point function (PPF / quantile). + +The gamma distribution with shape *a* and scale *θ* has PDF:: + + f(x; a, θ) = x^{a-1} exp(−x/θ) / (θ^a Γ(a)), x > 0 +""" + +from math import sqrt, log, lgamma, exp, nan, inf, floor, pow + +from stamojo.special import gammainc, gammaincc, ndtri + + +# ===----------------------------------------------------------------------=== # +# Constants +# ===----------------------------------------------------------------------=== # + +comptime _EPS = 1.0e-12 +comptime _MAX_ITER = 100 + + +# ===----------------------------------------------------------------------=== # +# Gamma distribution +# ===----------------------------------------------------------------------=== # + + +@fieldwise_init +struct Gamma(Copyable, Movable): + """Gamma distribution with shape `a` and scale `scale`. + + Fields: + a: Shape parameter. Must be positive. + scale: Scale parameter (θ). Must be positive. + """ + + var a: Float64 + var scale: Float64 + + # --- Density functions --------------------------------------------------- + + fn pdf(self, x: Float64) -> Float64: + """Probability density function at *x*.""" + if x <= 0.0: + return 0.0 + return exp(self.logpdf(x)) + + fn logpdf(self, x: Float64) -> Float64: + """Natural logarithm of the probability density function at *x*.""" + if x <= 0.0: + return -inf[DType.float64]() + return ( + (self.a - 1.0) * log(x) + - x / self.scale + - self.a * log(self.scale) + - lgamma(self.a) + ) + + # --- Distribution functions ---------------------------------------------- + + fn cdf(self, x: Float64) -> Float64: + """Cumulative distribution function P(X ≤ x). + + CDF(x; a, θ) = P(a, x/θ) (regularized lower incomplete gamma). + """ + if x <= 0.0: + return 0.0 + return gammainc(self.a, x / self.scale) + + fn logcdf(self, x: Float64) -> Float64: + """Natural logarithm of the CDF at *x*.""" + if x <= 0.0: + return -inf[DType.float64]() + var c = self.cdf(x) + if c <= 0.0: + return -inf[DType.float64]() + return log(c) + + fn sf(self, x: Float64) -> Float64: + """Survival function (1 − CDF) at *x*.""" + if x <= 0.0: + return 1.0 + return gammaincc(self.a, x / self.scale) + + fn logsf(self, x: Float64) -> Float64: + """Natural logarithm of the survival function at *x*.""" + if x <= 0.0: + return 0.0 + var s = self.sf(x) + if s <= 0.0: + return -inf[DType.float64]() + return log(s) + + fn ppf(self, p: Float64) -> Float64: + """Percent-point function (quantile / inverse CDF). + + Uses Newton-Raphson with bisection fallback. + + Args: + p: Probability value in [0, 1]. + + Returns: + The quantile corresponding to *p*. + """ + if p < 0.0 or p > 1.0: + return nan[DType.float64]() + if p == 0.0: + return 0.0 + if p == 1.0: + return inf[DType.float64]() + + var a = self.a + + # Initial guess using Wilson-Hilferty approximation. + var z = ndtri(p) + var wh = 1.0 / (9.0 * a) + var cube = 1.0 - wh + z * sqrt(wh) + var x: Float64 + if cube > 0.0: + x = a * cube * cube * cube + else: + x = a * 0.1 + + if x <= 0.0: + x = 0.01 + x *= self.scale + + # TODO: Since many use Newton-Raphson, we could have a separate func for this. + var lo = 0.0 + var hi = x * 4.0 + 10.0 * self.scale + while self.cdf(hi) < p: + hi *= 2.0 + + for _ in range(_MAX_ITER): + var f = self.cdf(x) - p + if abs(f) < _EPS: + return x + + var fp = self.pdf(x) + if fp > 1.0e-300: + var x_new = x - f / fp + if f > 0.0: + hi = x + else: + lo = x + if x_new <= lo or x_new >= hi: + x = (lo + hi) / 2.0 + else: + x = x_new + else: + if f > 0.0: + hi = x + else: + lo = x + x = (lo + hi) / 2.0 + + return x + + fn isf(self, q: Float64) -> Float64: + """Inverse survival function (inverse SF). + + Args: + q: Probability in [0, 1]. + + Returns: + The value *x* such that SF(x) = *q*. + """ + return self.ppf(1.0 - q) + + # --- Summary statistics -------------------------------------------------- + + fn median(self) -> Float64: + """Median of the distribution (approximation). + + Uses the approximation: scale * a * (1 - 1/(9a))^3 for a >= 1, + and scale * a * 2^(-1/a) for a < 1. + """ + if self.a >= 1.0: + return self.scale * self.a * pow(1.0 - 1.0 / (9.0 * self.a), 3) + else: + return self.scale * self.a * pow(2.0, -1.0 / self.a) + + fn mean(self) -> Float64: + """Distribution mean = a * θ.""" + return self.a * self.scale + + fn variance(self) -> Float64: + """Distribution variance = a * θ².""" + return self.a * self.scale * self.scale + + fn std(self) -> Float64: + """Distribution standard deviation = √(a) * θ.""" + return sqrt(self.a) * self.scale + + fn entropy(self) -> Float64: + """Differential entropy of the distribution. + + H = a + ln(θ) + ln(Γ(a)) + (1 - a) * ψ(a) + where ψ is the digamma function (approximated here). + For simplicity: H ≈ a + ln(θ) + ln(Γ(a)) - (a-1)*ψ(a) + Using approximation ψ(a) ≈ ln(a) - 1/(2a) for large a. + """ + # H = a + ln(scale) + ln(Gamma(a)) + (1-a)*digamma(a) + # Approximate digamma(a) ≈ ln(a) - 1/(2a) - 1/(12a²) + var digamma = ( + log(self.a) - 1.0 / (2.0 * self.a) - 1.0 / (12.0 * self.a * self.a) + ) + return ( + self.a + log(self.scale) + lgamma(self.a) + (1.0 - self.a) * digamma + ) diff --git a/src/stamojo/distributions/poisson.mojo b/src/stamojo/distributions/poisson.mojo new file mode 100644 index 0000000..bb8393a --- /dev/null +++ b/src/stamojo/distributions/poisson.mojo @@ -0,0 +1,220 @@ +# ===----------------------------------------------------------------------=== # +# Stamojo - Distributions - Poisson distribution +# Licensed under Apache 2.0 +# ===----------------------------------------------------------------------=== # +"""Poisson distribution. + +Provides the `Poisson` distribution struct with PMF, log-PMF, CDF, +survival function, and percent-point function (PPF / quantile). + +The Poisson distribution with rate parameter *μ* has PMF:: + + P(X = k; μ) = μ^k exp(−μ) / k!, k = 0, 1, 2, ... +""" + +from math import log, exp, lgamma, nan, inf, floor, sqrt + +from stamojo.distributions.traits import DiscretelyDistributed +from stamojo.special import gammaincc + + +# ===----------------------------------------------------------------------=== # +# Constants +# ===----------------------------------------------------------------------=== # + +comptime _MAX_K = 10000 + + +# ===----------------------------------------------------------------------=== # +# Poisson distribution +# ===----------------------------------------------------------------------=== # + + +struct Poisson(DiscretelyDistributed): + """Poisson distribution with rate parameter `mu`. + + Represents the Poisson distribution, a discrete probability distribution + that expresses the probability of a given number of events occurring in a + fixed interval of time or space, if these events occur with a known constant + mean rate and independently of the time since the last event. + + The probability mass function (PMF) for the Poisson distribution is: + + P(X = k; μ) = μ^k * exp(-μ) / k! + + Fields: + mu: Rate parameter (mean number of events). Must be positive. + """ + + var mu: Float64 + + fn __init__(out self, mu: Float64): + self.mu = mu + + # --- Probability functions ------------------------------------------------ + + fn pmf(self, k: Int) -> Float64: + """Probability mass function at *k*. + + Args: + k: Number of events (must be >= 0). + + Returns: + PMF value at *k*. Returns 0.0 for k < 0. + """ + return exp(self.logpmf(k)) + + fn logpmf(self, k: Int) -> Float64: + """Natural logarithm of the PMF at *k*. + + Args: + k: Number of events (must be >= 0). + + Returns: + Log-PMF value at *k*. Returns -∞ for k < 0. + """ + if k < 0: + return -inf[DType.float64]() + if self.mu == 0.0: + return 0.0 if k == 0 else -inf[DType.float64]() + return Float64(k) * log(self.mu) - self.mu - lgamma(Float64(k) + 1.0) + + fn cdf(self, k: Int) -> Float64: + """Cumulative distribution function P(X ≤ k). + + Args: + k: Number of events. + + Returns: + CDF value at *k*. Returns 1.0 for large k. + """ + if k < 0: + return 0.0 + if self.mu == 0.0: + return 1.0 + # CDF of Poisson(μ) at k = Q(k+1, μ) = gammaincc(k+1, μ) + return gammaincc(Float64(k + 1), self.mu) + + fn logcdf(self, k: Int) -> Float64: + """Natural logarithm of the CDF at *k*. + + Args: + k: Number of events. + + Returns: + Log-CDF value at *k*. + """ + var c = self.cdf(k) + if c <= 0.0: + return -inf[DType.float64]() + return log(c) + + fn sf(self, k: Int) -> Float64: + """Survival function (1 − CDF) at *k*. + + Args: + k: Number of events. + + Returns: + Survival function value at *k*. + """ + if k < 0: + return 1.0 + if self.mu == 0.0: + return 0.0 + return 1.0 - self.cdf(k) + + fn logsf(self, k: Int) -> Float64: + """Natural logarithm of the survival function at *k*. + + Args: + k: Number of events. + + Returns: + Log-survival function value at *k*. + """ + var s = self.sf(k) + if s <= 0.0: + return -inf[DType.float64]() + return log(s) + + fn ppf(self, q: Float64) -> Int: + """Percent point function (inverse CDF). + + Args: + q: Probability in [0, 1]. + + Returns: + Smallest integer k such that CDF(k) ≥ q. + """ + if q <= 0.0: + return 0 + if q >= 1.0: + return _MAX_K + + var cumulative: Float64 = 0.0 + var pk = exp(-self.mu) + cumulative = pk + + if cumulative >= q: + return 0 + + for k in range(1, _MAX_K): + pk *= self.mu / Float64(k) + cumulative += pk + if cumulative >= q: + return k + + return _MAX_K + + fn isf(self, q: Float64) -> Int: + """Inverse survival function (inverse SF). + + Args: + q: Probability in [0, 1]. + + Returns: + Smallest integer k such that SF(k) ≤ q. + """ + if q <= 0.0: + return _MAX_K + if q >= 1.0: + return 0 + + var cumulative: Float64 = 0.0 + var pk = exp(-self.mu) + cumulative = pk + + if 1.0 - cumulative <= q: + return 0 + + for k in range(1, _MAX_K): + pk *= self.mu / Float64(k) + cumulative += pk + if 1.0 - cumulative <= q: + return k + + return _MAX_K + + # --- Summary statistics -------------------------------------------------- + + fn median(self) -> UInt: + """Median of the distribution (approximation). + + Uses the approximation: floor(μ + 1/3 - 0.02/μ). + """ + if self.mu == 0.0: + return 0 + return UInt(floor(self.mu + 1.0 / 3.0 - 0.02 / self.mu)) + + fn mean(self) -> Float64: + """Distribution mean = μ.""" + return self.mu + + fn variance(self) -> Float64: + """Distribution variance = μ.""" + return self.mu + + fn std(self) -> Float64: + """Distribution standard deviation = √μ.""" + return sqrt(self.mu) From dd44a1fa1e39925fbc5879fafd70e90b397eb34f Mon Sep 17 00:00:00 2001 From: shivasankar Date: Sat, 4 Apr 2026 01:51:00 +0900 Subject: [PATCH 04/11] Update test_distributions.mojo --- tests/test_distributions.mojo | 170 ++++++++++++++++++++++++++++++++++ 1 file changed, 170 insertions(+) diff --git a/tests/test_distributions.mojo b/tests/test_distributions.mojo index b0898b1..0b8f83f 100644 --- a/tests/test_distributions.mojo +++ b/tests/test_distributions.mojo @@ -23,6 +23,9 @@ from stamojo.distributions import ( FDist, Exponential, Binomial, + Gamma, + Beta, + Poisson, ) @@ -588,6 +591,173 @@ fn test_binomial_scipy() raises: assert_almost_equal(Float64(b.ppf(q)), sp_ppf, atol=1e-10) +# ===----------------------------------------------------------------------=== # +# Gamma distribution tests +# ===----------------------------------------------------------------------=== # + + +fn test_gamma_pdf() raises: + """Test Gamma PDF at known values.""" + var g = Gamma(2.0, 1.0) + # PDF at x=1 for Gamma(2,1): 1*exp(-1) = exp(-1) + assert_almost_equal(g.pdf(1.0), exp(-1.0), atol=1e-12) + # PDF(x < 0) = 0 + assert_almost_equal(g.pdf(-1.0), 0.0, atol=1e-15) + + +fn test_gamma_cdf() raises: + """Test Gamma CDF at known values.""" + var g = Gamma(1.0, 1.0) + # Gamma(1,1) = Exponential(1): CDF(x) = 1 - exp(-x) + assert_almost_equal(g.cdf(1.0), 1.0 - exp(-1.0), atol=1e-12) + assert_almost_equal(g.cdf(2.0), 1.0 - exp(-2.0), atol=1e-12) + + +fn test_gamma_ppf_roundtrip() raises: + """Test Gamma PPF round-trip.""" + var g = Gamma(3.0, 2.0) + assert_almost_equal(g.cdf(g.ppf(0.5)), 0.5, atol=1e-6) + assert_almost_equal(g.cdf(g.ppf(0.95)), 0.95, atol=1e-6) + assert_almost_equal(g.cdf(g.ppf(0.1)), 0.1, atol=1e-6) + + +fn test_gamma_stats() raises: + """Test Gamma distribution statistics.""" + var g = Gamma(4.0, 3.0) + # mean = a*scale = 12 + assert_almost_equal(g.mean(), 12.0, atol=1e-12) + # variance = a*scale^2 = 36 + assert_almost_equal(g.variance(), 36.0, atol=1e-12) + # std = 6 + assert_almost_equal(g.std(), 6.0, atol=1e-12) + + +fn test_gamma_scipy() raises: + """Test Gamma distribution against scipy.stats.gamma.""" + var sp = _load_scipy_stats() + if sp is None: + print("test_gamma_scipy skipped (scipy not available)") + return + + var g = Gamma(2.5, 1.5) + var xs: List[Float64] = [1.0, 2.0, 5.0] + + for i in range(len(xs)): + var x = xs[i] + var sp_pdf = _py_f64(sp.gamma.pdf(x, 2.5, scale=1.5)) + var sp_cdf = _py_f64(sp.gamma.cdf(x, 2.5, scale=1.5)) + assert_almost_equal(g.pdf(x), sp_pdf, atol=1e-10) + assert_almost_equal(g.cdf(x), sp_cdf, atol=1e-10) + + +# ===----------------------------------------------------------------------=== # +# Beta distribution tests +# ===----------------------------------------------------------------------=== # + + +fn test_beta_pdf() raises: + """Test Beta PDF at known values.""" + var b = Beta(2.0, 2.0) + # PDF at 0.5 for Beta(2,2): 6 * 0.25 = 1.5 + assert_almost_equal(b.pdf(0.5), 1.5, atol=1e-12) + # PDF outside [0,1] = 0 + assert_almost_equal(b.pdf(-0.1), 0.0, atol=1e-15) + assert_almost_equal(b.pdf(1.1), 0.0, atol=1e-15) + + +fn test_beta_cdf() raises: + """Test Beta CDF at known values.""" + var b = Beta(1.0, 1.0) + # Beta(1,1) = Uniform(0,1): CDF(x) = x + assert_almost_equal(b.cdf(0.3), 0.3, atol=1e-12) + assert_almost_equal(b.cdf(0.7), 0.7, atol=1e-12) + + +fn test_beta_ppf_roundtrip() raises: + """Test Beta PPF round-trip.""" + var b = Beta(3.0, 5.0) + assert_almost_equal(b.cdf(b.ppf(0.5)), 0.5, atol=1e-6) + assert_almost_equal(b.cdf(b.ppf(0.9)), 0.9, atol=1e-6) + assert_almost_equal(b.cdf(b.ppf(0.1)), 0.1, atol=1e-6) + + +fn test_beta_stats() raises: + """Test Beta distribution statistics.""" + var b = Beta(2.0, 3.0) + # mean = a/(a+b) = 2/5 = 0.4 + assert_almost_equal(b.mean(), 0.4, atol=1e-12) + # variance = ab/((a+b)^2*(a+b+1)) = 6/(25*6) = 0.04 + assert_almost_equal(b.variance(), 0.04, atol=1e-12) + + +fn test_beta_scipy() raises: + """Test Beta distribution against scipy.stats.beta.""" + var sp = _load_scipy_stats() + if sp is None: + print("test_beta_scipy skipped (scipy not available)") + return + + var b = Beta(2.5, 3.5) + var xs: List[Float64] = [0.2, 0.5, 0.8] + + for i in range(len(xs)): + var x = xs[i] + var sp_pdf = _py_f64(sp.beta.pdf(x, 2.5, 3.5)) + var sp_cdf = _py_f64(sp.beta.cdf(x, 2.5, 3.5)) + assert_almost_equal(b.pdf(x), sp_pdf, atol=1e-10) + assert_almost_equal(b.cdf(x), sp_cdf, atol=1e-10) + + +# ===----------------------------------------------------------------------=== # +# Poisson distribution tests +# ===----------------------------------------------------------------------=== # + + +fn test_poisson_pmf() raises: + """Test Poisson PMF at known values.""" + var p = Poisson(3.0) + # PMF at k=0: exp(-3) + assert_almost_equal(p.pmf(0), exp(-3.0), atol=1e-12) + # PMF at k=3: 3^3 * exp(-3) / 6 = 27*exp(-3)/6 + assert_almost_equal(p.pmf(3), 27.0 * exp(-3.0) / 6.0, atol=1e-12) + # PMF for k < 0 = 0 + assert_almost_equal(p.pmf(-1), 0.0, atol=1e-15) + + +fn test_poisson_cdf() raises: + """Test Poisson CDF at known values.""" + var p = Poisson(1.0) + # CDF at k=0: exp(-1) + assert_almost_equal(p.cdf(0), exp(-1.0), atol=1e-12) + # CDF at k=1: exp(-1) + exp(-1) = 2*exp(-1) + assert_almost_equal(p.cdf(1), 2.0 * exp(-1.0), atol=1e-12) + + +fn test_poisson_stats() raises: + """Test Poisson distribution statistics.""" + var p = Poisson(5.0) + assert_almost_equal(p.mean(), 5.0, atol=1e-15) + assert_almost_equal(p.variance(), 5.0, atol=1e-15) + assert_almost_equal(p.std(), sqrt(5.0), atol=1e-12) + + +fn test_poisson_scipy() raises: + """Test Poisson distribution against scipy.stats.poisson.""" + var sp = _load_scipy_stats() + if sp is None: + print("test_poisson_scipy skipped (scipy not available)") + return + + var p = Poisson(4.0) + var ks: List[Int] = [0, 1, 2, 4, 8] + + for i in range(len(ks)): + var k = ks[i] + var sp_pmf = _py_f64(sp.poisson.pmf(k, 4.0)) + var sp_cdf = _py_f64(sp.poisson.cdf(k, 4.0)) + assert_almost_equal(p.pmf(k), sp_pmf, atol=1e-10) + assert_almost_equal(p.cdf(k), sp_cdf, atol=1e-10) + # ===----------------------------------------------------------------------=== # # Main test runner # ===----------------------------------------------------------------------=== # From 3965bb15fd26e91ca1713975da2bb8cf064d3132 Mon Sep 17 00:00:00 2001 From: shivasankar Date: Sat, 4 Apr 2026 01:55:01 +0900 Subject: [PATCH 05/11] change fn to def, update imports --- src/stamojo/distributions/__init__.mojo | 6 ++++++ src/stamojo/distributions/beta.mojo | 26 +++++++++++------------ src/stamojo/distributions/gamma.mojo | 28 ++++++++++++------------- src/stamojo/distributions/poisson.mojo | 26 +++++++++++------------ 4 files changed, 46 insertions(+), 40 deletions(-) diff --git a/src/stamojo/distributions/__init__.mojo b/src/stamojo/distributions/__init__.mojo index 82d1ee5..6d41354 100644 --- a/src/stamojo/distributions/__init__.mojo +++ b/src/stamojo/distributions/__init__.mojo @@ -14,6 +14,9 @@ Distributions provided: - `FDist` — F-distribution (Fisher-Snedecor) - `Exponential` — Exponential distribution - `Binomial` — Binomial distribution +- `Gamma` — Gamma distribution +- `Beta` — Beta distribution +- `Poisson` — Poisson distribution """ from .normal import Normal @@ -22,3 +25,6 @@ from .chi2 import ChiSquared from .f import FDist from .exponential import Exponential from .binomial import Binomial +from .gamma import Gamma +from .beta import Beta +from .poisson import Poisson diff --git a/src/stamojo/distributions/beta.mojo b/src/stamojo/distributions/beta.mojo index 3ab85a6..32d18ae 100644 --- a/src/stamojo/distributions/beta.mojo +++ b/src/stamojo/distributions/beta.mojo @@ -44,13 +44,13 @@ struct Beta(Copyable, Movable): # --- Density functions --------------------------------------------------- - fn pdf(self, x: Float64) -> Float64: + def pdf(self, x: Float64) -> Float64: """Probability density function at *x*.""" if x <= 0.0 or x >= 1.0: return 0.0 return exp(self.logpdf(x)) - fn logpdf(self, x: Float64) -> Float64: + def logpdf(self, x: Float64) -> Float64: """Natural logarithm of the probability density function at *x*.""" if x <= 0.0 or x >= 1.0: return -inf[DType.float64]() @@ -62,7 +62,7 @@ struct Beta(Copyable, Movable): # --- Distribution functions ---------------------------------------------- - fn cdf(self, x: Float64) -> Float64: + def cdf(self, x: Float64) -> Float64: """Cumulative distribution function P(X ≤ x). CDF(x; a, b) = I_x(a, b) (regularized incomplete beta). @@ -73,7 +73,7 @@ struct Beta(Copyable, Movable): return 1.0 return betainc(self.a, self.b, x) - fn logcdf(self, x: Float64) -> Float64: + def logcdf(self, x: Float64) -> Float64: """Natural logarithm of the CDF at *x*.""" if x <= 0.0: return -inf[DType.float64]() @@ -84,7 +84,7 @@ struct Beta(Copyable, Movable): return -inf[DType.float64]() return log(c) - fn sf(self, x: Float64) -> Float64: + def sf(self, x: Float64) -> Float64: """Survival function (1 − CDF) at *x*.""" if x <= 0.0: return 1.0 @@ -92,7 +92,7 @@ struct Beta(Copyable, Movable): return 0.0 return 1.0 - self.cdf(x) - fn logsf(self, x: Float64) -> Float64: + def logsf(self, x: Float64) -> Float64: """Natural logarithm of the survival function at *x*.""" if x <= 0.0: return 0.0 @@ -103,7 +103,7 @@ struct Beta(Copyable, Movable): return -inf[DType.float64]() return log(s) - fn ppf(self, p: Float64) -> Float64: + def ppf(self, p: Float64) -> Float64: """Percent-point function (quantile / inverse CDF). Uses Newton-Raphson with bisection fallback. @@ -166,7 +166,7 @@ struct Beta(Copyable, Movable): return x - fn isf(self, q: Float64) -> Float64: + def isf(self, q: Float64) -> Float64: """Inverse survival function (inverse SF). Args: @@ -179,7 +179,7 @@ struct Beta(Copyable, Movable): # --- Summary statistics -------------------------------------------------- - fn median(self) -> Float64: + def median(self) -> Float64: """Median of the distribution (approximation). Uses the approximation: (a - 1/3) / (a + b - 2/3) for a, b >= 1. @@ -188,20 +188,20 @@ struct Beta(Copyable, Movable): return (self.a - 1.0 / 3.0) / (self.a + self.b - 2.0 / 3.0) return self.a / (self.a + self.b) - fn mean(self) -> Float64: + def mean(self) -> Float64: """Distribution mean = a / (a + b).""" return self.a / (self.a + self.b) - fn variance(self) -> Float64: + def variance(self) -> Float64: """Distribution variance = ab / ((a+b)²(a+b+1)).""" var ab = self.a + self.b return self.a * self.b / (ab * ab * (ab + 1.0)) - fn std(self) -> Float64: + def std(self) -> Float64: """Distribution standard deviation.""" return sqrt(self.variance()) - fn entropy(self) -> Float64: + def entropy(self) -> Float64: """Differential entropy of the distribution. H = ln(B(a,b)) - (a-1)ψ(a) - (b-1)ψ(b) + (a+b-2)ψ(a+b) diff --git a/src/stamojo/distributions/gamma.mojo b/src/stamojo/distributions/gamma.mojo index fd68c1c..348b59d 100644 --- a/src/stamojo/distributions/gamma.mojo +++ b/src/stamojo/distributions/gamma.mojo @@ -44,13 +44,13 @@ struct Gamma(Copyable, Movable): # --- Density functions --------------------------------------------------- - fn pdf(self, x: Float64) -> Float64: + def pdf(self, x: Float64) -> Float64: """Probability density function at *x*.""" if x <= 0.0: return 0.0 return exp(self.logpdf(x)) - fn logpdf(self, x: Float64) -> Float64: + def logpdf(self, x: Float64) -> Float64: """Natural logarithm of the probability density function at *x*.""" if x <= 0.0: return -inf[DType.float64]() @@ -63,7 +63,7 @@ struct Gamma(Copyable, Movable): # --- Distribution functions ---------------------------------------------- - fn cdf(self, x: Float64) -> Float64: + def cdf(self, x: Float64) -> Float64: """Cumulative distribution function P(X ≤ x). CDF(x; a, θ) = P(a, x/θ) (regularized lower incomplete gamma). @@ -72,7 +72,7 @@ struct Gamma(Copyable, Movable): return 0.0 return gammainc(self.a, x / self.scale) - fn logcdf(self, x: Float64) -> Float64: + def logcdf(self, x: Float64) -> Float64: """Natural logarithm of the CDF at *x*.""" if x <= 0.0: return -inf[DType.float64]() @@ -81,13 +81,13 @@ struct Gamma(Copyable, Movable): return -inf[DType.float64]() return log(c) - fn sf(self, x: Float64) -> Float64: + def sf(self, x: Float64) -> Float64: """Survival function (1 − CDF) at *x*.""" if x <= 0.0: return 1.0 return gammaincc(self.a, x / self.scale) - fn logsf(self, x: Float64) -> Float64: + def logsf(self, x: Float64) -> Float64: """Natural logarithm of the survival function at *x*.""" if x <= 0.0: return 0.0 @@ -96,7 +96,7 @@ struct Gamma(Copyable, Movable): return -inf[DType.float64]() return log(s) - fn ppf(self, p: Float64) -> Float64: + def ppf(self, p: Float64) -> Float64: """Percent-point function (quantile / inverse CDF). Uses Newton-Raphson with bisection fallback. @@ -130,7 +130,7 @@ struct Gamma(Copyable, Movable): x = 0.01 x *= self.scale - # TODO: Since many use Newton-Raphson, we could have a separate func for this. + # TODO: Since many use Newton-Raphson, we could have a separate func for this. var lo = 0.0 var hi = x * 4.0 + 10.0 * self.scale while self.cdf(hi) < p: @@ -161,7 +161,7 @@ struct Gamma(Copyable, Movable): return x - fn isf(self, q: Float64) -> Float64: + def isf(self, q: Float64) -> Float64: """Inverse survival function (inverse SF). Args: @@ -174,7 +174,7 @@ struct Gamma(Copyable, Movable): # --- Summary statistics -------------------------------------------------- - fn median(self) -> Float64: + def median(self) -> Float64: """Median of the distribution (approximation). Uses the approximation: scale * a * (1 - 1/(9a))^3 for a >= 1, @@ -185,19 +185,19 @@ struct Gamma(Copyable, Movable): else: return self.scale * self.a * pow(2.0, -1.0 / self.a) - fn mean(self) -> Float64: + def mean(self) -> Float64: """Distribution mean = a * θ.""" return self.a * self.scale - fn variance(self) -> Float64: + def variance(self) -> Float64: """Distribution variance = a * θ².""" return self.a * self.scale * self.scale - fn std(self) -> Float64: + def std(self) -> Float64: """Distribution standard deviation = √(a) * θ.""" return sqrt(self.a) * self.scale - fn entropy(self) -> Float64: + def entropy(self) -> Float64: """Differential entropy of the distribution. H = a + ln(θ) + ln(Γ(a)) + (1 - a) * ψ(a) diff --git a/src/stamojo/distributions/poisson.mojo b/src/stamojo/distributions/poisson.mojo index bb8393a..1c8533a 100644 --- a/src/stamojo/distributions/poisson.mojo +++ b/src/stamojo/distributions/poisson.mojo @@ -48,12 +48,12 @@ struct Poisson(DiscretelyDistributed): var mu: Float64 - fn __init__(out self, mu: Float64): + def __init__(out self, mu: Float64): self.mu = mu # --- Probability functions ------------------------------------------------ - fn pmf(self, k: Int) -> Float64: + def pmf(self, k: Int) -> Float64: """Probability mass function at *k*. Args: @@ -64,7 +64,7 @@ struct Poisson(DiscretelyDistributed): """ return exp(self.logpmf(k)) - fn logpmf(self, k: Int) -> Float64: + def logpmf(self, k: Int) -> Float64: """Natural logarithm of the PMF at *k*. Args: @@ -79,7 +79,7 @@ struct Poisson(DiscretelyDistributed): return 0.0 if k == 0 else -inf[DType.float64]() return Float64(k) * log(self.mu) - self.mu - lgamma(Float64(k) + 1.0) - fn cdf(self, k: Int) -> Float64: + def cdf(self, k: Int) -> Float64: """Cumulative distribution function P(X ≤ k). Args: @@ -95,7 +95,7 @@ struct Poisson(DiscretelyDistributed): # CDF of Poisson(μ) at k = Q(k+1, μ) = gammaincc(k+1, μ) return gammaincc(Float64(k + 1), self.mu) - fn logcdf(self, k: Int) -> Float64: + def logcdf(self, k: Int) -> Float64: """Natural logarithm of the CDF at *k*. Args: @@ -109,7 +109,7 @@ struct Poisson(DiscretelyDistributed): return -inf[DType.float64]() return log(c) - fn sf(self, k: Int) -> Float64: + def sf(self, k: Int) -> Float64: """Survival function (1 − CDF) at *k*. Args: @@ -124,7 +124,7 @@ struct Poisson(DiscretelyDistributed): return 0.0 return 1.0 - self.cdf(k) - fn logsf(self, k: Int) -> Float64: + def logsf(self, k: Int) -> Float64: """Natural logarithm of the survival function at *k*. Args: @@ -138,7 +138,7 @@ struct Poisson(DiscretelyDistributed): return -inf[DType.float64]() return log(s) - fn ppf(self, q: Float64) -> Int: + def ppf(self, q: Float64) -> Int: """Percent point function (inverse CDF). Args: @@ -167,7 +167,7 @@ struct Poisson(DiscretelyDistributed): return _MAX_K - fn isf(self, q: Float64) -> Int: + def isf(self, q: Float64) -> Int: """Inverse survival function (inverse SF). Args: @@ -198,7 +198,7 @@ struct Poisson(DiscretelyDistributed): # --- Summary statistics -------------------------------------------------- - fn median(self) -> UInt: + def median(self) -> UInt: """Median of the distribution (approximation). Uses the approximation: floor(μ + 1/3 - 0.02/μ). @@ -207,14 +207,14 @@ struct Poisson(DiscretelyDistributed): return 0 return UInt(floor(self.mu + 1.0 / 3.0 - 0.02 / self.mu)) - fn mean(self) -> Float64: + def mean(self) -> Float64: """Distribution mean = μ.""" return self.mu - fn variance(self) -> Float64: + def variance(self) -> Float64: """Distribution variance = μ.""" return self.mu - fn std(self) -> Float64: + def std(self) -> Float64: """Distribution standard deviation = √μ.""" return sqrt(self.mu) From bd60844fed2823128d800657fdc12aeb732cd2ff Mon Sep 17 00:00:00 2001 From: shivasankar Date: Sat, 4 Apr 2026 02:06:11 +0900 Subject: [PATCH 06/11] fix test_distributions. --- tests/test_distributions.mojo | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/test_distributions.mojo b/tests/test_distributions.mojo index 0b8f83f..bbcd165 100644 --- a/tests/test_distributions.mojo +++ b/tests/test_distributions.mojo @@ -12,7 +12,7 @@ Each distribution is tested for: - Comparison against scipy.stats (when available) """ -from math import exp, log +from math import exp, log, sqrt from python import Python, PythonObject from testing import assert_almost_equal, TestSuite @@ -758,6 +758,7 @@ fn test_poisson_scipy() raises: assert_almost_equal(p.pmf(k), sp_pmf, atol=1e-10) assert_almost_equal(p.cdf(k), sp_cdf, atol=1e-10) + # ===----------------------------------------------------------------------=== # # Main test runner # ===----------------------------------------------------------------------=== # From 1dd6ea10ec2b8a55dc3fe13c18e6bd369cd7a78d Mon Sep 17 00:00:00 2001 From: shivasankar Date: Sat, 4 Apr 2026 02:07:44 +0900 Subject: [PATCH 07/11] fix test_stats --- src/stamojo/distributions/poisson.mojo | 8 +++----- tests/test_stats.mojo | 6 +++--- 2 files changed, 6 insertions(+), 8 deletions(-) diff --git a/src/stamojo/distributions/poisson.mojo b/src/stamojo/distributions/poisson.mojo index 1c8533a..6328b7f 100644 --- a/src/stamojo/distributions/poisson.mojo +++ b/src/stamojo/distributions/poisson.mojo @@ -152,9 +152,8 @@ struct Poisson(DiscretelyDistributed): if q >= 1.0: return _MAX_K - var cumulative: Float64 = 0.0 var pk = exp(-self.mu) - cumulative = pk + var cumulative: Float64 = pk if cumulative >= q: return 0 @@ -181,9 +180,8 @@ struct Poisson(DiscretelyDistributed): if q >= 1.0: return 0 - var cumulative: Float64 = 0.0 - var pk = exp(-self.mu) - cumulative = pk + var pk: Float64 = exp(-self.mu) + var cumulative: Float64 = pk if 1.0 - cumulative <= q: return 0 diff --git a/tests/test_stats.mojo b/tests/test_stats.mojo index 96fb632..893bfff 100644 --- a/tests/test_stats.mojo +++ b/tests/test_stats.mojo @@ -15,7 +15,7 @@ from testing import assert_almost_equal, TestSuite from stamojo.stats import ( mean, variance, - std, + stddev, median, quantile, skewness, @@ -68,7 +68,7 @@ fn test_std() raises: """Test standard deviation.""" var data: List[Float64] = [2.0, 4.0, 4.0, 4.0, 5.0, 5.0, 7.0, 9.0] - assert_almost_equal(std(data, ddof=0), 2.0, atol=1e-12) + assert_almost_equal(stddev(data, ddof=0), 2.0, atol=1e-12) fn test_median_odd() raises: @@ -146,7 +146,7 @@ fn test_scipy_comparison() raises: assert_almost_equal(mean(data), np_mean, atol=1e-10) assert_almost_equal(variance(data, ddof=0), np_var, atol=1e-10) - assert_almost_equal(std(data, ddof=0), np_std, atol=1e-10) + assert_almost_equal(stddev(data, ddof=0), np_std, atol=1e-10) assert_almost_equal(median(data), np_median, atol=1e-10) print("✓ test_scipy_comparison passed") From 67129dfe42814c706808c011aa399f012adbb741 Mon Sep 17 00:00:00 2001 From: ZHU Yuhao Date: Tue, 14 Apr 2026 12:31:41 +0200 Subject: [PATCH 08/11] The ppf function of Poisson would underflow if mu is large. So we need to use a binary search method to properly handle this. Moreover, `isf` can be just calculated as ppf(1.0-q) --- src/stamojo/distributions/beta.mojo | 2 +- src/stamojo/distributions/binomial.mojo | 2 +- src/stamojo/distributions/chi2.mojo | 2 +- src/stamojo/distributions/exponential.mojo | 2 +- src/stamojo/distributions/f.mojo | 2 +- src/stamojo/distributions/gamma.mojo | 2 +- src/stamojo/distributions/normal.mojo | 4 +- src/stamojo/distributions/poisson.mojo | 60 ++++++++++------------ src/stamojo/distributions/t.mojo | 2 +- src/stamojo/special/_bessel.mojo | 18 +++---- src/stamojo/special/_beta.mojo | 2 +- src/stamojo/special/_erf.mojo | 2 +- src/stamojo/special/_gamma.mojo | 2 +- src/stamojo/stats/correlation.mojo | 2 +- src/stamojo/stats/descriptive.mojo | 2 +- src/stamojo/stats/tests.mojo | 2 +- tests/test_distributions.mojo | 19 +++++-- tests/test_hypothesis.mojo | 6 +-- tests/test_special.mojo | 6 +-- tests/test_stats.mojo | 6 +-- 20 files changed, 76 insertions(+), 69 deletions(-) diff --git a/src/stamojo/distributions/beta.mojo b/src/stamojo/distributions/beta.mojo index 32d18ae..f17f671 100644 --- a/src/stamojo/distributions/beta.mojo +++ b/src/stamojo/distributions/beta.mojo @@ -12,7 +12,7 @@ The beta distribution with shape parameters *a* and *b* has PDF:: f(x; a, b) = x^{a-1} (1-x)^{b-1} / B(a, b), 0 < x < 1 """ -from math import sqrt, log, lgamma, exp, nan, inf +from std.math import sqrt, log, lgamma, exp, nan, inf from stamojo.special import betainc, lbeta, ndtri diff --git a/src/stamojo/distributions/binomial.mojo b/src/stamojo/distributions/binomial.mojo index 66122fc..b985608 100644 --- a/src/stamojo/distributions/binomial.mojo +++ b/src/stamojo/distributions/binomial.mojo @@ -14,7 +14,7 @@ The binomial distribution with parameters n and p has PMF: where C(n, k) is the binomial coefficient. """ -from math import log, log1p, exp, lgamma, nan, inf, floor, sqrt +from std.math import log, log1p, exp, lgamma, nan, inf, floor, sqrt from stamojo.distributions.traits import DiscretelyDistributed diff --git a/src/stamojo/distributions/chi2.mojo b/src/stamojo/distributions/chi2.mojo index fd0b021..ad25de1 100644 --- a/src/stamojo/distributions/chi2.mojo +++ b/src/stamojo/distributions/chi2.mojo @@ -12,7 +12,7 @@ The chi-squared distribution with *k* degrees of freedom has PDF:: f(x; k) = x^{k/2−1} exp(−x/2) / (2^{k/2} Γ(k/2)), x > 0 """ -from math import sqrt, log, lgamma, exp, nan, inf +from std.math import sqrt, log, lgamma, exp, nan, inf from stamojo.special import gammainc, gammaincc, ndtri diff --git a/src/stamojo/distributions/exponential.mojo b/src/stamojo/distributions/exponential.mojo index 41445f2..2a02f2c 100644 --- a/src/stamojo/distributions/exponential.mojo +++ b/src/stamojo/distributions/exponential.mojo @@ -12,7 +12,7 @@ The exponential distribution with rate parameter λ has PDF: f(x; λ) = λ exp(−λx), x ≥ 0 """ -from math import log, exp, nan, inf, log1p, expm1 +from std.math import log, exp, nan, inf, log1p, expm1 from stamojo.distributions.traits import ContinuouslyDistributed diff --git a/src/stamojo/distributions/f.mojo b/src/stamojo/distributions/f.mojo index 0bba2de..b32ac9e 100644 --- a/src/stamojo/distributions/f.mojo +++ b/src/stamojo/distributions/f.mojo @@ -13,7 +13,7 @@ The F-distribution with d₁ and d₂ degrees of freedom has PDF:: / (x · B(d₁/2, d₂/2)) """ -from math import sqrt, log, exp, nan, inf +from std.math import sqrt, log, exp, nan, inf from stamojo.special import betainc, lbeta, ndtri diff --git a/src/stamojo/distributions/gamma.mojo b/src/stamojo/distributions/gamma.mojo index 348b59d..a1e8b4a 100644 --- a/src/stamojo/distributions/gamma.mojo +++ b/src/stamojo/distributions/gamma.mojo @@ -12,7 +12,7 @@ The gamma distribution with shape *a* and scale *θ* has PDF:: f(x; a, θ) = x^{a-1} exp(−x/θ) / (θ^a Γ(a)), x > 0 """ -from math import sqrt, log, lgamma, exp, nan, inf, floor, pow +from std.math import sqrt, log, lgamma, exp, nan, inf, floor, pow from stamojo.special import gammainc, gammaincc, ndtri diff --git a/src/stamojo/distributions/normal.mojo b/src/stamojo/distributions/normal.mojo index df61bed..03d5546 100644 --- a/src/stamojo/distributions/normal.mojo +++ b/src/stamojo/distributions/normal.mojo @@ -18,8 +18,8 @@ Examples:: n.ppf(0.975) # ≈ 1.96 """ -from math import sqrt, log, cos, exp, erf, erfc, nan, inf -from random import random_float64 +from std.math import sqrt, log, cos, exp, erf, erfc, nan, inf +from std.random import random_float64 from stamojo.special import ndtri diff --git a/src/stamojo/distributions/poisson.mojo b/src/stamojo/distributions/poisson.mojo index 6328b7f..0b2a82c 100644 --- a/src/stamojo/distributions/poisson.mojo +++ b/src/stamojo/distributions/poisson.mojo @@ -12,7 +12,7 @@ The Poisson distribution with rate parameter *μ* has PMF:: P(X = k; μ) = μ^k exp(−μ) / k!, k = 0, 1, 2, ... """ -from math import log, exp, lgamma, nan, inf, floor, sqrt +from std.math import log, exp, lgamma, nan, inf, floor, sqrt from stamojo.distributions.traits import DiscretelyDistributed from stamojo.special import gammaincc @@ -23,6 +23,7 @@ from stamojo.special import gammaincc # ===----------------------------------------------------------------------=== # comptime _MAX_K = 10000 +"""Maximum k value for PPF search to prevent infinite loops in extreme cases.""" # ===----------------------------------------------------------------------=== # @@ -139,7 +140,11 @@ struct Poisson(DiscretelyDistributed): return log(s) def ppf(self, q: Float64) -> Int: - """Percent point function (inverse CDF). + """Finds the smallest integer k such that CDF(k) ≥ q + (percent point function). + + Uses binary search with the CDF to avoid numerical underflow + that would occur with incremental PMF summation for large mu. Args: q: Probability in [0, 1]. @@ -152,19 +157,25 @@ struct Poisson(DiscretelyDistributed): if q >= 1.0: return _MAX_K - var pk = exp(-self.mu) - var cumulative: Float64 = pk - - if cumulative >= q: - return 0 - - for k in range(1, _MAX_K): - pk *= self.mu / Float64(k) - cumulative += pk - if cumulative >= q: - return k - - return _MAX_K + # Binary search: find smallest k where CDF(k) >= q. + var lo = 0 + var hi = Int(self.mu + 10.0 * sqrt(self.mu) + 20.0) + if hi > _MAX_K: + hi = _MAX_K + # Ensure hi is large enough. + while self.cdf(hi) < q: + hi *= 2 + if hi > _MAX_K: + return _MAX_K + + while lo < hi: + var mid = (lo + hi) // 2 + if self.cdf(mid) < q: + lo = mid + 1 + else: + hi = mid + + return lo def isf(self, q: Float64) -> Int: """Inverse survival function (inverse SF). @@ -175,24 +186,7 @@ struct Poisson(DiscretelyDistributed): Returns: Smallest integer k such that SF(k) ≤ q. """ - if q <= 0.0: - return _MAX_K - if q >= 1.0: - return 0 - - var pk: Float64 = exp(-self.mu) - var cumulative: Float64 = pk - - if 1.0 - cumulative <= q: - return 0 - - for k in range(1, _MAX_K): - pk *= self.mu / Float64(k) - cumulative += pk - if 1.0 - cumulative <= q: - return k - - return _MAX_K + return self.ppf(1.0 - q) # --- Summary statistics -------------------------------------------------- diff --git a/src/stamojo/distributions/t.mojo b/src/stamojo/distributions/t.mojo index 6175110..46d83c8 100644 --- a/src/stamojo/distributions/t.mojo +++ b/src/stamojo/distributions/t.mojo @@ -12,7 +12,7 @@ The Student's t-distribution with ν degrees of freedom has PDF:: f(x; ν) = Γ((ν+1)/2) / (√(νπ) Γ(ν/2)) (1 + x²/ν)^{-(ν+1)/2} """ -from math import sqrt, log, lgamma, exp, nan, inf +from std.math import sqrt, log, lgamma, exp, nan, inf from stamojo.special import betainc, ndtri diff --git a/src/stamojo/special/_bessel.mojo b/src/stamojo/special/_bessel.mojo index 70eb993..14587fc 100644 --- a/src/stamojo/special/_bessel.mojo +++ b/src/stamojo/special/_bessel.mojo @@ -17,7 +17,7 @@ References: - https://en.wikipedia.org/wiki/Bessel_function """ -from math import cos, exp, inf, log, nan, sin, sqrt +from std.math import cos, exp, inf, log, nan, sin, sqrt # === --------------------------------------------------------------------=== # # General notes: @@ -64,7 +64,7 @@ fn j0(x: Float64) -> Float64: Examples: ```mojo from stamojo.special import j0 - from testing import assert_almost_equal + from std.testing import assert_almost_equal fn main() raises: assert_almost_equal(j0(1.0), 0.7651976865579666, atol=1e-12) @@ -99,7 +99,7 @@ fn j1(x: Float64) -> Float64: Examples: ```mojo from stamojo.special import j1 - from testing import assert_almost_equal + from std.testing import assert_almost_equal fn main() raises: assert_almost_equal(j1(1.0), 0.44005058574493355, atol=1e-12) @@ -192,7 +192,7 @@ fn i0(x: Float64) -> Float64: Examples: ```mojo from stamojo.special import i0 - from testing import assert_almost_equal + from std.testing import assert_almost_equal fn main() raises: assert_almost_equal(i0(1.0), 1.2660658777520082, atol=1e-12) @@ -219,7 +219,7 @@ fn i1(x: Float64) -> Float64: Examples: ```mojo from stamojo.special import i1 - from testing import assert_almost_equal + from std.testing import assert_almost_equal fn main() raises: assert_almost_equal(i1(1.0), 0.5651591039924851, atol=1e-12) @@ -247,7 +247,7 @@ fn i0e(x: Float64) -> Float64: Examples: ```mojo from stamojo.special import i0e - from testing import assert_almost_equal + from std.testing import assert_almost_equal fn main() raises: assert_almost_equal(i0e(1.0), 0.4657596075936405, atol=1e-12) @@ -269,7 +269,7 @@ fn i1e(x: Float64) -> Float64: Examples: ```mojo from stamojo.special import i1e - from testing import assert_almost_equal + from std.testing import assert_almost_equal fn main() raises: assert_almost_equal(i1e(1.0), 0.2079104153497085, atol=1e-12) @@ -297,7 +297,7 @@ fn y0(x: Float64) -> Float64: Examples: ```mojo from stamojo.special import y0 - from testing import assert_almost_equal + from std.testing import assert_almost_equal fn main() raises: assert_almost_equal(y0(1.0), 0.08825696421567697, atol=1e-12) @@ -339,7 +339,7 @@ fn y1(x: Float64) -> Float64: Examples: ```mojo from stamojo.special import y1 - from testing import assert_almost_equal + from std.testing import assert_almost_equal fn main() raises: assert_almost_equal(y1(1.0), -0.7812128213002887, atol=1e-12) diff --git a/src/stamojo/special/_beta.mojo b/src/stamojo/special/_beta.mojo index 6894dd5..c61d4cd 100644 --- a/src/stamojo/special/_beta.mojo +++ b/src/stamojo/special/_beta.mojo @@ -22,7 +22,7 @@ Reference: Press et al., Numerical Recipes, 3rd ed., Section 6.4. """ -from math import lgamma, exp, log, nan +from std.math import lgamma, exp, log, nan # ===----------------------------------------------------------------------=== # diff --git a/src/stamojo/special/_erf.mojo b/src/stamojo/special/_erf.mojo index d7c4361..1706185 100644 --- a/src/stamojo/special/_erf.mojo +++ b/src/stamojo/special/_erf.mojo @@ -20,7 +20,7 @@ Reference: https://web.archive.org/web/20151030215612/http://home.online.no/~pjacklam/notes/invnorm/ """ -from math import sqrt, log, exp, erf, erfc, nan, inf +from std.math import sqrt, log, exp, erf, erfc, nan, inf # ===----------------------------------------------------------------------=== # diff --git a/src/stamojo/special/_gamma.mojo b/src/stamojo/special/_gamma.mojo index 8bf9301..3f8ca74 100644 --- a/src/stamojo/special/_gamma.mojo +++ b/src/stamojo/special/_gamma.mojo @@ -29,7 +29,7 @@ Reference: Press et al., Numerical Recipes, 3rd ed., Section 6.2. """ -from math import lgamma, exp, log, nan, inf +from std.math import lgamma, exp, log, nan, inf # ===----------------------------------------------------------------------=== # diff --git a/src/stamojo/stats/correlation.mojo b/src/stamojo/stats/correlation.mojo index 8eaa900..e1d4744 100644 --- a/src/stamojo/stats/correlation.mojo +++ b/src/stamojo/stats/correlation.mojo @@ -14,7 +14,7 @@ The two-sided p-value tests the null hypothesis that the true correlation is zero. """ -from math import sqrt, nan +from std.math import sqrt, nan from stamojo.distributions import Normal, StudentT from stamojo.stats.descriptive import mean diff --git a/src/stamojo/stats/descriptive.mojo b/src/stamojo/stats/descriptive.mojo index c84a0c2..2cef397 100644 --- a/src/stamojo/stats/descriptive.mojo +++ b/src/stamojo/stats/descriptive.mojo @@ -19,7 +19,7 @@ Provides functions for computing summary statistics of ``List[Float64]`` data: - ``hmean`` — Harmonic mean """ -from math import sqrt, nan, log, exp +from std.math import sqrt, nan, log, exp # ===----------------------------------------------------------------------=== # diff --git a/src/stamojo/stats/tests.mojo b/src/stamojo/stats/tests.mojo index e629fa5..7a538bf 100644 --- a/src/stamojo/stats/tests.mojo +++ b/src/stamojo/stats/tests.mojo @@ -17,7 +17,7 @@ Each function returns a ``Tuple[Float64, Float64]`` of (test statistic, p-value) unless otherwise noted. """ -from math import sqrt, exp, nan, inf +from std.math import sqrt, exp, nan, inf from stamojo.distributions import Normal, StudentT, ChiSquared, FDist from stamojo.stats.descriptive import mean, variance diff --git a/tests/test_distributions.mojo b/tests/test_distributions.mojo index bbcd165..ffc7c39 100644 --- a/tests/test_distributions.mojo +++ b/tests/test_distributions.mojo @@ -12,9 +12,9 @@ Each distribution is tested for: - Comparison against scipy.stats (when available) """ -from math import exp, log, sqrt -from python import Python, PythonObject -from testing import assert_almost_equal, TestSuite +from std.math import exp, log, sqrt +from std.python import Python, PythonObject +from std.testing import assert_almost_equal, assert_true, TestSuite from stamojo.distributions import ( Normal, @@ -759,6 +759,19 @@ fn test_poisson_scipy() raises: assert_almost_equal(p.cdf(k), sp_cdf, atol=1e-10) +fn test_poisson_ppf_large_mu() raises: + """Test Poisson PPF for large mu (regression test for underflow bug).""" + var p = Poisson(1000.0) + # ppf(0.5) should be near 1000, not _MAX_K + var k = p.ppf(0.5) + assert_true( + k >= 990 and k <= 1010, "Poisson(1000).ppf(0.5) should be ~1000" + ) + # Round-trip: CDF(ppf(q)) >= q + assert_true(p.cdf(k) >= 0.5, "CDF(ppf(0.5)) must be >= 0.5") + assert_true(p.cdf(k - 1) < 0.5, "CDF(ppf(0.5)-1) must be < 0.5") + + # ===----------------------------------------------------------------------=== # # Main test runner # ===----------------------------------------------------------------------=== # diff --git a/tests/test_hypothesis.mojo b/tests/test_hypothesis.mojo index c79ae2d..1187f7a 100644 --- a/tests/test_hypothesis.mojo +++ b/tests/test_hypothesis.mojo @@ -12,9 +12,9 @@ Covers: - One-way ANOVA """ -from math import sqrt -from python import Python, PythonObject -from testing import assert_almost_equal, TestSuite +from std.math import sqrt +from std.python import Python, PythonObject +from std.testing import assert_almost_equal, TestSuite from stamojo.stats import ( ttest_1samp, diff --git a/tests/test_special.mojo b/tests/test_special.mojo index fdc10ff..8560c43 100644 --- a/tests/test_special.mojo +++ b/tests/test_special.mojo @@ -16,9 +16,9 @@ Two verification strategies are used: is printed for easy diagnosis. """ -from math import exp, log, lgamma, erf, sqrt -from python import Python, PythonObject -from testing import assert_almost_equal, TestSuite +from std.math import exp, log, lgamma, erf, sqrt +from std.python import Python, PythonObject +from std.testing import assert_almost_equal, TestSuite from stamojo.special import ( gammainc, diff --git a/tests/test_stats.mojo b/tests/test_stats.mojo index 893bfff..c65d7db 100644 --- a/tests/test_stats.mojo +++ b/tests/test_stats.mojo @@ -8,9 +8,9 @@ Covers mean, variance, std, median, quantile, skewness, and kurtosis with both analytical checks and scipy/numpy comparisons. """ -from math import sqrt, exp, log -from python import Python, PythonObject -from testing import assert_almost_equal, TestSuite +from std.math import sqrt, exp, log +from std.python import Python, PythonObject +from std.testing import assert_almost_equal, TestSuite from stamojo.stats import ( mean, From 7f196b4f492a7209be0769934f439dec71dcbfb6 Mon Sep 17 00:00:00 2001 From: ZHU Yuhao Date: Tue, 14 Apr 2026 12:32:40 +0200 Subject: [PATCH 09/11] @parameter -> Comptime if --- src/stamojo/special/_bessel.mojo | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/stamojo/special/_bessel.mojo b/src/stamojo/special/_bessel.mojo index 14587fc..3823dc2 100644 --- a/src/stamojo/special/_bessel.mojo +++ b/src/stamojo/special/_bessel.mojo @@ -136,12 +136,10 @@ fn jn[n: Int](x: Float64) -> Float64: Jₙ(x). """ - @parameter - if n == 0: + comptime if n == 0: return j0(x) - @parameter - if n == 1: + comptime if n == 1: return j1(x) comptime m = n if n >= 0 else -n From 81605a6ef20e2913ff77289091031c7590051a1c Mon Sep 17 00:00:00 2001 From: ZHU Yuhao Date: Tue, 14 Apr 2026 15:28:38 +0200 Subject: [PATCH 10/11] Make docstring compliant to convention --- pixi.toml | 2 +- src/stamojo/distributions/beta.mojo | 88 ++++++++-- src/stamojo/distributions/binomial.mojo | 32 ++-- src/stamojo/distributions/chi2.mojo | 56 +++++- src/stamojo/distributions/exponential.mojo | 30 ++-- src/stamojo/distributions/f.mojo | 58 ++++++- src/stamojo/distributions/gamma.mojo | 88 ++++++++-- src/stamojo/distributions/normal.mojo | 73 ++++++-- src/stamojo/distributions/poisson.mojo | 47 +++-- src/stamojo/distributions/t.mojo | 55 +++++- src/stamojo/distributions/traits.mojo | 192 ++++++++++++++++++--- src/stamojo/special/_beta.mojo | 8 +- src/stamojo/special/_erf.mojo | 4 +- src/stamojo/special/_gamma.mojo | 10 +- src/stamojo/stats/correlation.mojo | 8 +- src/stamojo/stats/descriptive.mojo | 24 +-- src/stamojo/stats/tests.mojo | 20 +-- tests/test_distributions.mojo | 108 ++++++------ tests/test_hypothesis.mojo | 44 ++--- tests/test_special.mojo | 41 ++--- tests/test_stats.mojo | 26 +-- 21 files changed, 744 insertions(+), 270 deletions(-) diff --git a/pixi.toml b/pixi.toml index 38e9123..b426be3 100644 --- a/pixi.toml +++ b/pixi.toml @@ -37,4 +37,4 @@ c = "clear && pixi run clean" clean = "rm -f tests/stamojo.mojopkg" # doc -doc = "clear && pixi run mojo doc -o docs/doc.json --diagnose-missing-doc-strings --validate-doc-strings src/stamojo" +doc = "pixi run mojo doc --diagnose-missing-doc-strings src/stamojo > /dev/null" diff --git a/src/stamojo/distributions/beta.mojo b/src/stamojo/distributions/beta.mojo index f17f671..6eb33ed 100644 --- a/src/stamojo/distributions/beta.mojo +++ b/src/stamojo/distributions/beta.mojo @@ -40,18 +40,35 @@ struct Beta(Copyable, Movable): """ var a: Float64 + """First shape parameter. Must be positive.""" + var b: Float64 + """Second shape parameter. Must be positive.""" # --- Density functions --------------------------------------------------- def pdf(self, x: Float64) -> Float64: - """Probability density function at *x*.""" + """Computes the probability density function at *x*. + + Args: + x: Point at which to evaluate the PDF. + + Returns: + The PDF value at *x*. + """ if x <= 0.0 or x >= 1.0: return 0.0 return exp(self.logpdf(x)) def logpdf(self, x: Float64) -> Float64: - """Natural logarithm of the probability density function at *x*.""" + """Computes the natural logarithm of the PDF at *x*. + + Args: + x: Point at which to evaluate the log-PDF. + + Returns: + The log-PDF value at *x*. + """ if x <= 0.0 or x >= 1.0: return -inf[DType.float64]() return ( @@ -63,9 +80,15 @@ struct Beta(Copyable, Movable): # --- Distribution functions ---------------------------------------------- def cdf(self, x: Float64) -> Float64: - """Cumulative distribution function P(X ≤ x). + """Computes the cumulative distribution function P(X ≤ x). CDF(x; a, b) = I_x(a, b) (regularized incomplete beta). + + Args: + x: Point at which to evaluate the CDF. + + Returns: + The CDF value at *x*. """ if x <= 0.0: return 0.0 @@ -74,7 +97,14 @@ struct Beta(Copyable, Movable): return betainc(self.a, self.b, x) def logcdf(self, x: Float64) -> Float64: - """Natural logarithm of the CDF at *x*.""" + """Computes the natural logarithm of the CDF at *x*. + + Args: + x: Point at which to evaluate the log-CDF. + + Returns: + The log-CDF value at *x*. + """ if x <= 0.0: return -inf[DType.float64]() if x >= 1.0: @@ -85,7 +115,14 @@ struct Beta(Copyable, Movable): return log(c) def sf(self, x: Float64) -> Float64: - """Survival function (1 − CDF) at *x*.""" + """Computes the survival function (1 − CDF) at *x*. + + Args: + x: Point at which to evaluate the survival function. + + Returns: + The survival function value at *x*. + """ if x <= 0.0: return 1.0 if x >= 1.0: @@ -93,7 +130,14 @@ struct Beta(Copyable, Movable): return 1.0 - self.cdf(x) def logsf(self, x: Float64) -> Float64: - """Natural logarithm of the survival function at *x*.""" + """Computes the natural logarithm of the survival function at *x*. + + Args: + x: Point at which to evaluate the log-SF. + + Returns: + The log-SF value at *x*. + """ if x <= 0.0: return 0.0 if x >= 1.0: @@ -104,7 +148,7 @@ struct Beta(Copyable, Movable): return log(s) def ppf(self, p: Float64) -> Float64: - """Percent-point function (quantile / inverse CDF). + """Computes the percent-point function (quantile / inverse CDF). Uses Newton-Raphson with bisection fallback. @@ -167,7 +211,7 @@ struct Beta(Copyable, Movable): return x def isf(self, q: Float64) -> Float64: - """Inverse survival function (inverse SF). + """Computes the inverse survival function (inverse SF). Args: q: Probability in [0, 1]. @@ -180,32 +224,50 @@ struct Beta(Copyable, Movable): # --- Summary statistics -------------------------------------------------- def median(self) -> Float64: - """Median of the distribution (approximation). + """Computes the median of the distribution (approximation). Uses the approximation: (a - 1/3) / (a + b - 2/3) for a, b >= 1. + + Returns: + The median of the distribution. """ if self.a >= 1.0 and self.b >= 1.0: return (self.a - 1.0 / 3.0) / (self.a + self.b - 2.0 / 3.0) return self.a / (self.a + self.b) def mean(self) -> Float64: - """Distribution mean = a / (a + b).""" + """Computes the distribution mean = a / (a + b). + + Returns: + The mean of the distribution. + """ return self.a / (self.a + self.b) def variance(self) -> Float64: - """Distribution variance = ab / ((a+b)²(a+b+1)).""" + """Computes the distribution variance = ab / ((a+b)²(a+b+1)). + + Returns: + The variance of the distribution. + """ var ab = self.a + self.b return self.a * self.b / (ab * ab * (ab + 1.0)) def std(self) -> Float64: - """Distribution standard deviation.""" + """Computes the distribution standard deviation. + + Returns: + The standard deviation of the distribution. + """ return sqrt(self.variance()) def entropy(self) -> Float64: - """Differential entropy of the distribution. + """Computes the differential entropy of the distribution. H = ln(B(a,b)) - (a-1)ψ(a) - (b-1)ψ(b) + (a+b-2)ψ(a+b) Using digamma approximation: ψ(x) ≈ ln(x) - 1/(2x) - 1/(12x²) + + Returns: + The differential entropy. """ var digamma_a = ( log(self.a) - 1.0 / (2.0 * self.a) - 1.0 / (12.0 * self.a * self.a) diff --git a/src/stamojo/distributions/binomial.mojo b/src/stamojo/distributions/binomial.mojo index b985608..b54ff90 100644 --- a/src/stamojo/distributions/binomial.mojo +++ b/src/stamojo/distributions/binomial.mojo @@ -43,13 +43,19 @@ struct Binomial(DiscretelyDistributed): # --- Initialization ------------------------------------------------------- fn __init__(out self, n: Int, p: Float64): + """Constructs a Binomial distribution. + + Args: + n: Number of trials (must be >= 0). + p: Probability of success in each trial (must be in [0, 1]). + """ self.n = n self.p = p # --- Probability functions ------------------------------------------------ fn pmf(self, k: Int) -> Float64: - """Probability mass function at *k*. + """Computes the probability mass function at *k*. Args: k: Number of successes (must be in [0, n]). @@ -60,7 +66,7 @@ struct Binomial(DiscretelyDistributed): return exp(self.logpmf(k)) fn logpmf(self, k: Int) -> Float64: - """Natural logarithm of the PMF at *k*. + """Computes the natural logarithm of the PMF at *k*. Args: k: Number of successes (must be in [0, n]). @@ -83,7 +89,7 @@ struct Binomial(DiscretelyDistributed): return logc + kf * log(self.p) + (nf - kf) * log1p(-self.p) fn cdf(self, k: Int) -> Float64: - """Cumulative distribution function P(X ≤ k). + """Computes the cumulative distribution function P(X ≤ k). Args: k: Number of successes (must be in [0, n]). @@ -114,7 +120,7 @@ struct Binomial(DiscretelyDistributed): return total fn logcdf(self, k: Int) -> Float64: - """Natural logarithm of the CDF at *k*. + """Computes the natural logarithm of the CDF at *k*. Args: k: Number of successes (must be in [0, n]). @@ -128,7 +134,7 @@ struct Binomial(DiscretelyDistributed): return log(c) fn sf(self, k: Int) -> Float64: - """Survival function (1 − CDF) at *k*. + """Computes the survival function (1 − CDF) at *k*. Args: k: Number of successes (must be in [0, n]). @@ -139,7 +145,7 @@ struct Binomial(DiscretelyDistributed): return 1.0 - self.cdf(k) fn logsf(self, k: Int) -> Float64: - """Natural logarithm of the survival function at *k*. + """Computes the natural logarithm of the survival function at *k*. Args: k: Number of successes (must be in [0, n]). @@ -150,7 +156,7 @@ struct Binomial(DiscretelyDistributed): return log1p(-self.cdf(k)) fn ppf(self, q: Float64) -> Int: - """Percent point function (inverse CDF). + """Computes the percent point function (inverse CDF). Args: q: Probability in [0, 1]. @@ -172,7 +178,7 @@ struct Binomial(DiscretelyDistributed): return self.n fn isf(self, q: Float64) -> Int: - """Inverse survival function (inverse SF). + """Computes the inverse survival function (inverse SF). Args: q: Probability in [0, 1]. @@ -195,7 +201,7 @@ struct Binomial(DiscretelyDistributed): # --- Summary statistics -------------------------------------------------- fn median(self) -> UInt: - """Median of the distribution: floor(n * p + 0.5). + """Computes the median of the distribution: floor(n * p + 0.5). Returns: The median of the distribution. @@ -203,7 +209,7 @@ struct Binomial(DiscretelyDistributed): return UInt(floor(Float64(self.n) * self.p + 0.5)) fn mean(self) -> Float64: - """Distribution mean: n * p. + """Computes the distribution mean: n * p. Returns: The mean of the distribution. @@ -211,7 +217,7 @@ struct Binomial(DiscretelyDistributed): return Float64(self.n) * self.p fn variance(self) -> Float64: - """Distribution variance: n * p * (1 - p). + """Computes the distribution variance: n * p * (1 - p). Returns: The variance of the distribution. @@ -220,7 +226,7 @@ struct Binomial(DiscretelyDistributed): return np * (1.0 - self.p) fn std(self) -> Float64: - """Distribution standard deviation: sqrt(n * p * (1 - p)). + """Computes the distribution standard deviation: sqrt(n * p * (1 - p)). Returns: The standard deviation of the distribution. @@ -234,7 +240,7 @@ struct Binomial(DiscretelyDistributed): fn _log_binomial_coefficient(n: Int, k: Int) -> Float64: - """Log of the binomial coefficient C(n, k). + """Computes the log of the binomial coefficient C(n, k). Args: n: Number of trials. diff --git a/src/stamojo/distributions/chi2.mojo b/src/stamojo/distributions/chi2.mojo index ad25de1..599f092 100644 --- a/src/stamojo/distributions/chi2.mojo +++ b/src/stamojo/distributions/chi2.mojo @@ -40,11 +40,19 @@ struct ChiSquared(Copyable, Movable): """ var df: Float64 + """Degrees of freedom. Must be positive.""" # --- Density functions --------------------------------------------------- fn pdf(self, x: Float64) -> Float64: - """Probability density function at *x*.""" + """Computes the probability density function at *x*. + + Args: + x: Point at which to evaluate the PDF. + + Returns: + The PDF value at *x*. + """ if x < 0.0: return 0.0 if x == 0.0: @@ -57,7 +65,14 @@ struct ChiSquared(Copyable, Movable): return exp(self.logpdf(x)) fn logpdf(self, x: Float64) -> Float64: - """Natural logarithm of the probability density function at *x*.""" + """Computes the natural logarithm of the PDF at *x*. + + Args: + x: Point at which to evaluate the log-PDF. + + Returns: + The log-PDF value at *x*. + """ if x <= 0.0: return -inf[DType.float64]() var k = self.df @@ -71,22 +86,35 @@ struct ChiSquared(Copyable, Movable): # --- Distribution functions ---------------------------------------------- fn cdf(self, x: Float64) -> Float64: - """Cumulative distribution function P(X ≤ x). + """Computes the cumulative distribution function P(X ≤ x). CDF(x; k) = P(k/2, x/2) (regularized lower incomplete gamma). + + Args: + x: Point at which to evaluate the CDF. + + Returns: + The CDF value at *x*. """ if x <= 0.0: return 0.0 return gammainc(self.df / 2.0, x / 2.0) fn sf(self, x: Float64) -> Float64: - """Survival function (1 − CDF) at *x*.""" + """Computes the survival function (1 − CDF) at *x*. + + Args: + x: Point at which to evaluate the survival function. + + Returns: + The survival function value at *x*. + """ if x <= 0.0: return 1.0 return gammaincc(self.df / 2.0, x / 2.0) fn ppf(self, p: Float64) -> Float64: - """Percent-point function (quantile / inverse CDF). + """Computes the percent-point function (quantile / inverse CDF). Uses the Wilson-Hilferty initial approximation refined by Newton-Raphson with bisection fallback. @@ -153,13 +181,25 @@ struct ChiSquared(Copyable, Movable): # --- Summary statistics -------------------------------------------------- fn mean(self) -> Float64: - """Distribution mean = k.""" + """Computes the distribution mean = k. + + Returns: + The mean of the distribution. + """ return self.df fn variance(self) -> Float64: - """Distribution variance = 2k.""" + """Computes the distribution variance = 2k. + + Returns: + The variance of the distribution. + """ return 2.0 * self.df fn std(self) -> Float64: - """Distribution standard deviation = √(2k).""" + """Computes the distribution standard deviation = √(2k). + + Returns: + The standard deviation of the distribution. + """ return sqrt(2.0 * self.df) diff --git a/src/stamojo/distributions/exponential.mojo b/src/stamojo/distributions/exponential.mojo index 2a02f2c..3eaecdd 100644 --- a/src/stamojo/distributions/exponential.mojo +++ b/src/stamojo/distributions/exponential.mojo @@ -51,13 +51,19 @@ struct Exponential(ContinuouslyDistributed): # --- Initialization ------------------------------------------------------- fn __init__(out self, loc: Float64 = 0.0, scale: Float64 = 1.0): + """Constructs an Exponential distribution. + + Args: + loc: Location (shift) parameter. Defaults to 0.0. + scale: Scale parameter (must be > 0). Defaults to 1.0. + """ self.loc = loc self.scale = scale # --- Density functions --------------------------------------------------- fn pdf(self, x: Float64) -> Float64: - """Probability density function at *x*. + """Computes the probability density function at *x*. Args: x: Point at which to evaluate the PDF. @@ -71,7 +77,7 @@ struct Exponential(ContinuouslyDistributed): return exp(-y) / self.scale fn logpdf(self, x: Float64) -> Float64: - """Natural logarithm of the PDF at *x*. + """Computes the natural logarithm of the PDF at *x*. Args: x: Point at which to evaluate the log-PDF. @@ -86,7 +92,7 @@ struct Exponential(ContinuouslyDistributed): # --- Distribution functions ---------------------------------------------- fn cdf(self, x: Float64) -> Float64: - """Cumulative distribution function P(X ≤ x). + """Computes the cumulative distribution function P(X ≤ x). Args: x: Value at which to evaluate the CDF. @@ -100,7 +106,7 @@ struct Exponential(ContinuouslyDistributed): return -expm1(-y) fn logcdf(self, x: Float64) -> Float64: - """Natural logarithm of the CDF at *x*. + """Computes the natural logarithm of the CDF at *x*. Uses ``log(-expm1(-y))`` instead of ``log1p(-exp(-y))`` for better numerical stability when *x* is close to *loc*. @@ -117,7 +123,7 @@ struct Exponential(ContinuouslyDistributed): return log(-expm1(-y)) fn sf(self, x: Float64) -> Float64: - """Survival function (1 − CDF) at *x*. + """Computes the survival function (1 − CDF) at *x*. Args: x: Value at which to evaluate the survival function. @@ -131,7 +137,7 @@ struct Exponential(ContinuouslyDistributed): return exp(-y) fn logsf(self, x: Float64) -> Float64: - """Natural logarithm of the survival function at *x*. + """Computes the natural logarithm of the survival function at *x*. Args: x: Value at which to evaluate the log-SF. @@ -145,7 +151,7 @@ struct Exponential(ContinuouslyDistributed): return -y fn ppf(self, q: Float64) -> Float64: - """Percent-point (quantile) function (inverse CDF). + """Computes the percent-point (quantile) function (inverse CDF). Args: q: Probability in [0, 1]. @@ -168,7 +174,7 @@ struct Exponential(ContinuouslyDistributed): return self.loc - self.scale * log1p(-q) fn isf(self, q: Float64) -> Float64: - """Inverse survival function (inverse SF). + """Computes the inverse survival function (inverse SF). Args: q: Probability in [0, 1]. @@ -192,7 +198,7 @@ struct Exponential(ContinuouslyDistributed): # --- Summary statistics -------------------------------------------------- fn median(self) -> Float64: - """Median of the distribution: loc + scale * ln(2). + """Computes the median of the distribution: loc + scale * ln(2). Returns: The median of the distribution. @@ -200,7 +206,7 @@ struct Exponential(ContinuouslyDistributed): return self.loc + self.scale * log(2.0) fn mean(self) -> Float64: - """Distribution mean: loc + scale. + """Computes the distribution mean: loc + scale. Returns: The mean of the distribution. @@ -208,7 +214,7 @@ struct Exponential(ContinuouslyDistributed): return self.loc + self.scale fn variance(self) -> Float64: - """Distribution variance: scale². + """Computes the distribution variance: scale². Returns: The variance of the distribution. @@ -216,7 +222,7 @@ struct Exponential(ContinuouslyDistributed): return self.scale * self.scale fn std(self) -> Float64: - """Distribution standard deviation: scale. + """Computes the distribution standard deviation: scale. Returns: The standard deviation of the distribution. diff --git a/src/stamojo/distributions/f.mojo b/src/stamojo/distributions/f.mojo index b32ac9e..8d879e3 100644 --- a/src/stamojo/distributions/f.mojo +++ b/src/stamojo/distributions/f.mojo @@ -42,12 +42,22 @@ struct FDist(Copyable, Movable): """ var dfn: Float64 + """Numerator degrees of freedom (d₁). Must be positive.""" + var dfd: Float64 + """Denominator degrees of freedom (d₂). Must be positive.""" # --- Density functions --------------------------------------------------- fn pdf(self, x: Float64) -> Float64: - """Probability density function at *x*.""" + """Computes the probability density function at *x*. + + Args: + x: Point at which to evaluate the PDF. + + Returns: + The PDF value at *x*. + """ if x < 0.0: return 0.0 if x == 0.0: @@ -60,7 +70,14 @@ struct FDist(Copyable, Movable): return exp(self.logpdf(x)) fn logpdf(self, x: Float64) -> Float64: - """Natural logarithm of the probability density function at *x*.""" + """Computes the natural logarithm of the PDF at *x*. + + Args: + x: Point at which to evaluate the log-PDF. + + Returns: + The log-PDF value at *x*. + """ if x <= 0.0: return -inf[DType.float64]() var d1 = self.dfn @@ -75,9 +92,15 @@ struct FDist(Copyable, Movable): # --- Distribution functions ---------------------------------------------- fn cdf(self, x: Float64) -> Float64: - """Cumulative distribution function P(X ≤ x). + """Computes the cumulative distribution function P(X ≤ x). CDF(x) = I_{d₁x/(d₁x+d₂)}(d₁/2, d₂/2). + + Args: + x: Point at which to evaluate the CDF. + + Returns: + The CDF value at *x*. """ if x <= 0.0: return 0.0 @@ -87,11 +110,18 @@ struct FDist(Copyable, Movable): return betainc(d1 / 2.0, d2 / 2.0, u) fn sf(self, x: Float64) -> Float64: - """Survival function (1 − CDF) at *x*.""" + """Computes the survival function (1 − CDF) at *x*. + + Args: + x: Point at which to evaluate the survival function. + + Returns: + The survival function value at *x*. + """ return 1.0 - self.cdf(x) fn ppf(self, p: Float64) -> Float64: - """Percent-point function (quantile / inverse CDF). + """Computes the percent-point function (quantile / inverse CDF). Computed via Newton-Raphson with bisection fallback. @@ -149,13 +179,21 @@ struct FDist(Copyable, Movable): # --- Summary statistics -------------------------------------------------- fn mean(self) -> Float64: - """Distribution mean. Defined for d₂ > 2.""" + """Computes the distribution mean. Defined for d₂ > 2. + + Returns: + The mean of the distribution. + """ if self.dfd > 2.0: return self.dfd / (self.dfd - 2.0) return nan[DType.float64]() fn variance(self) -> Float64: - """Distribution variance. Defined for d₂ > 4.""" + """Computes the distribution variance. Defined for d₂ > 4. + + Returns: + The variance of the distribution. + """ if self.dfd > 4.0: var d1 = self.dfn var d2 = self.dfd @@ -169,5 +207,9 @@ struct FDist(Copyable, Movable): return nan[DType.float64]() fn std(self) -> Float64: - """Distribution standard deviation.""" + """Computes the distribution standard deviation. + + Returns: + The standard deviation of the distribution. + """ return sqrt(self.variance()) diff --git a/src/stamojo/distributions/gamma.mojo b/src/stamojo/distributions/gamma.mojo index a1e8b4a..7a50aee 100644 --- a/src/stamojo/distributions/gamma.mojo +++ b/src/stamojo/distributions/gamma.mojo @@ -40,18 +40,35 @@ struct Gamma(Copyable, Movable): """ var a: Float64 + """Shape parameter. Must be positive.""" + var scale: Float64 + """Scale parameter (θ). Must be positive.""" # --- Density functions --------------------------------------------------- def pdf(self, x: Float64) -> Float64: - """Probability density function at *x*.""" + """Computes the probability density function at *x*. + + Args: + x: Point at which to evaluate the PDF. + + Returns: + The PDF value at *x*. + """ if x <= 0.0: return 0.0 return exp(self.logpdf(x)) def logpdf(self, x: Float64) -> Float64: - """Natural logarithm of the probability density function at *x*.""" + """Computes the natural logarithm of the PDF at *x*. + + Args: + x: Point at which to evaluate the log-PDF. + + Returns: + The log-PDF value at *x*. + """ if x <= 0.0: return -inf[DType.float64]() return ( @@ -64,16 +81,29 @@ struct Gamma(Copyable, Movable): # --- Distribution functions ---------------------------------------------- def cdf(self, x: Float64) -> Float64: - """Cumulative distribution function P(X ≤ x). + """Computes the cumulative distribution function P(X ≤ x). CDF(x; a, θ) = P(a, x/θ) (regularized lower incomplete gamma). + + Args: + x: Point at which to evaluate the CDF. + + Returns: + The CDF value at *x*. """ if x <= 0.0: return 0.0 return gammainc(self.a, x / self.scale) def logcdf(self, x: Float64) -> Float64: - """Natural logarithm of the CDF at *x*.""" + """Computes the natural logarithm of the CDF at *x*. + + Args: + x: Point at which to evaluate the log-CDF. + + Returns: + The log-CDF value at *x*. + """ if x <= 0.0: return -inf[DType.float64]() var c = self.cdf(x) @@ -82,13 +112,27 @@ struct Gamma(Copyable, Movable): return log(c) def sf(self, x: Float64) -> Float64: - """Survival function (1 − CDF) at *x*.""" + """Computes the survival function (1 − CDF) at *x*. + + Args: + x: Point at which to evaluate the survival function. + + Returns: + The survival function value at *x*. + """ if x <= 0.0: return 1.0 return gammaincc(self.a, x / self.scale) def logsf(self, x: Float64) -> Float64: - """Natural logarithm of the survival function at *x*.""" + """Computes the natural logarithm of the survival function at *x*. + + Args: + x: Point at which to evaluate the log-SF. + + Returns: + The log-SF value at *x*. + """ if x <= 0.0: return 0.0 var s = self.sf(x) @@ -97,7 +141,7 @@ struct Gamma(Copyable, Movable): return log(s) def ppf(self, p: Float64) -> Float64: - """Percent-point function (quantile / inverse CDF). + """Computes the percent-point function (quantile / inverse CDF). Uses Newton-Raphson with bisection fallback. @@ -162,7 +206,7 @@ struct Gamma(Copyable, Movable): return x def isf(self, q: Float64) -> Float64: - """Inverse survival function (inverse SF). + """Computes the inverse survival function (inverse SF). Args: q: Probability in [0, 1]. @@ -175,10 +219,13 @@ struct Gamma(Copyable, Movable): # --- Summary statistics -------------------------------------------------- def median(self) -> Float64: - """Median of the distribution (approximation). + """Computes the median of the distribution (approximation). Uses the approximation: scale * a * (1 - 1/(9a))^3 for a >= 1, and scale * a * 2^(-1/a) for a < 1. + + Returns: + The median of the distribution. """ if self.a >= 1.0: return self.scale * self.a * pow(1.0 - 1.0 / (9.0 * self.a), 3) @@ -186,24 +233,39 @@ struct Gamma(Copyable, Movable): return self.scale * self.a * pow(2.0, -1.0 / self.a) def mean(self) -> Float64: - """Distribution mean = a * θ.""" + """Computes the distribution mean = a * θ. + + Returns: + The mean of the distribution. + """ return self.a * self.scale def variance(self) -> Float64: - """Distribution variance = a * θ².""" + """Computes the distribution variance = a * θ². + + Returns: + The variance of the distribution. + """ return self.a * self.scale * self.scale def std(self) -> Float64: - """Distribution standard deviation = √(a) * θ.""" + """Computes the distribution standard deviation = √(a) * θ. + + Returns: + The standard deviation of the distribution. + """ return sqrt(self.a) * self.scale def entropy(self) -> Float64: - """Differential entropy of the distribution. + """Computes the differential entropy of the distribution. H = a + ln(θ) + ln(Γ(a)) + (1 - a) * ψ(a) where ψ is the digamma function (approximated here). For simplicity: H ≈ a + ln(θ) + ln(Γ(a)) - (a-1)*ψ(a) Using approximation ψ(a) ≈ ln(a) - 1/(2a) for large a. + + Returns: + The differential entropy. """ # H = a + ln(scale) + ln(Gamma(a)) + (1-a)*digamma(a) # Approximate digamma(a) ≈ ln(a) - 1/(2a) - 1/(12a²) diff --git a/src/stamojo/distributions/normal.mojo b/src/stamojo/distributions/normal.mojo index 03d5546..c2e4974 100644 --- a/src/stamojo/distributions/normal.mojo +++ b/src/stamojo/distributions/normal.mojo @@ -54,32 +54,63 @@ struct Normal(Copyable, Movable): """ var mu: Float64 + """Mean (location parameter).""" + var sigma: Float64 + """Standard deviation (scale parameter). Must be positive.""" # --- Density functions --------------------------------------------------- fn pdf(self, x: Float64) -> Float64: - """Probability density function at *x*.""" + """Computes the probability density function at *x*. + + Args: + x: Point at which to evaluate the PDF. + + Returns: + The PDF value at *x*. + """ var z = (x - self.mu) / self.sigma return _INV_SQRT_2PI / self.sigma * exp(-0.5 * z * z) fn logpdf(self, x: Float64) -> Float64: - """Natural logarithm of the probability density function at *x*.""" + """Computes the natural logarithm of the PDF at *x*. + + Args: + x: Point at which to evaluate the log-PDF. + + Returns: + The log-PDF value at *x*. + """ var z = (x - self.mu) / self.sigma return -_LN_SQRT_2PI - log(self.sigma) - 0.5 * z * z # --- Distribution functions ---------------------------------------------- fn cdf(self, x: Float64) -> Float64: - """Cumulative distribution function P(X ≤ x).""" + """Computes the cumulative distribution function P(X ≤ x). + + Args: + x: Point at which to evaluate the CDF. + + Returns: + The CDF value at *x*. + """ return 0.5 * erfc(-(x - self.mu) / (self.sigma * _SQRT2)) fn sf(self, x: Float64) -> Float64: - """Survival function (1 − CDF) at *x*.""" + """Computes the survival function (1 − CDF) at *x*. + + Args: + x: Point at which to evaluate the survival function. + + Returns: + The survival function value at *x*. + """ return 0.5 * erfc((x - self.mu) / (self.sigma * _SQRT2)) fn ppf(self, p: Float64) -> Float64: - """Percent-point function (quantile / inverse CDF). + """Computes the percent-point function (quantile / inverse CDF). Returns the value *x* such that P(X ≤ x) = p. @@ -100,26 +131,46 @@ struct Normal(Copyable, Movable): # --- Summary statistics -------------------------------------------------- fn mean(self) -> Float64: - """Distribution mean.""" + """Computes the distribution mean. + + Returns: + The mean of the distribution. + """ return self.mu fn variance(self) -> Float64: - """Distribution variance σ².""" + """Computes the distribution variance σ². + + Returns: + The variance of the distribution. + """ return self.sigma * self.sigma fn std(self) -> Float64: - """Distribution standard deviation σ.""" + """Computes the distribution standard deviation σ. + + Returns: + The standard deviation of the distribution. + """ return self.sigma fn entropy(self) -> Float64: - """Differential entropy of the distribution.""" + """Computes the differential entropy of the distribution. + + Returns: + The differential entropy. + """ # H = 0.5 * ln(2πeσ²) = ln(σ√(2πe)) = ln(σ) + 0.5*ln(2π) + 0.5 return _LN_SQRT_2PI + log(self.sigma) + 0.5 # --- Random variate generation ------------------------------------------- fn rvs(self) -> Float64: - """Generate a single random variate (Box-Muller transform).""" + """Generates a single random variate (Box-Muller transform). + + Returns: + A random variate from this distribution. + """ var u1 = random_float64() while u1 == 0.0: u1 = random_float64() @@ -128,7 +179,7 @@ struct Normal(Copyable, Movable): return self.mu + self.sigma * z fn rvs(self, n: Int) -> List[Float64]: - """Generate *n* random variates. + """Generates *n* random variates. Args: n: Number of variates to generate. diff --git a/src/stamojo/distributions/poisson.mojo b/src/stamojo/distributions/poisson.mojo index 0b2a82c..efe3e9b 100644 --- a/src/stamojo/distributions/poisson.mojo +++ b/src/stamojo/distributions/poisson.mojo @@ -48,14 +48,20 @@ struct Poisson(DiscretelyDistributed): """ var mu: Float64 + """Rate parameter (mean number of events). Must be positive.""" def __init__(out self, mu: Float64): + """Constructs a Poisson distribution with the given rate. + + Args: + mu: Rate parameter (mean number of events). Must be positive. + """ self.mu = mu # --- Probability functions ------------------------------------------------ def pmf(self, k: Int) -> Float64: - """Probability mass function at *k*. + """Computes the probability mass function at *k*. Args: k: Number of events (must be >= 0). @@ -66,7 +72,7 @@ struct Poisson(DiscretelyDistributed): return exp(self.logpmf(k)) def logpmf(self, k: Int) -> Float64: - """Natural logarithm of the PMF at *k*. + """Computes the natural logarithm of the PMF at *k*. Args: k: Number of events (must be >= 0). @@ -81,7 +87,7 @@ struct Poisson(DiscretelyDistributed): return Float64(k) * log(self.mu) - self.mu - lgamma(Float64(k) + 1.0) def cdf(self, k: Int) -> Float64: - """Cumulative distribution function P(X ≤ k). + """Computes the cumulative distribution function P(X ≤ k). Args: k: Number of events. @@ -97,7 +103,7 @@ struct Poisson(DiscretelyDistributed): return gammaincc(Float64(k + 1), self.mu) def logcdf(self, k: Int) -> Float64: - """Natural logarithm of the CDF at *k*. + """Computes the natural logarithm of the CDF at *k*. Args: k: Number of events. @@ -111,7 +117,7 @@ struct Poisson(DiscretelyDistributed): return log(c) def sf(self, k: Int) -> Float64: - """Survival function (1 − CDF) at *k*. + """Computes the survival function (1 − CDF) at *k*. Args: k: Number of events. @@ -126,7 +132,7 @@ struct Poisson(DiscretelyDistributed): return 1.0 - self.cdf(k) def logsf(self, k: Int) -> Float64: - """Natural logarithm of the survival function at *k*. + """Computes the natural logarithm of the survival function at *k*. Args: k: Number of events. @@ -150,7 +156,7 @@ struct Poisson(DiscretelyDistributed): q: Probability in [0, 1]. Returns: - Smallest integer k such that CDF(k) ≥ q. + The smallest integer k such that CDF(k) ≥ q. """ if q <= 0.0: return 0 @@ -178,35 +184,50 @@ struct Poisson(DiscretelyDistributed): return lo def isf(self, q: Float64) -> Int: - """Inverse survival function (inverse SF). + """Computes the inverse survival function (inverse SF). Args: q: Probability in [0, 1]. Returns: - Smallest integer k such that SF(k) ≤ q. + The smallest integer k such that SF(k) ≤ q. """ return self.ppf(1.0 - q) # --- Summary statistics -------------------------------------------------- def median(self) -> UInt: - """Median of the distribution (approximation). + """Computes the median of the distribution (approximation). Uses the approximation: floor(μ + 1/3 - 0.02/μ). + + Returns: + The median of the distribution. """ if self.mu == 0.0: return 0 return UInt(floor(self.mu + 1.0 / 3.0 - 0.02 / self.mu)) def mean(self) -> Float64: - """Distribution mean = μ.""" + """Computes the distribution mean = μ. + + Returns: + The mean of the distribution. + """ return self.mu def variance(self) -> Float64: - """Distribution variance = μ.""" + """Computes the distribution variance = μ. + + Returns: + The variance of the distribution. + """ return self.mu def std(self) -> Float64: - """Distribution standard deviation = √μ.""" + """Computes the distribution standard deviation = √μ. + + Returns: + The standard deviation of the distribution. + """ return sqrt(self.mu) diff --git a/src/stamojo/distributions/t.mojo b/src/stamojo/distributions/t.mojo index 46d83c8..a2ff94e 100644 --- a/src/stamojo/distributions/t.mojo +++ b/src/stamojo/distributions/t.mojo @@ -40,15 +40,30 @@ struct StudentT(Copyable, Movable): """ var df: Float64 + """Degrees of freedom. Must be positive.""" # --- Density functions --------------------------------------------------- fn pdf(self, x: Float64) -> Float64: - """Probability density function at *x*.""" + """Computes the probability density function at *x*. + + Args: + x: Point at which to evaluate the PDF. + + Returns: + The PDF value at *x*. + """ return exp(self.logpdf(x)) fn logpdf(self, x: Float64) -> Float64: - """Natural logarithm of the probability density function at *x*.""" + """Computes the natural logarithm of the PDF at *x*. + + Args: + x: Point at which to evaluate the log-PDF. + + Returns: + The log-PDF value at *x*. + """ var v = self.df return ( lgamma((v + 1.0) / 2.0) @@ -61,12 +76,18 @@ struct StudentT(Copyable, Movable): # --- Distribution functions ---------------------------------------------- fn cdf(self, x: Float64) -> Float64: - """Cumulative distribution function P(X ≤ x). + """Computes the cumulative distribution function P(X ≤ x). Uses the regularized incomplete beta function: CDF(t) = 1 − 0.5·I_u(ν/2, 1/2) for t ≥ 0 CDF(t) = 0.5·I_u(ν/2, 1/2) for t < 0 where u = ν / (ν + t²). + + Args: + x: Point at which to evaluate the CDF. + + Returns: + The CDF value at *x*. """ var v = self.df var u = v / (v + x * x) @@ -77,7 +98,14 @@ struct StudentT(Copyable, Movable): return 0.5 * ib fn sf(self, x: Float64) -> Float64: - """Survival function (1 − CDF) at *x*.""" + """Computes the survival function (1 − CDF) at *x*. + + Args: + x: Point at which to evaluate the survival function. + + Returns: + The survival function value at *x*. + """ var v = self.df var u = v / (v + x * x) var ib = betainc(v / 2.0, 0.5, u) @@ -87,7 +115,7 @@ struct StudentT(Copyable, Movable): return 1.0 - 0.5 * ib fn ppf(self, p: Float64) -> Float64: - """Percent-point function (quantile / inverse CDF). + """Computes the percent-point function (quantile / inverse CDF). Computed via Newton-Raphson with bisection fallback. @@ -141,13 +169,20 @@ struct StudentT(Copyable, Movable): # --- Summary statistics -------------------------------------------------- fn mean(self) -> Float64: - """Distribution mean. Defined for df > 1.""" + """Computes the distribution mean. Defined for df > 1. + + Returns: + The mean of the distribution. + """ if self.df > 1.0: return 0.0 return nan[DType.float64]() fn variance(self) -> Float64: - """Distribution variance. Defined for df > 2; infinite for 1 < df ≤ 2. + """Computes the distribution variance. Defined for df > 2; infinite for 1 < df ≤ 2. + + Returns: + The variance of the distribution. """ if self.df > 2.0: return self.df / (self.df - 2.0) @@ -156,5 +191,9 @@ struct StudentT(Copyable, Movable): return nan[DType.float64]() fn std(self) -> Float64: - """Distribution standard deviation.""" + """Computes the distribution standard deviation. + + Returns: + The standard deviation of the distribution. + """ return sqrt(self.variance()) diff --git a/src/stamojo/distributions/traits.mojo b/src/stamojo/distributions/traits.mojo index 892281f..54b3b34 100644 --- a/src/stamojo/distributions/traits.mojo +++ b/src/stamojo/distributions/traits.mojo @@ -11,55 +11,127 @@ trait ContinuouslyDistributed(Copyable, Movable): # --- Density functions --------------------------------------------------- fn pdf(self, x: Float64) -> Float64: - """Probability density function at *x*.""" + """Computes the probability density function at *x*. + + Args: + x: Point at which to evaluate the PDF. + + Returns: + The PDF value at *x*. + """ ... fn logpdf(self, x: Float64) -> Float64: - """Natural logarithm of the probability density function at *x*.""" + """Computes the natural logarithm of the PDF at *x*. + + Args: + x: Point at which to evaluate the log-PDF. + + Returns: + The log-PDF value at *x*. + """ ... # --- Distribution functions ---------------------------------------------- fn cdf(self, x: Float64) -> Float64: - """Cumulative distribution function P(X ≤ x).""" + """Computes the cumulative distribution function P(X ≤ x). + + Args: + x: Point at which to evaluate the CDF. + + Returns: + The CDF value at *x*. + """ ... fn logcdf(self, x: Float64) -> Float64: - """Natural logarithm of the cumulative distribution function at *x*.""" + """Computes the natural logarithm of the CDF at *x*. + + Args: + x: Point at which to evaluate the log-CDF. + + Returns: + The log-CDF value at *x*. + """ ... fn sf(self, x: Float64) -> Float64: - """Survival function (1 − CDF) at *x*.""" + """Computes the survival function (1 − CDF) at *x*. + + Args: + x: Point at which to evaluate the survival function. + + Returns: + The survival function value at *x*. + """ ... fn logsf(self, x: Float64) -> Float64: - """Natural logarithm of the survival function at *x*.""" + """Computes the natural logarithm of the survival function at *x*. + + Args: + x: Point at which to evaluate the log-SF. + + Returns: + The log-SF value at *x*. + """ ... fn ppf(self, q: Float64) -> Float64: - """Percent point function (inverse of CDF) at *q*.""" + """Computes the percent point function (inverse of CDF) at *q*. + + Args: + q: Probability in [0, 1]. + + Returns: + The quantile corresponding to *q*. + """ ... fn isf(self, q: Float64) -> Float64: - """Inverse survival function (inverse of SF) at *q*.""" + """Computes the inverse survival function (inverse of SF) at *q*. + + Args: + q: Probability in [0, 1]. + + Returns: + The value *x* such that SF(x) = *q*. + """ ... # --- Statistical properties ---------------------------------------------- fn median(self) -> Float64: - """Median of the distribution.""" + """Computes the median of the distribution. + + Returns: + The median value. + """ ... fn mean(self) -> Float64: - """Mean of the distribution.""" + """Computes the mean of the distribution. + + Returns: + The mean value. + """ ... fn variance(self) -> Float64: - """Variance of the distribution.""" + """Computes the variance of the distribution. + + Returns: + The variance value. + """ ... fn std(self) -> Float64: - """Standard deviation of the distribution.""" + """Computes the standard deviation of the distribution. + + Returns: + The standard deviation value. + """ ... @@ -69,53 +141,125 @@ trait DiscretelyDistributed(Copyable, Movable): # --- Probability mass functions ------------------------------------------ fn pmf(self, k: Int) -> Float64: - """Probability mass function at *k*.""" + """Computes the probability mass function at *k*. + + Args: + k: Point at which to evaluate the PMF. + + Returns: + The PMF value at *k*. + """ ... fn logpmf(self, k: Int) -> Float64: - """Natural logarithm of the probability mass function at *k*.""" + """Computes the natural logarithm of the PMF at *k*. + + Args: + k: Point at which to evaluate the log-PMF. + + Returns: + The log-PMF value at *k*. + """ ... # --- Distribution functions ---------------------------------------------- fn cdf(self, k: Int) -> Float64: - """Cumulative distribution function P(X ≤ k).""" + """Computes the cumulative distribution function P(X ≤ k). + + Args: + k: Point at which to evaluate the CDF. + + Returns: + The CDF value at *k*. + """ ... fn logcdf(self, k: Int) -> Float64: - """Natural logarithm of the cumulative distribution function at *k*.""" + """Computes the natural logarithm of the CDF at *k*. + + Args: + k: Point at which to evaluate the log-CDF. + + Returns: + The log-CDF value at *k*. + """ ... fn sf(self, k: Int) -> Float64: - """Survival function (1 − CDF) at *k*.""" + """Computes the survival function (1 − CDF) at *k*. + + Args: + k: Point at which to evaluate the survival function. + + Returns: + The survival function value at *k*. + """ ... fn logsf(self, k: Int) -> Float64: - """Natural logarithm of the survival function at *k*.""" + """Computes the natural logarithm of the survival function at *k*. + + Args: + k: Point at which to evaluate the log-SF. + + Returns: + The log-SF value at *k*. + """ ... fn ppf(self, q: Float64) -> Int: - """Percent point function (inverse of CDF) at *q*.""" + """Computes the percent point function (inverse of CDF) at *q*. + + Args: + q: Probability in [0, 1]. + + Returns: + The smallest integer k such that CDF(k) ≥ q. + """ ... fn isf(self, q: Float64) -> Int: - """Inverse survival function (inverse of SF) at *q*.""" + """Computes the inverse survival function (inverse of SF) at *q*. + + Args: + q: Probability in [0, 1]. + + Returns: + The smallest integer k such that SF(k) ≤ q. + """ ... # --- Statistical properties ---------------------------------------------- fn median(self) -> UInt: - """Median of the distribution.""" + """Computes the median of the distribution. + + Returns: + The median value. + """ ... fn mean(self) -> Float64: - """Mean of the distribution.""" + """Computes the mean of the distribution. + + Returns: + The mean value. + """ ... fn variance(self) -> Float64: - """Variance of the distribution.""" + """Computes the variance of the distribution. + + Returns: + The variance value. + """ ... fn std(self) -> Float64: - """Standard deviation of the distribution.""" + """Computes the standard deviation of the distribution. + + Returns: + The standard deviation value. + """ ... diff --git a/src/stamojo/special/_beta.mojo b/src/stamojo/special/_beta.mojo index c61d4cd..fb6094b 100644 --- a/src/stamojo/special/_beta.mojo +++ b/src/stamojo/special/_beta.mojo @@ -40,7 +40,7 @@ comptime _FPMIN = 1.0e-30 fn lbeta(a: Float64, b: Float64) -> Float64: - """Natural logarithm of the beta function. + """Computes the natural logarithm of the beta function. Computes ln(B(a, b)) = ln(Γ(a)) + ln(Γ(b)) - ln(Γ(a+b)). @@ -55,7 +55,7 @@ fn lbeta(a: Float64, b: Float64) -> Float64: fn beta(a: Float64, b: Float64) -> Float64: - """Beta function B(a, b) = Γ(a)Γ(b) / Γ(a+b). + """Computes the beta function B(a, b) = Γ(a)Γ(b) / Γ(a+b). Args: a: First parameter. Must be positive. @@ -68,7 +68,7 @@ fn beta(a: Float64, b: Float64) -> Float64: fn betainc(a: Float64, b: Float64, x: Float64) -> Float64: - """Regularized incomplete beta function I_x(a, b). + """Computes the regularized incomplete beta function I_x(a, b). Computes I_x(a, b) = B(x; a, b) / B(a, b), where B(x; a, b) is the incomplete beta function. @@ -110,7 +110,7 @@ fn betainc(a: Float64, b: Float64, x: Float64) -> Float64: fn _betainc_cf( a: Float64, b: Float64, x: Float64, lbeta_ab: Float64 ) -> Float64: - """Evaluate the regularized incomplete beta function using Lentz's + """Evaluates the regularized incomplete beta function using Lentz's continued fraction method. Computes: diff --git a/src/stamojo/special/_erf.mojo b/src/stamojo/special/_erf.mojo index 1706185..9947b5a 100644 --- a/src/stamojo/special/_erf.mojo +++ b/src/stamojo/special/_erf.mojo @@ -65,7 +65,7 @@ comptime _D4 = 3.754408661907416e0 fn ndtri(p: Float64) -> Float64: - """Inverse of the standard normal CDF (quantile / PPF). + """Computes the inverse of the standard normal CDF (quantile / PPF). Computes x such that Φ(x) = p, where Φ is the CDF of N(0,1). @@ -121,7 +121,7 @@ fn ndtri(p: Float64) -> Float64: fn erfinv(p: Float64) -> Float64: - """Inverse error function. + """Computes the inverse error function. Computes the value x such that erf(x) = p. diff --git a/src/stamojo/special/_gamma.mojo b/src/stamojo/special/_gamma.mojo index 3f8ca74..52cad49 100644 --- a/src/stamojo/special/_gamma.mojo +++ b/src/stamojo/special/_gamma.mojo @@ -48,7 +48,7 @@ comptime _FPMIN = 1.0e-30 # Near smallest representable floating-point number. fn _is_near_integer(a: Float64) -> Bool: - """Return True if `a` is within 1e-12 of a positive integer. + """Returns True if `a` is within 1e-12 of a positive integer. When a is (close to) an integer, the continued-fraction expansion has a zero numerator coefficient at step i == a, which causes @@ -67,7 +67,7 @@ fn _is_near_integer(a: Float64) -> Bool: fn gammainc(a: Float64, x: Float64) -> Float64: - """Regularized lower incomplete gamma function P(a, x). + """Computes the regularized lower incomplete gamma function P(a, x). Computes P(a, x) = γ(a, x) / Γ(a), where γ(a, x) is the lower incomplete gamma integral from 0 to x. @@ -94,7 +94,7 @@ fn gammainc(a: Float64, x: Float64) -> Float64: fn gammaincc(a: Float64, x: Float64) -> Float64: - """Regularized upper incomplete gamma function Q(a, x). + """Computes the regularized upper incomplete gamma function Q(a, x). Computes Q(a, x) = 1 - P(a, x) = Γ(a, x) / Γ(a), where Γ(a, x) is the upper incomplete gamma integral from x to infinity. @@ -127,7 +127,7 @@ fn gammaincc(a: Float64, x: Float64) -> Float64: fn _gamma_series(a: Float64, x: Float64) -> Float64: - """Evaluate the regularized lower incomplete gamma function P(a, x) + """Evaluates the regularized lower incomplete gamma function P(a, x) by its series representation. P(a, x) = e^{-x} x^a / Γ(a) * Σ_{n=0}^{∞} x^n / (a(a+1)...(a+n)) @@ -152,7 +152,7 @@ fn _gamma_series(a: Float64, x: Float64) -> Float64: fn _gamma_cf(a: Float64, x: Float64) -> Float64: - """Evaluate the regularized upper incomplete gamma function Q(a, x) + """Evaluates the regularized upper incomplete gamma function Q(a, x) by its continued fraction representation (modified Lentz's method). This converges quickly for x >= a + 1 when a is **not** near an diff --git a/src/stamojo/stats/correlation.mojo b/src/stamojo/stats/correlation.mojo index e1d4744..84e1450 100644 --- a/src/stamojo/stats/correlation.mojo +++ b/src/stamojo/stats/correlation.mojo @@ -26,7 +26,7 @@ from stamojo.stats.descriptive import mean fn _rank_data(data: List[Float64]) -> List[Float64]: - """Assign ranks to data, handling ties by averaging. + """Assigns ranks to data, handling ties by averaging. Returns a list of ranks (1-based) with the same length as *data*. """ @@ -73,7 +73,7 @@ fn _rank_data(data: List[Float64]) -> List[Float64]: fn pearsonr(x: List[Float64], y: List[Float64]) -> Tuple[Float64, Float64]: - """Pearson product-moment correlation coefficient and p-value. + """Computes the Pearson product-moment correlation coefficient and p-value. The p-value is two-sided and tests H₀: ρ = 0 using the t-distribution with n − 2 degrees of freedom. @@ -123,7 +123,7 @@ fn pearsonr(x: List[Float64], y: List[Float64]) -> Tuple[Float64, Float64]: fn spearmanr(x: List[Float64], y: List[Float64]) -> Tuple[Float64, Float64]: - """Spearman rank-order correlation coefficient and p-value. + """Computes the Spearman rank-order correlation coefficient and p-value. Computes the Pearson correlation of the rank-transformed data. The p-value is two-sided using the t-distribution approximation. @@ -146,7 +146,7 @@ fn spearmanr(x: List[Float64], y: List[Float64]) -> Tuple[Float64, Float64]: fn kendalltau(x: List[Float64], y: List[Float64]) -> Tuple[Float64, Float64]: - """Kendall's tau-b rank correlation coefficient and p-value. + """Computes Kendall's tau-b rank correlation coefficient and p-value. Tau-b adjusts for ties. The p-value is two-sided based on the normal approximation for large samples. diff --git a/src/stamojo/stats/descriptive.mojo b/src/stamojo/stats/descriptive.mojo index 2cef397..e9c1e50 100644 --- a/src/stamojo/stats/descriptive.mojo +++ b/src/stamojo/stats/descriptive.mojo @@ -28,7 +28,7 @@ from std.math import sqrt, nan, log, exp fn _sorted_copy(data: List[Float64]) -> List[Float64]: - """Return a sorted copy of *data* (ascending, insertion sort).""" + """Returns a sorted copy of *data* (ascending, insertion sort).""" var result = data.copy() var n = len(result) for i in range(1, n): @@ -47,7 +47,7 @@ fn _sorted_copy(data: List[Float64]) -> List[Float64]: fn mean(data: List[Float64]) -> Float64: - """Arithmetic mean of *data*. + """Computes the arithmetic mean of *data*. Args: data: A list of values. @@ -65,7 +65,7 @@ fn mean(data: List[Float64]) -> Float64: fn variance(data: List[Float64], ddof: Int = 0) -> Float64: - """Variance of *data*. + """Computes the variance of *data*. Args: data: A list of values. @@ -87,7 +87,7 @@ fn variance(data: List[Float64], ddof: Int = 0) -> Float64: fn stddev(data: List[Float64], ddof: Int = 0) -> Float64: - """Standard deviation of *data*. + """Computes the standard deviation of *data*. Args: data: A list of values. @@ -100,7 +100,7 @@ fn stddev(data: List[Float64], ddof: Int = 0) -> Float64: fn median(data: List[Float64]) -> Float64: - """Median of *data*. + """Computes the median of *data*. Args: data: A list of values. @@ -121,7 +121,7 @@ fn median(data: List[Float64]) -> Float64: fn quantile(data: List[Float64], q: Float64) -> Float64: - """Quantile of *data* using linear interpolation (NumPy default). + """Computes the quantile of *data* using linear interpolation (NumPy default). Args: data: A list of values. @@ -151,7 +151,7 @@ fn quantile(data: List[Float64], q: Float64) -> Float64: fn skewness(data: List[Float64]) -> Float64: - """Fisher's skewness (bias-corrected) of *data*. + """Computes Fisher's skewness (bias-corrected) of *data*. Computes the adjusted Fisher-Pearson standardized moment coefficient:: @@ -184,7 +184,7 @@ fn skewness(data: List[Float64]) -> Float64: fn kurtosis(data: List[Float64], excess: Bool = True) -> Float64: - """Kurtosis of *data* (bias-corrected). + """Computes the kurtosis of *data* (bias-corrected). Uses the standard bias-corrected formula matching ``scipy.stats.kurtosis`` with ``fisher=True, bias=False``. @@ -226,7 +226,7 @@ fn kurtosis(data: List[Float64], excess: Bool = True) -> Float64: fn data_min(data: List[Float64]) -> Float64: - """Minimum value in *data*. + """Finds the minimum value in *data*. Args: data: A list of values. @@ -245,7 +245,7 @@ fn data_min(data: List[Float64]) -> Float64: fn data_max(data: List[Float64]) -> Float64: - """Maximum value in *data*. + """Finds the maximum value in *data*. Args: data: A list of values. @@ -267,7 +267,7 @@ fn data_max(data: List[Float64]) -> Float64: # Once we have that, we can make weights optional and handle the unweighted case more cleanly. # For now, we can just require an empty list for unweighted case. fn gmean(data: List[Float64], weights: List[Float64]) -> Float64: - """Compute the weighted geometric mean of a list of values. + """Computes the weighted geometric mean of a list of values. The geometric mean is the nth root of the product of n values. If weights are provided, computes the weighted geometric mean using the formula: @@ -322,7 +322,7 @@ fn gmean(data: List[Float64], weights: List[Float64]) -> Float64: fn hmean(data: List[Float64], weights: List[Float64]) -> Float64: """ - Compute the weighted harmonic mean of a list of values. + Computes the weighted harmonic mean of a list of values. The harmonic mean is defined as n / (Σ(1/xᵢ)) for n values. If weights are provided, computes the weighted harmonic mean using the formula: diff --git a/src/stamojo/stats/tests.mojo b/src/stamojo/stats/tests.mojo index 7a538bf..a9649d5 100644 --- a/src/stamojo/stats/tests.mojo +++ b/src/stamojo/stats/tests.mojo @@ -29,7 +29,7 @@ from stamojo.stats.descriptive import mean, variance fn _sorted_copy(data: List[Float64]) -> List[Float64]: - """Return a sorted copy of *data* (ascending, insertion sort).""" + """Returns a sorted copy of *data* (ascending, insertion sort).""" var result = data.copy() var n = len(result) for i in range(1, n): @@ -50,7 +50,7 @@ fn _sorted_copy(data: List[Float64]) -> List[Float64]: fn ttest_1samp( data: List[Float64], mu0: Float64 = 0.0 ) -> Tuple[Float64, Float64]: - """One-sample t-test. + """Performs a one-sample t-test. Tests H₀: μ = mu0 against H₁: μ ≠ mu0 (two-sided). @@ -87,7 +87,7 @@ fn ttest_ind( y: List[Float64], equal_var: Bool = False, ) -> Tuple[Float64, Float64]: - """Independent two-sample t-test (Welch's by default). + """Performs an independent two-sample t-test (Welch's by default). Tests H₀: μ₁ = μ₂ against H₁: μ₁ ≠ μ₂ (two-sided). @@ -153,7 +153,7 @@ fn ttest_ind( fn ttest_rel(x: List[Float64], y: List[Float64]) -> Tuple[Float64, Float64]: - """Paired (related) samples t-test. + """Performs a paired (related) samples t-test. Tests H₀: μ_d = 0 against H₁: μ_d ≠ 0, where d = x − y. @@ -183,7 +183,7 @@ fn ttest_rel(x: List[Float64], y: List[Float64]) -> Tuple[Float64, Float64]: fn chi2_gof( observed: List[Float64], expected: List[Float64] ) -> Tuple[Float64, Float64]: - """Chi-squared goodness-of-fit test. + """Performs a chi-squared goodness-of-fit test. Tests H₀: the data follow the expected distribution. @@ -215,7 +215,7 @@ fn chi2_gof( fn chi2_ind( observed: List[List[Float64]], ) -> Tuple[Float64, Float64]: - """Chi-squared test of independence for a contingency table. + """Performs a chi-squared test of independence for a contingency table. Tests H₀: the row and column variables are independent. @@ -277,7 +277,7 @@ fn chi2_ind( fn ks_1samp(data: List[Float64]) -> Tuple[Float64, Float64]: - """One-sample Kolmogorov-Smirnov test against the standard normal N(0,1). + """Performs a one-sample Kolmogorov-Smirnov test against the standard normal N(0,1). Tests H₀: the data come from a standard normal distribution. @@ -318,7 +318,7 @@ fn ks_1samp(data: List[Float64]) -> Tuple[Float64, Float64]: fn _ks_pvalue(d: Float64, n: Int) -> Float64: - """Compute the two-sided KS test p-value using the asymptotic formula. + """Computes the two-sided KS test p-value using the asymptotic formula. P(D_n > d) ≈ 2 * sum_{k=1}^{inf} (-1)^{k+1} * exp(-2 k² (√n d)²) """ @@ -351,7 +351,7 @@ fn _ks_pvalue(d: Float64, n: Int) -> Float64: fn _exp_safe(x: Float64) -> Float64: - """Safe exponential that avoids underflow.""" + """Computes a safe exponential that avoids underflow.""" if x < -700.0: return 0.0 return exp(x) @@ -365,7 +365,7 @@ fn _exp_safe(x: Float64) -> Float64: fn f_oneway( groups: List[List[Float64]], ) -> Tuple[Float64, Float64]: - """One-way ANOVA F-test. + """Performs a one-way ANOVA F-test. Tests H₀: all group means are equal against H₁: at least one differs. diff --git a/tests/test_distributions.mojo b/tests/test_distributions.mojo index ffc7c39..c819851 100644 --- a/tests/test_distributions.mojo +++ b/tests/test_distributions.mojo @@ -43,7 +43,7 @@ fn _load_scipy_stats() -> PythonObject: fn _py_f64(obj: PythonObject) -> Float64: - """Convert a PythonObject holding a numeric value to Float64.""" + """Converts a PythonObject holding a numeric value to Float64.""" try: return atof(String(obj)) except: @@ -56,7 +56,7 @@ fn _py_f64(obj: PythonObject) -> Float64: fn test_normal_pdf() raises: - """Test Normal PDF at known values.""" + """Tests Normal PDF at known values.""" var n = Normal(0.0, 1.0) # PDF at 0 for standard normal ≈ 1/√(2π) ≈ 0.3989422804014327 assert_almost_equal(n.pdf(0.0), 0.3989422804014327, atol=1e-12) @@ -69,7 +69,7 @@ fn test_normal_pdf() raises: fn test_normal_cdf() raises: - """Test Normal CDF at known values.""" + """Tests Normal CDF at known values.""" var n = Normal(0.0, 1.0) assert_almost_equal(n.cdf(0.0), 0.5, atol=1e-15) # Φ(x) + Φ(−x) = 1 @@ -80,7 +80,7 @@ fn test_normal_cdf() raises: fn test_normal_ppf() raises: - """Test Normal PPF (inverse CDF).""" + """Tests Normal PPF (inverse CDF).""" var n = Normal(0.0, 1.0) assert_almost_equal(n.ppf(0.5), 0.0, atol=1e-12) # Round-trip: ppf(cdf(x)) ≈ x @@ -93,7 +93,7 @@ fn test_normal_ppf() raises: fn test_normal_cdf_ppf_roundtrip() raises: - """Test CDF(PPF(p)) ≈ p for many probability values.""" + """Tests CDF(PPF(p)) ≈ p for many probability values.""" var n = Normal(0.0, 1.0) var ps: List[Float64] = [0.01, 0.05, 0.1, 0.25, 0.5, 0.75, 0.9, 0.95, 0.99] @@ -103,14 +103,14 @@ fn test_normal_cdf_ppf_roundtrip() raises: fn test_normal_sf() raises: - """Test Normal survival function.""" + """Tests Normal survival function.""" var n = Normal(0.0, 1.0) assert_almost_equal(n.sf(0.0), 0.5, atol=1e-15) assert_almost_equal(n.cdf(1.5) + n.sf(1.5), 1.0, atol=1e-15) fn test_normal_stats() raises: - """Test Normal distribution statistics.""" + """Tests Normal distribution statistics.""" var n = Normal(3.0, 2.0) assert_almost_equal(n.mean(), 3.0, atol=1e-15) assert_almost_equal(n.variance(), 4.0, atol=1e-15) @@ -118,7 +118,7 @@ fn test_normal_stats() raises: fn test_normal_scipy() raises: - """Test Normal distribution against scipy.stats.norm.""" + """Tests Normal distribution against scipy.stats.norm.""" var sp = _load_scipy_stats() if sp is None: print("⊘ test_normal_scipy skipped (scipy not available)") @@ -141,14 +141,14 @@ fn test_normal_scipy() raises: fn test_t_pdf_symmetry() raises: - """Test Student's t PDF is symmetric about 0.""" + """Tests Student's t PDF is symmetric about 0.""" var t = StudentT(5.0) assert_almost_equal(t.pdf(1.0), t.pdf(-1.0), atol=1e-15) assert_almost_equal(t.pdf(2.5), t.pdf(-2.5), atol=1e-15) fn test_t_cdf() raises: - """Test Student's t CDF at known values.""" + """Tests Student's t CDF at known values.""" # Cauchy distribution (df=1): CDF(0)=0.5, CDF(1)=0.75 var t1 = StudentT(1.0) assert_almost_equal(t1.cdf(0.0), 0.5, atol=1e-12) @@ -161,7 +161,7 @@ fn test_t_cdf() raises: fn test_t_ppf() raises: - """Test Student's t PPF.""" + """Tests Student's t PPF.""" var t5 = StudentT(5.0) assert_almost_equal(t5.ppf(0.5), 0.0, atol=1e-10) # Round-trip @@ -171,14 +171,14 @@ fn test_t_ppf() raises: fn test_t_stats() raises: - """Test Student's t distribution statistics.""" + """Tests Student's t distribution statistics.""" var t5 = StudentT(5.0) assert_almost_equal(t5.mean(), 0.0, atol=1e-15) assert_almost_equal(t5.variance(), 5.0 / 3.0, atol=1e-12) fn test_t_scipy() raises: - """Test Student's t distribution against scipy.stats.t.""" + """Tests Student's t distribution against scipy.stats.t.""" var sp = _load_scipy_stats() if sp is None: print("⊘ test_t_scipy skipped (scipy not available)") @@ -205,7 +205,7 @@ fn test_t_scipy() raises: fn test_chi2_cdf() raises: - """Test Chi-squared CDF at known values. + """Tests Chi-squared CDF at known values. For df=2: CDF(x) = 1 − exp(−x/2). """ @@ -216,7 +216,7 @@ fn test_chi2_cdf() raises: fn test_chi2_ppf() raises: - """Test Chi-squared PPF (round-trip).""" + """Tests Chi-squared PPF (round-trip).""" var c5 = ChiSquared(5.0) assert_almost_equal(c5.cdf(c5.ppf(0.95)), 0.95, atol=1e-6) assert_almost_equal(c5.cdf(c5.ppf(0.5)), 0.5, atol=1e-6) @@ -224,14 +224,14 @@ fn test_chi2_ppf() raises: fn test_chi2_stats() raises: - """Test Chi-squared distribution statistics.""" + """Tests Chi-squared distribution statistics.""" var c5 = ChiSquared(5.0) assert_almost_equal(c5.mean(), 5.0, atol=1e-15) assert_almost_equal(c5.variance(), 10.0, atol=1e-15) fn test_chi2_scipy() raises: - """Test Chi-squared distribution against scipy.stats.chi2.""" + """Tests Chi-squared distribution against scipy.stats.chi2.""" var sp = _load_scipy_stats() if sp is None: print("⊘ test_chi2_scipy skipped (scipy not available)") @@ -256,7 +256,7 @@ fn test_chi2_scipy() raises: fn test_f_cdf_boundary() raises: - """Test F-distribution CDF boundary and monotonicity.""" + """Tests F-distribution CDF boundary and monotonicity.""" var f = FDist(5.0, 10.0) assert_almost_equal(f.cdf(0.0), 0.0, atol=1e-15) # Monotonically increasing @@ -268,7 +268,7 @@ fn test_f_cdf_boundary() raises: fn test_f_ppf() raises: - """Test F-distribution PPF (round-trip).""" + """Tests F-distribution PPF (round-trip).""" var f = FDist(5.0, 10.0) assert_almost_equal(f.cdf(f.ppf(0.95)), 0.95, atol=1e-6) assert_almost_equal(f.cdf(f.ppf(0.5)), 0.5, atol=1e-6) @@ -276,14 +276,14 @@ fn test_f_ppf() raises: fn test_f_stats() raises: - """Test F-distribution statistics.""" + """Tests F-distribution statistics.""" var f = FDist(5.0, 10.0) # mean = d2 / (d2 - 2) = 10/8 = 1.25 assert_almost_equal(f.mean(), 1.25, atol=1e-12) fn test_f_scipy() raises: - """Test F-distribution against scipy.stats.f.""" + """Tests F-distribution against scipy.stats.f.""" var sp = _load_scipy_stats() if sp is None: print("⊘ test_f_scipy skipped (scipy not available)") @@ -304,7 +304,7 @@ fn test_f_scipy() raises: fn test_expon_pdf() raises: - """Test Exponential PDF at known values.""" + """Tests Exponential PDF at known values.""" var e = Exponential() # Standard exponential: pdf(0) = 1.0 assert_almost_equal(e.pdf(0.0), 1.0, atol=1e-15) @@ -325,7 +325,7 @@ fn test_expon_pdf() raises: fn test_expon_logpdf() raises: - """Test Exponential log-PDF at known values.""" + """Tests Exponential log-PDF at known values.""" var e = Exponential() # logpdf(0) = 0.0 for standard exponential assert_almost_equal(e.logpdf(0.0), 0.0, atol=1e-15) @@ -339,7 +339,7 @@ fn test_expon_logpdf() raises: fn test_expon_cdf() raises: - """Test Exponential CDF at known values.""" + """Tests Exponential CDF at known values.""" var e = Exponential() # CDF(0) = 0 assert_almost_equal(e.cdf(0.0), 0.0, atol=1e-15) @@ -359,7 +359,7 @@ fn test_expon_cdf() raises: fn test_expon_sf() raises: - """Test Exponential survival function: SF(x) = 1 - CDF(x).""" + """Tests Exponential survival function: SF(x) = 1 - CDF(x).""" var e = Exponential() assert_almost_equal(e.sf(0.0), 1.0, atol=1e-15) assert_almost_equal(e.sf(1.0), exp(-1.0), atol=1e-15) @@ -372,7 +372,7 @@ fn test_expon_sf() raises: fn test_expon_ppf() raises: - """Test Exponential PPF (inverse CDF).""" + """Tests Exponential PPF (inverse CDF).""" var e = Exponential() # PPF(0) = 0 (loc) assert_almost_equal(e.ppf(0.0), 0.0, atol=1e-15) @@ -386,7 +386,7 @@ fn test_expon_ppf() raises: fn test_expon_cdf_ppf_roundtrip() raises: - """Test CDF(PPF(p)) ≈ p for many probability values.""" + """Tests CDF(PPF(p)) ≈ p for many probability values.""" var e = Exponential() var ps: List[Float64] = [0.01, 0.05, 0.1, 0.25, 0.5, 0.75, 0.9, 0.95, 0.99] for i in range(len(ps)): @@ -400,7 +400,7 @@ fn test_expon_cdf_ppf_roundtrip() raises: fn test_expon_isf() raises: - """Test Exponential ISF (inverse survival function).""" + """Tests Exponential ISF (inverse survival function).""" var e = Exponential() # ISF(1) = loc = 0 assert_almost_equal(e.isf(1.0), 0.0, atol=1e-15) @@ -414,7 +414,7 @@ fn test_expon_isf() raises: fn test_expon_logcdf_logsf() raises: - """Test log-CDF and log-SF against log of CDF and SF.""" + """Tests log-CDF and log-SF against log of CDF and SF.""" var e = Exponential() var xs: List[Float64] = [0.01, 0.1, 0.5, 1.0, 2.0, 5.0] for i in range(len(xs)): @@ -424,7 +424,7 @@ fn test_expon_logcdf_logsf() raises: fn test_expon_stats() raises: - """Test Exponential distribution summary statistics.""" + """Tests Exponential distribution summary statistics.""" var e = Exponential() # Standard exponential: mean=1, var=1, std=1, median=ln(2) assert_almost_equal(e.mean(), 1.0, atol=1e-15) @@ -440,7 +440,7 @@ fn test_expon_stats() raises: fn test_expon_loc_scale() raises: - """Test Exponential with non-default loc and scale across all functions.""" + """Tests Exponential with non-default loc and scale across all functions.""" var loc = 5.0 var scale = 2.0 var e = Exponential(loc, scale) @@ -455,7 +455,7 @@ fn test_expon_loc_scale() raises: fn test_expon_scipy() raises: - """Test Exponential distribution against scipy.stats.expon.""" + """Tests Exponential distribution against scipy.stats.expon.""" var sp = _load_scipy_stats() if sp is None: print("test_expon_scipy skipped (scipy not available)") @@ -498,7 +498,7 @@ fn test_expon_scipy() raises: fn test_binomial_pmf_basic() raises: - """Test Binomial PMF at known values.""" + """Tests Binomial PMF at known values.""" var b = Binomial(10, 0.5) assert_almost_equal(b.pmf(0), 1.0 / 1024.0, atol=1e-12) assert_almost_equal(b.pmf(5), 252.0 / 1024.0, atol=1e-12) @@ -507,7 +507,7 @@ fn test_binomial_pmf_basic() raises: fn test_binomial_cdf_sf() raises: - """Test Binomial CDF and SF at known values.""" + """Tests Binomial CDF and SF at known values.""" var b = Binomial(4, 0.5) assert_almost_equal(b.cdf(2), 0.6875, atol=1e-12) assert_almost_equal(b.sf(2), 0.3125, atol=1e-12) @@ -515,7 +515,7 @@ fn test_binomial_cdf_sf() raises: fn test_binomial_edge_p() raises: - """Test Binomial behavior for p=0 and p=1.""" + """Tests Binomial behavior for p=0 and p=1.""" var b0 = Binomial(5, 0.0) assert_almost_equal(b0.pmf(0), 1.0, atol=1e-12) assert_almost_equal(b0.pmf(1), 0.0, atol=1e-12) @@ -530,21 +530,21 @@ fn test_binomial_edge_p() raises: fn test_binomial_logpmf() raises: - """Test Binomial log-PMF consistency.""" + """Tests Binomial log-PMF consistency.""" var b = Binomial(6, 0.3) var k = 2 assert_almost_equal(b.logpmf(k), log(b.pmf(k)), atol=1e-12) fn test_binomial_symmetry_p_half() raises: - """Test Binomial symmetry for p=0.5.""" + """Tests Binomial symmetry for p=0.5.""" var b = Binomial(10, 0.5) for k in range(0, 11): assert_almost_equal(b.pmf(k), b.pmf(10 - k), atol=1e-12) fn test_binomial_ppf_isf_roundtrip() raises: - """Test Binomial PPF/ISF consistency with CDF/SF.""" + """Tests Binomial PPF/ISF consistency with CDF/SF.""" var b = Binomial(12, 0.4) var qs: List[Float64] = [0.01, 0.1, 0.25, 0.5, 0.75, 0.9, 0.99] @@ -564,7 +564,7 @@ fn test_binomial_ppf_isf_roundtrip() raises: fn test_binomial_scipy() raises: - """Test Binomial distribution against scipy.stats.binom.""" + """Tests Binomial distribution against scipy.stats.binom.""" var sp = _load_scipy_stats() if sp is None: print("test_binomial_scipy skipped (scipy not available)") @@ -597,7 +597,7 @@ fn test_binomial_scipy() raises: fn test_gamma_pdf() raises: - """Test Gamma PDF at known values.""" + """Tests Gamma PDF at known values.""" var g = Gamma(2.0, 1.0) # PDF at x=1 for Gamma(2,1): 1*exp(-1) = exp(-1) assert_almost_equal(g.pdf(1.0), exp(-1.0), atol=1e-12) @@ -606,7 +606,7 @@ fn test_gamma_pdf() raises: fn test_gamma_cdf() raises: - """Test Gamma CDF at known values.""" + """Tests Gamma CDF at known values.""" var g = Gamma(1.0, 1.0) # Gamma(1,1) = Exponential(1): CDF(x) = 1 - exp(-x) assert_almost_equal(g.cdf(1.0), 1.0 - exp(-1.0), atol=1e-12) @@ -614,7 +614,7 @@ fn test_gamma_cdf() raises: fn test_gamma_ppf_roundtrip() raises: - """Test Gamma PPF round-trip.""" + """Tests Gamma PPF round-trip.""" var g = Gamma(3.0, 2.0) assert_almost_equal(g.cdf(g.ppf(0.5)), 0.5, atol=1e-6) assert_almost_equal(g.cdf(g.ppf(0.95)), 0.95, atol=1e-6) @@ -622,7 +622,7 @@ fn test_gamma_ppf_roundtrip() raises: fn test_gamma_stats() raises: - """Test Gamma distribution statistics.""" + """Tests Gamma distribution statistics.""" var g = Gamma(4.0, 3.0) # mean = a*scale = 12 assert_almost_equal(g.mean(), 12.0, atol=1e-12) @@ -633,7 +633,7 @@ fn test_gamma_stats() raises: fn test_gamma_scipy() raises: - """Test Gamma distribution against scipy.stats.gamma.""" + """Tests Gamma distribution against scipy.stats.gamma.""" var sp = _load_scipy_stats() if sp is None: print("test_gamma_scipy skipped (scipy not available)") @@ -656,7 +656,7 @@ fn test_gamma_scipy() raises: fn test_beta_pdf() raises: - """Test Beta PDF at known values.""" + """Tests Beta PDF at known values.""" var b = Beta(2.0, 2.0) # PDF at 0.5 for Beta(2,2): 6 * 0.25 = 1.5 assert_almost_equal(b.pdf(0.5), 1.5, atol=1e-12) @@ -666,7 +666,7 @@ fn test_beta_pdf() raises: fn test_beta_cdf() raises: - """Test Beta CDF at known values.""" + """Tests Beta CDF at known values.""" var b = Beta(1.0, 1.0) # Beta(1,1) = Uniform(0,1): CDF(x) = x assert_almost_equal(b.cdf(0.3), 0.3, atol=1e-12) @@ -674,7 +674,7 @@ fn test_beta_cdf() raises: fn test_beta_ppf_roundtrip() raises: - """Test Beta PPF round-trip.""" + """Tests Beta PPF round-trip.""" var b = Beta(3.0, 5.0) assert_almost_equal(b.cdf(b.ppf(0.5)), 0.5, atol=1e-6) assert_almost_equal(b.cdf(b.ppf(0.9)), 0.9, atol=1e-6) @@ -682,7 +682,7 @@ fn test_beta_ppf_roundtrip() raises: fn test_beta_stats() raises: - """Test Beta distribution statistics.""" + """Tests Beta distribution statistics.""" var b = Beta(2.0, 3.0) # mean = a/(a+b) = 2/5 = 0.4 assert_almost_equal(b.mean(), 0.4, atol=1e-12) @@ -691,7 +691,7 @@ fn test_beta_stats() raises: fn test_beta_scipy() raises: - """Test Beta distribution against scipy.stats.beta.""" + """Tests Beta distribution against scipy.stats.beta.""" var sp = _load_scipy_stats() if sp is None: print("test_beta_scipy skipped (scipy not available)") @@ -714,7 +714,7 @@ fn test_beta_scipy() raises: fn test_poisson_pmf() raises: - """Test Poisson PMF at known values.""" + """Tests Poisson PMF at known values.""" var p = Poisson(3.0) # PMF at k=0: exp(-3) assert_almost_equal(p.pmf(0), exp(-3.0), atol=1e-12) @@ -725,7 +725,7 @@ fn test_poisson_pmf() raises: fn test_poisson_cdf() raises: - """Test Poisson CDF at known values.""" + """Tests Poisson CDF at known values.""" var p = Poisson(1.0) # CDF at k=0: exp(-1) assert_almost_equal(p.cdf(0), exp(-1.0), atol=1e-12) @@ -734,7 +734,7 @@ fn test_poisson_cdf() raises: fn test_poisson_stats() raises: - """Test Poisson distribution statistics.""" + """Tests Poisson distribution statistics.""" var p = Poisson(5.0) assert_almost_equal(p.mean(), 5.0, atol=1e-15) assert_almost_equal(p.variance(), 5.0, atol=1e-15) @@ -742,7 +742,7 @@ fn test_poisson_stats() raises: fn test_poisson_scipy() raises: - """Test Poisson distribution against scipy.stats.poisson.""" + """Tests Poisson distribution against scipy.stats.poisson.""" var sp = _load_scipy_stats() if sp is None: print("test_poisson_scipy skipped (scipy not available)") @@ -760,7 +760,7 @@ fn test_poisson_scipy() raises: fn test_poisson_ppf_large_mu() raises: - """Test Poisson PPF for large mu (regression test for underflow bug).""" + """Tests Poisson PPF for large mu (regression test for underflow bug).""" var p = Poisson(1000.0) # ppf(0.5) should be near 1000, not _MAX_K var k = p.ppf(0.5) diff --git a/tests/test_hypothesis.mojo b/tests/test_hypothesis.mojo index 1187f7a..424d224 100644 --- a/tests/test_hypothesis.mojo +++ b/tests/test_hypothesis.mojo @@ -44,7 +44,7 @@ fn _load_scipy_stats() -> PythonObject: fn _py_f64(obj: PythonObject) -> Float64: - """Convert a PythonObject holding a numeric value to Float64.""" + """Converts a PythonObject holding a numeric value to Float64.""" try: return atof(String(obj)) except: @@ -57,7 +57,7 @@ fn _py_f64(obj: PythonObject) -> Float64: fn test_ttest_1samp_basic() raises: - """Test one-sample t-test with known data.""" + """Tests one-sample t-test with known data.""" # Data with mean = 3.0; test H0: mu = 0 var data: List[Float64] = [1.0, 2.0, 3.0, 4.0, 5.0] @@ -73,7 +73,7 @@ fn test_ttest_1samp_basic() raises: fn test_ttest_1samp_no_effect() raises: - """Test one-sample t-test when data mean ≈ mu0.""" + """Tests one-sample t-test when data mean ≈ mu0.""" var data: List[Float64] = [-1.0, 0.0, 1.0] var result = ttest_1samp(data, 0.0) @@ -83,7 +83,7 @@ fn test_ttest_1samp_no_effect() raises: fn test_ttest_1samp_scipy() raises: - """Test one-sample t-test against scipy.""" + """Tests one-sample t-test against scipy.""" var sp = _load_scipy_stats() if sp is None: print("⊘ test_ttest_1samp_scipy skipped (scipy not available)") @@ -102,7 +102,7 @@ fn test_ttest_1samp_scipy() raises: fn test_ttest_ind_welch() raises: - """Test Welch's two-sample t-test.""" + """Tests Welch's two-sample t-test.""" var x: List[Float64] = [1.0, 2.0, 3.0, 4.0, 5.0] var y: List[Float64] = [4.0, 5.0, 6.0, 7.0, 8.0] @@ -116,7 +116,7 @@ fn test_ttest_ind_welch() raises: fn test_ttest_ind_scipy() raises: - """Test Welch's t-test against scipy.""" + """Tests Welch's t-test against scipy.""" var sp = _load_scipy_stats() if sp is None: print("⊘ test_ttest_ind_scipy skipped (scipy not available)") @@ -138,7 +138,7 @@ fn test_ttest_ind_scipy() raises: fn test_ttest_rel() raises: - """Test paired t-test.""" + """Tests paired t-test.""" # Before and after treatment. var before: List[Float64] = [10.0, 12.0, 14.0, 11.0, 13.0] @@ -159,7 +159,7 @@ fn test_ttest_rel() raises: fn test_chi2_gof_fair_die() raises: - """Test chi-squared GoF for a fair die.""" + """Tests chi-squared GoF for a fair die.""" var observed: List[Float64] = [16.0, 18.0, 16.0, 14.0, 12.0, 14.0] var expected: List[Float64] = [15.0, 15.0, 15.0, 15.0, 15.0, 15.0] @@ -175,7 +175,7 @@ fn test_chi2_gof_fair_die() raises: fn test_chi2_ind_basic() raises: - """Test chi-squared independence test with 2×2 table.""" + """Tests chi-squared independence test with 2×2 table.""" # Example: [[10, 20], [20, 40]] # This table has perfect proportionality, chi2 ≈ 0. var row1: List[Float64] = [10.0, 20.0] @@ -190,7 +190,7 @@ fn test_chi2_ind_basic() raises: fn test_chi2_ind_scipy() raises: - """Test chi-squared independence test against scipy.""" + """Tests chi-squared independence test against scipy.""" var sp = _load_scipy_stats() if sp is None: print("⊘ test_chi2_ind_scipy skipped (scipy not available)") @@ -220,7 +220,7 @@ fn test_chi2_ind_scipy() raises: fn test_ks_normal_data() raises: - """Test KS test with data drawn from N(0,1) (should not reject).""" + """Tests KS test with data drawn from N(0,1) (should not reject).""" # Pre-computed standard normal quantiles (approx). var data: List[Float64] = [ -1.28, @@ -244,7 +244,7 @@ fn test_ks_normal_data() raises: fn test_ks_uniform_data() raises: - """Test KS test with uniform data (should reject N(0,1)).""" + """Tests KS test with uniform data (should reject N(0,1)).""" # Uniform [0, 10] data — definitely not N(0,1). var data = List[Float64]() for i in range(20): @@ -265,7 +265,7 @@ fn test_ks_uniform_data() raises: fn test_pearsonr_perfect() raises: - """Test Pearson correlation with perfectly correlated data.""" + """Tests Pearson correlation with perfectly correlated data.""" var x = List[Float64]() var y = List[Float64]() for i in range(10): @@ -280,7 +280,7 @@ fn test_pearsonr_perfect() raises: fn test_pearsonr_negative() raises: - """Test Pearson correlation for negative correlation.""" + """Tests Pearson correlation for negative correlation.""" var x = List[Float64]() var y = List[Float64]() for i in range(10): @@ -292,7 +292,7 @@ fn test_pearsonr_negative() raises: fn test_pearsonr_scipy() raises: - """Test Pearson correlation against scipy.""" + """Tests Pearson correlation against scipy.""" var sp = _load_scipy_stats() if sp is None: print("⊘ test_pearsonr_scipy skipped (scipy not available)") @@ -314,7 +314,7 @@ fn test_pearsonr_scipy() raises: fn test_spearmanr_perfect_monotone() raises: - """Test Spearman correlation with perfect monotone data.""" + """Tests Spearman correlation with perfect monotone data.""" var x = List[Float64]() var y = List[Float64]() for i in range(10): @@ -326,7 +326,7 @@ fn test_spearmanr_perfect_monotone() raises: fn test_spearmanr_scipy() raises: - """Test Spearman correlation against scipy.""" + """Tests Spearman correlation against scipy.""" var sp = _load_scipy_stats() if sp is None: print("⊘ test_spearmanr_scipy skipped (scipy not available)") @@ -346,7 +346,7 @@ fn test_spearmanr_scipy() raises: fn test_kendalltau_concordant() raises: - """Test Kendall's tau with perfectly concordant data.""" + """Tests Kendall's tau with perfectly concordant data.""" var x = List[Float64]() var y = List[Float64]() for i in range(10): @@ -358,7 +358,7 @@ fn test_kendalltau_concordant() raises: fn test_kendalltau_discordant() raises: - """Test Kendall's tau with perfectly discordant data.""" + """Tests Kendall's tau with perfectly discordant data.""" var x = List[Float64]() var y = List[Float64]() for i in range(10): @@ -375,7 +375,7 @@ fn test_kendalltau_discordant() raises: fn test_f_oneway_identical() raises: - """Test ANOVA with identical group means (should not reject).""" + """Tests ANOVA with identical group means (should not reject).""" var g1: List[Float64] = [1.0, 2.0, 3.0] var g2: List[Float64] = [1.0, 2.0, 3.0] var g3: List[Float64] = [1.0, 2.0, 3.0] @@ -391,7 +391,7 @@ fn test_f_oneway_identical() raises: fn test_f_oneway_different() raises: - """Test ANOVA with clearly different group means.""" + """Tests ANOVA with clearly different group means.""" var g1: List[Float64] = [1.0, 2.0, 3.0] var g2: List[Float64] = [10.0, 11.0, 12.0] var g3: List[Float64] = [20.0, 21.0, 22.0] @@ -411,7 +411,7 @@ fn test_f_oneway_different() raises: fn test_f_oneway_scipy() raises: - """Test ANOVA against scipy.stats.f_oneway.""" + """Tests ANOVA against scipy.stats.f_oneway.""" var sp = _load_scipy_stats() if sp is None: print("⊘ test_f_oneway_scipy skipped (scipy not available)") diff --git a/tests/test_special.mojo b/tests/test_special.mojo index 8560c43..6e34f03 100644 --- a/tests/test_special.mojo +++ b/tests/test_special.mojo @@ -63,7 +63,7 @@ fn _load_scipy() -> PythonObject: fn _py_f64(obj: PythonObject) -> Float64: - """Convert a PythonObject holding a numeric value to Float64.""" + """Converts a PythonObject holding a numeric value to Float64.""" try: return atof(String(obj)) except: @@ -103,7 +103,7 @@ fn _assert_with_scipy( fn test_gammainc_boundary() raises: - """Test boundary conditions.""" + """Tests boundary conditions.""" assert_almost_equal(gammainc(1.0, 0.0), 0.0, atol=1e-15) assert_almost_equal(gammainc(5.0, 0.0), 0.0, atol=1e-15) assert_almost_equal(gammaincc(1.0, 0.0), 1.0, atol=1e-15) @@ -111,7 +111,7 @@ fn test_gammainc_boundary() raises: fn test_gammainc_exponential() raises: - """Test P(1, x) = 1 - e^{-x} (exponential distribution CDF).""" + """Tests P(1, x) = 1 - e^{-x} (exponential distribution CDF).""" var sp = _load_scipy() var test_x: List[Float64] = [0.5, 1.0, 2.0, 5.0, 10.0] @@ -130,7 +130,7 @@ fn test_gammainc_exponential() raises: fn test_gammainc_half() raises: - """Test P(0.5, x) = erf(sqrt(x)).""" + """Tests P(0.5, x) = erf(sqrt(x)).""" var sp = _load_scipy() var test_x: List[Float64] = [0.25, 0.5, 1.0, 2.0, 4.0] @@ -149,7 +149,8 @@ fn test_gammainc_half() raises: fn test_gammainc_integer_a() raises: - """Test gammainc/gammaincc against the Poisson sum formula for integer a.""" + """Tests gammainc/gammaincc against the Poisson sum formula for integer a. + """ var sp = _load_scipy() var test_a: List[Int] = [2, 3, 5, 5, 10, 10, 20] @@ -183,7 +184,7 @@ fn test_gammainc_integer_a() raises: fn test_gammainc_scipy() raises: - """Test gammainc/gammaincc against scipy for non-integer a values.""" + """Tests gammainc/gammaincc against scipy for non-integer a values.""" var sp = _load_scipy() if sp is None: print("⊘ test_gammainc_scipy skipped (scipy not available)") @@ -218,7 +219,7 @@ fn test_gammainc_scipy() raises: fn test_gammainc_complementary() raises: - """Test P(a,x) + Q(a,x) = 1.""" + """Tests P(a,x) + Q(a,x) = 1.""" var test_cases: List[Tuple[Float64, Float64]] = [ (0.5, 0.5), (1.0, 2.0), @@ -242,7 +243,7 @@ fn test_gammainc_complementary() raises: fn test_beta_basic() raises: - """Test beta function against known exact values.""" + """Tests beta function against known exact values.""" assert_almost_equal(beta(1.0, 1.0), 1.0, atol=1e-12) assert_almost_equal(beta(2.0, 2.0), 1.0 / 6.0, atol=1e-12) assert_almost_equal(beta(0.5, 0.5), 3.141592653589793, atol=1e-10) @@ -255,14 +256,14 @@ fn test_beta_basic() raises: fn test_betainc_boundary() raises: - """Test betainc boundary values.""" + """Tests betainc boundary values.""" assert_almost_equal(betainc(2.0, 3.0, 0.0), 0.0, atol=1e-15) assert_almost_equal(betainc(2.0, 3.0, 1.0), 1.0, atol=1e-15) assert_almost_equal(betainc(1.0, 1.0, 0.5), 0.5, atol=1e-12) fn test_betainc_symmetric() raises: - """Test I_{0.5}(a, a) = 0.5.""" + """Tests I_{0.5}(a, a) = 0.5.""" var test_a: List[Float64] = [1.0, 2.0, 5.0, 10.0] for i in range(len(test_a)): @@ -271,7 +272,7 @@ fn test_betainc_symmetric() raises: fn test_betainc_symmetry_identity() raises: - """Test I_x(a,b) = 1 - I_{1-x}(b,a).""" + """Tests I_x(a,b) = 1 - I_{1-x}(b,a).""" assert_almost_equal( betainc(3.0, 5.0, 0.4), 1.0 - betainc(5.0, 3.0, 0.6), @@ -285,7 +286,7 @@ fn test_betainc_symmetry_identity() raises: fn test_betainc_known_values() raises: - """Test I_x(1, n) = 1 - (1-x)^n for integer n.""" + """Tests I_x(1, n) = 1 - (1-x)^n for integer n.""" var x = 0.3 assert_almost_equal(betainc(1.0, 1.0, x), x, atol=1e-12) assert_almost_equal(betainc(1.0, 2.0, x), 1.0 - (1.0 - x) ** 2, atol=1e-10) @@ -293,7 +294,7 @@ fn test_betainc_known_values() raises: fn test_betainc_scipy() raises: - """Test betainc against scipy.special for general parameters.""" + """Tests betainc against scipy.special for general parameters.""" var sp = _load_scipy() if sp is None: print("⊘ test_betainc_scipy skipped (scipy not available)") @@ -325,7 +326,7 @@ fn test_betainc_scipy() raises: fn test_erfinv_basic() raises: - """Test erfinv by checking erf(erfinv(p)) ≈ p (round-trip).""" + """Tests erfinv by checking erf(erfinv(p)) ≈ p (round-trip).""" assert_almost_equal(erfinv(0.0), 0.0, atol=1e-15) var test_vals: List[Float64] = [ @@ -347,7 +348,7 @@ fn test_erfinv_basic() raises: fn test_erfinv_symmetry() raises: - """Test erfinv(-p) = -erfinv(p).""" + """Tests erfinv(-p) = -erfinv(p).""" var test_vals: List[Float64] = [0.1, 0.5, 0.9] for i in range(len(test_vals)): @@ -356,7 +357,7 @@ fn test_erfinv_symmetry() raises: fn test_erfinv_scipy() raises: - """Test erfinv against scipy.special.erfinv.""" + """Tests erfinv against scipy.special.erfinv.""" var sp = _load_scipy() if sp is None: print("⊘ test_erfinv_scipy skipped (scipy not available)") @@ -395,7 +396,7 @@ fn test_erfinv_scipy() raises: fn test_bessel_basic_values() raises: - """Test basic Bessel function values.""" + """Tests basic Bessel function values.""" assert_almost_equal(j0(0.0), 1.0, atol=1e-15) assert_almost_equal(j1(0.0), 0.0, atol=1e-15) assert_almost_equal(jn[1](0.0), 0.0, atol=1e-15) @@ -407,7 +408,7 @@ fn test_bessel_basic_values() raises: fn test_bessel_symmetry() raises: - """Test symmetry relations for Bessel functions.""" + """Tests symmetry relations for Bessel functions.""" var x = 2.5 assert_almost_equal(j0(-x), j0(x), atol=1e-12) assert_almost_equal(j1(-x), -j1(x), atol=1e-12) @@ -415,14 +416,14 @@ fn test_bessel_symmetry() raises: fn test_bessel_scaled() raises: - """Test scaled modified Bessel functions.""" + """Tests scaled modified Bessel functions.""" var x = 2.0 assert_almost_equal(i0e(x), i0(x) * exp(-x), atol=1e-12) assert_almost_equal(i1e(x), i1(x) * exp(-x), atol=1e-12) fn test_bessel_scipy() raises: - """Test Bessel functions against scipy.special.""" + """Tests Bessel functions against scipy.special.""" var sp = _load_scipy() if sp is None: print("test_bessel_scipy skipped (scipy not available)") diff --git a/tests/test_stats.mojo b/tests/test_stats.mojo index c65d7db..e267037 100644 --- a/tests/test_stats.mojo +++ b/tests/test_stats.mojo @@ -33,7 +33,7 @@ from stamojo.stats import ( fn _py_f64(obj: PythonObject) -> Float64: - """Convert a PythonObject holding a numeric value to Float64.""" + """Converts a PythonObject holding a numeric value to Float64.""" try: return atof(String(obj)) except: @@ -46,7 +46,7 @@ fn _py_f64(obj: PythonObject) -> Float64: fn test_mean() raises: - """Test arithmetic mean.""" + """Tests arithmetic mean.""" var data: List[Float64] = [1.0, 2.0, 3.0, 4.0, 5.0] assert_almost_equal(mean(data), 3.0, atol=1e-15) @@ -55,7 +55,7 @@ fn test_mean() raises: fn test_variance() raises: - """Test variance (population and sample).""" + """Tests variance (population and sample).""" var data: List[Float64] = [2.0, 4.0, 4.0, 4.0, 5.0, 5.0, 7.0, 9.0] # Population variance = 4.0 (Wikipedia example) @@ -65,14 +65,14 @@ fn test_variance() raises: fn test_std() raises: - """Test standard deviation.""" + """Tests standard deviation.""" var data: List[Float64] = [2.0, 4.0, 4.0, 4.0, 5.0, 5.0, 7.0, 9.0] assert_almost_equal(stddev(data, ddof=0), 2.0, atol=1e-12) fn test_median_odd() raises: - """Test median with odd-length data.""" + """Tests median with odd-length data.""" var data: List[Float64] = [3.0, 1.0, 2.0] assert_almost_equal(median(data), 2.0, atol=1e-15) @@ -81,13 +81,13 @@ fn test_median_odd() raises: fn test_median_even() raises: - """Test median with even-length data.""" + """Tests median with even-length data.""" var data: List[Float64] = [3.0, 1.0, 2.0, 4.0] assert_almost_equal(median(data), 2.5, atol=1e-15) fn test_quantile() raises: - """Test quantile function.""" + """Tests quantile function.""" var data = List[Float64]() for i in range(1, 11): data.append(Float64(i)) @@ -102,13 +102,13 @@ fn test_quantile() raises: fn test_skewness_symmetric() raises: - """Test skewness of perfectly symmetric data is 0.""" + """Tests skewness of perfectly symmetric data is 0.""" var data: List[Float64] = [1.0, 2.0, 3.0, 4.0, 5.0] assert_almost_equal(skewness(data), 0.0, atol=1e-12) fn test_kurtosis_uniform() raises: - """Test kurtosis of uniform-like data is negative (platykurtic).""" + """Tests kurtosis of uniform-like data is negative (platykurtic).""" var data = List[Float64]() for i in range(1, 101): data.append(Float64(i)) @@ -122,7 +122,7 @@ fn test_kurtosis_uniform() raises: fn test_min_max() raises: - """Test data_min and data_max.""" + """Tests data_min and data_max.""" var data: List[Float64] = [3.0, 1.0, 4.0, 1.5, 9.0, 2.6] assert_almost_equal(data_min(data), 1.0, atol=1e-15) @@ -130,7 +130,7 @@ fn test_min_max() raises: fn test_scipy_comparison() raises: - """Test descriptive statistics against numpy/scipy.""" + """Tests descriptive statistics against numpy/scipy.""" try: var np = Python.import_module("numpy") @@ -155,7 +155,7 @@ fn test_scipy_comparison() raises: fn test_gmean() raises: - """Test geometric mean.""" + """Tests geometric mean.""" # first three test values are from scipy examples. var data: List[Float64] = [1.0, 4.0] var res = gmean(data, List[Float64]()) @@ -190,7 +190,7 @@ fn test_gmean() raises: fn test_hmean() raises: - """Test harmonic mean.""" + """Tests harmonic mean.""" # first three test values are from scipy examples. var data: List[Float64] = [1.0, 4.0] var res = hmean(data, List[Float64]()) From f554a5849e8e036c3929b91c1b79a43d79bb3aff Mon Sep 17 00:00:00 2001 From: ZHU Yuhao Date: Tue, 14 Apr 2026 15:30:29 +0200 Subject: [PATCH 11/11] Update system --- .github/workflows/run_tests.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/run_tests.yaml b/.github/workflows/run_tests.yaml index 91ffa0a..057fb31 100644 --- a/.github/workflows/run_tests.yaml +++ b/.github/workflows/run_tests.yaml @@ -16,7 +16,7 @@ jobs: strategy: fail-fast: false matrix: - os: ["ubuntu-22.04"] + os: ["macos-latest"] runs-on: ${{ matrix.os }} timeout-minutes: 30