POMDPPlanners.tests.test_environments.test_push_pomdp package
Tests for Push POMDP environments.
This package contains test modules for the Push POMDP environments: - test_push_pomdp.py: Discrete Push POMDP environment tests - test_continuous_push_pomdp.py: Continuous Push POMDP environment tests - test_continuous_push_geometry.py: Continuous Push geometry utility tests - test_push_pomdp_beliefs/: Belief factory and vectorized updater tests
Subpackages
- POMDPPlanners.tests.test_environments.test_push_pomdp.push_pomdp_utils package
- POMDPPlanners.tests.test_environments.test_push_pomdp.test_push_pomdp_beliefs package
- Submodules
- POMDPPlanners.tests.test_environments.test_push_pomdp.test_push_pomdp_beliefs.test_continuous_push_belief_factory module
- POMDPPlanners.tests.test_environments.test_push_pomdp.test_push_pomdp_beliefs.test_continuous_push_vectorized_updater module
TestBeliefEquivalenceWithBaselineTestContinuousPushVectorizedUpdaterTestContinuousPushVectorizedUpdater.setup_method()TestContinuousPushVectorizedUpdater.test_batch_obs_log_likelihood_matches_per_particle_loop()TestContinuousPushVectorizedUpdater.test_batch_observation_log_likelihood_shape()TestContinuousPushVectorizedUpdater.test_batch_transition_matches_per_particle_loop()TestContinuousPushVectorizedUpdater.test_batch_transition_shape()TestContinuousPushVectorizedUpdater.test_batch_transition_target_preserved()TestContinuousPushVectorizedUpdater.test_batch_transition_with_string_action()TestContinuousPushVectorizedUpdater.test_config_id_deterministic()TestContinuousPushVectorizedUpdater.test_from_environment_discrete()TestContinuousPushVectorizedUpdater.test_log_likelihood_finite()
- POMDPPlanners.tests.test_environments.test_push_pomdp.test_push_pomdp_beliefs.test_push_belief_factory module
- POMDPPlanners.tests.test_environments.test_push_pomdp.test_push_pomdp_beliefs.test_push_vectorized_updater module
Submodules
POMDPPlanners.tests.test_environments.test_push_pomdp.test_continuous_push_geometry module
Tests for Continuous Push POMDP geometry utilities.
This module tests circle-AABB overlap, point-inside-AABB, collision resolution, and grid clamping functions, including their batch variants.
- class POMDPPlanners.tests.test_environments.test_push_pomdp.test_continuous_push_geometry.TestContinuousPushGeometry[source]
Bases:
objectTest circle-AABB and point-AABB geometry utilities.
- test_batch_clamp_circle_to_grid_shapes()[source]
Test batch circle grid clamping output shape.
Purpose: Validates output shape of batch circle clamping.
Given: 10 random positions. When: batch_clamp_circle_to_grid is called. Then: Output shape matches (10, 2) and values are in range.
Test type: unit
- test_batch_clamp_point_to_grid()[source]
Test batch point grid clamping.
Purpose: Validates batch point clamping bounds.
Given: Points at (-1, 20) and (5, 5). When: batch_clamp_point_to_grid is called with grid_size=10. Then: First is clamped to (0, 9), second unchanged.
Test type: unit
- test_batch_point_inside_aabb()[source]
Test batch point-inside-AABB detection.
Purpose: Validates batch point-inside-AABB returns correct booleans.
Given: Points at (5, 5) inside and (0, 0) outside the AABB. When: batch_point_inside_aabb is called. Then: First is True, second is False.
Test type: unit
- test_batch_resolve_circle_wall_collision_shapes()[source]
Test batch circle-wall collision resolution output shape.
Purpose: Validates output shape of batch collision resolution.
Given: 10 random positions with radius 0.5 and one wall. When: batch_resolve_circle_wall_collision is called. Then: Output shape matches input shape (10, 2).
Test type: unit
- test_circle_aabb_overlap_false()[source]
Test that non-overlapping circle-AABB returns False.
Purpose: Validates that distant circles are not detected as overlapping.
- Given: A circle centered at (1.0, 1.0) with radius 0.3 and an AABB
centered at (5, 5) with half-extent 1.
When: circle_aabb_overlap is called. Then: Returns False.
Test type: unit
- test_circle_aabb_overlap_true()[source]
Test that overlapping circle-AABB returns True.
Purpose: Validates circle-AABB overlap detection.
- Given: A circle centered at (3.5, 5.0) with radius 1.0 and
an AABB centered at (5, 5) with half-extent 1.
When: circle_aabb_overlap is called. Then: Returns True because the circle reaches into the AABB.
Test type: unit
- test_clamp_circle_to_grid()[source]
Test that circle clamping keeps circle within grid.
Purpose: Validates grid clamping for circles.
Given: A circle centered at (-1, 12) with radius 0.3 on a grid of size 10. When: clamp_circle_to_grid is called. Then: Center is clamped to [radius, grid_size - 1 - radius].
Test type: unit
- test_clamp_point_to_grid()[source]
Test that point clamping keeps point within [0, grid_size-1].
Purpose: Validates grid clamping for points.
Given: A point at (-2, 15) on a grid of size 10. When: clamp_point_to_grid is called. Then: Point is clamped to [0, 9].
Test type: unit
- test_point_inside_aabb_false()[source]
Test that a point outside an AABB is not detected.
Purpose: Validates point-outside-AABB.
Given: A point at (1.0, 1.0) outside the AABB [4, 6] x [4, 6]. When: point_inside_aabb is called. Then: Returns False.
Test type: unit
- test_point_inside_aabb_true()[source]
Test that a point inside an AABB is detected.
Purpose: Validates point-inside-AABB test.
Given: A point at (5.0, 5.0) inside the AABB [4, 6] x [4, 6]. When: point_inside_aabb is called. Then: Returns True.
Test type: unit
- test_resolve_circle_wall_collision_no_walls()[source]
Test collision resolution with no walls returns copy.
Purpose: Validates no-op when there are no walls.
Given: Empty walls array. When: resolve_circle_wall_collision is called. Then: Returns a copy of the original position.
Test type: unit
- test_resolve_circle_wall_collision_pushes_out()[source]
Test that collision resolution pushes circle away from AABB.
Purpose: Validates that an overlapping circle is pushed out.
- Given: A circle centered at (4.5, 5.0) with radius 0.3 overlapping
the AABB [4, 6] x [4, 6].
When: resolve_circle_wall_collision is called. Then: The returned position moves the circle center away from
the original overlap.
Test type: unit
POMDPPlanners.tests.test_environments.test_push_pomdp.test_continuous_push_hazard_terminal module
POMDPPlanners.tests.test_environments.test_push_pomdp.test_continuous_push_native_equivalence module
POMDPPlanners.tests.test_environments.test_push_pomdp.test_continuous_push_pomdp module
POMDPPlanners.tests.test_environments.test_push_pomdp.test_continuous_push_pomdp_features module
POMDPPlanners.tests.test_environments.test_push_pomdp.test_push_discrete_native_transition module
POMDPPlanners.tests.test_environments.test_push_pomdp.test_push_pomdp module
POMDPPlanners.tests.test_environments.test_push_pomdp.test_push_pomdp_feature_driven module
Feature-driven bug-hunting tests for PushPOMDP (discrete).
This module complements test_push_pomdp.py with feature-driven tests
that target asymmetries and edge cases between scalar and batch APIs,
boundary semantics for terminal/obstacle-collision predicates, and the
sample/PDF pair on the observation model.
The test file was created after a sibling skill run on the light-dark
POMDP exposed a real asymmetry between
observation_log_probability (scalar, floored) and
observation_log_probability_per_state (batch, un-floored). The
tests below specifically check that no analogous asymmetry exists in
the Push POMDP and exercise other features that lack dedicated coverage.
- POMDPPlanners.tests.test_environments.test_push_pomdp.test_push_pomdp_feature_driven.test_hash_observation_consistent_with_equality()[source]
hash_observationreturns equal hashes for equal observations.- Return type:
- Purpose: Sanity-check the hash-equality contract used by belief
clustering. Equal observations (per
is_equal_observation) must hash to equal values; unequal observations should hash to different values for at least one numerically-different pair.- Given: A PushPOMDP and three observations: two that are
np.array_equaland one that differs in the object slice.
When: Their hash values (as bytes) are compared. Then: The two equal observations have the same hash; the third
differs from them.
Test type: unit
- POMDPPlanners.tests.test_environments.test_push_pomdp.test_push_pomdp_feature_driven.test_is_terminal_strictly_less_than_half_unit()[source]
is_terminal uses strict
< 0.25on squared distance, NOT<=.- Return type:
- Purpose: Pins down the boundary semantics of
is_terminalso a future change from
<to<=(or vice versa) is caught.- Given: A state where the object-target squared distance equals
exactly 0.25 (object 0.5 units away from target).
When:
env.is_terminal(state)is queried. Then: Returns False (because 0.25 < 0.25 is False).And for distance epsilon under 0.5, returns True.
Test type: unit
- POMDPPlanners.tests.test_environments.test_push_pomdp.test_push_pomdp_feature_driven.test_metric_names_match_compute_metrics_output()[source]
get_metric_namesmatches the names emitted bycompute_metrics.- Return type:
- Purpose: Validates the data-integrity contract: the
get_metric_namesdeclaration must exactly match the names produced bycompute_metricsso downstream simulation consumers can index by name reliably.
Given: A PushPOMDP and a one-step history. When:
get_metric_names()andcompute_metrics(...)are bothinvoked.
Then: The set of names from each is identical.
Test type: unit
- POMDPPlanners.tests.test_environments.test_push_pomdp.test_push_pomdp_feature_driven.test_native_simulate_rollout_with_error_prob_runs_and_is_finite()[source]
Native rollout with non-zero transition_error_prob returns a finite scalar.
- Return type:
- Purpose: Smoke-test the C++ error-action path in
simulate_rollout_discrete(which uses the kErrorActions table and an extra RNG draw per step). Without this test, the error branch in C++ would be untested by the existing deterministic-only parity tests.- Given: A PushPOMDP with transition_error_prob=0.4 and a fixed
initial state. Native RNG seeded and called via
env.simulate_random_rollout(which delegates to the C++ kernel).
When: A 30-step rollout is executed. Then: The discounted return is finite, lies in
[reward_range[0]*30, reward_range[1]*30], and a second call with a different native seed yields a (likely) different return, confirming the error-action RNG is actually used.Test type: integration
- POMDPPlanners.tests.test_environments.test_push_pomdp.test_push_pomdp_feature_driven.test_observation_log_probability_extreme_far_observation_no_floor_asymmetry()[source]
At extreme distance both scalar and batch return the same un-floored value.
- Return type:
- Purpose: Specifically targets the light-dark-style asymmetry where
the scalar path could clip
log(p)atlog(1e-300)while the batch path would return the raw kernel output. An extreme observation (object position 1e6 away from next_state’s object position) drives the kernel into log-prob territory far belowlog(1e-300) ≈ -690.- Given: A PushPOMDP and a next_state with object at (5, 5); an
observation with object at (1e6, 1e6). At that distance the true Gaussian log-pdf is on the order of -1e13.
When: Both scalar and batch log-prob APIs evaluate this pair. Then: Both return identical, finite (non-NaN) values that are far
below -700 (i.e. neither path floors). If the scalar path is floored, this test fails.
Test type: unit
- POMDPPlanners.tests.test_environments.test_push_pomdp.test_push_pomdp_feature_driven.test_observation_log_probability_scalar_matches_batch_kernel()[source]
Scalar
observation_log_probabilityequals batchper_stateform.- Return type:
- Purpose: Mirror of the asymmetry found in the light-dark POMDP:
scalar floored at log(1e-300) while the batch path returned the un-floored kernel. This test asserts no such asymmetry exists in the Push POMDP for a fixed observation evaluated against many next-states (or vice versa).
- Given: A PushPOMDP with observation_noise=0.1 and no obstacles. A
fixed observation and a fixed next-state.
- When: ``env.observation_log_probability(next_state, action,
[observation])`` (scalar path) and
env.observation_log_probability_per_state([next_state], action, observation)(batch path) are both evaluated.- Then: Both return the same value (single Gaussian log-pdf at the
same point). Tested across a sweep of (next_state, observation) pairs that include points far from the mean (where the light-dark bug manifests via under/un-flooring).
Test type: unit
- POMDPPlanners.tests.test_environments.test_push_pomdp.test_push_pomdp_feature_driven.test_reward_at_target_includes_terminal_bonus()[source]
Reward includes +100 bonus when next-state object is within 0.5 of target.
- Return type:
- Purpose: Validates that
_reward_from_next_stateadds the +100 terminal bonus exactly when the object distance to target is below 0.5, and that the bonus is omitted just outside that band.
- Given: A PushPOMDP without obstacles. Two next-states that share the
same robot position but differ only in the object-target distance: one with object exactly at the target (distance 0), another with object 0.5 units away (distance == 0.5).
When:
_reward_from_next_stateis called for both. Then: The first returns +100.0 (bonus) - 0.0 (distance) = 100.0.The second returns -0.5 (no bonus, because 0.5 is NOT < 0.5).
Test type: unit
- POMDPPlanners.tests.test_environments.test_push_pomdp.test_push_pomdp_feature_driven.test_reward_batch_obstacle_radius_boundary_matches_scalar()[source]
Batch and scalar obstacle-penalty agree at the exact radius boundary.
- Return type:
- Purpose: Both
_obstacle_penalty_batchand the scalar _is_colliding_with_obstacle_scalaruse<=against the squared radius, which is the only consistent choice. This test confirms they agree when the intended position lies exactly on the obstacle radius (squared distance == r^2).- Given: A PushPOMDP with obstacle at (3, 3), radius 0.5,
friction_coefficient=0.0 and transition_error_prob=0 (so the transition is fully deterministic). Robot at (2.5, 3.0): action “right” intends (3.5, 3.0) which is at squared distance 0.25 from the obstacle centre — exactly on the boundary.
- When:
reward_batchis called on a batch of 5 copies and rewardon one scalar.
Then: Both yield the same reward (same obstacle-penalty decision).
Test type: unit
- POMDPPlanners.tests.test_environments.test_push_pomdp.test_push_pomdp_feature_driven.test_reward_obstacle_penalty_uses_realised_position_not_intended()[source]
Obstacle penalty triggers off the REALISED robot position, not the intended move.
- Return type:
- Purpose: Pins the corrected design —
_reward_from_next_stateapplies obstacle_penaltybased on the realisednext_state[:2], not onstate[:2] + action_dxy. When a move is blocked by an obstacle the robot stays put, the realised position is clear, and no penalty fires.- Given: A PushPOMDP with one obstacle at (3, 3), radius 0.5. Robot at
(2, 3); action “right” intends (3, 3) which is inside the obstacle, but the transition blocks the move so the robot stays at (2, 3).
When:
env.reward(state, "right")is called. Then: The reward equals the bare-distanceterm — no obstaclepenalty (because the realised position is clear).
Test type: unit
- POMDPPlanners.tests.test_environments.test_push_pomdp.test_push_pomdp_feature_driven.test_reward_range_bounds_actual_rewards_across_random_states()[source]
All sampled rewards lie inside
env.reward_rangefor many random states.- Return type:
- Purpose: Cross-checks that the
reward_rangeadvertised by the environment actually bounds the rewards returned by
env.reward(...)for a representative random sample of states. A mismatch (e.g. obstacle penalty pushing the reward below the lower bound) would expose a stale or wrong range.
Given: A PushPOMDP with obstacles and obstacle_penalty=-10.0. When: For each of 50 random states and each action, we compute
env.reward(state, action).- Then: Every reward lies within the closed interval
[reward_range[0], reward_range[1]].
Test type: unit
- POMDPPlanners.tests.test_environments.test_push_pomdp.test_push_pomdp_feature_driven.test_sample_next_state_batch_matches_scalar_deterministic()[source]
Batch
sample_next_state_batchagrees byte-exactly with scalar path.- Return type:
- Purpose: Validates that
PushVectorizedUpdater.batch_transition (the engine behind
sample_next_state_batch) produces results identical to_sample_one_next_statewhentransition_error_prob=0(so no RNG is involved). Any divergence in collision-radius semantics (<vs<=), clipping, or push-threshold comparison would surface here.- Given: A PushPOMDP with obstacles and
transition_error_prob=0. A diverse batch of 200 random states and one fixed action.
- When:
sample_next_state_batch(states, action)and a scalar loop [sample_next_state(s, action) for s in states]are both evaluated.- Then: Every row of the batch result equals the corresponding scalar
result exactly (atol=1e-12).
Test type: unit
- POMDPPlanners.tests.test_environments.test_push_pomdp.test_push_pomdp_feature_driven.test_sample_next_state_batch_push_threshold_boundary()[source]
Batch path uses
<(strict) on push-threshold, matching scalar path.- Return type:
- Purpose: Pins down the push-threshold comparison. Scalar path uses
dist_sq < push_threshold_sq(strict). Batch path usesdist_to_obj < self.push_threshold(strict). This test verifies both yield the same answer at the exact boundary.- Given: A PushPOMDP with push_threshold=1.0 and friction=0.3. Robot
positioned exactly 1.0 unit away from the object. Action “right” attempts to move the robot directly toward the object.
When: Batch and scalar transitions are computed. Then: Both produce identical next-states. The object’s position
determines whether a strict-less-than at exactly 1.0 means “no push” (the documented behaviour). This test asserts the two APIs agree on whatever the boundary semantics are.
Test type: unit
- POMDPPlanners.tests.test_environments.test_push_pomdp.test_push_pomdp_feature_driven.test_sample_observation_matches_log_probability_density_2d_gaussian()[source]
Empirical density from samples matches closed-form log-prob (2-D Gaussian).
- Return type:
- Purpose: Validates the sample/PDF pair for
sample_observationand observation_log_probabilityunder the 2-D Gaussian noise on the object slice (cols 2:4). An asymmetry between sampler and PDF (e.g. wrong variance, missing factor of 2*pi) would surface as a Wilson-CI violation.- Given: A PushPOMDP with grid_size large enough that clipping is
negligible (grid_size=100) and observation_noise=0.5 (small relative to grid). next_state object centred at (50, 50). N=5000 observations sampled.
- When: We bin the sampled object positions (col 2 only — the
marginal in x) into a histogram and compare the empirical bin probability to the integral of the predicted PDF over each bin (computed from
observation_log_probabilityevaluated at bin centres, multiplied by bin width).- Then: Each bin’s empirical probability is within 3/sqrt(N)
(Wilson-style) of the predicted probability.
Test type: unit
- POMDPPlanners.tests.test_environments.test_push_pomdp.test_push_pomdp_feature_driven.test_transition_log_probability_distribution_sums_to_one_with_error()[source]
transition_log_probability gives probabilities that sum to 1 across distinct outcomes.
- Return type:
- Purpose: Validates the closed-form mixture formula in
transition_log_probabilitywhentransition_error_prob>0: the total mass over the at-most-4 distinct intended outcomes (for the 4 actions) sums exactly to 1.0. A mistake in thenum_error_actionsdenominator or in theerror_match_countaccumulator would break this invariant.- Given: A PushPOMDP with no obstacles,
transition_error_prob=0.5, and a state where the 4 actions yield 4 distinct next-states (robot in the interior of the grid; no friction; no pushing).
- When: We enumerate the 4 distinct intended next-states and sum the
probabilities
np.exp(transition_log_probability(...)).
Then: The sum equals 1.0 exactly (within 1e-12).
Test type: unit