POMDPPlanners.tests.test_core.test_belief package

Submodules

POMDPPlanners.tests.test_core.test_belief.belief_equivalence_utils module

Shared belief-level equivalence checks for particle beliefs.

This module provides environment-agnostic assertion helpers that compare a standard WeightedParticleBelief against a VectorizedWeightedParticleBelief through their public interface (update, normalized_weights, sample).

Callers build the two beliefs with aligned particles and weights; the helpers run the supplied action/observation through both paths and assert the expected invariants. Each update-invoking helper seeds numpy’s global RNG identically on both paths so stochastic transitions and observation draws consume the same random numbers, mirroring the pattern used in POMDPPlanners.tests.test_core.test_belief.vectorized_updater_test_utils.

Functions:

assert_update_particles_match: Next particles agree after one update. assert_update_weights_match: Normalized weights agree after one update. assert_update_top_k_ranking_agrees: Top-K particle ranking agrees. assert_update_equivalence: Combined particle + weight + ranking check. assert_chained_update_equivalence: Invariants hold across a sequence of updates. assert_normalized_weights_match: Pre-update weight-vector sanity check. assert_sample_distributions_match: Empirical sample histograms agree.

POMDPPlanners.tests.test_core.test_belief.belief_equivalence_utils.assert_chained_update_equivalence(base, vec, steps, pomdp, atol_particles=1e-10, atol_weights=1e-05, seed=None, particle_to_array=None)[source]

Run a sequence of updates and assert final particles and weights agree.

Parameters:
  • base (WeightedParticleBelief) – Baseline WeightedParticleBelief with aligned particles.

  • vec (VectorizedWeightedParticleBelief) – Vectorized belief holding the same particles as base.

  • steps (Sequence[Tuple[Any, Any]]) – Iterable of (action, observation) pairs applied in order.

  • pomdp (Environment) – Environment used by the baseline’s per-particle transition loop.

  • atol_particles (float) – Absolute tolerance for the final particle comparison.

  • atol_weights (float) – Absolute tolerance for the final normalized-weight comparison.

  • seed (Optional[int]) – If provided, numpy’s global RNG is seeded to this value before each path of every step.

  • particle_to_array (Callable[[Any], ndarray] | None)

Return type:

Tuple[WeightedParticleBelief, VectorizedWeightedParticleBelief]

Returns:

The final (base, vec) belief pair.

POMDPPlanners.tests.test_core.test_belief.belief_equivalence_utils.assert_normalized_weights_match(base, vec, atol=1e-10)[source]

Assert the two beliefs expose the same probability vector over particles.

Intended as a pre-update sanity check on aligned beliefs.

Parameters:
Return type:

None

POMDPPlanners.tests.test_core.test_belief.belief_equivalence_utils.assert_sample_distributions_match(base, vec, n_samples=20000, tol=0.03, atol_weights=0.03, seed=None, particle_to_array=None)[source]

Assert sample output distributions agree across beliefs and match weights.

Draws n_samples from each belief, aggregates by particle identity (duplicate particle rows are merged into their first occurrence so discrete-state environments are handled correctly), and runs three checks:

  1. The two empirical histograms agree in L-infinity within tol.

  2. base’s histogram agrees with its own normalized_weights within atol_weights (verifies base.sample() is unbiased).

  3. Same for vec (verifies vec.sample() is unbiased).

Check 1 alone would pass even if both sample() impls were biased the same way. Checks 2 and 3 close that hole.

The helper assumes particles are convertible to fixed-length numeric arrays – the same constraint VectorizedWeightedParticleBelief imposes on the particle store itself.

Parameters:
  • base (WeightedParticleBelief) – Baseline WeightedParticleBelief.

  • vec (VectorizedWeightedParticleBelief) – Vectorized belief sharing the same particles as base.

  • n_samples (int) – Number of samples drawn from each belief.

  • tol (float) – L-infinity tolerance for the two histograms agreeing.

  • atol_weights (float) – L-infinity tolerance for each histogram agreeing with its belief’s normalized_weights.

  • seed (Optional[int]) – If provided, numpy’s global RNG is seeded to this value before each sampling path so the test is deterministic.

  • particle_to_array (Callable[[Any], ndarray] | None)

