From 70536ac4408c9d9f4b55e3fea018abb97a3d43de Mon Sep 17 00:00:00 2001 From: SIKAI ZHANG <34108862+MatthewSZhang@users.noreply.github.com> Date: Wed, 9 Apr 2025 15:48:14 +0800 Subject: [PATCH 1/3] ENH speed up grad computation via Cython --- fastcan/_cancorr_fast.pyx | 6 +- fastcan/_fastcan.py | 2 +- fastcan/_narx_fast.pyx | 113 ++++++++++++++ fastcan/meson.build | 8 + fastcan/narx.py | 202 +++++++++++++++---------- pixi.lock | 302 ++++++++++++++++++-------------------- tests/test_narx_jac.py | 49 ++++--- 7 files changed, 420 insertions(+), 262 deletions(-) create mode 100644 fastcan/_narx_fast.pyx diff --git a/fastcan/_cancorr_fast.pyx b/fastcan/_cancorr_fast.pyx index ba3fb4d..5d8cea4 100644 --- a/fastcan/_cancorr_fast.pyx +++ b/fastcan/_cancorr_fast.pyx @@ -11,7 +11,7 @@ from cython.parallel import prange from scipy.linalg.cython_blas cimport isamax, idamax from sklearn.utils._cython_blas cimport ColMajor, NoTrans from sklearn.utils._cython_blas cimport _dot, _scal, _nrm2, _gemm, _axpy -from sklearn.utils._typedefs cimport int32_t, uint8_t +from sklearn.utils._typedefs cimport uint8_t @final @@ -106,7 +106,7 @@ cdef floating _sscvm( cdef void _mgsvv( const floating* w, # IN const floating* x, # IN/OUT - int n_samples, # IN + int n_samples, # IN ) noexcept nogil: """ Modified Gram-Schmidt process. x = x - w*w.T*x @@ -133,7 +133,7 @@ cpdef int _forward_search( int num_threads, # IN int verbose, # IN uint8_t[::1] mask, # IN/TEMP - int32_t[::1] indices, # OUT + int[::1] indices, # OUT floating[::1] scores, # OUT ) except -1 nogil: """ diff --git a/fastcan/_fastcan.py b/fastcan/_fastcan.py index 2441858..01af376 100644 --- a/fastcan/_fastcan.py +++ b/fastcan/_fastcan.py @@ -293,7 +293,7 @@ def _get_support_mask(self): def _prepare_search(n_features, n_features_to_select, indices_include, indices_exclude): # initiated with -1 - indices = np.full(n_features_to_select, -1, dtype=np.intc, order="F") + indices = np.full(n_features_to_select, -1, dtype=np.int32, order="F") indices[: indices_include.size] = indices_include scores = np.zeros(n_features_to_select, dtype=float, order="F") mask = np.zeros(n_features, dtype=np.ubyte, order="F") diff --git a/fastcan/_narx_fast.pyx b/fastcan/_narx_fast.pyx new file mode 100644 index 0000000..85d46ca --- /dev/null +++ b/fastcan/_narx_fast.pyx @@ -0,0 +1,113 @@ +""" +Fast gradient computation for narx +""" +# Authors: The fastcan developers +# SPDX-License-Identifier: MIT + +from cython cimport floating, final + + +@final +cpdef void _update_terms( + const floating[:, ::1] X, # IN + const floating[:, ::1] y_hat, # IN + floating[::1] terms, # OUT + const int[:, ::1] feat_ids, # IN + const int[:, ::1] delay_ids, # IN + const int k, # IN +) noexcept nogil: + """ + Evaluate all terms for the given features and delays at timestep k. + """ + cdef: + int i + int n_coefs = feat_ids.shape[0] + + for i in range(n_coefs): + terms[i] = _evaluate_term( + X, y_hat, feat_ids[i], delay_ids[i], k + ) + + +@final +cpdef void _predict_step( + const floating[:, ::1] X, # IN + const floating[:, ::1] y_hat, # IN + floating[::1] y_pred, # OUT + const floating[::1] coef, # IN + const int[:, ::1] feat_ids, # IN + const int[:, ::1] delay_ids, # IN + const int[::1] output_ids, # IN + const int k, # IN +) noexcept nogil: + """ + Evaluate the expression for all outputs at timestep k. + """ + cdef: + int n_terms = feat_ids.shape[0] + int i, output_i + + # Add all terms + for i in range(n_terms): + output_i = output_ids[i] + y_pred[output_i] += coef[i] * _evaluate_term( + X, y_hat, feat_ids[i], delay_ids[i], k + ) + + +@final +cdef floating _evaluate_term( + const floating[:, ::1] X, # IN + const floating[:, ::1] y_hat, # IN + const int[::1] feat_ids, # IN + const int[::1] delay_ids, # IN + const int k, # IN +) noexcept nogil: + """ + Evaluate a term based on feature and delay IDs. + """ + cdef: + int n_feats = X.shape[1] + int n_vars = feat_ids.shape[0] + floating term = 1.0 + int i, feat_id + + for i in range(n_vars): + feat_id = feat_ids[i] + if feat_id != -1: + if feat_id < n_feats: + term *= X[k - delay_ids[i], feat_id] + else: + term *= y_hat[k - delay_ids[i], feat_id - n_feats] + + return term + + +@final +cpdef void _update_cfd( + const floating[:, ::1] X, # IN + const floating[:, ::1] y_hat, # IN + floating[:, :, ::1] cfd, # OUT + const floating[::1] coef, # IN + const int[:, ::1] grad_yyd_ids, # IN + const int[::1] grad_coef_ids, # IN + const int[:, ::1] grad_feat_ids, # IN + const int[:, ::1] grad_delay_ids, # IN + const int k, # IN +) noexcept nogil: + """ + Updates CFD matrix based on the current state. + """ + cdef: + int n_grad_terms = grad_yyd_ids.shape[0] + int i, row_y_id, col_y_id, delay_id_1 + + for i in range(n_grad_terms): + row_y_id = grad_yyd_ids[i, 0] + col_y_id = grad_yyd_ids[i, 1] + delay_id_1 = grad_yyd_ids[i, 2] + + cfd[row_y_id, col_y_id, delay_id_1] += coef[grad_coef_ids[i]] * \ + _evaluate_term( + X, y_hat, grad_feat_ids[i], grad_delay_ids[i], k + ) diff --git a/fastcan/meson.build b/fastcan/meson.build index 934ad7a..402f933 100644 --- a/fastcan/meson.build +++ b/fastcan/meson.build @@ -13,4 +13,12 @@ py.extension_module( subdir: 'fastcan', cython_args: cython_args, install: true +) + +py.extension_module( + '_narx_fast', + '_narx_fast.pyx', + subdir: 'fastcan', + cython_args: cython_args, + install: true ) \ No newline at end of file diff --git a/fastcan/narx.py b/fastcan/narx.py index 288f11b..f5299f7 100644 --- a/fastcan/narx.py +++ b/fastcan/narx.py @@ -25,6 +25,7 @@ ) from ._fastcan import FastCan +from ._narx_fast import _predict_step, _update_cfd, _update_terms # type: ignore from ._refine import refine @@ -342,7 +343,8 @@ def _validate_feat_delay_ids( feat_ids_ = check_array( feat_ids, ensure_2d=True, - dtype=int, + dtype=np.int32, + order="C", ) if (feat_ids_.min() < -1) or (feat_ids_.max() > n_features + n_outputs - 1): raise ValueError( @@ -353,7 +355,8 @@ def _validate_feat_delay_ids( delay_ids_ = check_array( delay_ids, ensure_2d=True, - dtype=int, + dtype=np.int32, + order="C", ) if delay_ids_.shape != feat_ids_.shape: raise ValueError( @@ -692,9 +695,9 @@ def fit(self, X, y, sample_weight=None, coef_init=None, **params): self : object Fitted Estimator. """ - check_X_params = dict(dtype=float, ensure_all_finite="allow-nan") + check_X_params = dict(dtype=float, order="C", ensure_all_finite="allow-nan") check_y_params = dict( - ensure_2d=False, dtype=float, ensure_all_finite="allow-nan" + ensure_2d=False, dtype=float, order="C", ensure_all_finite="allow-nan" ) X, y = validate_data( self, X, y, validate_separately=(check_X_params, check_y_params) @@ -732,11 +735,11 @@ def fit(self, X, y, sample_weight=None, coef_init=None, **params): n_terms = self.feat_ids_.shape[0] # Validate output_ids if self.output_ids is None: - self.output_ids_ = np.zeros(n_terms, dtype=int) + self.output_ids_ = np.zeros(n_terms, dtype=np.int32) else: self.output_ids_ = column_or_1d( self.output_ids, - dtype=int, + dtype=np.int32, warn=True, ) if len(self.output_ids_) != n_terms: @@ -806,7 +809,7 @@ def fit(self, X, y, sample_weight=None, coef_init=None, **params): f"({(n_coef_intercept,)}), but got {coef_init.shape}." ) - cfd_ids = NARX._get_cfd_ids( + grad_yyd_ids, grad_coef_ids, grad_feat_ids, grad_delay_ids = NARX._get_cfd_ids( self.feat_ids_, self.delay_ids_, self.output_ids_, X.shape[1] ) sample_weight_sqrt = np.sqrt(sample_weight).reshape(-1, 1) @@ -815,14 +818,17 @@ def fit(self, X, y, sample_weight=None, coef_init=None, **params): x0=coef_init, jac=NARX._grad, args=( - NARX._expression, + _predict_step, X, y, self.feat_ids_, self.delay_ids_, self.output_ids_, sample_weight_sqrt, - cfd_ids, + grad_yyd_ids, + grad_coef_ids, + grad_feat_ids, + grad_delay_ids, ), **params, ) @@ -830,31 +836,16 @@ def fit(self, X, y, sample_weight=None, coef_init=None, **params): self.intercept_ = res.x[-self.n_outputs_ :] return self - @staticmethod - def _evaluate_term(feat_ids, delay_ids, X, y_hat, k): - n_features_in = X.shape[1] - term = 1 - for i, feat_id in enumerate(feat_ids): - if feat_id != -1: - if feat_id < n_features_in: - term *= X[k - delay_ids[i], feat_id] - else: - term *= y_hat[k - delay_ids[i], feat_id - n_features_in] - return term - - @staticmethod - def _expression(X, y_hat, coef, intercept, feat_ids, delay_ids, output_ids, k): - y_pred = np.copy(intercept) - for i, feat_id in enumerate(feat_ids): - output_i = output_ids[i] - y_pred[output_i] += coef[i] * NARX._evaluate_term( - feat_id, delay_ids[i], X, y_hat, k - ) - return y_pred - @staticmethod def _predict( - expression, X, y_ref, coef, intercept, feat_ids, delay_ids, output_ids + expression, + X, + y_ref, + coef, + intercept, + feat_ids, + delay_ids, + output_ids, ): n_samples = X.shape[0] n_ref, n_outputs = y_ref.shape @@ -874,8 +865,16 @@ def _predict( if at_init: y_hat[k] = y_ref[k % n_ref] else: - y_hat[k] = expression( - X, y_hat, coef, intercept, feat_ids, delay_ids, output_ids, k + y_hat[k] = intercept + expression( + X, + y_hat, + y_hat[k], + coef, + feat_ids, + delay_ids, + output_ids, + k, ) if np.any(y_hat[k] > 1e20): y_hat[k:] = 1e20 @@ -888,58 +887,50 @@ def _get_cfd_ids(feat_ids, delay_ids, output_ids, n_features_in): Get ids of CFD (Coef, Feature, and Delay) matrix to update dyn(k)/dx. Maps coefficients to their corresponding features and delays. """ - n_outputs = np.max(output_ids) + 1 - max_delay = np.max(delay_ids) # Initialize cfd_ids as a list of lists n_outputs * n_outputs * max_delay # axis-0 (i): [dy0(k)/dx, dy1(k)/dx, ..., dyn(k)/dx] # axis-1 (j): [dy0(k-d)/dx, dy1(k-d)/dx, ..., dyn(k-d)/dx] # axis-2 (d): [dyj(k-1)/dx, dyj(k-2)/dx, ..., dyj(k-max_delay)/dx] - cfd_ids = [ - [[[] for _ in range(max_delay)] for _ in range(n_outputs)] - for _ in range(n_outputs) - ] + grad_yyd_ids = [] + grad_coef_ids = [] + grad_feat_ids = [] + grad_delay_ids = [] for coef_id, (term_feat_ids, term_delay_ids) in enumerate( zip(feat_ids, delay_ids) ): - row_y_id = output_ids[coef_id] + row_y_id = output_ids[coef_id] # y(k, id) for var_id, (feat_id, delay_id) in enumerate( zip(term_feat_ids, term_delay_ids) ): if feat_id >= n_features_in and delay_id > 0: - col_y_id = feat_id - n_features_in - cfd_ids[row_y_id][col_y_id][delay_id - 1].append( - [ - coef_id, - np.delete(term_feat_ids, var_id), - np.delete(term_delay_ids, var_id), - ] - ) - - return cfd_ids - - @staticmethod - def _update_cfd(X, y_hat, coef, cfd_ids, k): - """ - Updates CFD matrix based on the current state. - """ - n_outputs, max_delay = y_hat.shape[1], len(cfd_ids[0][0]) - cfd = np.zeros((n_outputs, n_outputs, max_delay)) - - for i, yi_ids in enumerate(cfd_ids): - for j, yiyj in enumerate(yi_ids): - for d, yiyjd in enumerate(yiyj): - if yiyjd: - cfd[i, j, d] = sum( - coef[coef_id] - * NARX._evaluate_term(feat_id, delay_id, X, y_hat, k) - for coef_id, feat_id, delay_id in yiyjd - ) - return cfd + col_y_id = feat_id - n_features_in # y(k-1, id) + grad_yyd_ids.append([row_y_id, col_y_id, delay_id - 1]) + grad_coef_ids.append(coef_id) + grad_feat_ids.append(np.delete(term_feat_ids, var_id)) + grad_delay_ids.append(np.delete(term_delay_ids, var_id)) + + return ( + np.array(grad_yyd_ids, dtype=np.int32), + np.array(grad_coef_ids, dtype=np.int32), + np.array(grad_feat_ids, dtype=np.int32), + np.array(grad_delay_ids, dtype=np.int32), + ) @staticmethod - def _update_dydx(X, y_hat, coef, feat_ids, delay_ids, output_ids, cfd_ids): + def _update_dydx( + X, + y_hat, + coef, + feat_ids, + delay_ids, + output_ids, + grad_yyd_ids, + grad_coef_ids, + grad_feat_ids, + grad_delay_ids, + ): """ Computation of the Jacobian matrix dydx. @@ -970,15 +961,32 @@ def _update_dydx(X, y_hat, coef, feat_ids, delay_ids, output_ids, cfd_ids): continue # Compute terms for time step k terms = np.ones(n_x, dtype=float) - for j in range(n_coefs): - terms[j] = NARX._evaluate_term(feat_ids[j], delay_ids[j], X, y_hat, k) + _update_terms( + X, + y_hat, + terms, + feat_ids, + delay_ids, + k, + ) # Update constant terms of Jacobian dydx[k, y_ids, x_ids] = terms # Update dynamic terms of Jacobian + cfd = np.zeros((n_y, n_y, max_delay), dtype=float) if max_delay > 0: - cfd = NARX._update_cfd(X, y_hat, coef, cfd_ids, k) + _update_cfd( + X, + y_hat, + cfd, + coef, + grad_yyd_ids, + grad_coef_ids, + grad_feat_ids, + grad_delay_ids, + k, + ) for d in range(max_delay): dydx[k] += cfd[:, :, d] @ dydx[k - d - 1] @@ -1007,7 +1015,14 @@ def _loss( intercept = coef_intercept[-n_outputs:] y_hat = NARX._predict( - expression, X, y, coef, intercept, feat_ids, delay_ids, output_ids + expression, + X, + y, + coef, + intercept, + feat_ids, + delay_ids, + output_ids, ) y_masked, y_hat_masked, sample_weight_sqrt_masked = _mask_missing_value( @@ -1026,7 +1041,10 @@ def _grad( delay_ids, output_ids, sample_weight_sqrt, - cfd_ids, + grad_yyd_ids, + grad_coef_ids, + grad_feat_ids, + grad_delay_ids, ): # Sum of squared errors n_outputs = y.shape[1] @@ -1034,10 +1052,26 @@ def _grad( intercept = coef_intercept[-n_outputs:] y_hat = NARX._predict( - expression, X, y, coef, intercept, feat_ids, delay_ids, output_ids + expression, + X, + y, + coef, + intercept, + feat_ids, + delay_ids, + output_ids, ) dydx = NARX._update_dydx( - X, y_hat, coef, feat_ids, delay_ids, output_ids, cfd_ids + X, + y_hat, + coef, + feat_ids, + delay_ids, + output_ids, + grad_yyd_ids, + grad_coef_ids, + grad_feat_ids, + grad_delay_ids, ) mask_nomissing = _mask_missing_value( @@ -1075,7 +1109,14 @@ def predict(self, X, y_init=None): """ check_is_fitted(self) - X = validate_data(self, X, reset=False, ensure_all_finite="allow-nan") + X = validate_data( + self, + X, + dtype=float, + order="C", + reset=False, + ensure_all_finite="allow-nan", + ) if y_init is None: y_init = np.zeros((self.max_delay_, self.n_outputs_)) else: @@ -1093,9 +1134,8 @@ def predict(self, X, y_init=None): f"`y_init` should have {self.n_outputs_} outputs " f"but got {y_init.shape[1]}." ) - y_hat = NARX._predict( - NARX._expression, + _predict_step, X, y_init, self.coef_, diff --git a/pixi.lock b/pixi.lock index 8ed8c9e..c2ecfcd 100644 --- a/pixi.lock +++ b/pixi.lock @@ -37,7 +37,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/linux-64/ncurses-6.5-h2d0b736_3.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/ninja-1.12.1-h297d8ca_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/numpy-2.2.4-py313h17eae1a_0.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/openssl-3.4.1-h7b32b05_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/openssl-3.5.0-h7b32b05_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/packaging-24.2-pyhd8ed1ab_2.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pyproject-metadata-0.9.1-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/python-3.13.2-hf636f53_101_cp313.conda @@ -57,11 +57,11 @@ environments: - conda: https://conda.anaconda.org/conda-forge/osx-64/ca-certificates-2025.1.31-h8857fd0_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/cctools-1010.6-ha66f10e_6.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/cctools_osx-64-1010.6-hd19c6af_6.conda - - conda: https://conda.anaconda.org/conda-forge/osx-64/clang-18-18.1.8-default_h3571c67_8.conda - - conda: https://conda.anaconda.org/conda-forge/osx-64/clang-18.1.8-default_h576c50e_8.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/clang-18-18.1.8-default_h3571c67_9.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/clang-18.1.8-default_h576c50e_9.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/clang_impl_osx-64-18.1.8-h6a44ed1_24.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/clang_osx-64-18.1.8-h7e5c614_24.conda - - conda: https://conda.anaconda.org/conda-forge/osx-64/clangxx-18.1.8-default_heb2e8d1_8.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/clangxx-18.1.8-default_heb2e8d1_9.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/clangxx_impl_osx-64-18.1.8-h4b7810f_24.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/clangxx_osx-64-18.1.8-h7e5c614_24.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/compiler-rt-18.1.8-h1020d70_1.conda @@ -81,7 +81,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/osx-64/ld64_osx-64-951.9-h33512f0_6.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/libblas-3.9.0-31_h7f60823_openblas.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/libcblas-3.9.0-31_hff6cab4_openblas.conda - - conda: https://conda.anaconda.org/conda-forge/osx-64/libclang-cpp18.1-18.1.8-default_h3571c67_8.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/libclang-cpp18.1-18.1.8-default_h3571c67_9.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/libcxx-20.1.2-hf95d169_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/libcxx-devel-18.1.8-h7c275be_8.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/libexpat-2.7.0-h240833e_0.conda @@ -108,7 +108,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/osx-64/ncurses-6.5-h0622a9a_3.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/ninja-1.12.1-h3c5361c_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/numpy-2.2.4-py313hc518a0f_0.conda - - conda: https://conda.anaconda.org/conda-forge/osx-64/openssl-3.4.1-hc426f3f_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/openssl-3.5.0-hc426f3f_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/packaging-24.2-pyhd8ed1ab_2.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pyproject-metadata-0.9.1-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/python-3.13.2-h534c281_101_cp313.conda @@ -132,11 +132,11 @@ environments: - conda: https://conda.anaconda.org/conda-forge/osx-arm64/ca-certificates-2025.1.31-hf0a4a13_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/cctools-1010.6-hb4fb6a3_6.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/cctools_osx-arm64-1010.6-h3b4f5d3_6.conda - - conda: https://conda.anaconda.org/conda-forge/osx-arm64/clang-18-18.1.8-default_hf90f093_8.conda - - conda: https://conda.anaconda.org/conda-forge/osx-arm64/clang-18.1.8-default_h474c9e2_8.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/clang-18-18.1.8-default_hf90f093_9.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/clang-18.1.8-default_h474c9e2_9.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/clang_impl_osx-arm64-18.1.8-h2ae9ea5_24.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/clang_osx-arm64-18.1.8-h07b0088_24.conda - - conda: https://conda.anaconda.org/conda-forge/osx-arm64/clangxx-18.1.8-default_h1ffe849_8.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/clangxx-18.1.8-default_h1ffe849_9.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/clangxx_impl_osx-arm64-18.1.8-h555f467_24.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/clangxx_osx-arm64-18.1.8-h07b0088_24.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/compiler-rt-18.1.8-h856b3c1_1.conda @@ -155,7 +155,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/osx-arm64/ld64_osx-arm64-951.9-hb6b49e2_6.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libblas-3.9.0-31_h10e41b3_openblas.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libcblas-3.9.0-31_hb3479ef_openblas.conda - - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libclang-cpp18.1-18.1.8-default_hf90f093_8.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libclang-cpp18.1-18.1.8-default_hf90f093_9.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libcxx-20.1.2-ha82da77_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libcxx-devel-18.1.8-h6dc3340_8.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libexpat-2.7.0-h286801f_0.conda @@ -182,7 +182,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/osx-arm64/ncurses-6.5-h5e97a16_3.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/ninja-1.12.1-h420ef59_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/numpy-2.2.4-py313h41a2e72_0.conda - - conda: https://conda.anaconda.org/conda-forge/osx-arm64/openssl-3.4.1-h81ee809_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/openssl-3.5.0-h81ee809_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/packaging-24.2-pyhd8ed1ab_2.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pyproject-metadata-0.9.1-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/python-3.13.2-h81fe080_101_cp313.conda @@ -224,7 +224,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/win-64/mkl-2024.2.2-h66d3029_15.conda - conda: https://conda.anaconda.org/conda-forge/win-64/ninja-1.12.1-hc790b64_0.conda - conda: https://conda.anaconda.org/conda-forge/win-64/numpy-2.2.4-py313hefb8edb_0.conda - - conda: https://conda.anaconda.org/conda-forge/win-64/openssl-3.4.1-ha4e3fda_0.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/openssl-3.5.0-ha4e3fda_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/packaging-24.2-pyhd8ed1ab_2.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pyproject-metadata-0.9.1-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/win-64/python-3.13.2-h261c0b1_101_cp313.conda @@ -301,7 +301,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/linux-64/graphite2-1.3.13-h59595ed_1003.conda - conda: https://conda.anaconda.org/conda-forge/noarch/h11-0.14.0-pyhd8ed1ab_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/h2-4.2.0-pyhd8ed1ab_0.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/harfbuzz-11.0.0-h76408a6_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/harfbuzz-11.0.1-h2c12942_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/hpack-4.1.0-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/httpcore-1.0.7-pyh29332c3_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/httpx-0.28.1-pyhd8ed1ab_0.conda @@ -312,7 +312,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/noarch/importlib_resources-6.5.2-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/iniconfig-2.0.0-pyhd8ed1ab_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/ipykernel-6.29.5-pyh3099207_0.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/ipython-9.0.2-pyhfb0248b_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/ipython-9.1.0-pyhfb0248b_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/ipython_pygments_lexers-1.1.1-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/isoduration-20.11.0-pyhd8ed1ab_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/jedi-0.19.2-pyhd8ed1ab_1.conda @@ -393,8 +393,8 @@ environments: - conda: https://conda.anaconda.org/conda-forge/noarch/meson-python-0.17.1-pyh70fd9c4_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/mistune-3.1.3-pyh29332c3_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/munkres-1.1.4-pyh9f0ad1d_0.tar.bz2 - - conda: https://conda.anaconda.org/conda-forge/linux-64/mysql-common-9.0.1-h266115a_5.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/mysql-libs-9.0.1-he0572af_5.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/mysql-common-9.0.1-h266115a_6.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/mysql-libs-9.0.1-he0572af_6.conda - conda: https://conda.anaconda.org/conda-forge/noarch/nbclient-0.10.2-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/nbconvert-core-7.16.6-pyh29332c3_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/nbformat-5.10.4-pyhd8ed1ab_1.conda @@ -406,7 +406,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/linux-64/numpy-2.2.4-py313h17eae1a_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/openjpeg-2.5.3-h5fbd93e_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/openldap-2.6.9-he970967_0.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/openssl-3.4.1-h7b32b05_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/openssl-3.5.0-h7b32b05_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/overrides-7.7.0-pyhd8ed1ab_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/packaging-24.2-pyhd8ed1ab_2.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/pandas-2.2.3-py313ha87cce1_1.conda @@ -551,11 +551,11 @@ environments: - conda: https://conda.anaconda.org/conda-forge/noarch/certifi-2025.1.31-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/cffi-1.17.1-py313h49682b3_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/charset-normalizer-3.4.1-pyhd8ed1ab_0.conda - - conda: https://conda.anaconda.org/conda-forge/osx-64/clang-18-18.1.8-default_h3571c67_8.conda - - conda: https://conda.anaconda.org/conda-forge/osx-64/clang-18.1.8-default_h576c50e_8.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/clang-18-18.1.8-default_h3571c67_9.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/clang-18.1.8-default_h576c50e_9.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/clang_impl_osx-64-18.1.8-h6a44ed1_24.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/clang_osx-64-18.1.8-h7e5c614_24.conda - - conda: https://conda.anaconda.org/conda-forge/osx-64/clangxx-18.1.8-default_heb2e8d1_8.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/clangxx-18.1.8-default_heb2e8d1_9.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/clangxx_impl_osx-64-18.1.8-h4b7810f_24.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/clangxx_osx-64-18.1.8-h7e5c614_24.conda - conda: https://conda.anaconda.org/conda-forge/noarch/colorama-0.4.6-pyhd8ed1ab_1.conda @@ -593,7 +593,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/noarch/importlib_resources-6.5.2-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/iniconfig-2.0.0-pyhd8ed1ab_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/ipykernel-6.29.5-pyh57ce528_0.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/ipython-9.0.2-pyhfb0248b_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/ipython-9.1.0-pyhfb0248b_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/ipython_pygments_lexers-1.1.1-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/isl-0.26-imath32_h2e86a7b_101.conda - conda: https://conda.anaconda.org/conda-forge/noarch/isoduration-20.11.0-pyhd8ed1ab_1.conda @@ -625,7 +625,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/osx-64/libbrotlidec-1.1.0-h00291cd_2.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/libbrotlienc-1.1.0-h00291cd_2.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/libcblas-3.9.0-31_hff6cab4_openblas.conda - - conda: https://conda.anaconda.org/conda-forge/osx-64/libclang-cpp18.1-18.1.8-default_h3571c67_8.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/libclang-cpp18.1-18.1.8-default_h3571c67_9.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/libcxx-20.1.2-hf95d169_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/libcxx-devel-18.1.8-h7c275be_8.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/libdeflate-1.23-he65b83e_0.conda @@ -673,7 +673,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/noarch/notebook-shim-0.2.4-pyhd8ed1ab_1.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/numpy-2.2.4-py313hc518a0f_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/openjpeg-2.5.3-h7fd6d84_0.conda - - conda: https://conda.anaconda.org/conda-forge/osx-64/openssl-3.4.1-hc426f3f_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/openssl-3.5.0-hc426f3f_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/overrides-7.7.0-pyhd8ed1ab_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/packaging-24.2-pyhd8ed1ab_2.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/pandas-2.2.3-py313h38cdd20_1.conda @@ -798,11 +798,11 @@ environments: - conda: https://conda.anaconda.org/conda-forge/noarch/certifi-2025.1.31-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/cffi-1.17.1-py313hc845a76_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/charset-normalizer-3.4.1-pyhd8ed1ab_0.conda - - conda: https://conda.anaconda.org/conda-forge/osx-arm64/clang-18-18.1.8-default_hf90f093_8.conda - - conda: https://conda.anaconda.org/conda-forge/osx-arm64/clang-18.1.8-default_h474c9e2_8.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/clang-18-18.1.8-default_hf90f093_9.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/clang-18.1.8-default_h474c9e2_9.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/clang_impl_osx-arm64-18.1.8-h2ae9ea5_24.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/clang_osx-arm64-18.1.8-h07b0088_24.conda - - conda: https://conda.anaconda.org/conda-forge/osx-arm64/clangxx-18.1.8-default_h1ffe849_8.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/clangxx-18.1.8-default_h1ffe849_9.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/clangxx_impl_osx-arm64-18.1.8-h555f467_24.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/clangxx_osx-arm64-18.1.8-h07b0088_24.conda - conda: https://conda.anaconda.org/conda-forge/noarch/colorama-0.4.6-pyhd8ed1ab_1.conda @@ -839,7 +839,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/noarch/importlib_resources-6.5.2-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/iniconfig-2.0.0-pyhd8ed1ab_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/ipykernel-6.29.5-pyh57ce528_0.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/ipython-9.0.2-pyhfb0248b_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/ipython-9.1.0-pyhfb0248b_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/ipython_pygments_lexers-1.1.1-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/isl-0.26-imath32_h347afa1_101.conda - conda: https://conda.anaconda.org/conda-forge/noarch/isoduration-20.11.0-pyhd8ed1ab_1.conda @@ -871,7 +871,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libbrotlidec-1.1.0-hd74edd7_2.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libbrotlienc-1.1.0-hd74edd7_2.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libcblas-3.9.0-31_hb3479ef_openblas.conda - - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libclang-cpp18.1-18.1.8-default_hf90f093_8.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libclang-cpp18.1-18.1.8-default_hf90f093_9.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libcxx-20.1.2-ha82da77_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libcxx-devel-18.1.8-h6dc3340_8.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libdeflate-1.23-hec38601_0.conda @@ -919,7 +919,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/noarch/notebook-shim-0.2.4-pyhd8ed1ab_1.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/numpy-2.2.4-py313h41a2e72_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/openjpeg-2.5.3-h8a3d83b_0.conda - - conda: https://conda.anaconda.org/conda-forge/osx-arm64/openssl-3.4.1-h81ee809_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/openssl-3.5.0-h81ee809_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/overrides-7.7.0-pyhd8ed1ab_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/packaging-24.2-pyhd8ed1ab_2.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/pandas-2.2.3-py313h47b39a6_1.conda @@ -1068,7 +1068,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/win-64/graphite2-1.3.13-h63175ca_1003.conda - conda: https://conda.anaconda.org/conda-forge/noarch/h11-0.14.0-pyhd8ed1ab_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/h2-4.2.0-pyhd8ed1ab_0.conda - - conda: https://conda.anaconda.org/conda-forge/win-64/harfbuzz-11.0.0-h9e37d49_0.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/harfbuzz-11.0.1-h078c0c3_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/hpack-4.1.0-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/httpcore-1.0.7-pyh29332c3_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/httpx-0.28.1-pyhd8ed1ab_0.conda @@ -1080,7 +1080,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/noarch/iniconfig-2.0.0-pyhd8ed1ab_1.conda - conda: https://conda.anaconda.org/conda-forge/win-64/intel-openmp-2024.2.1-h57928b3_1083.conda - conda: https://conda.anaconda.org/conda-forge/noarch/ipykernel-6.29.5-pyh4bbf305_0.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/ipython-9.0.2-pyhca29cf9_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/ipython-9.1.0-pyhca29cf9_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/ipython_pygments_lexers-1.1.1-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/isoduration-20.11.0-pyhd8ed1ab_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/jedi-0.19.2-pyhd8ed1ab_1.conda @@ -1151,7 +1151,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/noarch/notebook-shim-0.2.4-pyhd8ed1ab_1.conda - conda: https://conda.anaconda.org/conda-forge/win-64/numpy-2.2.4-py313hefb8edb_0.conda - conda: https://conda.anaconda.org/conda-forge/win-64/openjpeg-2.5.3-h4d64b90_0.conda - - conda: https://conda.anaconda.org/conda-forge/win-64/openssl-3.4.1-ha4e3fda_0.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/openssl-3.5.0-ha4e3fda_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/overrides-7.7.0-pyhd8ed1ab_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/packaging-24.2-pyhd8ed1ab_2.conda - conda: https://conda.anaconda.org/conda-forge/win-64/pandas-2.2.3-py313hf91d08e_1.conda @@ -1283,7 +1283,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/linux-64/mypy-1.15.0-py313h536fd9c_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/mypy_extensions-1.0.0-pyha770c72_1.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.4.1-h7b32b05_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/openssl-3.5.0-h7b32b05_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/packaging-24.2-pyhd8ed1ab_2.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pathspec-0.12.1-pyhd8ed1ab_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/platformdirs-4.3.7-pyh29332c3_0.conda @@ -1314,7 +1314,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/osx-64/mypy-1.15.0-py312h01d7ebd_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/mypy_extensions-1.0.0-pyha770c72_1.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/ncurses-6.5-h0622a9a_3.conda - - conda: https://conda.anaconda.org/conda-forge/osx-64/openssl-3.4.1-hc426f3f_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/openssl-3.5.0-hc426f3f_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/packaging-24.2-pyhd8ed1ab_2.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pathspec-0.12.1-pyhd8ed1ab_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/platformdirs-4.3.7-pyh29332c3_0.conda @@ -1330,7 +1330,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/noarch/typing_extensions-4.13.1-pyh29332c3_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/tzdata-2025b-h78e105d_0.conda osx-arm64: - - conda: https://conda.anaconda.org/conda-forge/osx-arm64/black-25.1.0-py313h8f79df9_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/black-25.1.0-pyh866005b_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/bzip2-1.0.8-h99b78c6_7.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/ca-certificates-2025.1.31-hf0a4a13_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/click-8.1.8-pyh707e725_0.conda @@ -1346,7 +1346,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/osx-arm64/mypy-1.15.0-py313h90d716c_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/mypy_extensions-1.0.0-pyha770c72_1.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.4.1-h81ee809_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/openssl-3.5.0-h81ee809_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/packaging-24.2-pyhd8ed1ab_2.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pathspec-0.12.1-pyhd8ed1ab_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/platformdirs-4.3.7-pyh29332c3_0.conda @@ -1377,7 +1377,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/win-64/libzlib-1.3.1-h2466b09_2.conda - conda: https://conda.anaconda.org/conda-forge/win-64/mypy-1.15.0-py313ha7868ed_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/mypy_extensions-1.0.0-pyha770c72_1.conda - - conda: https://conda.anaconda.org/conda-forge/win-64/openssl-3.4.1-ha4e3fda_0.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/openssl-3.5.0-ha4e3fda_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/packaging-24.2-pyhd8ed1ab_2.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pathspec-0.12.1-pyhd8ed1ab_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/platformdirs-4.3.7-pyh29332c3_0.conda @@ -1423,7 +1423,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/noarch/meson-python-0.17.1-pyh70fd9c4_1.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/ninja-1.12.1-h297d8ca_0.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/openssl-3.4.1-h7b32b05_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/openssl-3.5.0-h7b32b05_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/packaging-24.2-pyhd8ed1ab_2.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pip-25.0.1-pyh145f28c_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pyproject-metadata-0.9.1-pyhd8ed1ab_0.conda @@ -1456,7 +1456,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/noarch/meson-python-0.17.1-pyh70fd9c4_1.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/ncurses-6.5-h0622a9a_3.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/ninja-1.12.1-h3c5361c_0.conda - - conda: https://conda.anaconda.org/conda-forge/osx-64/openssl-3.4.1-hc426f3f_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/openssl-3.5.0-hc426f3f_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/packaging-24.2-pyhd8ed1ab_2.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pip-25.0.1-pyh145f28c_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pyproject-metadata-0.9.1-pyhd8ed1ab_0.conda @@ -1489,7 +1489,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/noarch/meson-python-0.17.1-pyh70fd9c4_1.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/ninja-1.12.1-h420ef59_0.conda - - conda: https://conda.anaconda.org/conda-forge/osx-arm64/openssl-3.4.1-h81ee809_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/openssl-3.5.0-h81ee809_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/packaging-24.2-pyhd8ed1ab_2.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pip-25.0.1-pyh145f28c_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pyproject-metadata-0.9.1-pyhd8ed1ab_0.conda @@ -1520,7 +1520,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/noarch/meson-1.7.1-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/meson-python-0.17.1-pyh70fd9c4_1.conda - conda: https://conda.anaconda.org/conda-forge/win-64/ninja-1.12.1-hc790b64_0.conda - - conda: https://conda.anaconda.org/conda-forge/win-64/openssl-3.4.1-ha4e3fda_0.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/openssl-3.5.0-ha4e3fda_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/packaging-24.2-pyhd8ed1ab_2.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pip-25.0.1-pyh145f28c_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pyproject-metadata-0.9.1-pyhd8ed1ab_0.conda @@ -1802,22 +1802,6 @@ packages: license_family: MIT size: 393484 timestamp: 1738616259890 -- conda: https://conda.anaconda.org/conda-forge/osx-arm64/black-25.1.0-py313h8f79df9_0.conda - sha256: ef2f742f6abefc32506038a4c64bf0c086c8e13234c1fe80c8675c7f92589cc2 - md5: 698e6c77b39a4f3d82c8e2e7d82b81c8 - depends: - - click >=8.0.0 - - mypy_extensions >=0.4.3 - - packaging >=22.0 - - pathspec >=0.9 - - platformdirs >=2 - - python >=3.13,<3.14.0a0 - - python >=3.13,<3.14.0a0 *_cp313 - - python_abi 3.13.* *_cp313 - license: MIT - license_family: MIT - size: 400095 - timestamp: 1738616517582 - conda: https://conda.anaconda.org/conda-forge/noarch/bleach-6.2.0-pyh29332c3_4.conda sha256: a05971bb80cca50ce9977aad3f7fc053e54ea7d5321523efc7b9a6e12901d3cd md5: f0b4c8e370446ef89797608d60a564b3 @@ -2328,52 +2312,52 @@ packages: - pkg:pypi/charset-normalizer?source=hash-mapping size: 47438 timestamp: 1735929811779 -- conda: https://conda.anaconda.org/conda-forge/osx-64/clang-18.1.8-default_h576c50e_8.conda - sha256: ff3ec1361dadb7d47ae0e1276e861e48f1a3e5a23c11eb832915cbada3da0861 - md5: 0a7a5caf8e1f0b52b96104bbd2ee677f +- conda: https://conda.anaconda.org/conda-forge/osx-64/clang-18.1.8-default_h576c50e_9.conda + sha256: 0e7e33950d9dc2a01a14e3830bfa37575642f338d09526c5b3b78af381311352 + md5: 266e7e8fa2190df09e6f236571c91511 depends: - - clang-18 18.1.8 default_h3571c67_8 + - clang-18 18.1.8 default_h3571c67_9 license: Apache-2.0 WITH LLVM-exception license_family: Apache purls: [] - size: 76209 - timestamp: 1742267099930 -- conda: https://conda.anaconda.org/conda-forge/osx-arm64/clang-18.1.8-default_h474c9e2_8.conda - sha256: 42965afb7a7a2af44b164d079b256127a9d9580e756cce08f8a00836d1e82952 - md5: 2c01e8675aa80bf6a25494b76005ffdc + size: 76304 + timestamp: 1744061943238 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/clang-18.1.8-default_h474c9e2_9.conda + sha256: 2c800b88d50cc4c83a24e0ad92db1cc617f29f299ef2b090c1bce8b0ee4d78b1 + md5: ac42b10184bf26c80a3de9f049cf183e depends: - - clang-18 18.1.8 default_hf90f093_8 + - clang-18 18.1.8 default_hf90f093_9 license: Apache-2.0 WITH LLVM-exception license_family: Apache purls: [] - size: 76217 - timestamp: 1742266196177 -- conda: https://conda.anaconda.org/conda-forge/osx-64/clang-18-18.1.8-default_h3571c67_8.conda - sha256: 25f572a069d9ff1d6306d6d29a2b42d0395017cc36e9df581c98d6ad2c5876aa - md5: c40e72e808995df189d70d9a438d77ac + size: 76181 + timestamp: 1744062704325 +- conda: https://conda.anaconda.org/conda-forge/osx-64/clang-18-18.1.8-default_h3571c67_9.conda + sha256: 6033b98373bbf8b8748eee1e6ac6fb57ff3ff20dc49c93c11e3a5fc6f1bba224 + md5: e29d8d2866f15f3b167938cc0e775b2f depends: - __osx >=10.13 - - libclang-cpp18.1 18.1.8 default_h3571c67_8 + - libclang-cpp18.1 18.1.8 default_h3571c67_9 - libcxx >=18.1.8 - libllvm18 >=18.1.8,<18.2.0a0 license: Apache-2.0 WITH LLVM-exception license_family: Apache purls: [] - size: 815278 - timestamp: 1742266953803 -- conda: https://conda.anaconda.org/conda-forge/osx-arm64/clang-18-18.1.8-default_hf90f093_8.conda - sha256: 984da230a6197273060fcdb4c97e7d2430f8393547a478ac4e8b32d33a64c89c - md5: 8d92b636afa379ae7845575d87ae1ad0 + size: 811182 + timestamp: 1744061841745 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/clang-18-18.1.8-default_hf90f093_9.conda + sha256: 3b3e0ab23f4b473e89f756c65208f5a3cfb0ddc52114dbc6cc25a25eb238618a + md5: d6e73d7ad81e92ffe60f69eee87e0bca depends: - __osx >=11.0 - - libclang-cpp18.1 18.1.8 default_hf90f093_8 + - libclang-cpp18.1 18.1.8 default_hf90f093_9 - libcxx >=18.1.8 - libllvm18 >=18.1.8,<18.2.0a0 license: Apache-2.0 WITH LLVM-exception license_family: Apache purls: [] - size: 811547 - timestamp: 1742266095150 + size: 808948 + timestamp: 1744062517394 - conda: https://conda.anaconda.org/conda-forge/osx-64/clang_impl_osx-64-18.1.8-h6a44ed1_24.conda sha256: 27b5f4400cee37eea37160d0f65061804d34e403ed3d43a5e8fcad585b6efc6e md5: 5224d53acc2604a86d790f664d7fcbc4 @@ -2422,28 +2406,28 @@ packages: purls: [] size: 21584 timestamp: 1742540373638 -- conda: https://conda.anaconda.org/conda-forge/osx-64/clangxx-18.1.8-default_heb2e8d1_8.conda - sha256: a99947172ab2a3bf244ea1c024e7e3a8e1aabb8921cc5e648004f246f5df87c7 - md5: 06a53a18fa886ec96f519b9022eeb449 +- conda: https://conda.anaconda.org/conda-forge/osx-64/clangxx-18.1.8-default_heb2e8d1_9.conda + sha256: f09da8c88a60115821bb6dded23116bd900d42188154012196068251fb28c344 + md5: 4ba6bd39da787a7306eba77555e86dd3 depends: - - clang 18.1.8 default_h576c50e_8 + - clang 18.1.8 default_h576c50e_9 - libcxx-devel 18.1.8.* license: Apache-2.0 WITH LLVM-exception license_family: Apache purls: [] - size: 76312 - timestamp: 1742267130243 -- conda: https://conda.anaconda.org/conda-forge/osx-arm64/clangxx-18.1.8-default_h1ffe849_8.conda - sha256: c002e7ff1511a0278c693fb05d8c6f729fda4e76b65faef91bb6721b93b24d4b - md5: 6f88136be9a2b5e5e6e7bb69c35d8180 + size: 76375 + timestamp: 1744061961403 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/clangxx-18.1.8-default_h1ffe849_9.conda + sha256: 445427ded667d57c8e5dc9484e66b21a2b3f92c79ff4e29a69a91d6ff789171f + md5: e0c5555dcbcd2f588f7926554fd14a0c depends: - - clang 18.1.8 default_h474c9e2_8 + - clang 18.1.8 default_h474c9e2_9 - libcxx-devel 18.1.8.* license: Apache-2.0 WITH LLVM-exception license_family: Apache purls: [] - size: 76359 - timestamp: 1742266208123 + size: 76287 + timestamp: 1744062725915 - conda: https://conda.anaconda.org/conda-forge/osx-64/clangxx_impl_osx-64-18.1.8-h4b7810f_24.conda sha256: 1735b123cebcffaa54699fcae4295c0bd308c9bf27df3924cab78f3b3d1a9890 md5: 9d27517a71e7268679f1c47e7f34e47b @@ -3472,35 +3456,35 @@ packages: - pkg:pypi/h2?source=hash-mapping size: 53888 timestamp: 1738578623567 -- conda: https://conda.anaconda.org/conda-forge/linux-64/harfbuzz-11.0.0-h76408a6_0.conda - sha256: 9d33201d3e12a61d4ea4b1252a3468afb18b11a418f095dceffdf09bc6792f59 - md5: 347cb348bfc8d77062daee11c326e518 +- conda: https://conda.anaconda.org/conda-forge/linux-64/harfbuzz-11.0.1-h2c12942_0.conda + sha256: 5013bfd767f7fa00e1cd103d76800c10542953f6dc5f225e538c7c35d5aaf1c7 + md5: c90105cecb8bf8248f6666f1f5a40bbb depends: - __glibc >=2.17,<3.0.a0 - cairo >=1.18.4,<2.0a0 - freetype >=2.13.3,<3.0a0 - graphite2 - icu >=75.1,<76.0a0 - - libexpat >=2.6.4,<3.0a0 + - libexpat >=2.7.0,<3.0a0 - libgcc >=13 - - libglib >=2.84.0,<3.0a0 + - libglib >=2.84.1,<3.0a0 - libstdcxx >=13 - libzlib >=1.3.1,<2.0a0 license: MIT license_family: MIT purls: [] - size: 1720702 - timestamp: 1743082646624 -- conda: https://conda.anaconda.org/conda-forge/win-64/harfbuzz-11.0.0-h9e37d49_0.conda - sha256: f1ab5960a52a11186f528249bec5ce5e43bb4c44c87ffa24334255f07c3fd4b8 - md5: b7648427f5b6797ae3904ad76e4c7f19 + size: 2029831 + timestamp: 1744033845291 +- conda: https://conda.anaconda.org/conda-forge/win-64/harfbuzz-11.0.1-h078c0c3_0.conda + sha256: a908178119ed98bdb1b46817be8c843416e10dd8f928148acd9ec861d611374a + md5: 81b86b68c534852535acc9c5cfce7469 depends: - cairo >=1.18.4,<2.0a0 - freetype >=2.13.3,<3.0a0 - graphite2 - icu >=75.1,<76.0a0 - - libexpat >=2.6.4,<3.0a0 - - libglib >=2.84.0,<3.0a0 + - libexpat >=2.7.0,<3.0a0 + - libglib >=2.84.1,<3.0a0 - libzlib >=1.3.1,<2.0a0 - ucrt >=10.0.20348.0 - vc >=14.2,<15 @@ -3508,8 +3492,8 @@ packages: license: MIT license_family: MIT purls: [] - size: 1125019 - timestamp: 1743083466989 + size: 1119818 + timestamp: 1744035191347 - conda: https://conda.anaconda.org/conda-forge/noarch/hpack-4.1.0-pyhd8ed1ab_0.conda sha256: 6ad78a180576c706aabeb5b4c8ceb97c0cb25f1e112d76495bff23e3779948ba md5: 0a802cb9888dd14eeefc611f05c40b6e @@ -3731,9 +3715,9 @@ packages: - pkg:pypi/ipykernel?source=hash-mapping size: 119568 timestamp: 1719845667420 -- conda: https://conda.anaconda.org/conda-forge/noarch/ipython-9.0.2-pyhca29cf9_0.conda - sha256: 72ad5d59719d7639641f21032de870fadd43ec2349229161728b736f1df720d1 - md5: e5ba968166136311157765e8b2ccb9d0 +- conda: https://conda.anaconda.org/conda-forge/noarch/ipython-9.1.0-pyhca29cf9_0.conda + sha256: 330d452de42f10537bff1490f6ff08bf4e6c0c7288255be43f9e895e15dd2969 + md5: 4f71690ae510b365a22bb1cb926e6df2 depends: - __win - colorama @@ -3753,12 +3737,12 @@ packages: license: BSD-3-Clause license_family: BSD purls: - - pkg:pypi/ipython?source=hash-mapping - size: 614763 - timestamp: 1741457145171 -- conda: https://conda.anaconda.org/conda-forge/noarch/ipython-9.0.2-pyhfb0248b_0.conda - sha256: 98f14471e0f492d290c4882f1e2c313fffc67a0f9a3a36e699d7b0c5d42a5196 - md5: b031bcd65b260a0a3353531eab50d465 + - pkg:pypi/ipython?source=compressed-mapping + size: 619172 + timestamp: 1744033183734 +- conda: https://conda.anaconda.org/conda-forge/noarch/ipython-9.1.0-pyhfb0248b_0.conda + sha256: 24cabcd711d03d2865a67ebc17941bc9bde949b3f0c9a34655c4153dce1c34c3 + md5: b6c7f97b71c0f670dd9e585d3f65e867 depends: - __unix - pexpect >4.3 @@ -3779,8 +3763,8 @@ packages: license_family: BSD purls: - pkg:pypi/ipython?source=hash-mapping - size: 615519 - timestamp: 1741457126430 + size: 619977 + timestamp: 1744033187813 - conda: https://conda.anaconda.org/conda-forge/noarch/ipython_pygments_lexers-1.1.1-pyhd8ed1ab_0.conda sha256: 894682a42a7d659ae12878dbcb274516a7031bbea9104e92f8e88c1f2765a104 md5: bd80ba060603cc228d9d81c257093119 @@ -4720,9 +4704,9 @@ packages: purls: [] size: 3733549 timestamp: 1740088502127 -- conda: https://conda.anaconda.org/conda-forge/osx-64/libclang-cpp18.1-18.1.8-default_h3571c67_8.conda - sha256: 9e9af164c1ddfd114a786aceacf64df0041c3528a97cc96c06f3bf1040485e29 - md5: 1444a2cd1f78fccea7dacb658f8aeb39 +- conda: https://conda.anaconda.org/conda-forge/osx-64/libclang-cpp18.1-18.1.8-default_h3571c67_9.conda + sha256: a3453cf08393f4a369a70795036d60dd8ea0de1efbf683594cbcaba49d8e3e74 + md5: ef1a444913775b76f3391431967090a9 depends: - __osx >=10.13 - libcxx >=18.1.8 @@ -4730,11 +4714,11 @@ packages: license: Apache-2.0 WITH LLVM-exception license_family: Apache purls: [] - size: 13905920 - timestamp: 1742266347128 -- conda: https://conda.anaconda.org/conda-forge/osx-arm64/libclang-cpp18.1-18.1.8-default_hf90f093_8.conda - sha256: b736c4c3a32d4aa16b4af7b2094b4f3786ea34723cccb9918579206706000f90 - md5: a5f883cd77dcc0f62a0eca8445d9e147 + size: 13908110 + timestamp: 1744061729284 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/libclang-cpp18.1-18.1.8-default_hf90f093_9.conda + sha256: 23eb5b180fadbe0b9a1d1aa123e44ef7ff774174b8a43fa40495c4ecc80f1328 + md5: 88893bbbccb1400d677f747b0c8f226f depends: - __osx >=11.0 - libcxx >=18.1.8 @@ -4742,8 +4726,8 @@ packages: license: Apache-2.0 WITH LLVM-exception license_family: Apache purls: [] - size: 13330731 - timestamp: 1742265504673 + size: 13330734 + timestamp: 1744062341062 - conda: https://conda.anaconda.org/conda-forge/linux-64/libclang-cpp20.1-20.1.2-default_hb5137d0_0.conda sha256: d87e9fd20c05be07c236fd56ff1b559614648d4848d0ea9334221e71db55e556 md5: 729198eae19e9dbf8e0ffe355d416bde @@ -6621,9 +6605,9 @@ packages: license_family: MIT size: 10854 timestamp: 1733230986902 -- conda: https://conda.anaconda.org/conda-forge/linux-64/mysql-common-9.0.1-h266115a_5.conda - sha256: df9e895e8933ade7d362ab42bfe97e52a6b93d4d30df517324d60f6f35da1540 - md5: 6cf2f0c19b0b7ff3d5349c9826c26a9e +- conda: https://conda.anaconda.org/conda-forge/linux-64/mysql-common-9.0.1-h266115a_6.conda + sha256: 9c2e3f9e9883e4b8d7e9e6abf7b235dc00bdcd5ef66640a360464a9f5756294d + md5: 94116b69829e90b72d566e64421e1bff depends: - __glibc >=2.17,<3.0.a0 - libgcc >=13 @@ -6632,24 +6616,24 @@ packages: license: GPL-2.0-or-later license_family: GPL purls: [] - size: 633439 - timestamp: 1741896463089 -- conda: https://conda.anaconda.org/conda-forge/linux-64/mysql-libs-9.0.1-he0572af_5.conda - sha256: f37303d2fb453bbc47d1e09d56ef06b20570d0eaf375115707ffc1e609c9b508 - md5: d13932a2a61de7c0fb7864b592034a6e + size: 616215 + timestamp: 1744124836761 +- conda: https://conda.anaconda.org/conda-forge/linux-64/mysql-libs-9.0.1-he0572af_6.conda + sha256: 274467a602944d12722f757f660ad034de6f5f5d7d2ea1b913ef6fd836c1b8ce + md5: 9802ae6d20982f42c0f5d69008988763 depends: - __glibc >=2.17,<3.0.a0 - libgcc >=13 - libstdcxx >=13 - libzlib >=1.3.1,<2.0a0 - - mysql-common 9.0.1 h266115a_5 + - mysql-common 9.0.1 h266115a_6 - openssl >=3.4.1,<4.0a0 - zstd >=1.5.7,<1.6.0a0 license: GPL-2.0-or-later license_family: GPL purls: [] - size: 1371634 - timestamp: 1741896565103 + size: 1369369 + timestamp: 1744124916632 - conda: https://conda.anaconda.org/conda-forge/noarch/nbclient-0.10.2-pyhd8ed1ab_0.conda sha256: a20cff739d66c2f89f413e4ba4c6f6b59c50d5c30b5f0d840c13e8c9c2df9135 md5: 6bb0d77277061742744176ab555b723c @@ -6995,9 +6979,9 @@ packages: purls: [] size: 784483 timestamp: 1732674189726 -- conda: https://conda.anaconda.org/conda-forge/linux-64/openssl-3.4.1-h7b32b05_0.conda - sha256: cbf62df3c79a5c2d113247ddea5658e9ff3697b6e741c210656e239ecaf1768f - md5: 41adf927e746dc75ecf0ef841c454e48 +- conda: https://conda.anaconda.org/conda-forge/linux-64/openssl-3.5.0-h7b32b05_0.conda + sha256: 38285d280f84f1755b7c54baf17eccf2e3e696287954ce0adca16546b85ee62c + md5: bb539841f2a3fde210f387d00ed4bb9d depends: - __glibc >=2.17,<3.0.a0 - ca-certificates @@ -7005,33 +6989,33 @@ packages: license: Apache-2.0 license_family: Apache purls: [] - size: 2939306 - timestamp: 1739301879343 -- conda: https://conda.anaconda.org/conda-forge/osx-64/openssl-3.4.1-hc426f3f_0.conda - sha256: 505a46671dab5d66df8e684f99a9ae735a607816b12810b572d63caa512224df - md5: a7d63f8e7ab23f71327ea6d27e2d5eae + size: 3121673 + timestamp: 1744132167438 +- conda: https://conda.anaconda.org/conda-forge/osx-64/openssl-3.5.0-hc426f3f_0.conda + sha256: 7ee137b67f2de89d203e5ac2ebffd6d42252700005bf6af2bbf3dc11a9dfedbd + md5: e06e13c34056b6334a7a1188b0f4c83c depends: - __osx >=10.13 - ca-certificates license: Apache-2.0 license_family: Apache purls: [] - size: 2591479 - timestamp: 1739302628009 -- conda: https://conda.anaconda.org/conda-forge/osx-arm64/openssl-3.4.1-h81ee809_0.conda - sha256: 4f8e2389e1b711b44182a075516d02c80fa7a3a7e25a71ff1b5ace9eae57a17a - md5: 75f9f0c7b1740017e2db83a53ab9a28e + size: 2737547 + timestamp: 1744140967264 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/openssl-3.5.0-h81ee809_0.conda + sha256: 53f825acb8d3e13bdad5c869f6dc7df931941450eea7f6473b955b0aaea1a399 + md5: 3d2936da7e240d24c656138e07fa2502 depends: - __osx >=11.0 - ca-certificates license: Apache-2.0 license_family: Apache purls: [] - size: 2934522 - timestamp: 1739301896733 -- conda: https://conda.anaconda.org/conda-forge/win-64/openssl-3.4.1-ha4e3fda_0.conda - sha256: 56dcc2b4430bfc1724e32661c34b71ae33a23a14149866fc5645361cfd3b3a6a - md5: 0730f8094f7088592594f9bf3ae62b3f + size: 3067649 + timestamp: 1744132084304 +- conda: https://conda.anaconda.org/conda-forge/win-64/openssl-3.5.0-ha4e3fda_0.conda + sha256: 43dd7f56da142ca83c614c8b0085589650ae9032b351a901c190e48eefc73675 + md5: 4ea7db75035eb8c13fa680bb90171e08 depends: - ca-certificates - ucrt >=10.0.20348.0 @@ -7040,8 +7024,8 @@ packages: license: Apache-2.0 license_family: Apache purls: [] - size: 8515197 - timestamp: 1739304103653 + size: 8999138 + timestamp: 1744135594688 - conda: https://conda.anaconda.org/conda-forge/noarch/overrides-7.7.0-pyhd8ed1ab_1.conda sha256: 1840bd90d25d4930d60f57b4f38d4e0ae3f5b8db2819638709c36098c6ba770c md5: e51f1e4089cad105b6cac64bd8166587 diff --git a/tests/test_narx_jac.py b/tests/test_narx_jac.py index 850b456..9405815 100644 --- a/tests/test_narx_jac.py +++ b/tests/test_narx_jac.py @@ -5,6 +5,7 @@ from scipy.integrate import odeint from sklearn.metrics import r2_score +from fastcan._narx_fast import _predict_step # type: ignore from fastcan.narx import NARX, make_narx @@ -18,16 +19,16 @@ def test_simple(): X = np.array([1.5, 1.5, 1.5]).reshape(-1, 1) y = np.array([1, 2.9, 3.66]).reshape(-1, 1) - feat_ids = np.array([1, 0]).reshape(-1, 1) - delay_ids = np.array([1, 1]).reshape(-1, 1) - output_ids = np.array([0, 0]) + feat_ids = np.array([1, 0], dtype=np.int32).reshape(-1, 1) + delay_ids = np.array([1, 1], dtype=np.int32).reshape(-1, 1) + output_ids = np.array([0, 0], dtype=np.int32) coef = np.array([0.4, 1]) intercept = np.array([1], dtype=float) sample_weight = np.array([1, 1, 1], dtype=float) y_hat = NARX._predict( - NARX._expression, + _predict_step, X=X, y_ref=y, coef=coef, @@ -43,7 +44,7 @@ def test_simple(): coef_1 = np.array([0.4+delta_w, 1]) y_hat_1 = NARX._predict( - NARX._expression, + _predict_step, X=X, y_ref=y, coef=coef_1, @@ -60,17 +61,22 @@ def test_simple(): ]) - cfd_ids = NARX._get_cfd_ids(feat_ids, delay_ids, output_ids, 1) + grad_yyd_ids, grad_coef_ids, grad_feat_ids, grad_delay_ids = NARX._get_cfd_ids( + feat_ids, delay_ids, output_ids, 1 + ) grad = NARX._grad( np.r_[coef_1, intercept], - NARX._expression, + _predict_step, X, y, feat_ids, delay_ids, output_ids, - sample_weight_sqrt=np.sqrt(sample_weight), - cfd_ids=cfd_ids, + np.sqrt(sample_weight), + grad_yyd_ids, + grad_coef_ids, + grad_feat_ids, + grad_delay_ids, ) assert_almost_equal(grad.sum(axis=0), grad_truth, decimal=4) @@ -117,7 +123,8 @@ def test_complex(): [2, 3], [1, 1], [1, 0], - ] + ], + dtype=np.int32 ) delay_ids = np.array( @@ -131,10 +138,11 @@ def test_complex(): [1, 2], [0, 0], [2, 3], - ] + ], + dtype=np.int32 ) - output_ids = np.array([0, 0, 0, 0, 0, 1, 1, 1, 1]) + output_ids = np.array([0, 0, 0, 0, 0, 1, 1, 1, 1], dtype=np.int32) coef = np.array( [ @@ -153,22 +161,27 @@ def test_complex(): intercept = np.array([1, 0.5]) # NARX Jacobian - cfd_ids = NARX._get_cfd_ids(feat_ids, delay_ids, output_ids, X.shape[1]) + grad_yyd_ids, grad_coef_ids, grad_feat_ids, grad_delay_ids = NARX._get_cfd_ids( + feat_ids, delay_ids, output_ids, X.shape[1] + ) grad = NARX._grad( np.r_[coef, intercept], - NARX._expression, + _predict_step, X, y, feat_ids, delay_ids, output_ids, - sample_weight_sqrt=np.sqrt(np.ones((y.shape[0], 1))), - cfd_ids=cfd_ids, + np.sqrt(np.ones((y.shape[0], 1))), + grad_yyd_ids, + grad_coef_ids, + grad_feat_ids, + grad_delay_ids, ) # Numerical gradient y_hat_0 = NARX._predict( - NARX._expression, + _predict_step, X=X, y_ref=y, coef=coef, @@ -191,7 +204,7 @@ def test_complex(): intercept_1[i-len(coef)] += delta_w y_hat_1 = NARX._predict( - NARX._expression, + _predict_step, X=X, y_ref=y, coef=coef_1, From 74ed9b20aa98d16c49d10a9c7532a42bffb90d30 Mon Sep 17 00:00:00 2001 From: SIKAI ZHANG <34108862+MatthewSZhang@users.noreply.github.com> Date: Wed, 9 Apr 2025 16:23:25 +0800 Subject: [PATCH 2/3] MNT fix time-narx put all code in setup and timing empty --- pixi.lock | 2 +- pyproject.toml | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/pixi.lock b/pixi.lock index c2ecfcd..5717f3b 100644 --- a/pixi.lock +++ b/pixi.lock @@ -3034,7 +3034,7 @@ packages: - pypi: . name: fastcan version: 0.3.2 - sha256: 91dc839be1251db991da3b261369f5f145a325c33fc7a7f2b08dc9f56cda574a + sha256: 47bb0010fe7a5d9799f463daa4ad6f2e5b26021750c245afd3ff45c84f72895e requires_dist: - scikit-learn>=1.6.0 - furo ; extra == 'docs' diff --git a/pyproject.toml b/pyproject.toml index 8b03d29..629ae6e 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -92,10 +92,10 @@ compilers = "*" compilers = "*" [tool.pixi.tasks] -time-h = "python -m timeit -n 5 -s 'import numpy as np; from fastcan import FastCan; X = np.random.rand(3000, 100); y = np.random.rand(3000, 20); s = FastCan(100, verbose=0).fit(X, y)'" -time-eta = "python -m timeit -n 5 -s 'import numpy as np; from fastcan import FastCan; X = np.random.rand(3000, 100); y = np.random.rand(3000, 20); s = FastCan(100, eta=True, verbose=0).fit(X, y)'" +time-h = "python -m timeit -n 5 -s 'import numpy as np; from fastcan import FastCan; X = np.random.rand(3000, 100); y = np.random.rand(3000, 20)' 's = FastCan(100, verbose=0).fit(X, y)'" +time-eta = "python -m timeit -n 5 -s 'import numpy as np; from fastcan import FastCan; X = np.random.rand(3000, 100); y = np.random.rand(3000, 20)' 's = FastCan(100, eta=True, verbose=0).fit(X, y)'" profile-minibatch = { cmd = '''python -c "import cProfile; import numpy as np; from fastcan import minibatch; X = np.random.rand(100, 3000); y = np.random.rand(100, 20); cProfile.run('minibatch(X, y, 1000, 10, verbose=0)', sort='$SORT')"''', env = { SORT = "cumtime" } } -time-narx = '''python -m timeit -n 1 -s "import numpy as np; from fastcan.narx import make_narx; rng = np.random.default_rng(5); X = rng.random((1000, 10)); y = rng.random((1000, 2)); s = make_narx(X, y, 10, max_delay=2, poly_degree=2, verbose=0).fit(X, y, coef_init='one_step_ahead', verbose=1)"''' +time-narx = '''python -m timeit -n 1 -s "import numpy as np; from fastcan.narx import make_narx; rng = np.random.default_rng(5); X = rng.random((1000, 10)); y = rng.random((1000, 2)); m = make_narx(X, y, 10, max_delay=2, poly_degree=2, verbose=0)" "m.fit(X, y, coef_init='one_step_ahead', verbose=1)"''' [tool.pixi.feature.test.tasks] test = { cmd = "pytest", cwd = "tests" } From b96534ea560a531ccedf3dd73b66b4b010cfa63f Mon Sep 17 00:00:00 2001 From: SIKAI ZHANG <34108862+MatthewSZhang@users.noreply.github.com> Date: Wed, 9 Apr 2025 16:32:12 +0800 Subject: [PATCH 3/3] MNT fix nogil-h, nogil-eta put all code in setup and timing empty --- pixi.lock | 2 +- pyproject.toml | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/pixi.lock b/pixi.lock index 5717f3b..87d8e2c 100644 --- a/pixi.lock +++ b/pixi.lock @@ -3034,7 +3034,7 @@ packages: - pypi: . name: fastcan version: 0.3.2 - sha256: 47bb0010fe7a5d9799f463daa4ad6f2e5b26021750c245afd3ff45c84f72895e + sha256: e5bb5ff118a28f9e719f00a46fa3048c6d70304835a57046fbc32f79ec576a05 requires_dist: - scikit-learn>=1.6.0 - furo ; extra == 'docs' diff --git a/pyproject.toml b/pyproject.toml index 629ae6e..144a2f7 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -121,10 +121,10 @@ doc-clean = { cmd = "rm -rf $BUILDDIR generated auto_examples", cwd = "doc", env [tool.pixi.feature.nogil.tasks] nogil-build = { cmd = "pip install --editable . --verbose --no-build-isolation --config-settings editable-verbose=true" } -nogil-h = { cmd = "python -Xgil=0 -m timeit -n 5 -s 'import numpy as np; from fastcan import FastCan; X = np.random.rand(3000, 100); y = np.random.rand(3000, 20); s = FastCan(100, verbose=0).fit(X, y)'", depends-on = [ +nogil-h = { cmd = "python -Xgil=0 -m timeit -n 5 -s 'import numpy as np; from fastcan import FastCan; X = np.random.rand(3000, 100); y = np.random.rand(3000, 20)' 's = FastCan(100, verbose=0).fit(X, y)'", depends-on = [ "nogil-build", ] } -nogil-eta = { cmd = "python -Xgil=0 -m timeit -n 5 -s 'import numpy as np; from fastcan import FastCan; X = np.random.rand(3000, 100); y = np.random.rand(3000, 20); s = FastCan(100, eta=True, verbose=0).fit(X, y)'", depends-on = [ +nogil-eta = { cmd = "python -Xgil=0 -m timeit -n 5 -s 'import numpy as np; from fastcan import FastCan; X = np.random.rand(3000, 100); y = np.random.rand(3000, 20)' 's = FastCan(100, eta=True, verbose=0).fit(X, y)'", depends-on = [ "nogil-build", ] }