From afe79c073cc53305709992ee1b47cb3c94b25923 Mon Sep 17 00:00:00 2001 From: Florian Pfaff <6773539+FlorianPfaff@users.noreply.github.com> Date: Tue, 18 Aug 2026 21:58:20 +0800 Subject: [PATCH 1/4] Initialize hyperhemispherical particles on manifold --- src/pyrecest/filters/hyperhemispherical_particle_filter.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/pyrecest/filters/hyperhemispherical_particle_filter.py b/src/pyrecest/filters/hyperhemispherical_particle_filter.py index f6e25b4016..591316999b 100644 --- a/src/pyrecest/filters/hyperhemispherical_particle_filter.py +++ b/src/pyrecest/filters/hyperhemispherical_particle_filter.py @@ -1,6 +1,6 @@ from numbers import Integral -from pyrecest.backend import empty +from pyrecest.backend import hstack, ones, zeros from pyrecest.distributions.hypersphere_subset.abstract_hyperhemispherical_distribution import ( AbstractHyperhemisphericalDistribution, ) @@ -34,9 +34,10 @@ def __init__(self, n_particles: int, dim: int) -> None: """ n_particles = _validate_positive_integer(n_particles, "n_particles") dim = _validate_positive_integer(dim, "dim") - initial_filter_state = HyperhemisphericalDiracDistribution( - empty((n_particles, dim + 1)) + initial_particles = hstack( + (zeros((n_particles, dim)), ones((n_particles, 1))) ) + initial_filter_state = HyperhemisphericalDiracDistribution(initial_particles) HyperhemisphericalFilterMixin.__init__(self) AbstractParticleFilter.__init__(self, initial_filter_state=initial_filter_state) From 3d771688c12c4928464423b4e821402e05746ad8 Mon Sep 17 00:00:00 2001 From: Florian Pfaff <6773539+FlorianPfaff@users.noreply.github.com> Date: Tue, 18 Aug 2026 21:58:46 +0800 Subject: [PATCH 2/4] Initialize product particles on hemispheres --- .../hyperhemisphere_cart_prod_particle_filter.py | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/pyrecest/filters/hyperhemisphere_cart_prod_particle_filter.py b/src/pyrecest/filters/hyperhemisphere_cart_prod_particle_filter.py index ed70d7d220..b0edfd31b7 100644 --- a/src/pyrecest/filters/hyperhemisphere_cart_prod_particle_filter.py +++ b/src/pyrecest/filters/hyperhemisphere_cart_prod_particle_filter.py @@ -4,7 +4,7 @@ from beartype import beartype # pylint: disable=no-name-in-module,no-member -from pyrecest.backend import empty, ones, ones_like +from pyrecest.backend import hstack, ones, ones_like, zeros from pyrecest.distributions import AbstractHypersphericalDistribution from pyrecest.distributions.cart_prod.hyperhemisphere_cart_prod_dirac_distribution import ( HyperhemisphereCartProdDiracDistribution, @@ -45,8 +45,15 @@ def __init__( n_particles = _validate_positive_integer(n_particles, "n_particles") dim_hemisphere = _validate_positive_integer(dim_hemisphere, "dim_hemisphere") n_hemispheres = _validate_positive_integer(n_hemispheres, "n_hemispheres") + initial_component = hstack( + ( + zeros((n_particles, dim_hemisphere)), + ones((n_particles, 1)), + ) + ) + initial_particles = hstack([initial_component] * n_hemispheres) initial_filter_state = HyperhemisphereCartProdDiracDistribution( - empty((n_particles, (dim_hemisphere + 1) * n_hemispheres)), + initial_particles, ones(n_particles) / n_particles, dim_hemisphere, n_hemispheres, From 15b7f9c28f93c456d17b81d9b7a48e32d1b820a8 Mon Sep 17 00:00:00 2001 From: Florian Pfaff <6773539+FlorianPfaff@users.noreply.github.com> Date: Tue, 18 Aug 2026 21:59:09 +0800 Subject: [PATCH 3/4] Test hyperhemispherical initialization geometry --- tests/filters/test_hyperhemispherical_particle_filter.py | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/tests/filters/test_hyperhemispherical_particle_filter.py b/tests/filters/test_hyperhemispherical_particle_filter.py index 3b142fc39e..a9bf2ea7e3 100644 --- a/tests/filters/test_hyperhemispherical_particle_filter.py +++ b/tests/filters/test_hyperhemispherical_particle_filter.py @@ -4,7 +4,7 @@ import pyrecest.backend # pylint: disable=redefined-builtin,no-name-in-module,no-member -from pyrecest.backend import array, linalg, random +from pyrecest.backend import allclose, array, hstack, linalg, ones, random, zeros from pyrecest.distributions import HyperhemisphericalWatsonDistribution from pyrecest.distributions.hypersphere_subset.hyperhemispherical_dirac_distribution import ( HyperhemisphericalDiracDistribution, @@ -32,6 +32,13 @@ def test_initialization(self): hpf = HyperhemisphericalParticleFilter(self.n_particles, 3) self.assertEqual(hpf.filter_state.w.shape, (self.n_particles,)) self.assertEqual(hpf.filter_state.d.shape, (self.n_particles, 4)) + expected_particles = hstack( + ( + zeros((self.n_particles, 3)), + ones((self.n_particles, 1)), + ) + ) + self.assertTrue(bool(allclose(hpf.filter_state.d, expected_particles))) def test_constructor_rejects_invalid_particle_count(self): for n_particles in (True, 0, -1, 1.5): From 92cfc6433c95e287ebaf4c07ae5992bece320e9b Mon Sep 17 00:00:00 2001 From: Florian Pfaff <6773539+FlorianPfaff@users.noreply.github.com> Date: Tue, 18 Aug 2026 21:59:40 +0800 Subject: [PATCH 4/4] Test product particle initialization geometry --- ...test_hyperhemisphere_cart_prod_particle_filter.py | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/tests/filters/test_hyperhemisphere_cart_prod_particle_filter.py b/tests/filters/test_hyperhemisphere_cart_prod_particle_filter.py index dd909eba5b..457a89106c 100644 --- a/tests/filters/test_hyperhemisphere_cart_prod_particle_filter.py +++ b/tests/filters/test_hyperhemisphere_cart_prod_particle_filter.py @@ -3,8 +3,12 @@ import pyrecest.backend # pylint: disable=no-name-in-module,no-member from pyrecest.backend import ( # pylint: disable=no-name-in-module,no-member,redefined-builtin abs, + allclose, array, + hstack, + ones, sum, + zeros, ) from pyrecest.distributions import VonMisesFisherDistribution from pyrecest.distributions.cart_prod.hyperhemisphere_cart_prod_dirac_distribution import ( @@ -27,6 +31,14 @@ def test_init(self): pf.filter_state.d.shape, (n_particles, (dim_hemisphere + 1) * n_hemispheres), ) + expected_component = hstack( + ( + zeros((n_particles, dim_hemisphere)), + ones((n_particles, 1)), + ) + ) + expected_particles = hstack([expected_component] * n_hemispheres) + self.assertTrue(bool(allclose(pf.filter_state.d, expected_particles))) def test_constructor_rejects_invalid_particle_count(self): for n_particles in (True, 0, -1, 1.5):