Return type:

None

POMDPPlanners.tests.test_core.test_belief.belief_equivalence_utils.assert_update_equivalence(base, vec, action, observation, pomdp, atol_particles=1e-10, atol_weights=1e-06, significance_threshold=0.0001, top_k=5, seed=None, particle_to_array=None)[source]

Run one update and assert particles, weights, and top-k all agree.

Combines assert_update_particles_match(), assert_update_weights_match(), and assert_update_top_k_ranking_agrees() into a single end-to-end check for callers that want the full equivalence invariant in one line.

Parameters:
  • base (WeightedParticleBelief) – Baseline WeightedParticleBelief with aligned particles.

  • vec (VectorizedWeightedParticleBelief) – Vectorized belief holding the same particles as base.

  • action (Any) – Action passed to both update calls.

  • observation (Any) – Observation passed to both update calls.

  • pomdp (Environment) – Environment used by the baseline’s per-particle transition loop.

  • atol_particles (float) – Absolute tolerance for the next-particle comparison.

  • atol_weights (float) – Absolute tolerance for the normalized-weight comparison.

  • significance_threshold (Optional[float]) – Weight-masking threshold passed to the weight check; set to None to disable masking.

  • top_k (int) – Number of top particles by weight compared for ranking agreement.

  • seed (Optional[int]) – If provided, numpy’s global RNG is seeded to this value before each path.

  • particle_to_array (Callable[[Any], ndarray] | None)

Return type:

Tuple[WeightedParticleBelief, VectorizedWeightedParticleBelief]

Returns:

The updated (base, vec) belief pair.

POMDPPlanners.tests.test_core.test_belief.belief_equivalence_utils.assert_update_equivalence_per_particle_seeded(base, vec, action, observation, pomdp, atol_particles=1e-10, atol_weights=1e-06, significance_threshold=None, top_k=5, base_seed=0, particle_to_array=None)[source]

Per-particle-seeded variant of assert_update_equivalence().

For each particle index i, build a single-particle belief on both sides, seed numpy’s global RNG to base_seed + i, run one update, and stitch the per-particle results back into aggregate beliefs before running the usual particle / weight / top-K checks.

Use this helper for environments whose vectorized batch_transition consumes the RNG in a different order than the baseline per-particle loop (e.g. LaserTag, which bulk-samples robot noise then opponent noise while the standard path interleaves them per particle). Under bulk-vs-interleaved ordering, a single shared seed cannot make the two paths agree for N > 1; per-particle seeding restores bit-for-bit equivalence at the cost of O(N) update calls.

Parameters:
  • base (WeightedParticleBelief) – Baseline WeightedParticleBelief with aligned particles.

  • vec (VectorizedWeightedParticleBelief) – Vectorized belief holding the same particles as base.

  • action (Any) – Action passed to both update calls.

  • observation (Any) – Observation passed to both update calls.

  • pomdp (Environment) – Environment used by the baseline’s per-particle transition loop.

  • atol_particles (float) – Absolute tolerance for the next-particle comparison.

  • atol_weights (float) – Absolute tolerance for the normalized-weight comparison.

  • significance_threshold (Optional[float]) – Weight-masking threshold; None disables.

  • top_k (int) – Number of top particles by weight compared for ranking agreement.

  • base_seed (int) – Seed for particle i is base_seed + i.

  • particle_to_array (Optional[Callable[[Any], ndarray]]) – Optional converter passed through to the particle comparison. See assert_update_particles_match().

Return type:

Tuple[WeightedParticleBelief, VectorizedWeightedParticleBelief]

Returns:

The updated (base, vec) belief pair built by aggregating the per-particle results.

POMDPPlanners.tests.test_core.test_belief.belief_equivalence_utils.assert_update_particles_match(base, vec, action, observation, pomdp, atol=1e-10, seed=None, particle_to_array=None)[source]

Run one update on both beliefs and assert next particles agree.

