From c0ff63e65dc232281feab6d5f2df6ee7bfb00565 Mon Sep 17 00:00:00 2001 From: "henrydingliu@gmail.com" Date: Sun, 26 Jul 2026 01:49:44 +0000 Subject: [PATCH 1/9] fixing fixture expecting errors --- conftest.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/conftest.py b/conftest.py index 867c8e0bf..9f1fd175c 100644 --- a/conftest.py +++ b/conftest.py @@ -57,12 +57,14 @@ def _sample_fixture( """ # Set the backend to sparse for a sparse-only-run. + cl.options.set_option("AUTO_SPARSE", False) cl.options.set_option("ARRAY_BACKEND", "sparse" if request.param == "sparse_only_run" else "numpy") # Load the sample data. tri = cl.load_sample(sample) # Apply a transformation if supplied, then yield the triangle to the test. yield transform(tri) if transform else tri # After the test, reset the backend to default numpy. + cl.options.set_option("AUTO_SPARSE", True) cl.options.set_option("ARRAY_BACKEND", "numpy") From c2d4061fefee2c293bc395ff5c7a632decb44210 Mon Sep 17 00:00:00 2001 From: "henrydingliu@gmail.com" Date: Sun, 26 Jul 2026 02:01:05 +0000 Subject: [PATCH 2/9] fixing prism --- conftest.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/conftest.py b/conftest.py index 9f1fd175c..76cc3bc67 100644 --- a/conftest.py +++ b/conftest.py @@ -28,7 +28,7 @@ def pytest_generate_tests(metafunc): "prism_dense", ["normal_run", "sparse_only_run"], indirect=True ) if "prism" in metafunc.fixturenames: - metafunc.parametrize("prism", ["normal_run"], indirect=True) + metafunc.parametrize("prism", ["sparse_only_run"], indirect=True) if "xyz" in metafunc.fixturenames: metafunc.parametrize("xyz", ["normal_run", "sparse_only_run"], indirect=True) From b4da81b31ff809aec67d68c58a42fa29f58b477c Mon Sep 17 00:00:00 2001 From: "henrydingliu@gmail.com" Date: Sun, 26 Jul 2026 03:12:38 +0000 Subject: [PATCH 3/9] trying another approach --- conftest.py | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/conftest.py b/conftest.py index 76cc3bc67..407c29708 100644 --- a/conftest.py +++ b/conftest.py @@ -56,16 +56,12 @@ def _sample_fixture( """ - # Set the backend to sparse for a sparse-only-run. - cl.options.set_option("AUTO_SPARSE", False) - cl.options.set_option("ARRAY_BACKEND", "sparse" if request.param == "sparse_only_run" else "numpy") # Load the sample data. tri = cl.load_sample(sample) - # Apply a transformation if supplied, then yield the triangle to the test. - yield transform(tri) if transform else tri - # After the test, reset the backend to default numpy. - cl.options.set_option("AUTO_SPARSE", True) - cl.options.set_option("ARRAY_BACKEND", "numpy") + # Apply a transformation if supplied + tri = transform(tri) if transform else tri + # Set the backend to sparse for a sparse-only-run, then yield the triangle to the test. + yield tri.set_backend("sparse" if request.param == "sparse_only_run" else "numpy") @pytest.fixture From 93882854fcedb32a72e0cf3227b047d8d0c2700a Mon Sep 17 00:00:00 2001 From: "henrydingliu@gmail.com" Date: Sun, 26 Jul 2026 06:38:59 +0000 Subject: [PATCH 4/9] some fixes --- chainladder/core/tests/test_triangle.py | 10 +++++----- conftest.py | 7 +++++++ 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/chainladder/core/tests/test_triangle.py b/chainladder/core/tests/test_triangle.py index 1a0857e79..df33781e4 100644 --- a/chainladder/core/tests/test_triangle.py +++ b/chainladder/core/tests/test_triangle.py @@ -164,8 +164,7 @@ def test_printer(raa): def test_value_order(clrd): a = clrd[["CumPaidLoss", "BulkLoss"]] b = clrd[["BulkLoss", "CumPaidLoss"]] - xp = a.get_array_module() - xp.testing.assert_array_equal(a.values[:, -1], b.values[:, 0]) + assert a.iloc[:, -1] == b.iloc[:, 0] def test_trend(raa, atol): @@ -303,7 +302,8 @@ def test_dropna_latest_diagonal(raa: Triangle) -> None: None """ t = raa.copy() - t.values[:, :, 0, :] = np.nan + xp = t.get_array_module() + t.values[:, :, 0, :] = xp.nan result = t.latest_diagonal.dropna() assert result.shape == (1, 1, 9, 1) assert result.origin.min().year == 1982 @@ -436,7 +436,7 @@ def test_groupby_agg_auto_sparse(prism: Triangle) -> None: assert result_default == result_no_sparse -def test_auto_sparse_disabled_returns_self(prism: Triangle) -> None: +def test_auto_sparse_disabled_returns_self(prism_convert: Triangle) -> None: """ When cl.options.AUTO_SPARSE is False, _auto_sparse() returns the triangle unchanged without switching backends. @@ -450,7 +450,7 @@ def test_auto_sparse_disabled_returns_self(prism: Triangle) -> None: ------- None """ - dense = prism.set_backend("numpy") + dense = prism_convert.set_backend("numpy") cl.options.set_option("AUTO_SPARSE", False) try: result = dense._auto_sparse() diff --git a/conftest.py b/conftest.py index 407c29708..41db1e50a 100644 --- a/conftest.py +++ b/conftest.py @@ -23,6 +23,10 @@ def pytest_generate_tests(metafunc): metafunc.parametrize("clrd", ["normal_run", "sparse_only_run"], indirect=True) if "genins" in metafunc.fixturenames: metafunc.parametrize("genins", ["normal_run", "sparse_only_run"], indirect=True) + if "prism_convert" in metafunc.fixturenames: + metafunc.parametrize( + "prism_convert", ["normal_run", "sparse_only_run"], indirect=True + ) if "prism_dense" in metafunc.fixturenames: metafunc.parametrize( "prism_dense", ["normal_run", "sparse_only_run"], indirect=True @@ -88,6 +92,9 @@ def genins(request): def prism(request): yield from _sample_fixture(request, "prism") +@pytest.fixture +def prism_convert(request): + yield from _sample_fixture(request, "prism", transform=lambda t: t.iloc[:10000]) @pytest.fixture def prism_dense(request): From ba0ab7fb376e86df2aa49aa3d6a4ecd67131f599 Mon Sep 17 00:00:00 2001 From: "henrydingliu@gmail.com" Date: Sun, 26 Jul 2026 07:22:09 +0000 Subject: [PATCH 5/9] more fixes --- chainladder/development/tests/test_development.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/chainladder/development/tests/test_development.py b/chainladder/development/tests/test_development.py index d92a05935..a91e0aa33 100644 --- a/chainladder/development/tests/test_development.py +++ b/chainladder/development/tests/test_development.py @@ -22,7 +22,9 @@ def __init__(self,dev): def fit(self, X, y: None = None, sample_weight: None = None): if hasattr(X,'age_to_age'): - super().fit(X.incr_to_cum().age_to_age) + #following precedent _set_fit_groups() from DevelopmentBase + backend = "numpy" if X.array_backend in ["sparse", "numpy"] else "cupy" + super().fit(X.set_backend(backend).incr_to_cum().age_to_age) xp = X.get_array_module() indices = X.values.shape[0] columns = X.values.shape[1] From 369b7a33fcee2938ed909a816a18b1fccc399c95 Mon Sep 17 00:00:00 2001 From: "henrydingliu@gmail.com" Date: Sun, 26 Jul 2026 07:50:05 +0000 Subject: [PATCH 6/9] more fixes --- .../development/tests/test_development.py | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/chainladder/development/tests/test_development.py b/chainladder/development/tests/test_development.py index a91e0aa33..f8bc6687b 100644 --- a/chainladder/development/tests/test_development.py +++ b/chainladder/development/tests/test_development.py @@ -24,20 +24,21 @@ def fit(self, X, y: None = None, sample_weight: None = None): if hasattr(X,'age_to_age'): #following precedent _set_fit_groups() from DevelopmentBase backend = "numpy" if X.array_backend in ["sparse", "numpy"] else "cupy" - super().fit(X.set_backend(backend).incr_to_cum().age_to_age) - xp = X.get_array_module() - indices = X.values.shape[0] - columns = X.values.shape[1] - origins = X.age_to_age.values.shape[2] - reg_x = X.incr_to_cum().values[...,:origins,:-1] - reg_y = X.incr_to_cum().values[...,:origins,1:] + obj = X.set_backend(backend) + super().fit(obj.incr_to_cum().age_to_age) + xp = obj.get_array_module() + indices = obj.values.shape[0] + columns = obj.values.shape[1] + origins = obj.age_to_age.values.shape[2] + reg_x = obj.incr_to_cum().values[...,:origins,:-1] + reg_y = obj.incr_to_cum().values[...,:origins,1:] dev_len = reg_x.shape[3] average_param = self._cascade_param(dev_len, self.average, "volume") average_param = np.tile(average_param,(indices,columns,1,1)) params = cl.WeightedRegression(axis=2, thru_orig=True, xp=xp).fit( reg_x, reg_y, self.w_.values, average_param ) - self.ldf_ = self.dev._param_property(X, params.slope_.swapaxes(2, 3), 0) + self.ldf_ = self.dev._param_property(obj, params.slope_.swapaxes(2, 3), 0) return self def test_full_slice(genins): From a5ce6146e8919d0d23f749ad064cdafb616b7667 Mon Sep 17 00:00:00 2001 From: "henrydingliu@gmail.com" Date: Sun, 26 Jul 2026 09:51:00 +0000 Subject: [PATCH 7/9] fix for learning --- chainladder/development/learning.py | 1 + 1 file changed, 1 insertion(+) diff --git a/chainladder/development/learning.py b/chainladder/development/learning.py index 0d9ab2ac3..d79bc616e 100644 --- a/chainladder/development/learning.py +++ b/chainladder/development/learning.py @@ -255,6 +255,7 @@ def _prep_w_ml(self,X,sample_weight=None): weight = weight * TriangleWeight(drop=self.drop,drop_valuation=self.drop_valuation).fit(X).w_.fillzero().values if sample_weight is not None: weight = weight * sample_weight.values + idx = np.where(weight_base.flatten()>0) if X.array_backend != 'sparse' else (weight_base.flatten()>0).coords[0] return weight.flatten()[weight_base.flatten()>0] def fit(self, X, y=None, sample_weight=None): From 979a12cd562916d005b7eddaf1851237c3fdcb59 Mon Sep 17 00:00:00 2001 From: "henrydingliu@gmail.com" Date: Sun, 26 Jul 2026 10:31:03 +0000 Subject: [PATCH 8/9] more learning fix --- chainladder/development/learning.py | 10 ++++++---- conftest.py | 2 +- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/chainladder/development/learning.py b/chainladder/development/learning.py index d79bc616e..01b76fb35 100644 --- a/chainladder/development/learning.py +++ b/chainladder/development/learning.py @@ -250,12 +250,14 @@ def _prep_X_ml(self, X): return df def _prep_w_ml(self,X,sample_weight=None): - weight_base = (~np.isnan(X.values)).astype(float) + #scikit-learn requires a dense sample_weight + backend = "cupy" if X.array_backend == "cupy" else "numpy" + obj = X.set_backend(backend) + weight_base = (~np.isnan(obj.values)).astype(float) weight = weight_base.copy() - weight = weight * TriangleWeight(drop=self.drop,drop_valuation=self.drop_valuation).fit(X).w_.fillzero().values + weight = weight * TriangleWeight(drop=self.drop,drop_valuation=self.drop_valuation).fit(obj).w_.fillzero().values if sample_weight is not None: - weight = weight * sample_weight.values - idx = np.where(weight_base.flatten()>0) if X.array_backend != 'sparse' else (weight_base.flatten()>0).coords[0] + weight = weight * sample_weight.set_backend(backend).values return weight.flatten()[weight_base.flatten()>0] def fit(self, X, y=None, sample_weight=None): diff --git a/conftest.py b/conftest.py index 41db1e50a..be08e77e1 100644 --- a/conftest.py +++ b/conftest.py @@ -94,7 +94,7 @@ def prism(request): @pytest.fixture def prism_convert(request): - yield from _sample_fixture(request, "prism", transform=lambda t: t.iloc[:10000]) + yield from _sample_fixture(request, "prism", transform=lambda t: t.iloc[:5000]) @pytest.fixture def prism_dense(request): From 07cd3c37d8737a7ec0d6151f572ef7b932808b0c Mon Sep 17 00:00:00 2001 From: "henrydingliu@gmail.com" Date: Sun, 26 Jul 2026 17:06:01 +0000 Subject: [PATCH 9/9] restoring test still fails --- chainladder/core/tests/test_triangle.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/chainladder/core/tests/test_triangle.py b/chainladder/core/tests/test_triangle.py index df33781e4..e0ba3caa0 100644 --- a/chainladder/core/tests/test_triangle.py +++ b/chainladder/core/tests/test_triangle.py @@ -302,8 +302,7 @@ def test_dropna_latest_diagonal(raa: Triangle) -> None: None """ t = raa.copy() - xp = t.get_array_module() - t.values[:, :, 0, :] = xp.nan + t.values[:, :, 0, :] = np.nan result = t.latest_diagonal.dropna() assert result.shape == (1, 1, 9, 1) assert result.origin.min().year == 1982