From 7bc218c7a1edf866333d6dd7c530402739e6645c Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 31 Mar 2026 20:23:59 +0000 Subject: [PATCH 1/7] Add S2CondS2GridDistribution class and tests Agent-Logs-Url: https://github.com/FlorianPfaff/PyRecEst/sessions/5ab618f7-210c-4d7c-a7d7-2406930e6fc2 Co-authored-by: FlorianPfaff <6773539+FlorianPfaff@users.noreply.github.com> --- .../distributions/conditional/__init__.py | 3 +- .../s2_cond_s2_grid_distribution.py | 115 ++++++++ .../test_s2_cond_s2_grid_distribution.py | 246 ++++++++++++++++++ 3 files changed, 363 insertions(+), 1 deletion(-) create mode 100644 pyrecest/distributions/conditional/s2_cond_s2_grid_distribution.py create mode 100644 pyrecest/tests/distributions/test_s2_cond_s2_grid_distribution.py diff --git a/pyrecest/distributions/conditional/__init__.py b/pyrecest/distributions/conditional/__init__.py index 986f13346..34c123b7c 100644 --- a/pyrecest/distributions/conditional/__init__.py +++ b/pyrecest/distributions/conditional/__init__.py @@ -1,3 +1,4 @@ +from .s2_cond_s2_grid_distribution import S2CondS2GridDistribution from .sd_cond_sd_grid_distribution import SdCondSdGridDistribution -__all__ = ["SdCondSdGridDistribution"] +__all__ = ["S2CondS2GridDistribution", "SdCondSdGridDistribution"] diff --git a/pyrecest/distributions/conditional/s2_cond_s2_grid_distribution.py b/pyrecest/distributions/conditional/s2_cond_s2_grid_distribution.py new file mode 100644 index 000000000..db9b0a5f9 --- /dev/null +++ b/pyrecest/distributions/conditional/s2_cond_s2_grid_distribution.py @@ -0,0 +1,115 @@ +from .sd_cond_sd_grid_distribution import SdCondSdGridDistribution + + +class S2CondS2GridDistribution(SdCondSdGridDistribution): + """ + Conditional distribution on S2 x S2 represented by a grid of values. + + This is a specialisation of :class:`SdCondSdGridDistribution` for the + two-sphere (S²). The grid is restricted to embedding dimension 3 + (``grid.shape[1] == 3``), and factory / slicing methods return + :class:`~pyrecest.distributions.hypersphere_subset.spherical_grid_distribution.SphericalGridDistribution` + instances instead of the generic + :class:`~pyrecest.distributions.hypersphere_subset.hyperspherical_grid_distribution.HypersphericalGridDistribution`. + """ + + def __init__(self, grid, grid_values, enforce_pdf_nonnegative=True): + """ + Parameters + ---------- + grid : array of shape (n_points, 3) + Grid points on S². + grid_values : array of shape (n_points, n_points) + Conditional pdf values: ``grid_values[i, j] = f(grid[i] | grid[j])``. + enforce_pdf_nonnegative : bool + Whether non-negativity of ``grid_values`` is required. + """ + if grid.ndim != 2 or grid.shape[1] != 3: + raise ValueError( + "S2CondS2GridDistribution requires a grid of shape (n_points, 3)." + ) + super().__init__(grid, grid_values, enforce_pdf_nonnegative) + + # ------------------------------------------------------------------ + # Marginalisation and conditioning – return SphericalGridDistribution + # ------------------------------------------------------------------ + + def marginalize_out(self, first_or_second): + """ + Marginalize out one of the two spheres. + + Returns a :class:`SphericalGridDistribution` (S²-specific). + + Parameters + ---------- + first_or_second : int (1 or 2) + """ + # pylint: disable=import-outside-toplevel + from pyrecest.distributions.hypersphere_subset.spherical_grid_distribution import ( + SphericalGridDistribution, + ) + + hgd = super().marginalize_out(first_or_second) + return SphericalGridDistribution(hgd.grid, hgd.grid_values) + + def fix_dim(self, first_or_second, point): + """ + Return the conditional slice for a fixed grid point. + + Returns a :class:`SphericalGridDistribution` (S²-specific). + + Parameters + ---------- + first_or_second : int (1 or 2) + point : array of shape (3,) + """ + # pylint: disable=import-outside-toplevel + from pyrecest.distributions.hypersphere_subset.spherical_grid_distribution import ( + SphericalGridDistribution, + ) + + hgd = super().fix_dim(first_or_second, point) + return SphericalGridDistribution(hgd.grid, hgd.grid_values) + + # ------------------------------------------------------------------ + # Factory + # ------------------------------------------------------------------ + + @staticmethod + def from_function( + fun, + no_of_grid_points, + fun_does_cartesian_product=False, + grid_type="leopardi", + ): + """ + Construct an :class:`S2CondS2GridDistribution` from a callable. + + Parameters + ---------- + fun : callable + Conditional pdf ``f(a, b)`` – see + :meth:`SdCondSdGridDistribution.from_function` for the + ``fun_does_cartesian_product`` convention. + no_of_grid_points : int + Number of grid points for each sphere. + fun_does_cartesian_product : bool + If ``True``, ``fun`` is called with the full grids of shape + ``(n_points, 3)`` and must return ``(n_points, n_points)``. + If ``False`` (default), ``fun`` receives paired rows and must + return a 1-D array. + grid_type : str + Grid type passed to the sampler. Defaults to ``'leopardi'``. + + Returns + ------- + S2CondS2GridDistribution + """ + sdsd = SdCondSdGridDistribution.from_function( + fun, + no_of_grid_points, + fun_does_cartesian_product, + grid_type, + dim=6, + ) + return S2CondS2GridDistribution(sdsd.grid, sdsd.grid_values) diff --git a/pyrecest/tests/distributions/test_s2_cond_s2_grid_distribution.py b/pyrecest/tests/distributions/test_s2_cond_s2_grid_distribution.py new file mode 100644 index 000000000..d322be485 --- /dev/null +++ b/pyrecest/tests/distributions/test_s2_cond_s2_grid_distribution.py @@ -0,0 +1,246 @@ +""" +Tests for S2CondS2GridDistribution. + +These tests mirror the MATLAB test class S2CondS2GridDistributionTest. +""" +import unittest +import warnings + +import numpy.testing as npt +import pyrecest + +from pyrecest.backend import array, ones +from pyrecest.distributions.conditional.s2_cond_s2_grid_distribution import ( + S2CondS2GridDistribution, +) +from pyrecest.distributions.hypersphere_subset.spherical_grid_distribution import ( + SphericalGridDistribution, +) +from pyrecest.distributions.hypersphere_subset.von_mises_fisher_distribution import ( + VonMisesFisherDistribution, +) + + +def _skip_jax(test_fn): + return unittest.skipIf( + pyrecest.backend.__backend_name__ == "jax", # pylint: disable=no-member + reason="Not supported on JAX backend", + )(test_fn) + + +class TestS2CondS2GridDistributionInit(unittest.TestCase): + """Basic construction and validation.""" + + @_skip_jax + def test_basic_construction(self): + no_grid_points = 50 + + def uniform_trans(xkk, xk): + # xkk: (n1, 3), xk: (n2, 3) -> (n1, n2) + from pyrecest.distributions.hypersphere_subset.abstract_hypersphere_subset_distribution import ( + AbstractHypersphereSubsetDistribution, + ) + + surface = ( + AbstractHypersphereSubsetDistribution.compute_unit_hypersphere_surface( + 2 + ) + ) + return ones((xkk.shape[0], xk.shape[0])) / surface + + s2s2 = S2CondS2GridDistribution.from_function( + uniform_trans, no_grid_points, True + ) + self.assertEqual(s2s2.dim, 6) + self.assertEqual(s2s2.grid.shape[1], 3) + self.assertEqual(s2s2.grid_values.shape, (no_grid_points, no_grid_points)) + + @_skip_jax + def test_wrong_grid_dim_raises(self): + from pyrecest.sampling.hyperspherical_sampler import get_grid_hypersphere + + # Build a 2-sphere grid and misshape it to 4D + grid, _ = get_grid_hypersphere("leopardi", 10, 2) + n = grid.shape[0] + surface = 4 * 3.141592653589793 + gv = ones((n, n)) / surface + # Simulate a non-S2 grid (embed in 4D instead of 3D) - should raise + import numpy as np + + grid_4d = np.column_stack([grid, np.zeros(n)]) + with self.assertRaises(ValueError): + S2CondS2GridDistribution(grid_4d, gv) + + +class TestS2CondS2GridDistributionFromFunction(unittest.TestCase): + """Tests mirroring the MATLAB S2CondS2GridDistributionTest class.""" + + @_skip_jax + def test_warning_free_normalized_vmf(self): + """testWarningFreeNormalizedVMF: VMF-based conditional should warn-free.""" + no_grid_points = 112 + + def trans(xkk, xk): + # xkk: (n1, 3), xk: (n2, 3) -> (n1, n2) + import numpy as np + + result = np.zeros((xkk.shape[0], xk.shape[0])) + for i in range(xk.shape[0]): + vmf = VonMisesFisherDistribution(xk[i], 1.0) + result[:, i] = vmf.pdf(xkk) + return result + + with warnings.catch_warnings(): + warnings.simplefilter("error") + S2CondS2GridDistribution.from_function( + trans, no_grid_points, True, "leopardi" + ) + + @_skip_jax + def test_warning_unnormalized(self): + """testWarningUnnormalized: unnormalized transition should emit UserWarning.""" + no_grid_points = 112 + + def trans(xkk, xk): + import numpy as np + + # xkk, xk both (n_pairs, 3) when fun_does_cartesian_product=False + D = array([0.1, 0.15, 1.0]) + diff = (xkk - xk) * D[None, :] + return 1.0 / (np.sum(diff**2, axis=1) + 0.01) + + with self.assertWarns(UserWarning): + S2CondS2GridDistribution.from_function( + trans, no_grid_points, False, "leopardi" + ) + + @_skip_jax + def test_warning_free_custom_normalized(self): + """testWarningFreeCustomNormalized: manually normalized transition should be warn-free.""" + no_grid_points = 1000 + + def trans(xkk, xk): + # xkk: (n1, 3), xk: (n2, 3) -> (n1, n2) (cartesian product mode) + import numpy as np + from pyrecest.distributions.hypersphere_subset.custom_hyperspherical_distribution import ( + CustomHypersphericalDistribution, + ) + + D = array([0.1, 0.15, 0.3]) + + def trans_unnorm(pts, fixed): + diff = (pts - fixed[None, :]) * D[None, :] + return 1.0 / (np.sum(diff**2, axis=1) + 0.01) + + p = np.zeros((xkk.shape[0], xk.shape[0])) + for i in range(xk.shape[0]): + chd = CustomHypersphericalDistribution( + lambda pts, fi=xk[i]: trans_unnorm(pts, fi), 2 + ) + norm_const = chd.integrate_numerically() + p[:, i] = trans_unnorm(xkk, xk[i]) / norm_const + return p + + with warnings.catch_warnings(): + warnings.simplefilter("error") + S2CondS2GridDistribution.from_function( + trans, no_grid_points, True, "leopardi" + ) + + @_skip_jax + def test_equal_with_and_without_cart(self): + """testEqualWithAndWithoutCart: Cartesian and non-Cartesian modes should agree.""" + no_grid_points = 100 + dist = VonMisesFisherDistribution(array([0.0, -1.0, 0.0]), 100.0) + + def f_trans1(xkk, xk): + import numpy as np + + vals = dist.pdf(xkk) # (n1,) + return np.tile(vals[:, None], (1, xk.shape[0])) # (n1, n2) + + def f_trans2(xkk, xk): + return dist.pdf(xkk) # (n_pairs,) in non-Cartesian mode + + s2s2_1 = S2CondS2GridDistribution.from_function(f_trans1, no_grid_points, True) + s2s2_2 = S2CondS2GridDistribution.from_function( + f_trans2, no_grid_points, False + ) + + npt.assert_array_equal(s2s2_1.grid, s2s2_2.grid) + npt.assert_allclose(s2s2_1.grid_values, s2s2_2.grid_values, rtol=1e-10) + + @_skip_jax + def test_fix_dim_returns_spherical_grid_distribution(self): + """fix_dim should return SphericalGridDistribution instances.""" + no_grid_points = 50 + + def trans(xkk, xk): + import numpy as np + + result = np.zeros((xkk.shape[0], xk.shape[0])) + for i in range(xk.shape[0]): + vmf = VonMisesFisherDistribution(xk[i], 1.0) + result[:, i] = vmf.pdf(xkk) + return result + + s2s2 = S2CondS2GridDistribution.from_function( + trans, no_grid_points, True, "leopardi" + ) + + point = s2s2.grid[0] + sgd1 = s2s2.fix_dim(1, point) + sgd2 = s2s2.fix_dim(2, point) + self.assertIsInstance(sgd1, SphericalGridDistribution) + self.assertIsInstance(sgd2, SphericalGridDistribution) + + @_skip_jax + def test_fix_dim_mean_direction(self): + """ + testFixDim: fixing dim 2 at a grid point and computing mean_direction + should give back the conditioning point (approx). + """ + no_grid_points = 112 + + def trans(xkk, xk): + import numpy as np + + result = np.zeros((xkk.shape[0], xk.shape[0])) + for i in range(xk.shape[0]): + vmf = VonMisesFisherDistribution(xk[i], 1.0) + result[:, i] = vmf.pdf(xkk) + return result + + s2s2 = S2CondS2GridDistribution.from_function( + trans, no_grid_points, True, "leopardi" + ) + + for point in s2s2.grid: + sgd = s2s2.fix_dim(2, point) + npt.assert_allclose(sgd.mean_direction(), point, atol=1e-1) + + @_skip_jax + def test_marginalize_out_returns_spherical_grid_distribution(self): + """marginalize_out should return SphericalGridDistribution.""" + no_grid_points = 50 + + def trans(xkk, xk): + import numpy as np + + result = np.zeros((xkk.shape[0], xk.shape[0])) + for i in range(xk.shape[0]): + vmf = VonMisesFisherDistribution(xk[i], 1.0) + result[:, i] = vmf.pdf(xkk) + return result + + s2s2 = S2CondS2GridDistribution.from_function( + trans, no_grid_points, True, "leopardi" + ) + sgd1 = s2s2.marginalize_out(1) + sgd2 = s2s2.marginalize_out(2) + self.assertIsInstance(sgd1, SphericalGridDistribution) + self.assertIsInstance(sgd2, SphericalGridDistribution) + + +if __name__ == "__main__": + unittest.main() From e5e0b206f7d7dd83056616548020c6cf33301ddf Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 31 Mar 2026 20:25:52 +0000 Subject: [PATCH 2/7] Fix hardcoded pi constant in test Agent-Logs-Url: https://github.com/FlorianPfaff/PyRecEst/sessions/5ab618f7-210c-4d7c-a7d7-2406930e6fc2 Co-authored-by: FlorianPfaff <6773539+FlorianPfaff@users.noreply.github.com> --- .../tests/distributions/test_s2_cond_s2_grid_distribution.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/pyrecest/tests/distributions/test_s2_cond_s2_grid_distribution.py b/pyrecest/tests/distributions/test_s2_cond_s2_grid_distribution.py index d322be485..265266190 100644 --- a/pyrecest/tests/distributions/test_s2_cond_s2_grid_distribution.py +++ b/pyrecest/tests/distributions/test_s2_cond_s2_grid_distribution.py @@ -62,7 +62,9 @@ def test_wrong_grid_dim_raises(self): # Build a 2-sphere grid and misshape it to 4D grid, _ = get_grid_hypersphere("leopardi", 10, 2) n = grid.shape[0] - surface = 4 * 3.141592653589793 + import numpy as np + + surface = 4 * np.pi gv = ones((n, n)) / surface # Simulate a non-S2 grid (embed in 4D instead of 3D) - should raise import numpy as np From 1ebcdaca19ec317c6452fcd6ba9e370e4b6266f8 Mon Sep 17 00:00:00 2001 From: Florian Pfaff Date: Wed, 1 Apr 2026 16:47:59 +0200 Subject: [PATCH 3/7] Cleanup and using backend --- .../test_s2_cond_s2_grid_distribution.py | 37 +++++-------------- .../test_sd_cond_sd_grid_distribution.py | 6 +-- 2 files changed, 12 insertions(+), 31 deletions(-) diff --git a/pyrecest/tests/distributions/test_s2_cond_s2_grid_distribution.py b/pyrecest/tests/distributions/test_s2_cond_s2_grid_distribution.py index 265266190..e8a778de8 100644 --- a/pyrecest/tests/distributions/test_s2_cond_s2_grid_distribution.py +++ b/pyrecest/tests/distributions/test_s2_cond_s2_grid_distribution.py @@ -1,15 +1,10 @@ -""" -Tests for S2CondS2GridDistribution. - -These tests mirror the MATLAB test class S2CondS2GridDistributionTest. -""" import unittest import warnings +from matplotlib.pylab import column_stack import numpy.testing as npt -import pyrecest +import pyrecest.backend import array, zeros, pi, ones, sum -from pyrecest.backend import array, ones from pyrecest.distributions.conditional.s2_cond_s2_grid_distribution import ( S2CondS2GridDistribution, ) @@ -62,14 +57,12 @@ def test_wrong_grid_dim_raises(self): # Build a 2-sphere grid and misshape it to 4D grid, _ = get_grid_hypersphere("leopardi", 10, 2) n = grid.shape[0] - import numpy as np - surface = 4 * np.pi + surface = 4 * pi gv = ones((n, n)) / surface # Simulate a non-S2 grid (embed in 4D instead of 3D) - should raise - import numpy as np - grid_4d = np.column_stack([grid, np.zeros(n)]) + grid_4d = column_stack([grid, zeros(n)]) with self.assertRaises(ValueError): S2CondS2GridDistribution(grid_4d, gv) @@ -84,9 +77,7 @@ def test_warning_free_normalized_vmf(self): def trans(xkk, xk): # xkk: (n1, 3), xk: (n2, 3) -> (n1, n2) - import numpy as np - - result = np.zeros((xkk.shape[0], xk.shape[0])) + result = zeros((xkk.shape[0], xk.shape[0])) for i in range(xk.shape[0]): vmf = VonMisesFisherDistribution(xk[i], 1.0) result[:, i] = vmf.pdf(xkk) @@ -109,7 +100,7 @@ def trans(xkk, xk): # xkk, xk both (n_pairs, 3) when fun_does_cartesian_product=False D = array([0.1, 0.15, 1.0]) diff = (xkk - xk) * D[None, :] - return 1.0 / (np.sum(diff**2, axis=1) + 0.01) + return 1.0 / (sum(diff**2, axis=1) + 0.01) with self.assertWarns(UserWarning): S2CondS2GridDistribution.from_function( @@ -134,7 +125,7 @@ def trans_unnorm(pts, fixed): diff = (pts - fixed[None, :]) * D[None, :] return 1.0 / (np.sum(diff**2, axis=1) + 0.01) - p = np.zeros((xkk.shape[0], xk.shape[0])) + p = zeros((xkk.shape[0], xk.shape[0])) for i in range(xk.shape[0]): chd = CustomHypersphericalDistribution( lambda pts, fi=xk[i]: trans_unnorm(pts, fi), 2 @@ -156,8 +147,6 @@ def test_equal_with_and_without_cart(self): dist = VonMisesFisherDistribution(array([0.0, -1.0, 0.0]), 100.0) def f_trans1(xkk, xk): - import numpy as np - vals = dist.pdf(xkk) # (n1,) return np.tile(vals[:, None], (1, xk.shape[0])) # (n1, n2) @@ -178,9 +167,7 @@ def test_fix_dim_returns_spherical_grid_distribution(self): no_grid_points = 50 def trans(xkk, xk): - import numpy as np - - result = np.zeros((xkk.shape[0], xk.shape[0])) + result = zeros((xkk.shape[0], xk.shape[0])) for i in range(xk.shape[0]): vmf = VonMisesFisherDistribution(xk[i], 1.0) result[:, i] = vmf.pdf(xkk) @@ -205,9 +192,7 @@ def test_fix_dim_mean_direction(self): no_grid_points = 112 def trans(xkk, xk): - import numpy as np - - result = np.zeros((xkk.shape[0], xk.shape[0])) + result = zeros((xkk.shape[0], xk.shape[0])) for i in range(xk.shape[0]): vmf = VonMisesFisherDistribution(xk[i], 1.0) result[:, i] = vmf.pdf(xkk) @@ -227,9 +212,7 @@ def test_marginalize_out_returns_spherical_grid_distribution(self): no_grid_points = 50 def trans(xkk, xk): - import numpy as np - - result = np.zeros((xkk.shape[0], xk.shape[0])) + result = zeros((xkk.shape[0], xk.shape[0])) for i in range(xk.shape[0]): vmf = VonMisesFisherDistribution(xk[i], 1.0) result[:, i] = vmf.pdf(xkk) diff --git a/pyrecest/tests/distributions/test_sd_cond_sd_grid_distribution.py b/pyrecest/tests/distributions/test_sd_cond_sd_grid_distribution.py index 51e8f7e75..fac750782 100644 --- a/pyrecest/tests/distributions/test_sd_cond_sd_grid_distribution.py +++ b/pyrecest/tests/distributions/test_sd_cond_sd_grid_distribution.py @@ -3,10 +3,8 @@ import numpy.testing as npt import pyrecest -from pyrecest.backend import ( - array, - ones, -) +from pyrecest.backend import array, ones + from pyrecest.distributions.conditional.sd_cond_sd_grid_distribution import ( SdCondSdGridDistribution, ) From 5d5deffb918e1669c666761f31bc5e30ae4486e0 Mon Sep 17 00:00:00 2001 From: Florian Pfaff Date: Thu, 2 Apr 2026 19:41:13 +0200 Subject: [PATCH 4/7] Fixed bug in TestS2CondS2GridDistribution --- .../tests/distributions/test_s2_cond_s2_grid_distribution.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/pyrecest/tests/distributions/test_s2_cond_s2_grid_distribution.py b/pyrecest/tests/distributions/test_s2_cond_s2_grid_distribution.py index e8a778de8..2fc0f2a80 100644 --- a/pyrecest/tests/distributions/test_s2_cond_s2_grid_distribution.py +++ b/pyrecest/tests/distributions/test_s2_cond_s2_grid_distribution.py @@ -3,7 +3,8 @@ from matplotlib.pylab import column_stack import numpy.testing as npt -import pyrecest.backend import array, zeros, pi, ones, sum +import pyrecest +from pyrecest.backend import array, zeros, pi, ones, sum from pyrecest.distributions.conditional.s2_cond_s2_grid_distribution import ( S2CondS2GridDistribution, From 68f03b7a048d46dfde0be06b5a102c5b0eecc572 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 3 Apr 2026 10:14:42 +0000 Subject: [PATCH 5/7] Replace numpy/matplotlib imports with pyrecest.backend equivalents in test file Agent-Logs-Url: https://github.com/FlorianPfaff/PyRecEst/sessions/1f2766e8-1110-4de3-a516-b0205d621324 Co-authored-by: FlorianPfaff <6773539+FlorianPfaff@users.noreply.github.com> --- .../distributions/test_s2_cond_s2_grid_distribution.py | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/pyrecest/tests/distributions/test_s2_cond_s2_grid_distribution.py b/pyrecest/tests/distributions/test_s2_cond_s2_grid_distribution.py index 2fc0f2a80..4cbd0290c 100644 --- a/pyrecest/tests/distributions/test_s2_cond_s2_grid_distribution.py +++ b/pyrecest/tests/distributions/test_s2_cond_s2_grid_distribution.py @@ -1,10 +1,9 @@ import unittest import warnings -from matplotlib.pylab import column_stack import numpy.testing as npt import pyrecest -from pyrecest.backend import array, zeros, pi, ones, sum +from pyrecest.backend import array, column_stack, ones, pi, sum, tile, zeros from pyrecest.distributions.conditional.s2_cond_s2_grid_distribution import ( S2CondS2GridDistribution, @@ -96,8 +95,6 @@ def test_warning_unnormalized(self): no_grid_points = 112 def trans(xkk, xk): - import numpy as np - # xkk, xk both (n_pairs, 3) when fun_does_cartesian_product=False D = array([0.1, 0.15, 1.0]) diff = (xkk - xk) * D[None, :] @@ -115,7 +112,6 @@ def test_warning_free_custom_normalized(self): def trans(xkk, xk): # xkk: (n1, 3), xk: (n2, 3) -> (n1, n2) (cartesian product mode) - import numpy as np from pyrecest.distributions.hypersphere_subset.custom_hyperspherical_distribution import ( CustomHypersphericalDistribution, ) @@ -124,7 +120,7 @@ def trans(xkk, xk): def trans_unnorm(pts, fixed): diff = (pts - fixed[None, :]) * D[None, :] - return 1.0 / (np.sum(diff**2, axis=1) + 0.01) + return 1.0 / (sum(diff**2, axis=1) + 0.01) p = zeros((xkk.shape[0], xk.shape[0])) for i in range(xk.shape[0]): @@ -149,7 +145,7 @@ def test_equal_with_and_without_cart(self): def f_trans1(xkk, xk): vals = dist.pdf(xkk) # (n1,) - return np.tile(vals[:, None], (1, xk.shape[0])) # (n1, n2) + return tile(vals[:, None], (1, xk.shape[0])) # (n1, n2) def f_trans2(xkk, xk): return dist.pdf(xkk) # (n_pairs,) in non-Cartesian mode From 7814d621fefcb0abe32d11fcd7a93e536c4cbc5f Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 3 Apr 2026 13:46:18 +0000 Subject: [PATCH 6/7] Fix pylint W0622 (redefined-builtin sum) and W0613 (unused argument xk) Agent-Logs-Url: https://github.com/FlorianPfaff/PyRecEst/sessions/8f721113-58cd-484b-a086-b44f38831fd0 Co-authored-by: FlorianPfaff <6773539+FlorianPfaff@users.noreply.github.com> --- .../tests/distributions/test_s2_cond_s2_grid_distribution.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pyrecest/tests/distributions/test_s2_cond_s2_grid_distribution.py b/pyrecest/tests/distributions/test_s2_cond_s2_grid_distribution.py index 4cbd0290c..de97fe813 100644 --- a/pyrecest/tests/distributions/test_s2_cond_s2_grid_distribution.py +++ b/pyrecest/tests/distributions/test_s2_cond_s2_grid_distribution.py @@ -3,7 +3,7 @@ import numpy.testing as npt import pyrecest -from pyrecest.backend import array, column_stack, ones, pi, sum, tile, zeros +from pyrecest.backend import array, column_stack, ones, pi, sum, tile, zeros # pylint: disable=redefined-builtin from pyrecest.distributions.conditional.s2_cond_s2_grid_distribution import ( S2CondS2GridDistribution, @@ -147,7 +147,7 @@ def f_trans1(xkk, xk): vals = dist.pdf(xkk) # (n1,) return tile(vals[:, None], (1, xk.shape[0])) # (n1, n2) - def f_trans2(xkk, xk): + def f_trans2(xkk, _xk): return dist.pdf(xkk) # (n_pairs,) in non-Cartesian mode s2s2_1 = S2CondS2GridDistribution.from_function(f_trans1, no_grid_points, True) From f3bbb8fea0693dcb0f60995745e30dcd4f9f684b Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 3 Apr 2026 20:21:01 +0000 Subject: [PATCH 7/7] Fix pytorch backend test failures: use simplefilter(\"error\", UserWarning) instead of simplefilter(\"error\") Agent-Logs-Url: https://github.com/FlorianPfaff/PyRecEst/sessions/1dd4271f-8e52-4d2f-8a36-a54a1b5e6e22 Co-authored-by: FlorianPfaff <6773539+FlorianPfaff@users.noreply.github.com> --- .../tests/distributions/test_s2_cond_s2_grid_distribution.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pyrecest/tests/distributions/test_s2_cond_s2_grid_distribution.py b/pyrecest/tests/distributions/test_s2_cond_s2_grid_distribution.py index de97fe813..4f0e0f260 100644 --- a/pyrecest/tests/distributions/test_s2_cond_s2_grid_distribution.py +++ b/pyrecest/tests/distributions/test_s2_cond_s2_grid_distribution.py @@ -84,7 +84,7 @@ def trans(xkk, xk): return result with warnings.catch_warnings(): - warnings.simplefilter("error") + warnings.simplefilter("error", UserWarning) S2CondS2GridDistribution.from_function( trans, no_grid_points, True, "leopardi" ) @@ -132,7 +132,7 @@ def trans_unnorm(pts, fixed): return p with warnings.catch_warnings(): - warnings.simplefilter("error") + warnings.simplefilter("error", UserWarning) S2CondS2GridDistribution.from_function( trans, no_grid_points, True, "leopardi" )