Parameters:
  • base (WeightedParticleBelief) – Baseline WeightedParticleBelief with aligned particles.

  • vec (VectorizedWeightedParticleBelief) – Vectorized belief holding the same particles as base.

  • action (Any) – Action passed to both update calls.

  • observation (Any) – Observation passed to both update calls.

  • pomdp (Environment) – Environment used by the baseline’s per-particle transition loop.

  • atol (float) – Absolute tolerance for the particle array comparison.

  • seed (Optional[int]) – If provided, numpy’s global RNG is seeded to this value before each path so stochastic transitions consume identical random sequences.

  • particle_to_array (Optional[Callable[[Any], ndarray]]) – Optional callable converting a baseline particle to a 1-D np.ndarray. Needed when base.particles holds non-ndarray objects (e.g. dataclasses) whose layout matches vec.particles rows. Defaults to np.asarray().

Return type:

Tuple[WeightedParticleBelief, VectorizedWeightedParticleBelief]

Returns:

The updated (base, vec) belief pair so callers can chain asserts.

POMDPPlanners.tests.test_core.test_belief.belief_equivalence_utils.assert_update_particles_match_per_particle_seeded(base, vec, action, observation, pomdp, atol=1e-10, base_seed=0, particle_to_array=None)[source]

Per-particle-seeded variant of assert_update_particles_match().

See assert_update_equivalence_per_particle_seeded() for why bulk-vs-interleaved RNG ordering forces per-particle seeding. This helper only checks the next-particle array – use it when weight agreement is blocked by the log(eps + prob) floor in WeightedParticleBelief._update_weights for observations that underflow the Gaussian PDF across every particle.

Parameters:
  • base (WeightedParticleBelief) – Baseline WeightedParticleBelief with aligned particles.

  • vec (VectorizedWeightedParticleBelief) – Vectorized belief holding the same particles as base.

  • action (Any) – Action passed to both update calls.

  • observation (Any) – Observation passed to both update calls.

  • pomdp (Environment) – Environment used by the baseline’s per-particle transition loop.

  • atol (float) – Absolute tolerance for the particle array comparison.

  • base_seed (int) – Seed for particle i is base_seed + i.

  • particle_to_array (Optional[Callable[[Any], ndarray]]) – Optional converter passed through to the particle comparison. See assert_update_particles_match().

Return type:

Tuple[WeightedParticleBelief, VectorizedWeightedParticleBelief]

Returns:

The updated (base, vec) belief pair.

POMDPPlanners.tests.test_core.test_belief.belief_equivalence_utils.assert_update_top_k_ranking_agrees(base, vec, action, observation, pomdp, k=5, seed=None)[source]

Run one update and assert the top-k particle indices agree.

Parameters:
  • base (WeightedParticleBelief) – Baseline WeightedParticleBelief with aligned particles.

  • vec (VectorizedWeightedParticleBelief) – Vectorized belief holding the same particles as base.

  • action (Any) – Action passed to both update calls.

  • observation (Any) – Observation passed to both update calls.

  • pomdp (Environment) – Environment used by the baseline’s per-particle transition loop.

  • k (int) – Number of top particles by weight to compare.

  • seed (Optional[int]) – If provided, numpy’s global RNG is seeded to this value before each path.

Return type:

Tuple[WeightedParticleBelief, VectorizedWeightedParticleBelief]

Returns:

The updated (base, vec) belief pair.

POMDPPlanners.tests.test_core.test_belief.belief_equivalence_utils.assert_update_weights_match(base, vec, action, observation, pomdp, atol=1e-06, significance_threshold=None, seed=None)[source]

Run one update on both beliefs and assert normalized weights agree.

