diff --git a/build_tools/azure/pylatest_conda_forge_mkl_linux-64_conda.lock b/build_tools/azure/pylatest_conda_forge_mkl_linux-64_conda.lock index a9ea47c37078e..600f32ce525d1 100644 --- a/build_tools/azure/pylatest_conda_forge_mkl_linux-64_conda.lock +++ b/build_tools/azure/pylatest_conda_forge_mkl_linux-64_conda.lock @@ -1,20 +1,21 @@ # Generated by conda-lock. # platform: linux-64 -# input_hash: 15de7a0d1a0d046ada825ffa5ad3547c790bf903bd5d9b03e7c0e9a6a62c680d +# input_hash: 96e0d4e2ab4d0a2d543fdc457c546ea2815a9a4581e6e2190c35f0ef1a6812c0 @EXPLICIT https://conda.anaconda.org/conda-forge/linux-64/ca-certificates-2025.1.31-hbcca054_0.conda#19f3a56f68d2fd06c516076bff482c52 https://conda.anaconda.org/conda-forge/noarch/font-ttf-dejavu-sans-mono-2.37-hab24e00_0.tar.bz2#0c96522c6bdaed4b1566d11387caaf45 https://conda.anaconda.org/conda-forge/noarch/font-ttf-inconsolata-3.000-h77eed37_0.tar.bz2#34893075a5c9e55cdafac56607368fc6 https://conda.anaconda.org/conda-forge/noarch/font-ttf-source-code-pro-2.038-h77eed37_0.tar.bz2#4d59c254e01d9cde7957100457e2d5fb https://conda.anaconda.org/conda-forge/noarch/font-ttf-ubuntu-0.83-h77eed37_3.conda#49023d73832ef61042f6a237cb2687e7 -https://conda.anaconda.org/conda-forge/linux-64/libopentelemetry-cpp-headers-1.19.0-ha770c72_0.conda#6a85954c6b124241afa7d3d1897321e2 +https://conda.anaconda.org/conda-forge/linux-64/libopentelemetry-cpp-headers-1.20.0-ha770c72_0.conda#96806e6c31dc89253daff2134aeb58f3 https://conda.anaconda.org/conda-forge/linux-64/mkl-include-2024.2.2-ha957f24_16.conda#42b0d14354b5910a9f41e29289914f6b +https://conda.anaconda.org/conda-forge/linux-64/nlohmann_json-3.12.0-h3f2d84a_0.conda#d76872d096d063e226482c99337209dc https://conda.anaconda.org/conda-forge/linux-64/python_abi-3.13-6_cp313.conda#ef1d8e55d61220011cceed0b94a920d2 https://conda.anaconda.org/conda-forge/noarch/tzdata-2025b-h78e105d_0.conda#4222072737ccff51314b5ece9c7d6f5a https://conda.anaconda.org/conda-forge/noarch/fonts-conda-forge-1-0.tar.bz2#f766549260d6815b0c52253f1fb1bb29 https://conda.anaconda.org/conda-forge/linux-64/ld_impl_linux-64-2.43-h712a8e2_4.conda#01f8d123c96816249efd255a31ad7712 https://conda.anaconda.org/conda-forge/linux-64/libglvnd-1.7.0-ha4b6fd6_2.conda#434ca7e50e40f4918ab701e3facd59a0 -https://conda.anaconda.org/conda-forge/linux-64/llvm-openmp-20.1.2-h024ca30_0.conda#322da3c0641a7f0dafd5be6d3ea23d96 +https://conda.anaconda.org/conda-forge/linux-64/llvm-openmp-20.1.2-h024ca30_1.conda#39a3992c2624b8d8e6b4994dedf3102a https://conda.anaconda.org/conda-forge/linux-64/_openmp_mutex-4.5-3_kmp_llvm.conda#ee5c2118262e30b972bc0b4db8ef0ba5 https://conda.anaconda.org/conda-forge/noarch/fonts-conda-ecosystem-1-0.tar.bz2#fee5683a3f04bd15cbd8318b096a27ab https://conda.anaconda.org/conda-forge/linux-64/libegl-1.7.0-ha4b6fd6_2.conda#c151d5eb730e9b7480e6d48c0fc44048 @@ -22,7 +23,7 @@ https://conda.anaconda.org/conda-forge/linux-64/libopengl-1.7.0-ha4b6fd6_2.conda https://conda.anaconda.org/conda-forge/linux-64/libgcc-14.2.0-h767d61c_2.conda#ef504d1acbd74b7cc6849ef8af47dd03 https://conda.anaconda.org/conda-forge/linux-64/alsa-lib-1.2.13-hb9d3cd8_0.conda#ae1370588aa6a5157c34c73e9bbb36a0 https://conda.anaconda.org/conda-forge/linux-64/aws-c-common-0.12.1-hb9d3cd8_0.conda#eac0ac2d6cf8c0aba9d2028bff9a4374 -https://conda.anaconda.org/conda-forge/linux-64/c-ares-1.34.4-hb9d3cd8_0.conda#e2775acf57efd5af15b8e3d1d74d72d3 +https://conda.anaconda.org/conda-forge/linux-64/c-ares-1.34.5-hb9d3cd8_0.conda#f7f0d6cc2dc986d42ac2689ec88192be https://conda.anaconda.org/conda-forge/linux-64/libbrotlicommon-1.1.0-hb9d3cd8_2.conda#41b599ed2b02abcfdd84302bff174b23 https://conda.anaconda.org/conda-forge/linux-64/libdeflate-1.23-h4ddbbb0_0.conda#8dfae1d2e74767e9ce36d5fa0d8605db https://conda.anaconda.org/conda-forge/linux-64/libexpat-2.7.0-h5888daf_0.conda#db0bfbe7dd197b68ad5f30333bae6ce0 @@ -38,7 +39,7 @@ https://conda.anaconda.org/conda-forge/linux-64/libuv-1.50.0-hb9d3cd8_0.conda#77 https://conda.anaconda.org/conda-forge/linux-64/libwebp-base-1.5.0-h851e524_0.conda#63f790534398730f59e1b899c3644d4a https://conda.anaconda.org/conda-forge/linux-64/libzlib-1.3.1-hb9d3cd8_2.conda#edb0dca6bc32e4f4789199455a1dbeb8 https://conda.anaconda.org/conda-forge/linux-64/ncurses-6.5-h2d0b736_3.conda#47e340acb35de30501a76c7c799c41d7 -https://conda.anaconda.org/conda-forge/linux-64/openssl-3.4.1-h7b32b05_0.conda#41adf927e746dc75ecf0ef841c454e48 +https://conda.anaconda.org/conda-forge/linux-64/openssl-3.5.0-h7b32b05_0.conda#bb539841f2a3fde210f387d00ed4bb9d https://conda.anaconda.org/conda-forge/linux-64/pthread-stubs-0.4-hb9d3cd8_1002.conda#b3c17d95b5a10c6e64a21fa17573e70e https://conda.anaconda.org/conda-forge/linux-64/xorg-libice-1.1.2-hb9d3cd8_0.conda#fb901ff28063514abb6046c9ec2c4a45 https://conda.anaconda.org/conda-forge/linux-64/xorg-libxau-1.0.12-hb9d3cd8_0.conda#f6ebe2cb3f82ba6c057dde5d9debe4f7 @@ -69,13 +70,14 @@ https://conda.anaconda.org/conda-forge/linux-64/libstdcxx-ng-14.2.0-h4852527_2.c https://conda.anaconda.org/conda-forge/linux-64/libuuid-2.38.1-h0b41bf4_0.conda#40b61aab5c7ba9ff276c41cfffe6b80b https://conda.anaconda.org/conda-forge/linux-64/libxcb-1.17.0-h8a09558_0.conda#92ed62436b625154323d40d5f2f11dd7 https://conda.anaconda.org/conda-forge/linux-64/lz4-c-1.10.0-h5888daf_1.conda#9de5350a85c4a20c685259b889aa6393 -https://conda.anaconda.org/conda-forge/linux-64/mysql-common-9.0.1-h266115a_5.conda#6cf2f0c19b0b7ff3d5349c9826c26a9e +https://conda.anaconda.org/conda-forge/linux-64/mysql-common-9.2.0-h266115a_0.conda#db22a0962c953e81a2a679ecb1fc6027 https://conda.anaconda.org/conda-forge/linux-64/pixman-0.44.2-h29eaf8c_0.conda#5e2a7acfa2c24188af39e7944e1b3604 https://conda.anaconda.org/conda-forge/linux-64/readline-8.2-h8c095d6_2.conda#283b96675859b20a825f8fa30f311446 https://conda.anaconda.org/conda-forge/linux-64/s2n-1.5.15-hd830067_0.conda#81bde3ad0187adf0dd37fe86e84aff46 https://conda.anaconda.org/conda-forge/linux-64/sleef-3.8-h1b44611_0.conda#aec4dba5d4c2924730088753f6fa164b https://conda.anaconda.org/conda-forge/linux-64/snappy-1.2.1-h8bd8927_1.conda#3b3e64af585eadfb52bb90b553db5edf https://conda.anaconda.org/conda-forge/linux-64/tk-8.6.13-noxft_h4845f30_101.conda#d453b98d9c83e71da0741bb0ff4d76bc +https://conda.anaconda.org/conda-forge/linux-64/yaml-0.2.5-h7f98852_2.tar.bz2#4cb3ad778ec2d5a7acbdf254eb1c42ae https://conda.anaconda.org/conda-forge/linux-64/zlib-1.3.1-hb9d3cd8_2.conda#c9f075ab2f33b3bbee9e62d4ad0a6cd8 https://conda.anaconda.org/conda-forge/linux-64/zstd-1.5.7-hb8e6e7a_2.conda#6432cb5d4ac0046c3ac0a8a0f95842f9 https://conda.anaconda.org/conda-forge/linux-64/aws-c-io-0.17.0-ha855f32_8.conda#310a7a7bc53c1e00f938ee2e8c219930 @@ -94,11 +96,10 @@ https://conda.anaconda.org/conda-forge/linux-64/libnghttp2-1.64.0-h161d5f1_0.con https://conda.anaconda.org/conda-forge/linux-64/libprotobuf-5.29.3-h501fc15_0.conda#452518a9744fbac05fb45531979bdf29 https://conda.anaconda.org/conda-forge/linux-64/libre2-11-2024.07.02-hba17884_3.conda#545e93a513c10603327c76c15485e946 https://conda.anaconda.org/conda-forge/linux-64/libthrift-0.21.0-h0e7cc3e_0.conda#dcb95c0a98ba9ff737f7ae482aef7833 -https://conda.anaconda.org/conda-forge/linux-64/mysql-libs-9.0.1-he0572af_5.conda#d13932a2a61de7c0fb7864b592034a6e +https://conda.anaconda.org/conda-forge/linux-64/mysql-libs-9.2.0-he0572af_0.conda#93340b072c393d23c4700a1d40565dca https://conda.anaconda.org/conda-forge/linux-64/ninja-1.12.1-h297d8ca_0.conda#3aa1c7e292afeff25a0091ddd7c69b72 -https://conda.anaconda.org/conda-forge/linux-64/nlohmann_json-3.11.3-he02047a_1.conda#e46f7ac4917215b49df2ea09a694a3fa https://conda.anaconda.org/conda-forge/linux-64/pcre2-10.44-hba22ea6_2.conda#df359c09c41cd186fffb93a2d87aa6f5 -https://conda.anaconda.org/conda-forge/linux-64/python-3.13.2-hf636f53_101_cp313.conda#a7902a3611fe773da3921cbbf7bc2c5c +https://conda.anaconda.org/conda-forge/linux-64/python-3.13.3-hf636f53_100_cp313.conda#6092d3c7241e67614af8e4d7b1fdf3ee https://conda.anaconda.org/conda-forge/linux-64/qhull-2020.2-h434a139_5.conda#353823361b1d27eb3960efb076dfcaf6 https://conda.anaconda.org/conda-forge/linux-64/wayland-1.23.1-h3e06ad9_0.conda#0a732427643ae5e0486a727927791da1 https://conda.anaconda.org/conda-forge/linux-64/xcb-util-0.4.1-hb711507_2.conda#8637c3e5821654d0edf97e2b0404b443 @@ -110,8 +111,11 @@ https://conda.anaconda.org/conda-forge/linux-64/xorg-libx11-1.8.12-h4f16b4b_0.co https://conda.anaconda.org/conda-forge/linux-64/aws-c-event-stream-0.5.4-h286e7e7_3.conda#aac4138e5fe70061b0e4126ee71e3a9f https://conda.anaconda.org/conda-forge/linux-64/aws-c-http-0.9.5-hbca0721_0.conda#9cb70e8f68551738d478117fe973c114 https://conda.anaconda.org/conda-forge/linux-64/brotli-1.1.0-hb9d3cd8_2.conda#98514fe74548d768907ce7a13f680e8f +https://conda.anaconda.org/conda-forge/linux-64/brotli-python-1.1.0-py313h46c70d0_2.conda#f6bb3742e17a4af0dc3c8ca942683ef6 +https://conda.anaconda.org/conda-forge/noarch/click-8.1.8-pyh707e725_0.conda#f22f4d4970e09d68a10b922cbb0408d3 +https://conda.anaconda.org/conda-forge/noarch/cloudpickle-3.1.1-pyhd8ed1ab_0.conda#364ba6c9fb03886ac979b482f39ebb92 https://conda.anaconda.org/conda-forge/noarch/colorama-0.4.6-pyhd8ed1ab_1.conda#962b9857ee8e7018c22f2776ffa0b2d7 -https://conda.anaconda.org/conda-forge/noarch/cpython-3.13.2-py313hd8ed1ab_101.conda#d6be72c63da6e99ac2a1b87b120d135a +https://conda.anaconda.org/conda-forge/noarch/cpython-3.13.3-py313hd8ed1ab_100.conda#488690e9d736c1273ca839d853ca883b https://conda.anaconda.org/conda-forge/noarch/cycler-0.12.1-pyhd8ed1ab_1.conda#44600c4667a319d67dbe0681fc0bc833 https://conda.anaconda.org/conda-forge/linux-64/cyrus-sasl-2.1.27-h54b06d7_7.conda#dce22f70b4e5a407ce88f2be046f4ceb https://conda.anaconda.org/conda-forge/linux-64/cython-3.0.12-py313h5dec8f5_0.conda#24a42a0c1cc33743e33572d63d489b54 @@ -120,6 +124,8 @@ https://conda.anaconda.org/conda-forge/noarch/execnet-2.1.1-pyhd8ed1ab_1.conda#a https://conda.anaconda.org/conda-forge/noarch/filelock-3.18.0-pyhd8ed1ab_0.conda#4547b39256e296bb758166893e909a7c https://conda.anaconda.org/conda-forge/linux-64/fontconfig-2.15.0-h7e30c49_1.conda#8f5b0b297b59e1ac160ad4beec99dbee https://conda.anaconda.org/conda-forge/noarch/fsspec-2025.3.2-pyhd8ed1ab_0.conda#9c40692c3d24c7aaf335f673ac09d308 +https://conda.anaconda.org/conda-forge/noarch/hpack-4.1.0-pyhd8ed1ab_0.conda#0a802cb9888dd14eeefc611f05c40b6e +https://conda.anaconda.org/conda-forge/noarch/hyperframe-6.1.0-pyhd8ed1ab_0.conda#8e6923fc12f1fe8f8c4e5c9f343256ac https://conda.anaconda.org/conda-forge/noarch/iniconfig-2.0.0-pyhd8ed1ab_1.conda#6837f3eff7dcea42ecd714ce1ac2b108 https://conda.anaconda.org/conda-forge/linux-64/kiwisolver-1.4.7-py313h33d0bda_0.conda#9862d13a5e466273d5a4738cffcb8d6c https://conda.anaconda.org/conda-forge/linux-64/libcups-2.3.3-h4637d8d_4.conda#d4529f4dff3057982a7617c7ac58fde3 @@ -129,40 +135,58 @@ https://conda.anaconda.org/conda-forge/linux-64/libglx-1.7.0-ha4b6fd6_2.conda#c8 https://conda.anaconda.org/conda-forge/linux-64/libhiredis-1.0.2-h2cc385e_0.tar.bz2#b34907d3a81a3cd8095ee83d174c074a https://conda.anaconda.org/conda-forge/linux-64/libtiff-4.7.0-hd9ff511_3.conda#0ea6510969e1296cc19966fad481f6de https://conda.anaconda.org/conda-forge/linux-64/libxml2-2.13.7-h4bc477f_1.conda#ad1f1f8238834cd3c88ceeaee8da444a +https://conda.anaconda.org/conda-forge/noarch/locket-1.0.0-pyhd8ed1ab_0.tar.bz2#91e27ef3d05cc772ce627e51cff111c4 +https://conda.anaconda.org/conda-forge/linux-64/lz4-4.3.3-py313h8756d67_2.conda#135da13cb96aba211acd7feeca301154 https://conda.anaconda.org/conda-forge/linux-64/markupsafe-3.0.2-py313h8060acc_1.conda#21b62c55924f01b6eef6827167b46acb https://conda.anaconda.org/conda-forge/linux-64/mpfr-4.2.1-h90cbb55_3.conda#2eeb50cab6652538eee8fc0bc3340c81 https://conda.anaconda.org/conda-forge/noarch/mpmath-1.3.0-pyhd8ed1ab_1.conda#3585aa87c43ab15b167b574cd73b057b +https://conda.anaconda.org/conda-forge/linux-64/msgpack-python-1.1.0-py313h33d0bda_0.conda#7f907b1065247efa419bb70d3a3341b5 https://conda.anaconda.org/conda-forge/noarch/munkres-1.1.4-pyh9f0ad1d_0.tar.bz2#2ba8498c1018c1e9c61eb99b973dfe19 +https://conda.anaconda.org/conda-forge/noarch/narwhals-1.34.1-pyhd8ed1ab_0.conda#38ee2961b442f786de810610de6f6b0e https://conda.anaconda.org/conda-forge/noarch/networkx-3.4.2-pyh267e887_2.conda#fd40bf7f7f4bc4b647dc8512053d9873 https://conda.anaconda.org/conda-forge/linux-64/orc-2.1.1-h17f744e_1.conda#cfe9bc267c22b6d53438eff187649d43 https://conda.anaconda.org/conda-forge/noarch/packaging-24.2-pyhd8ed1ab_2.conda#3bfed7e6228ebf2f7b9eaa47f1b4e2aa https://conda.anaconda.org/conda-forge/noarch/pip-25.0.1-pyh145f28c_0.conda#9ba21d75dc722c29827988a575a65707 https://conda.anaconda.org/conda-forge/noarch/pluggy-1.5.0-pyhd8ed1ab_1.conda#e9dcbce5f45f9ee500e728ae58b605b6 +https://conda.anaconda.org/conda-forge/linux-64/psutil-7.0.0-py313h536fd9c_0.conda#8f315d1fce04a046c1b93fa6e536661d https://conda.anaconda.org/conda-forge/noarch/pybind11-global-2.13.6-pyh415d2e4_2.conda#120541563e520d12d8e39abd7de9092c +https://conda.anaconda.org/conda-forge/noarch/pycparser-2.22-pyh29332c3_1.conda#12c566707c80111f9799308d9e265aef https://conda.anaconda.org/conda-forge/noarch/pyparsing-3.2.3-pyhd8ed1ab_1.conda#513d3c262ee49b54a8fec85c5bc99764 +https://conda.anaconda.org/conda-forge/noarch/pysocks-1.7.1-pyha55dd90_7.conda#461219d1a5bd61342293efa2c0c90eac https://conda.anaconda.org/conda-forge/noarch/python-tzdata-2025.2-pyhd8ed1ab_0.conda#88476ae6ebd24f39261e0854ac244f33 -https://conda.anaconda.org/conda-forge/noarch/pytz-2024.1-pyhd8ed1ab_0.conda#3eeeeb9e4827ace8c0c1419c85d590ad +https://conda.anaconda.org/conda-forge/noarch/pytz-2025.2-pyhd8ed1ab_0.conda#bc8e3267d44011051f2eb14d22fb0960 +https://conda.anaconda.org/conda-forge/linux-64/pyyaml-6.0.2-py313h8060acc_2.conda#50992ba61a8a1f8c2d346168ae1c86df https://conda.anaconda.org/conda-forge/linux-64/re2-2024.07.02-h9925aae_3.conda#6f445fb139c356f903746b2b91bbe786 https://conda.anaconda.org/conda-forge/noarch/setuptools-75.8.2-pyhff2d567_0.conda#9bddfdbf4e061821a1a443f93223be61 https://conda.anaconda.org/conda-forge/noarch/six-1.17.0-pyhd8ed1ab_0.conda#a451d576819089b0d672f18768be0f65 +https://conda.anaconda.org/conda-forge/noarch/sortedcontainers-2.4.0-pyhd8ed1ab_1.conda#0401a17ae845fa72c7210e206ec5647d +https://conda.anaconda.org/conda-forge/noarch/tblib-3.1.0-pyhd8ed1ab_0.conda#a15c62b8a306b8978f094f76da2f903f https://conda.anaconda.org/conda-forge/noarch/threadpoolctl-3.6.0-pyhecae5ae_0.conda#9d64911b31d57ca443e9f1e36b04385f https://conda.anaconda.org/conda-forge/noarch/toml-0.10.2-pyhd8ed1ab_1.conda#b0dd904de08b7db706167240bf37b164 https://conda.anaconda.org/conda-forge/noarch/tomli-2.2.1-pyhd8ed1ab_1.conda#ac944244f1fed2eb49bae07193ae8215 +https://conda.anaconda.org/conda-forge/noarch/toolz-1.0.0-pyhd8ed1ab_1.conda#40d0ed782a8aaa16ef248e68c06c168d https://conda.anaconda.org/conda-forge/linux-64/tornado-6.4.2-py313h536fd9c_0.conda#5f5cbdd527d2e74e270d8b6255ba714f -https://conda.anaconda.org/conda-forge/noarch/typing_extensions-4.13.1-pyh29332c3_0.conda#5710c79a5fb0a6bfdba0a887f90583b1 +https://conda.anaconda.org/conda-forge/noarch/typing_extensions-4.13.2-pyh29332c3_0.conda#83fc6ae00127671e301c9f44254c31b8 https://conda.anaconda.org/conda-forge/linux-64/xcb-util-image-0.4.0-hb711507_2.conda#a0901183f08b6c7107aab109733a3c91 https://conda.anaconda.org/conda-forge/linux-64/xkeyboard-config-2.43-hb9d3cd8_0.conda#f725c7425d6d7c15e31f3b99a88ea02f https://conda.anaconda.org/conda-forge/linux-64/xorg-libxext-1.3.6-hb9d3cd8_0.conda#febbab7d15033c913d53c7a2c102309d https://conda.anaconda.org/conda-forge/linux-64/xorg-libxfixes-6.0.1-hb9d3cd8_0.conda#4bdb303603e9821baf5fe5fdff1dc8f8 https://conda.anaconda.org/conda-forge/linux-64/xorg-libxrender-0.9.12-hb9d3cd8_0.conda#96d57aba173e878a2089d5638016dc5e +https://conda.anaconda.org/conda-forge/noarch/xyzservices-2025.1.0-pyhd8ed1ab_0.conda#fdf07e281a9e5e10fc75b2dd444136e9 +https://conda.anaconda.org/conda-forge/noarch/zict-3.0.0-pyhd8ed1ab_1.conda#e52c2ef711ccf31bb7f70ca87d144b9e +https://conda.anaconda.org/conda-forge/noarch/zipp-3.21.0-pyhd8ed1ab_1.conda#0c3cc595284c5e8f0f9900a9b228a332 https://conda.anaconda.org/conda-forge/linux-64/aws-c-auth-0.8.7-h7743f02_1.conda#185af639e073ef45fbd75f9d4f30605b https://conda.anaconda.org/conda-forge/linux-64/aws-c-mqtt-0.12.2-hffac463_3.conda#18d498ed5cd14ab8d7d745a18303edf4 https://conda.anaconda.org/conda-forge/linux-64/azure-core-cpp-1.14.0-h5cfcd09_0.conda#0a8838771cc2e985cd295e01ae83baf1 https://conda.anaconda.org/conda-forge/linux-64/cairo-1.18.4-h3394656_0.conda#09262e66b19567aff4f592fb53b28760 https://conda.anaconda.org/conda-forge/linux-64/ccache-4.11.2-hd714d17_0.conda#35ae7ce74089ab05fdb1cb9746c0fbe4 +https://conda.anaconda.org/conda-forge/linux-64/cffi-1.17.1-py313hfab6e84_0.conda#ce6386a5892ef686d6d680c345c40ad1 https://conda.anaconda.org/conda-forge/linux-64/coverage-7.8.0-py313h8060acc_0.conda#375064d30e709bf7c1d4580e70aaea61 +https://conda.anaconda.org/conda-forge/linux-64/cytoolz-1.0.1-py313h536fd9c_0.conda#e886bb6a3c24f8b9dd4fcd1d617a1f64 https://conda.anaconda.org/conda-forge/linux-64/dbus-1.13.6-h5008d03_3.tar.bz2#ecfff944ba3960ecb334b9a2663d708d https://conda.anaconda.org/conda-forge/linux-64/fonttools-4.57.0-py313h8060acc_0.conda#76b3a3367ac578a7cc43f4b7814e7e87 +https://conda.anaconda.org/conda-forge/noarch/h2-4.2.0-pyhd8ed1ab_0.conda#b4754fb1bdcb70c8fd54f918301582c6 +https://conda.anaconda.org/conda-forge/noarch/importlib-metadata-8.6.1-pyha770c72_0.conda#f4b39bf00c69f56ac01e020ebfac066c https://conda.anaconda.org/conda-forge/noarch/jinja2-3.1.6-pyhd8ed1ab_0.conda#446bd6c8cb26050d528881df495ce646 https://conda.anaconda.org/conda-forge/noarch/joblib-1.4.2-pyhd8ed1ab_1.conda#bf8243ee348f3a10a14ed0cae323e0c1 https://conda.anaconda.org/conda-forge/linux-64/lcms2-2.17-h717163a_0.conda#000e85703f0fd9594c81710dd5066471 @@ -176,12 +200,13 @@ https://conda.anaconda.org/conda-forge/noarch/meson-1.7.1-pyhd8ed1ab_0.conda#900 https://conda.anaconda.org/conda-forge/linux-64/mpc-1.3.1-h24ddda3_1.conda#aa14b9a5196a6d8dd364164b7ce56acf https://conda.anaconda.org/conda-forge/linux-64/openjpeg-2.5.3-h5fbd93e_0.conda#9e5816bc95d285c115a3ebc2f8563564 https://conda.anaconda.org/conda-forge/linux-64/openldap-2.6.9-he970967_0.conda#ca2de8bbdc871bce41dbf59e51324165 +https://conda.anaconda.org/conda-forge/noarch/partd-1.4.2-pyhd8ed1ab_0.conda#0badf9c54e24cecfb0ad2f99d680c163 https://conda.anaconda.org/conda-forge/linux-64/prometheus-cpp-1.3.0-ha5d0236_0.conda#a83f6a2fdc079e643237887a37460668 https://conda.anaconda.org/conda-forge/noarch/pybind11-2.13.6-pyh1ec8472_2.conda#8088a5e7b2888c780738c3130f2a969d https://conda.anaconda.org/conda-forge/noarch/pyproject-metadata-0.9.1-pyhd8ed1ab_0.conda#22ae7c6ea81e0c8661ef32168dda929b https://conda.anaconda.org/conda-forge/noarch/pytest-8.3.5-pyhd8ed1ab_0.conda#c3c9316209dec74a705a36797970c6be https://conda.anaconda.org/conda-forge/noarch/python-dateutil-2.9.0.post0-pyhff2d567_1.conda#5ba79d7c71f03c678c8ead841f347d6e -https://conda.anaconda.org/conda-forge/noarch/typing-extensions-4.13.1-hf5ce1d7_0.conda#e37cf790f710cf72fd13dcb6b2d4370c +https://conda.anaconda.org/conda-forge/noarch/typing-extensions-4.13.2-h0e9735f_0.conda#568ed1300869dca0ba09fb750cda5dbb https://conda.anaconda.org/conda-forge/linux-64/xcb-util-cursor-0.1.5-hb9d3cd8_0.conda#eb44b3b6deb1cab08d72cb61686fe64c https://conda.anaconda.org/conda-forge/linux-64/xorg-libxcomposite-0.4.6-hb9d3cd8_2.conda#d3c295b50f092ab525ffe3c2aa4b7413 https://conda.anaconda.org/conda-forge/linux-64/xorg-libxcursor-1.2.3-hb9d3cd8_0.conda#2ccd714aa2242315acaf0a67faea780b @@ -192,53 +217,59 @@ https://conda.anaconda.org/conda-forge/linux-64/xorg-libxxf86vm-1.1.6-hb9d3cd8_0 https://conda.anaconda.org/conda-forge/linux-64/aws-c-s3-0.7.13-h4c9fe3b_3.conda#207518c1b938d5ca2a970c24e342d98f https://conda.anaconda.org/conda-forge/linux-64/azure-identity-cpp-1.10.0-h113e628_0.conda#73f73f60854f325a55f1d31459f2ab73 https://conda.anaconda.org/conda-forge/linux-64/azure-storage-common-cpp-12.8.0-h736e048_1.conda#13de36be8de3ae3f05ba127631599213 +https://conda.anaconda.org/conda-forge/noarch/dask-core-2025.3.0-pyhd8ed1ab_0.conda#36f6cc22457e3d6a6051c5370832f96c https://conda.anaconda.org/conda-forge/linux-64/gmpy2-2.1.5-py313h11186cd_3.conda#846a773cdc154eda7b86d7f4427432f2 -https://conda.anaconda.org/conda-forge/linux-64/harfbuzz-11.0.0-h76408a6_0.conda#347cb348bfc8d77062daee11c326e518 +https://conda.anaconda.org/conda-forge/linux-64/harfbuzz-11.0.1-h2c12942_0.conda#c90105cecb8bf8248f6666f1f5a40bbb https://conda.anaconda.org/conda-forge/linux-64/libclang-cpp20.1-20.1.2-default_hb5137d0_0.conda#729198eae19e9dbf8e0ffe355d416bde https://conda.anaconda.org/conda-forge/linux-64/libclang13-20.1.2-default_h9c6a7e4_0.conda#c5fe177150aecc6ec46609b0a6123f39 https://conda.anaconda.org/conda-forge/linux-64/libgoogle-cloud-2.36.0-hc4361e1_1.conda#ae36e6296a8dd8e8a9a8375965bf6398 -https://conda.anaconda.org/conda-forge/linux-64/libopentelemetry-cpp-1.19.0-hd1b1c89_0.conda#21fdfc7394cf73e8f5d46e66a1eeed09 +https://conda.anaconda.org/conda-forge/linux-64/libopentelemetry-cpp-1.20.0-hd1b1c89_0.conda#e1185384cc23e3bbf85486987835df94 https://conda.anaconda.org/conda-forge/linux-64/libpq-17.4-h27ae623_1.conda#37fba334855ef3b51549308e61ed7a3d https://conda.anaconda.org/conda-forge/noarch/meson-python-0.17.1-pyh70fd9c4_1.conda#7a02679229c6c2092571b4c025055440 -https://conda.anaconda.org/conda-forge/linux-64/optree-0.14.1-py313h33d0bda_1.conda#951a8b89db3ca099f93586919c03226d +https://conda.anaconda.org/conda-forge/linux-64/optree-0.15.0-py313h33d0bda_0.conda#151f92ff0806c7c700419c8b8cf7cb4b https://conda.anaconda.org/conda-forge/linux-64/pillow-11.1.0-py313h8db990d_0.conda#1e86810c6c3fb6d6aebdba26564eb2e8 https://conda.anaconda.org/conda-forge/noarch/pytest-cov-6.1.1-pyhd8ed1ab_0.conda#1e35d8f975bc0e984a19819aa91c440a https://conda.anaconda.org/conda-forge/noarch/pytest-xdist-3.6.1-pyhd8ed1ab_1.conda#59aad4fb37cabc0bacc73cf344612ddd https://conda.anaconda.org/conda-forge/linux-64/tbb-2021.13.0-hceb3a55_1.conda#ba7726b8df7b9d34ea80e82b097a4893 https://conda.anaconda.org/conda-forge/linux-64/xorg-libxtst-1.2.5-hb9d3cd8_3.conda#7bbe9a0cc0df0ac5f5a8ad6d6a11af2f +https://conda.anaconda.org/conda-forge/linux-64/zstandard-0.23.0-py313h536fd9c_1.conda#22b773d9a4bcf7a25ad5bc8591abc80f https://conda.anaconda.org/conda-forge/linux-64/aws-crt-cpp-0.31.1-h46b750d_1.conda#df4a6731864b1d6e125c0b94328262fe https://conda.anaconda.org/conda-forge/linux-64/azure-storage-blobs-cpp-12.13.0-h3cf044e_1.conda#7eb66060455c7a47d9dcdbfa9f46579b https://conda.anaconda.org/conda-forge/linux-64/libgoogle-cloud-storage-2.36.0-h0121fbd_1.conda#a0f7588c1f0a26d550e7bae4fb49427a https://conda.anaconda.org/conda-forge/linux-64/mkl-2024.2.2-ha957f24_16.conda#1459379c79dda834673426504d52b319 -https://conda.anaconda.org/conda-forge/linux-64/qt6-main-6.9.0-h6441bc3_0.conda#d3df16592e15a3f833cfc4d19ae58677 +https://conda.anaconda.org/conda-forge/linux-64/qt6-main-6.9.0-h6441bc3_1.conda#4029a8dcb1d97ea241dbe5abfda1fad6 https://conda.anaconda.org/conda-forge/noarch/sympy-1.13.3-pyh2585a3b_105.conda#254cd5083ffa04d96e3173397a3d30f4 +https://conda.anaconda.org/conda-forge/noarch/urllib3-2.4.0-pyhd8ed1ab_0.conda#c1e349028e0052c4eea844e94f773065 https://conda.anaconda.org/conda-forge/linux-64/aws-sdk-cpp-1.11.510-h1fa5cb7_4.conda#b2269aa463cefee750c73da2baf8d583 https://conda.anaconda.org/conda-forge/linux-64/azure-storage-files-datalake-cpp-12.12.0-ha633028_1.conda#7c1980f89dd41b097549782121a73490 +https://conda.anaconda.org/conda-forge/noarch/distributed-2025.3.0-pyhd8ed1ab_0.conda#968a7a4ff98bcfb515b0f1c94d35553f https://conda.anaconda.org/conda-forge/linux-64/libblas-3.9.0-31_hfdb39a5_mkl.conda#bdf4a57254e8248222cb631db4393ff1 https://conda.anaconda.org/conda-forge/linux-64/mkl-devel-2024.2.2-ha770c72_16.conda#140891ea14285fc634353b31e9e40a95 https://conda.anaconda.org/conda-forge/linux-64/pyside6-6.9.0-py313h5f61773_0.conda#f51f25ec8fcbf777f8b186bb5deeed40 -https://conda.anaconda.org/conda-forge/linux-64/libarrow-19.0.1-h052fb8e_6_cpu.conda#eb77601ca27712a919673aec187e941f +https://conda.anaconda.org/conda-forge/linux-64/libarrow-19.0.1-hb90904d_7_cpu.conda#cb63f3394929ba771ac798bbda23dfc9 https://conda.anaconda.org/conda-forge/linux-64/libcblas-3.9.0-31_h372d94f_mkl.conda#2a06a6c16b45bd3d10002927ca204b67 https://conda.anaconda.org/conda-forge/linux-64/liblapack-3.9.0-31_hc41d3b0_mkl.conda#10d012ddd7cc1c7ff9093d4974a34e53 -https://conda.anaconda.org/conda-forge/linux-64/libarrow-acero-19.0.1-hcb10f89_6_cpu.conda#758177a069e22e081f0ab3dcb03174c0 +https://conda.anaconda.org/conda-forge/linux-64/libarrow-acero-19.0.1-hcb10f89_7_cpu.conda#90382dd59eecda17d7c639b8c921d5d4 https://conda.anaconda.org/conda-forge/linux-64/liblapacke-3.9.0-31_hbc6e62b_mkl.conda#562026e418363dc346ad5a9e18cce73c -https://conda.anaconda.org/conda-forge/linux-64/libparquet-19.0.1-h081d1f1_6_cpu.conda#f5dc9977d49bdb7b521e2cc96369c1c0 -https://conda.anaconda.org/conda-forge/linux-64/libtorch-2.6.0-cpu_mkl_hec71012_103.conda#f5c1ba21fa4f28b26f518c1954fd8125 +https://conda.anaconda.org/conda-forge/linux-64/libparquet-19.0.1-h081d1f1_7_cpu.conda#9fa0679126b39a5b9d77063430fe9607 +https://conda.anaconda.org/conda-forge/linux-64/libtorch-2.6.0-cpu_mkl_hf6ddc5a_104.conda#828146bb6100e9a4217e8351b18c8e83 https://conda.anaconda.org/conda-forge/linux-64/numpy-2.2.4-py313h17eae1a_0.conda#6c905a8f170edd64f3a390c76572e331 https://conda.anaconda.org/conda-forge/linux-64/pyarrow-core-19.0.1-py313he5f92c8_0_cpu.conda#7d8649531c807b24295c8f9a0a396a78 https://conda.anaconda.org/conda-forge/noarch/array-api-strict-2.3.1-pyhd8ed1ab_0.conda#11107d0aeb8c590a34fee0894909816b https://conda.anaconda.org/conda-forge/linux-64/blas-devel-3.9.0-31_hcf00494_mkl.conda#368c93bde87a67d24a74de15bf4c49fd https://conda.anaconda.org/conda-forge/linux-64/contourpy-1.3.1-py313h33d0bda_0.conda#6b6768e7c585d7029f79a04cbc4cbff0 -https://conda.anaconda.org/conda-forge/linux-64/libarrow-dataset-19.0.1-hcb10f89_6_cpu.conda#bc879ea62f1811a73d928c01762bedb1 -https://conda.anaconda.org/conda-forge/linux-64/pandas-2.2.3-py313ha87cce1_1.conda#c5d63dd501db554b84a30dea33824164 -https://conda.anaconda.org/conda-forge/linux-64/polars-1.26.0-py313hae41bca_0.conda#14817d4747f3996cdf8efbba164c65b9 -https://conda.anaconda.org/conda-forge/linux-64/pytorch-2.6.0-cpu_mkl_py313_h69cc176_103.conda#ca8a8e8ce4ce7fd935f17d6475deba20 +https://conda.anaconda.org/conda-forge/linux-64/libarrow-dataset-19.0.1-hcb10f89_7_cpu.conda#14adc5f9f5f602e03538a16540c05784 +https://conda.anaconda.org/conda-forge/linux-64/pandas-2.2.3-py313ha87cce1_3.conda#6248b529e537b1d4cb5ab3ef7f537795 +https://conda.anaconda.org/conda-forge/linux-64/polars-1.27.1-py313hae41bca_0.conda#acd55ae120e730edf3eb24de04b9d6f8 +https://conda.anaconda.org/conda-forge/linux-64/pytorch-2.6.0-cpu_mkl_py313_hea9ba1b_104.conda#5544fa15f47f4c53222f263eb51dd6b3 https://conda.anaconda.org/conda-forge/linux-64/scipy-1.15.2-py313h86fcf2b_0.conda#ca68acd9febc86448eeed68d0c6c8643 https://conda.anaconda.org/conda-forge/noarch/scipy-doctest-1.7.1-pyh29332c3_0.conda#d3b3b7b88385648eff6ae39694692f27 https://conda.anaconda.org/conda-forge/linux-64/blas-2.131-mkl.conda#9bb865b7e01104255ca54e61a58ded15 -https://conda.anaconda.org/conda-forge/linux-64/libarrow-substrait-19.0.1-h1bed206_6_cpu.conda#5bcca23c52ca5a0522b22814c4aff927 +https://conda.anaconda.org/conda-forge/noarch/bokeh-3.7.2-pyhd8ed1ab_1.conda#2f31c581e29bdb830ec77e112f3776ae +https://conda.anaconda.org/conda-forge/linux-64/libarrow-substrait-19.0.1-h1bed206_7_cpu.conda#f75ac4838bdca785c0ab3339911704ee https://conda.anaconda.org/conda-forge/linux-64/matplotlib-base-3.10.1-py313h129903b_0.conda#4e23b3fabf434b418e0d9c6975a6453f https://conda.anaconda.org/conda-forge/linux-64/pyamg-5.2.1-py313hf0ab243_1.conda#4c769bf3858f424cb2ecf952175ec600 -https://conda.anaconda.org/conda-forge/linux-64/pytorch-cpu-2.6.0-cpu_mkl_hc60beec_103.conda#2c6ebe539ac8f9a75f3160dd551fb33e +https://conda.anaconda.org/conda-forge/linux-64/pytorch-cpu-2.6.0-cpu_mkl_hc60beec_104.conda#ccdc8b6254649dd4ed448b94fe80070e https://conda.anaconda.org/conda-forge/linux-64/matplotlib-3.10.1-py313h78bf25f_0.conda#d0c80dea550ca97fc0710b2ecef919ba https://conda.anaconda.org/conda-forge/linux-64/pyarrow-19.0.1-py313h78bf25f_0.conda#e8efe6998a383dd149787c83d3d6a92e +https://conda.anaconda.org/conda-forge/noarch/dask-2025.3.0-pyhd8ed1ab_0.conda#95e33679c10ef9ef65df0fc01a71fdc5 diff --git a/build_tools/azure/pylatest_conda_forge_mkl_linux-64_environment.yml b/build_tools/azure/pylatest_conda_forge_mkl_linux-64_environment.yml index e804bf1ce8e31..69365c4cee03b 100644 --- a/build_tools/azure/pylatest_conda_forge_mkl_linux-64_environment.yml +++ b/build_tools/azure/pylatest_conda_forge_mkl_linux-64_environment.yml @@ -23,6 +23,7 @@ dependencies: - pytest-cov - coverage - ccache + - dask - pytorch - pytorch-cpu - polars diff --git a/build_tools/update_environments_and_lock_files.py b/build_tools/update_environments_and_lock_files.py index 0edf62b5a0d7b..5f716cb9f0aea 100644 --- a/build_tools/update_environments_and_lock_files.py +++ b/build_tools/update_environments_and_lock_files.py @@ -118,6 +118,7 @@ def remove_from(alist, to_remove): "conda_dependencies": common_dependencies + [ "ccache", + "dask", "pytorch", "pytorch-cpu", "polars", diff --git a/doc/modules/array_api.rst b/doc/modules/array_api.rst index b4940eccec2fc..a545a17ca8120 100644 --- a/doc/modules/array_api.rst +++ b/doc/modules/array_api.rst @@ -36,6 +36,10 @@ explicitly as explained in the following. Currently, only `array-api-strict`, `cupy`, and `PyTorch` are known to work with scikit-learn's estimators. + `dask.array` support is incomplete at the time of writing: some methods and + estimators may not work while we work out a way to handle Dask's lazy evaluation + semantics in a library-agnostic way. + The following video provides an overview of the standard's design principles and how it facilitates interoperability between array libraries: diff --git a/doc/whats_new/v1.5.rst b/doc/whats_new/v1.5.rst index 1ce5aa4839426..f6658b47fca44 100644 --- a/doc/whats_new/v1.5.rst +++ b/doc/whats_new/v1.5.rst @@ -211,6 +211,11 @@ See :ref:`array_api` for more details. **Classes:** +**Libraries:** + +- ``dask.array`` is now experimentally supported as an array API backend. + Some methods and estimators may not work with dask. + :pr:`28588` by :user:`Thomas Li ` - :class:`linear_model.Ridge` now supports the Array API for the `svd` solver. See :ref:`array_api` for more details. :pr:`27800` by :user:`Franck Charras `, :user:`Olivier Grisel ` diff --git a/sklearn/_min_dependencies.py b/sklearn/_min_dependencies.py index 03fd53d047249..e0a4228a8bedc 100644 --- a/sklearn/_min_dependencies.py +++ b/sklearn/_min_dependencies.py @@ -19,6 +19,7 @@ # It will NOT be included in setup's extras_require # The values are (version_spec, comma separated tags) dependent_packages = { + "array-api-compat": ("1.5.1", "tests"), "numpy": (NUMPY_MIN_VERSION, "build, install"), "scipy": (SCIPY_MIN_VERSION, "build, install"), "joblib": (JOBLIB_MIN_VERSION, "install"), diff --git a/sklearn/conftest.py b/sklearn/conftest.py index 6af3a2a51c0ce..2c6910dab5c1d 100644 --- a/sklearn/conftest.py +++ b/sklearn/conftest.py @@ -363,6 +363,27 @@ def print_changed_only_false(): set_config(print_changed_only=True) # reset to default +@pytest.fixture +def skip_dask_array_api_compliance(request): + """ + Xfails an array API compliance test for dask. + (i.e. when the array_namespace fixture yields 'dask.array') + + When using this fixture, please insert a comment to explain what particular + aspect of Dask is preventing the tests to pass, e.g. missing module level + function or array level method, value-dependent shape item values or array + assignments with a value-dependent boolean mask. + """ + array_namespace = request.getfixturevalue("array_namespace") + if array_namespace == "dask.array": + pytest.skip( + reason=( + "Estimator/method does not work because of dask array API compliance" + " issues" + ) + ) + + if dt_config is not None: # Strict mode to differentiate between 3.14 and np.float64(3.14) dt_config.strict_check = True diff --git a/sklearn/decomposition/_base.py b/sklearn/decomposition/_base.py index 13202d56c50f4..70be5753bcb79 100644 --- a/sklearn/decomposition/_base.py +++ b/sklearn/decomposition/_base.py @@ -47,7 +47,7 @@ def get_covariance(self): xp.asarray(0.0, device=device(exp_var), dtype=exp_var.dtype), ) cov = (components_.T * exp_var_diff) @ components_ - _fill_or_add_to_diagonal(cov, self.noise_variance_, xp) + cov = _fill_or_add_to_diagonal(cov, self.noise_variance_, xp) return cov def get_precision(self): @@ -89,10 +89,10 @@ def get_precision(self): xp.asarray(0.0, device=device(exp_var)), ) precision = components_ @ components_.T / self.noise_variance_ - _fill_or_add_to_diagonal(precision, 1.0 / exp_var_diff, xp) + precision = _fill_or_add_to_diagonal(precision, 1.0 / exp_var_diff, xp) precision = components_.T @ linalg_inv(precision) @ components_ precision /= -(self.noise_variance_**2) - _fill_or_add_to_diagonal(precision, 1.0 / self.noise_variance_, xp) + precision = _fill_or_add_to_diagonal(precision, 1.0 / self.noise_variance_, xp) return precision @abstractmethod diff --git a/sklearn/decomposition/tests/test_pca.py b/sklearn/decomposition/tests/test_pca.py index 2b97138c4dea3..8b5608dd94bfb 100644 --- a/sklearn/decomposition/tests/test_pca.py +++ b/sklearn/decomposition/tests/test_pca.py @@ -13,6 +13,7 @@ from sklearn.decomposition import PCA from sklearn.decomposition._pca import _assess_dimension, _infer_dimension from sklearn.utils._array_api import ( + _array_api_skips, _atol_for_type, _convert_to_numpy, _get_namespace_device_dtype_ids, @@ -1036,8 +1037,14 @@ def check_array_api_get_precision(name, estimator, array_namespace, device, dtyp def test_pca_array_api_compliance( estimator, check, array_namespace, device, dtype_name ): + skip_methods = _array_api_skips["PCA"] name = estimator.__class__.__name__ - check(name, estimator, array_namespace, device=device, dtype_name=dtype_name) + kwargs = {} + if check is check_array_api_input_and_values: + kwargs = {"skip_methods": skip_methods} + check( + name, estimator, array_namespace, device=device, dtype_name=dtype_name, **kwargs + ) @pytest.mark.parametrize( diff --git a/sklearn/discriminant_analysis.py b/sklearn/discriminant_analysis.py index 6df26a05a8781..d13960ad0c7c9 100644 --- a/sklearn/discriminant_analysis.py +++ b/sklearn/discriminant_analysis.py @@ -20,7 +20,7 @@ from .covariance import empirical_covariance, ledoit_wolf, shrunk_covariance from .linear_model._base import LinearClassifierMixin from .preprocessing import StandardScaler -from .utils._array_api import _expit, device, get_namespace, size +from .utils._array_api import _expit, device, get_namespace, size, xpx from .utils._param_validation import HasMethods, Interval, StrOptions from .utils.extmath import softmax from .utils.multiclass import check_classification_targets, unique_labels @@ -106,11 +106,12 @@ def _class_means(X, y): Class means. """ xp, is_array_api_compliant = get_namespace(X) - classes, y = xp.unique_inverse(y) - means = xp.zeros((classes.shape[0], X.shape[1]), device=device(X), dtype=X.dtype) + n_classes = xpx.nunique(y) + _, y = xp.unique_inverse(y) + means = xp.zeros((n_classes, X.shape[1]), device=device(X), dtype=X.dtype) if is_array_api_compliant: - for i in range(classes.shape[0]): + for i in range(n_classes): means[i, :] = xp.mean(X[y == i], axis=0) else: # TODO: Explore the choice of using bincount + add.at as it seems sub optimal @@ -577,20 +578,29 @@ def _solve_svd(self, X, y): svd = scipy.linalg.svd n_samples, n_features = X.shape - n_classes = self.classes_.shape[0] + # TODO: this is a duplicate computation + # in + n_classes = int(xpx.nunique(y)) self.means_ = _class_means(X, y) if self.store_covariance: self.covariance_ = _class_cov(X, y, self.priors_) - Xc = [] - for idx, group in enumerate(self.classes_): - Xg = X[y == group] - Xc.append(Xg - self.means_[idx, :]) - - self.xbar_ = self.priors_ @ self.means_ - - Xc = xp.concat(Xc, axis=0) + def calc_xc(classes): + Xc = [] + for idx, group in enumerate(classes): + Xg = X[y == group] + Xc.append(Xg - self.means_[idx, :]) + Xc = xp.concat(Xc, axis=0) + return Xc + + Xc = xpx.lazy_apply(calc_xc, self.classes_, shape=(n_samples, n_features)) + self.xbar_ = xpx.lazy_apply( + lambda priors, means: priors @ means, + self.priors_, + self.means_, + shape=(n_classes, n_features), + ) # 1) within (univariate) scaling by with classes std-dev std = xp.std(Xc, axis=0) diff --git a/sklearn/linear_model/_ridge.py b/sklearn/linear_model/_ridge.py index c22690b2b01c6..52da97a5a9fc4 100644 --- a/sklearn/linear_model/_ridge.py +++ b/sklearn/linear_model/_ridge.py @@ -287,10 +287,13 @@ def _solve_svd(X, y, alpha, xp=None): xp, _ = get_namespace(X, xp=xp) U, s, Vt = xp.linalg.svd(X, full_matrices=False) idx = s > 1e-15 # same default value as scipy.linalg.pinv - s_nnz = s[idx][:, None] + s = s[:, None] UTy = U.T @ y d = xp.zeros((s.shape[0], alpha.shape[0]), dtype=X.dtype, device=device(X)) - d[idx] = s_nnz / (s_nnz**2 + alpha) + + # Use where to do the equivalent of boolean indexing for + d = xp.where(idx[:, None], s / (s**2 + alpha), d) + d_UT_y = d * UTy return (Vt.T @ d_UT_y).T diff --git a/sklearn/metrics/_regression.py b/sklearn/metrics/_regression.py index 9be9f1d954fcc..8f2d8ac821bc5 100644 --- a/sklearn/metrics/_regression.py +++ b/sklearn/metrics/_regression.py @@ -951,8 +951,8 @@ def _assemble_r2_explained_variance( # Non-zero Numerator and Non-zero Denominator: use the formula valid_score = nonzero_denominator & nonzero_numerator - output_scores[valid_score] = 1 - ( - numerator[valid_score] / denominator[valid_score] + output_scores = xp.where( + valid_score, 1 - numerator / denominator, output_scores ) # Non-zero Numerator and Zero Denominator: diff --git a/sklearn/metrics/pairwise.py b/sklearn/metrics/pairwise.py index cca8f2b6ae1c7..209155594c1df 100644 --- a/sklearn/metrics/pairwise.py +++ b/sklearn/metrics/pairwise.py @@ -433,7 +433,7 @@ def _euclidean_distances(X, Y, X_norm_squared=None, Y_norm_squared=None, squared # Ensure that distances between vectors and themselves are set to 0.0. # This may not be the case due to floating point rounding errors. if X is Y: - _fill_or_add_to_diagonal(distances, 0, xp=xp, add_value=False) + distances = _fill_or_add_to_diagonal(distances, 0, xp=xp, add_value=False) if squared: return distances @@ -1171,7 +1171,7 @@ def cosine_distances(X, Y=None): if X is Y or Y is None: # Ensure that distances between vectors and themselves are set to 0.0. # This may not be the case due to floating point rounding errors. - _fill_or_add_to_diagonal(S, 0.0, xp, add_value=False) + S = _fill_or_add_to_diagonal(S, 0.0, xp, add_value=False) return S diff --git a/sklearn/metrics/tests/test_common.py b/sklearn/metrics/tests/test_common.py index 6f9e11d4f4780..ab8a8094bfb93 100644 --- a/sklearn/metrics/tests/test_common.py +++ b/sklearn/metrics/tests/test_common.py @@ -72,6 +72,7 @@ from sklearn.preprocessing import LabelBinarizer from sklearn.utils import shuffle from sklearn.utils._array_api import ( + _array_api_skips, _atol_for_type, _convert_to_numpy, _get_namespace_device_dtype_ids, @@ -1843,6 +1844,12 @@ def test_metrics_pos_label_error_str(metric, y_pred_threshold, dtype_y_str): def check_array_api_metric( metric, array_namespace, device, dtype_name, a_np, b_np, **metric_kwargs ): + func_name = metric.func.__name__ if isinstance(metric, partial) else metric.__name__ + if _array_api_skips.get(func_name, {}).get(array_namespace) == "all": + pytest.skip( + f"{array_namespace} is not Array API compliant for {metric.__name__}" + ) + xp = _array_api_for_tests(array_namespace, device) a_xp = xp.asarray(a_np, device=device) diff --git a/sklearn/utils/_array_api.py b/sklearn/utils/_array_api.py index 48c941f3c6e85..7f25730490d22 100644 --- a/sklearn/utils/_array_api.py +++ b/sklearn/utils/_array_api.py @@ -16,12 +16,27 @@ from .._config import get_config from ..externals import array_api_compat from ..externals import array_api_extra as xpx +from ..externals.array_api_compat import is_dask_namespace, is_lazy_array from ..externals.array_api_compat import numpy as np_compat from .fixes import parse_version # TODO: complete __all__ __all__ = ["xpx"] # we import xpx here just to re-export it, need this to appease ruff +# Dictionary listing the methods/estimators to skip +# testing for a certain array api namespace + +# use "all" to skip all testing for an estimator/method +# for a namespace (not just specific methods) +# (see the dask.array skip in LinearDiscriminantAnalysis for an example of this) +_array_api_skips = { + # Dask doesn't implement slogdet from the Array API + # which is used in score/score_samples + "PCA": {"dask.array": ["score", "score_samples"]}, + # Lazy evaluation semantics: value-dependent shape item value (nan): + # "LinearDiscriminantAnalysis": {"dask.array": "all"}, +} + _NUMPY_NAMESPACE_NAMES = {"numpy", "sklearn.externals.array_api_compat.numpy"} @@ -50,6 +65,7 @@ def yield_namespaces(include_numpy_namespaces=True): "array_api_strict", "cupy", "torch", + "dask.array", ]: if not include_numpy_namespaces and array_namespace in _NUMPY_NAMESPACE_NAMES: continue @@ -543,6 +559,10 @@ def _fill_or_add_to_diagonal(array, value, xp, add_value=True, wrap=False): ) value = xp.asarray(value, dtype=array.dtype, device=device(array)) + + # TODO: candidate for upstreaming to array-api-extra + # This can't work in-place for dask/jax + end = None # Explicit, fast formula for the common case. For 2-d arrays, we # accept rectangular ones. @@ -555,6 +575,10 @@ def _fill_or_add_to_diagonal(array, value, xp, add_value=True, wrap=False): array_flat[:end:step] += value else: array_flat[:end:step] = value + if is_dask_namespace(xp): + # hack to make sure correct value is returned for dask + return xp.reshape(array_flat, array.shape) + return array def _is_xp_namespace(xp, name): @@ -621,13 +645,15 @@ def _average(a, axis=None, weights=None, normalize=True, xp=None): weights = xp.asarray(weights, device=device_) if weights is not None and a.shape != weights.shape: - if axis is None: + # shape checks are disabled here for dask + # TODO: figure out a strategy for doing this across sklearn + if axis is None and not is_lazy_array(a): raise TypeError( f"Axis must be specified when the shape of a {tuple(a.shape)} and " f"weights {tuple(weights.shape)} differ." ) - if tuple(weights.shape) != (a.shape[axis],): + if tuple(weights.shape) != (a.shape[axis],) and not is_lazy_array(a): raise ValueError( f"Shape of weights weights.shape={tuple(weights.shape)} must be " f"consistent with a.shape={tuple(a.shape)} and {axis=}." @@ -910,6 +936,10 @@ def _in1d(ar1, ar2, xp, assume_unique=False, invert=False): present in numpy: https://github.com/numpy/numpy/blob/v1.26.0/numpy/lib/arraysetops.py#L524-L758 """ + if is_dask_namespace(xp): + import dask.array as da + + return da.isin(ar1, ar2, assume_unique, invert) xp, _ = get_namespace(ar1, ar2, xp=xp) # This code is run to make the code significantly faster diff --git a/sklearn/utils/estimator_checks.py b/sklearn/utils/estimator_checks.py index 5142de2348e2a..b29e968cff0f0 100644 --- a/sklearn/utils/estimator_checks.py +++ b/sklearn/utils/estimator_checks.py @@ -64,6 +64,7 @@ from ..preprocessing import StandardScaler, scale from ..utils import _safe_indexing from ..utils._array_api import ( + _array_api_skips, _atol_for_type, _convert_to_numpy, get_namespace, @@ -349,6 +350,7 @@ def _yield_array_api_checks(estimator): array_namespace=array_namespace, dtype_name=dtype_name, device=device, + skips=_array_api_skips.get(estimator.__class__.__name__, {}), ) @@ -1040,6 +1042,7 @@ def check_array_api_input( name, estimator_orig, array_namespace, + skips, device=None, dtype_name="float64", check_values=False, @@ -1051,7 +1054,14 @@ def check_array_api_input( When check_values is True, it also checks that calling the estimator on the array_api Array gives the same results as ndarrays. + + skips is a dictionary mapping the name of the array_namespace to skip to + the names of the methods to skip (for estimators), or the string "all" + (to skip all methods for this estimator) """ + if skips.get(array_namespace) == "all": + raise SkipTest(f"{array_namespace} is not Array API compliant for {name}") + xp = _array_api_for_tests(array_namespace, device) X, y = make_classification(random_state=42) @@ -1112,6 +1122,7 @@ def check_array_api_input( "transform", ) + methods_to_skip = skips.get(array_namespace, []) try: np.asarray(X_xp) np.asarray(y_xp) @@ -1148,8 +1159,11 @@ def check_array_api_input( for method_name in methods: method = getattr(est, method_name, None) - if method is None: - continue + if method is None or method_name in methods_to_skip: + raise SkipTest( + f"{array_namespace} is not Array API compliant for method" + f" {method_name} of {name}" + ) if method_name == "score": result = method(X, y) @@ -1159,6 +1173,8 @@ def check_array_api_input( assert isinstance(result, float) assert isinstance(result_xp, float) if check_values: + print(result) + print(result_xp) assert abs(result - result_xp) < _atol_for_type(X.dtype) continue else: @@ -1219,6 +1235,7 @@ def check_array_api_input_and_values( array_namespace, device=None, dtype_name="float64", + skip_methods={}, ): return check_array_api_input( name, @@ -1227,6 +1244,7 @@ def check_array_api_input_and_values( device=device, dtype_name=dtype_name, check_values=True, + skips=skip_methods, ) diff --git a/sklearn/utils/multiclass.py b/sklearn/utils/multiclass.py index 6c089069387be..5e4e5e485e44e 100644 --- a/sklearn/utils/multiclass.py +++ b/sklearn/utils/multiclass.py @@ -10,7 +10,7 @@ import numpy as np from scipy.sparse import issparse -from ..utils._array_api import get_namespace +from ..utils._array_api import get_namespace, xpx from ..utils.fixes import VisibleDeprecationWarning from ._unique import attach_unique, cached_unique from .validation import _assert_all_finite, check_array @@ -190,11 +190,12 @@ def is_multilabel(y): and (y.dtype.kind in "biu" or _is_integral_float(labels)) # bool, int, uint ) else: - labels = cached_unique(y, xp=xp) + # TODO: caching? + # labels = cached_unique(y, xp=xp) - return labels.shape[0] < 3 and ( + return int(xpx.nunique(y)) < 3 and ( xp.isdtype(y.dtype, ("bool", "signed integer", "unsigned integer")) - or _is_integral_float(labels) + or _is_integral_float(y) ) @@ -418,7 +419,8 @@ def _raise_or_return(): # Check multiclass if issparse(first_row_or_val): first_row_or_val = first_row_or_val.data - if cached_unique(y).shape[0] > 2 or (y.ndim == 2 and len(first_row_or_val) > 1): + # cast to int to force computation for Dask + if int(xpx.nunique(y)) > 2 or (y.ndim == 2 and len(first_row_or_val) > 1): # [1, 2, 3] or [[1., 2., 3]] or [[1, 2]] return "multiclass" + suffix else: diff --git a/sklearn/utils/tests/test_array_api.py b/sklearn/utils/tests/test_array_api.py index 164e3024a31e7..8bbfbcbd38346 100644 --- a/sklearn/utils/tests/test_array_api.py +++ b/sklearn/utils/tests/test_array_api.py @@ -583,7 +583,9 @@ def test_fill_or_add_to_diagonal(array_namespace, device_, dtype_name, wrap): xp = _array_api_for_tests(array_namespace, device_) array_np = numpy.zeros((5, 4), dtype=numpy.int64) array_xp = xp.asarray(array_np) - _fill_or_add_to_diagonal(array_xp, value=1, xp=xp, add_value=False, wrap=wrap) + array_xp = _fill_or_add_to_diagonal( + array_xp, value=1, xp=xp, add_value=False, wrap=wrap + ) numpy.fill_diagonal(array_np, val=1, wrap=wrap) assert_array_equal(_convert_to_numpy(array_xp, xp=xp), array_np) diff --git a/sklearn/utils/tests/test_estimator_checks.py b/sklearn/utils/tests/test_estimator_checks.py index 4e573c8d1793f..bb63d90eb6135 100644 --- a/sklearn/utils/tests/test_estimator_checks.py +++ b/sklearn/utils/tests/test_estimator_checks.py @@ -584,6 +584,7 @@ def test_check_array_api_input(): "BrokenArrayAPI", BrokenArrayAPI(), array_namespace="array_api_strict", + skips={}, check_values=True, ) diff --git a/sklearn/utils/tests/test_multiclass.py b/sklearn/utils/tests/test_multiclass.py index e361a93e41b10..d44994d9b961f 100644 --- a/sklearn/utils/tests/test_multiclass.py +++ b/sklearn/utils/tests/test_multiclass.py @@ -39,6 +39,8 @@ multilabel_explicit_zero = np.array([[0, 1], [1, 0]]) multilabel_explicit_zero[:, 0] = 0 +skip_dask = pytest.mark.usefixtures("skip_dask_array_api_compliance") + def _generate_sparse( data, @@ -382,6 +384,7 @@ def test_is_multilabel(): ), f"is_multilabel({example!r}) should be {dense_exp}" +@skip_dask # lazy evaluation semantics for value-dependent shape values @pytest.mark.parametrize( "array_namespace, device, dtype_name", yield_namespace_device_dtype_combinations(),