HippocampAIF / hippocampaif /tests /test_core_knowledge.py
algorembrant's picture
Upload 253 files
32d978d verified
Raw
History Blame Contribute Delete
9.32 kB
"""
Tests for Phase 5: Spelke's Core Knowledge Systems
Validates that innate priors produce biologically correct behavior:
- Object permanence tracking
- Physics predictions (gravity, bounce, support)
- Numerosity discrimination (Weber ratio)
- Agent detection and social evaluation
Author: Algorembrant, Rembrant Oyangoren Albeos (2026)
"""
import numpy as np
from hippocampaif.core_knowledge.object_system import ObjectSystem
from hippocampaif.core_knowledge.agent_system import AgentSystem
from hippocampaif.core_knowledge.number_system import NumberSystem
from hippocampaif.core_knowledge.geometry_system import GeometrySystem
from hippocampaif.core_knowledge.social_system import SocialSystem
from hippocampaif.core_knowledge.physics_system import PhysicsSystem, PhysicsState
def test_object_permanence():
"""Objects persist when occluded — they don't vanish."""
obj_sys = ObjectSystem(max_objects=10, max_occlusion_frames=30)
# Register an object
obj_id = obj_sys.register_object(np.array([5.0, 5.0]), size=1.0)
# Update with the object visible
obj_sys.update([{'position': np.array([5.0, 5.0]), 'size': 1.0}])
assert obj_sys.num_objects == 1
# Object disappears (occluded)
obj_sys.update([]) # No detections
# Object should STILL be tracked (permanence!)
assert obj_sys.num_objects == 1, "Object permanence violated — object was deleted!"
# Predicted position should exist
pred = obj_sys.predict_occluded(obj_id)
assert pred is not None, "System lost track of occluded object"
print(" PASS Object Permanence (objects persist when occluded)")
def test_object_continuity_violation():
"""Objects cannot teleport — continuity violations generate surprise."""
obj_sys = ObjectSystem()
# Track a moving object
obj_sys.register_object(np.array([0.0, 0.0]))
obj_sys.update([{'position': np.array([1.0, 0.0])}])
obj_sys.update([{'position': np.array([2.0, 0.0])}])
# Teleport the object far away (violation!)
violations = obj_sys.update([{'position': np.array([100.0, 0.0])}])
continuity_violations = [v for v in violations if v['type'] == 'continuity_violation']
assert len(continuity_violations) > 0, "System failed to detect teleportation!"
print(" PASS Object Continuity (teleportation detected)")
def test_physics_gravity():
"""Unsupported objects fall downward."""
phys = PhysicsSystem(gravity=9.8, friction=0.0, dt=0.1)
# An object at rest in the air
state = PhysicsState(
position=np.array([5.0, 0.0]),
velocity=np.array([0.0, 0.0]),
mass=1.0
)
trajectory = phys.predict_trajectory(state, steps=20)
# Y should increase (falling down in y-down coords)
assert trajectory[-1][1] > trajectory[0][1], "Object did not fall under gravity!"
print(" PASS Physics Gravity (objects fall downward)")
def test_physics_bounce():
"""Objects bounce off walls (elasticity prior)."""
phys = PhysicsSystem(gravity=0.0, friction=0.0, dt=0.1)
# Ball moving right toward a wall
state = PhysicsState(
position=np.array([8.0, 5.0]),
velocity=np.array([5.0, 0.0]),
elasticity=1.0,
radius=0.5
)
bounds = (np.array([0.0, 0.0]), np.array([10.0, 10.0]))
trajectory = phys.predict_trajectory(state, steps=20, bounds=bounds)
# Ball should have bounced back (negative x velocity at some point)
x_positions = [t[0] for t in trajectory]
went_right = any(x > 8.0 for x in x_positions)
came_back = any(x < 8.0 for x in x_positions[5:])
assert went_right or came_back, "Ball did not bounce off wall!"
print(" PASS Physics Bounce (elastic collision with boundary)")
def test_physics_support():
"""Unsupported objects should fall; supported objects should not."""
phys = PhysicsSystem()
# Object on a surface
surfaces = [{'y': 10.0, 'x_min': 0, 'x_max': 20}]
supported = phys.check_support(np.array([5.0, 9.7]), 0.5, surfaces)
assert supported, "Object on surface should be supported"
not_supported = phys.check_support(np.array([5.0, 5.0]), 0.5, surfaces)
assert not not_supported, "Object in air should NOT be supported"
print(" PASS Physics Support (support detection)")
def test_number_subitizing():
"""Exact enumeration for 1-4 items."""
num_sys = NumberSystem(weber_fraction=0.15, subitize_limit=4)
for n in range(1, 5):
result = num_sys.perceive_numerosity(n)
assert result['exact'] is True, f"Should subitize {n} items exactly"
assert result['estimate'] == n, f"Subitized count wrong for {n}"
# Larger numbers should NOT be exact
result = num_sys.perceive_numerosity(20)
assert result['exact'] is False, "20 items should not be subitized"
print(" PASS Number Subitizing (exact 1-4, approximate >4)")
def test_number_weber_ratio():
"""Discrimination follows Weber's law: ratio matters, not difference."""
num_sys = NumberSystem(weber_fraction=0.15)
# Easy ratio (1:2) — should be highly discriminable
easy = num_sys.compare(10, 20)
assert easy['discriminability'] > 2.0, "1:2 ratio should be easy to discriminate"
# Hard ratio (9:10) — should be harder
hard = num_sys.compare(9, 10)
assert hard['discriminability'] < easy['discriminability'], \
"9:10 should be harder than 10:20"
print(" PASS Number Weber Ratio (ratio-dependent discrimination)")
def test_geometry_spatial_relations():
"""Basic spatial relation computations."""
geo = GeometrySystem()
rel = geo.spatial_relation(np.array([0.0, 0.0]), np.array([5.0, -3.0]))
assert rel['right_of'] is True
assert rel['above'] is True # y=-3 is above y=0 in image coords
assert rel['distance'] > 0
print(" PASS Geometry Spatial Relations")
def test_geometry_deformation():
"""Smooth deformation fields from Distortable Canvas paper."""
geo = GeometrySystem()
# Create a test image
image = np.random.rand(28, 28)
# Create deformation field
u, v = geo.create_deformation_field((28, 28), smoothness=3.0)
# Apply deformation
warped = geo.apply_deformation(image, u, v)
assert warped.shape == image.shape, "Warped image shape mismatch"
# Canvas distance should be positive
dist = geo.canvas_distance(u, v)
assert dist > 0, "Canvas distance should be positive for non-zero deformation"
# Dual distance
dual = geo.dual_distance(image, image, u * 0, v * 0)
assert dual == 0.0 or abs(dual) < 1e-10, \
"Zero deformation of image to itself should have near-zero distance"
print(" PASS Geometry Deformation (Distortable Canvas)")
def test_agent_detection():
"""Self-propelled entities with direction changes should be classified as agents."""
agent_sys = AgentSystem(self_propulsion_threshold=0.1)
# Simulate an agent with self-propelled direction changes
positions = [
np.array([0.0, 0.0]),
np.array([1.0, 0.0]),
np.array([2.0, 0.0]),
np.array([2.0, 1.0]), # Direction change!
np.array([1.0, 1.0]), # Another direction change!
np.array([0.0, 2.0]),
]
for pos in positions:
agent_sys.update_entity(entity_id=0, position=pos, was_contacted=False)
score = agent_sys.get_agency_score(0)
assert score > 0.3, f"Self-propelled entity with direction changes should have agency score > 0.3, got {score}"
print(" PASS Agent Detection (self-propulsion + direction change)")
def test_social_helper_preference():
"""Helpers should be preferred over hinderers."""
soc = SocialSystem()
# Entity 1 helps entity 0
soc.observe_interaction(actor_id=1, target_id=0, outcome='help')
soc.observe_interaction(actor_id=1, target_id=0, outcome='help')
# Entity 2 hinders entity 0
soc.observe_interaction(actor_id=2, target_id=0, outcome='hinder')
soc.observe_interaction(actor_id=2, target_id=0, outcome='hinder')
preferred = soc.evaluate_preference(1, 2)
assert preferred == 1, "Helper should be preferred over hinderer!"
score_helper = soc.get_prosocial_score(1)
score_hinderer = soc.get_prosocial_score(2)
assert score_helper > score_hinderer, "Helper score should exceed hinderer score"
print(" PASS Social Helper Preference (prosocial > antisocial)")
def run_all_tests():
print("============================================================")
print("HippocampAIF Phase 5: Core Knowledge Tests")
print("============================================================")
test_object_permanence()
test_object_continuity_violation()
test_physics_gravity()
test_physics_bounce()
test_physics_support()
test_number_subitizing()
test_number_weber_ratio()
test_geometry_spatial_relations()
test_geometry_deformation()
test_agent_detection()
test_social_helper_preference()
print("\n============================================================")
print("ALL PHASE 5 TESTS PASSED")
print("============================================================")
if __name__ == "__main__":
run_all_tests()