Parameters:
  • base (WeightedParticleBelief) – Baseline WeightedParticleBelief with aligned particles.

  • vec (VectorizedWeightedParticleBelief) – Vectorized belief holding the same particles as base.

  • action (Any) – Action passed to both update calls.

  • observation (Any) – Observation passed to both update calls.

  • pomdp (Environment) – Environment used by the baseline’s per-particle transition loop.

  • atol (float) – Absolute tolerance for the weight comparison.

  • significance_threshold (Optional[float]) – If given, only compare normalized weights for baseline particles with normalized_weight > significance_threshold. This absorbs the log(eps + p) floor in WeightedParticleBelief._update_weights vs. the vectorized path’s direct log-space accumulation, which drives tiny low-weight particles apart without affecting the belief’s effective distribution.

  • seed (Optional[int]) – If provided, numpy’s global RNG is seeded to this value before each path so stochastic transitions consume identical random sequences.

Return type:

Tuple[WeightedParticleBelief, VectorizedWeightedParticleBelief]

Returns:

The updated (base, vec) belief pair.

POMDPPlanners.tests.test_core.test_belief.test_base module

POMDPPlanners.tests.test_core.test_belief.test_belief_environment_integration module

POMDPPlanners.tests.test_core.test_belief.test_belief_utils module

POMDPPlanners.tests.test_core.test_belief.test_gaussian_belief module

POMDPPlanners.tests.test_core.test_belief.test_gaussian_belief_updaters module

Tests for Gaussian belief updater classes.

This module tests the concrete updater implementations: - LinearKalmanFilterUpdater: linear-Gaussian systems - ExtendedKalmanFilterUpdater: nonlinear systems with Jacobians - UnscentedKalmanFilterUpdater: nonlinear systems without Jacobians

class POMDPPlanners.tests.test_core.test_belief.test_gaussian_belief_updaters.TestExtendedKalmanFilterUpdater[source]

Bases: object

test_config_id_deterministic()[source]

Test that config_id is deterministic for identical EKF updaters.

Purpose: Validates that the same Q and R produce the same config_id.

Given: Two ExtendedKalmanFilterUpdater instances with identical Q and R. When: config_id is computed for both. Then: Both config_ids are equal.

Test type: unit

test_config_id_sensitive_to_parameters()[source]

Test that config_id differs when Q differs.

Purpose: Validates config_id sensitivity to noise parameters.

Given: Two ExtendedKalmanFilterUpdater instances with different Q matrices. When: config_id is computed for both. Then: The config_ids are different.

Test type: unit

test_ekf_covariance_is_symmetric()[source]

Test that the EKF posterior covariance is symmetric.

Purpose: Validates the symmetrization step in the EKF implementation.

Given: A nonlinear EKF system. When: An update is performed. Then: The resulting covariance is symmetric.

Test type: unit

test_integration_with_gaussian_belief()[source]

Test that the EKF updater works with GaussianBelief.update().

Purpose: Validates end-to-end integration of the EKF class with GaussianBelief.

Given: A GaussianBelief using an EKF updater for a linear system. When: belief.update() is called. Then: Returns a new GaussianBelief with updated parameters.

Test type: integration

test_linear_system_matches_kf()[source]

Test that the EKF matches the linear KF on a linear system.

Purpose: Validates that the EKF reduces to the standard KF for linear models.

Given: A linear system represented as both KF and EKF. When: Both are updated with the same observation. Then: Posterior means and covariances match within numerical tolerance.

Test type: unit

test_nonlinear_system_reduces_covariance()[source]

Test EKF on a nonlinear system reduces covariance after observation.

Purpose: Validates that the EKF incorporates observations to reduce uncertainty.

Given: A nonlinear system f(x,u)=x, h(x)=x^3 (cube observation). When: An observation is incorporated. Then: Posterior covariance trace is smaller than predicted covariance trace.

Test type: unit

class POMDPPlanners.tests.test_core.test_belief.test_gaussian_belief_updaters.TestLinearKalmanFilterUpdater[source]

Bases: object

test_1d_analytical_values()[source]

Test 1D Kalman filter against hand-computed analytical solution.

Purpose: Validates KF predict-correct matches textbook formula.

Given: A=1, B=0, H=1, Q=0, R=1, prior mean=0, prior cov=1. When: Observation z=2.0 is incorporated. Then: Posterior mean = 1.0, posterior variance = 0.5.

Test type: unit

test_1d_static_system()[source]

Test 1D Kalman filter on a static system with perfect observation.

Purpose: Validates that the KF converges toward the observation for a static system.

Given: A=1, B=0, H=1, Q=0.1, R=0.5 (1D static system with noisy observation). When: A single predict-correct cycle is performed with observation z=3.0. Then: The posterior mean moves toward 3.0 and covariance decreases.

Test type: unit

test_2d_tracking_covariance_decreases()[source]

Test 2D Kalman filter covariance reduction over multiple steps.

Purpose: Validates that repeated observations reduce uncertainty.

Given: 2D identity system with Q=0.01*I and R=0.5*I. When: 10 observations at [1, 1] are incorporated sequentially. Then: Covariance trace decreases monotonically.

Test type: unit

test_config_id_deterministic()[source]

Test that config_id is deterministic for identical updaters.

Purpose: Validates that the same parameters produce the same config_id.

Given: Two LinearKalmanFilterUpdater instances with identical parameters. When: config_id is computed for both. Then: Both config_ids are equal.

Test type: unit

test_config_id_sensitive_to_parameters()[source]

Test that config_id differs when parameters differ.

Purpose: Validates config_id sensitivity to matrix values.

Given: Two LinearKalmanFilterUpdater instances with different Q matrices. When: config_id is computed for both. Then: The config_ids are different.

Test type: unit

test_integration_with_gaussian_belief()[source]

Test that the linear KF updater works with GaussianBelief.update().

Purpose: Validates end-to-end integration of the updater class with GaussianBelief.

Given: A GaussianBelief using a linear KF updater. When: belief.update() is called. Then: Returns a new GaussianBelief with updated mean and covariance.

Test type: integration

test_with_control_input()[source]

Test Kalman filter with a non-zero control input.

Purpose: Validates that the control matrix B shifts the predicted mean.

Given: A=1, B=1, H=1, Q=0, R=1, prior mean=0, prior cov=1. When: Action u=5 and observation z=5 are applied. Then: Posterior mean is close to 5.

Test type: unit

class POMDPPlanners.tests.test_core.test_belief.test_gaussian_belief_updaters.TestUnscentedKalmanFilterUpdater[source]

Bases: object

test_config_id_deterministic()[source]

Test that config_id is deterministic for identical UKF updaters.

Purpose: Validates that the same parameters produce the same config_id.

Given: Two UnscentedKalmanFilterUpdater instances with identical parameters. When: config_id is computed for both. Then: Both config_ids are equal.

Test type: unit

test_config_id_sensitive_to_parameters()[source]

Test that config_id differs when scaling parameters differ.

Purpose: Validates config_id sensitivity to alpha/beta/kappa.

Given: Two UnscentedKalmanFilterUpdater instances with different alpha. When: config_id is computed for both. Then: The config_ids are different.

Test type: unit

test_higher_dimensional_system()[source]

Test UKF on a higher-dimensional system (d=5 state, p=3 observation).

Purpose: Validates that the UKF handles dimension mismatches between

state and observation spaces correctly.

Given: A 5D state system with 3D observations via a projection matrix. When: An update is performed. Then: State mean is 5D, covariance is 5x5, and covariance is symmetric PSD.

Test type: unit

test_integration_with_gaussian_belief()[source]

Test that the UKF updater works with GaussianBelief.update().

Purpose: Validates end-to-end integration of the UKF class with GaussianBelief.

Given: A GaussianBelief using a UKF updater for a linear system. When: belief.update() is called. Then: Returns a new GaussianBelief with updated parameters.

Test type: integration

test_linear_system_matches_kf()[source]

Test that the UKF matches the linear KF on a linear system.

Purpose: Validates that the UKF reduces to the standard KF for linear models.

Given: A linear system represented as both KF and UKF. When: Both are updated with the same observation. Then: Posterior means and covariances match within numerical tolerance.

Test type: unit

test_nonlinear_system_reduces_covariance()[source]

Test UKF on a nonlinear system reduces covariance after observation.

Purpose: Validates that the UKF incorporates observations to reduce uncertainty.

Given: A nonlinear system f(x,u)=x, h(x)=x^3 (cube observation). When: An observation is incorporated. Then: Posterior covariance trace is smaller than predicted covariance trace.

Test type: unit

test_sigma_point_scaling_parameters()[source]

Test UKF with custom alpha, beta, kappa scaling parameters.

Purpose: Validates that non-default sigma point parameters produce valid results.

Given: A UKF with alpha=0.5, beta=2.0, kappa=1.0. When: An update is performed. Then: Output mean has correct shape and covariance is symmetric PSD.

Test type: unit

test_ukf_covariance_is_symmetric()[source]

Test that the UKF posterior covariance is symmetric.

Purpose: Validates the symmetrization step in the UKF implementation.

Given: A nonlinear UKF system with off-diagonal covariance. When: An update is performed. Then: The resulting covariance is symmetric.

Test type: unit

test_ukf_matches_ekf_on_linear_system()[source]

Test that UKF and EKF produce identical results on a linear system.

Purpose: Validates UKF-EKF equivalence when the system is linear.

Given: The same linear system represented as both EKF and UKF. When: Both are updated with identical inputs. Then: Posterior means and covariances match within tolerance.

Test type: unit

POMDPPlanners.tests.test_core.test_belief.test_gaussian_mixture_belief module

POMDPPlanners.tests.test_core.test_belief.test_particle_beliefs module

POMDPPlanners.tests.test_core.test_belief.test_vectorized_weighted_particle_belief module

POMDPPlanners.tests.test_core.test_belief.vectorized_updater_test_utils module

Shared test utilities for comparing vectorized vs per-particle belief updates.

This module provides reusable assertion functions that verify vectorized batch operations (batch_transition, batch_observation_log_likelihood) produce the same results as the equivalent per-particle loop through the environment’s state_transition_model and observation_model.

Functions:

assert_batch_transition_matches_loop: Compare batch_transition vs per-particle transitions. assert_batch_obs_log_likelihood_matches_loop: Compare batch log-likelihoods vs per-particle.

POMDPPlanners.tests.test_core.test_belief.vectorized_updater_test_utils.assert_batch_obs_log_likelihood_matches_loop(updater, particles, action, observation, per_particle_ll_fn, atol=1e-10, compare_mode='absolute', err_msg='')[source]

Assert that batch_observation_log_likelihood matches a per-particle loop.

Parameters:
  • updater (VectorizedParticleBeliefUpdater) – Vectorized updater to test.

  • particles (ndarray) – Particle array of shape (N, d).

  • action (Any) – Action used for the observation model.

  • observation (Any) – Observation value.

  • per_particle_ll_fn (Callable[[ndarray, Any, Any], float]) – Callable(particle_1d, action, observation) -> float that wraps the environment’s per-particle log-likelihood logic.

  • atol (float) – Absolute tolerance for comparison.

  • compare_mode (str) – "absolute" for direct comparison, or "pairwise_diff" to compare ll - ll[0] (for environments whose per-particle path omits a normalisation constant).

  • err_msg (str) – Optional message appended on failure.

Raises:

ValueError – If compare_mode is not "absolute" or "pairwise_diff".

Return type:

None

POMDPPlanners.tests.test_core.test_belief.vectorized_updater_test_utils.assert_batch_transition_matches_loop(updater, particles, action, per_particle_transition_fn, atol=1e-10, seed=None, err_msg='')[source]

Assert that batch_transition matches a per-particle transition loop.

Parameters:
  • updater (VectorizedParticleBeliefUpdater) – Vectorized updater to test.

  • particles (ndarray) – Particle array of shape (N, d).

  • action (Any) – Action to apply.

  • per_particle_transition_fn (Callable[[ndarray, Any], ndarray]) – Callable(particle_1d, action) -> next_state_1d that wraps the environment’s per-particle transition logic.

  • atol (float) – Absolute tolerance for comparison.

  • seed (Optional[int]) – If provided, seeds np.random before each path so stochastic transitions consume the same random sequence.

  • err_msg (str) – Optional message appended on failure.

Return type:

None