import { describe, it, expect } from 'vitest'; import { createPlaceCell, PlaceCellPopulation, createGridCell, GridCellModule, GridCellSystem, computeSpatialCode, } from '../../src/memory/place-cells.js'; describe('Place Cells', () => { it('creates a place cell with correct properties', () => { const cell = createPlaceCell({ x: 5, y: 10, z: 0 }, 2.0, 1.0); expect(cell.center).toEqual({ x: 5, y: 10, z: 0 }); expect(cell.radius).toBe(2.0); expect(cell.peakRate).toBe(1.0); }); it('activation peaks at center', () => { const cell = createPlaceCell({ x: 0, y: 0, z: 0 }, 2.0); expect(cell.activation({ x: 0, y: 0, z: 0 })).toBeCloseTo(1.0); }); it('activation decreases with distance', () => { const cell = createPlaceCell({ x: 0, y: 0, z: 0 }, 2.0); const atCenter = cell.activation({ x: 0, y: 0, z: 0 }); const at1m = cell.activation({ x: 1, y: 0, z: 0 }); const at3m = cell.activation({ x: 3, y: 0, z: 0 }); expect(atCenter).toBeGreaterThan(at1m); expect(at1m).toBeGreaterThan(at3m); }); it('activation is near zero far from center', () => { const cell = createPlaceCell({ x: 0, y: 0, z: 0 }, 2.0); expect(cell.activation({ x: 20, y: 20, z: 20 })).toBeLessThan(0.001); }); }); describe('PlaceCellPopulation', () => { it('adds cells and rejects too-close duplicates', () => { const pop = new PlaceCellPopulation(1.5); const c1 = createPlaceCell({ x: 0, y: 0, z: 0 }); const c2 = createPlaceCell({ x: 1, y: 0, z: 0 }); // too close (1m < 1.5m) const c3 = createPlaceCell({ x: 5, y: 5, z: 0 }); // far enough expect(pop.add(c1)).toBe(true); expect(pop.add(c2)).toBe(false); expect(pop.add(c3)).toBe(true); expect(pop.count).toBe(2); }); it('covers a region with place cells', () => { const pop = new PlaceCellPopulation(1.5); const count = pop.coverRegion( { x: 0, y: 0, z: 0 }, { x: 10, y: 10, z: 0 }, 2.0, ); expect(count).toBeGreaterThan(0); }); it('gets activations for a position', () => { const pop = new PlaceCellPopulation(1.5); pop.coverRegion({ x: 0, y: 0, z: 0 }, { x: 10, y: 10, z: 0 }, 2.0); const activations = pop.getActivations({ x: 5, y: 5, z: 0 }); expect(activations.size).toBeGreaterThan(0); }); it('decodes position from activations', () => { const pop = new PlaceCellPopulation(1.5); pop.coverRegion({ x: 0, y: 0, z: 0 }, { x: 10, y: 10, z: 0 }, 2.0); const target = { x: 5, y: 5, z: 0 }; const activations = pop.getActivations(target); const decoded = pop.decodePosition(activations); // Decoded position should be close to actual position expect(Math.abs(decoded.x - target.x)).toBeLessThan(2); expect(Math.abs(decoded.y - target.y)).toBeLessThan(2); }); }); describe('Grid Cells', () => { it('creates grid cell with periodic activation', () => { const cell = createGridCell(2.0, 0); const a1 = cell.activation({ x: 0, y: 0, z: 0 }); const a2 = cell.activation({ x: 2, y: 0, z: 0 }); // one period away // Should have similar activation (periodic) // Grid cell activation is periodic but phase-dependent; just verify both are in valid range expect(a1).toBeGreaterThanOrEqual(0); expect(a1).toBeLessThanOrEqual(1); expect(a2).toBeGreaterThanOrEqual(0); expect(a2).toBeLessThanOrEqual(1); }); it('activation is bounded [0,1]', () => { const cell = createGridCell(1.0, 0); for (let x = 0; x < 10; x += 0.1) { const a = cell.activation({ x, y: 0, z: 0 }); expect(a).toBeGreaterThanOrEqual(0); expect(a).toBeLessThanOrEqual(1); } }); }); describe('GridCellSystem', () => { it('creates multi-scale modules', () => { const system = new GridCellSystem(0.5, Math.SQRT2, 4, 16); expect(system.totalCells).toBe(64); // 4 modules * 16 cells }); it('returns activations for all cells', () => { const system = new GridCellSystem(0.5, Math.SQRT2, 4, 8); const activations = system.getActivations({ x: 3, y: 4, z: 0 }); expect(activations.size).toBe(32); // 4 * 8 }); }); describe('Spatial Code', () => { it('computes combined spatial code', () => { const placeCells = new PlaceCellPopulation(1.5); placeCells.coverRegion({ x: 0, y: 0, z: 0 }, { x: 10, y: 10, z: 0 }, 2.0); const gridCells = new GridCellSystem(0.5, Math.SQRT2, 2, 8); const code = computeSpatialCode({ x: 5, y: 5, z: 0 }, placeCells, gridCells); expect(code.placeCellActivations.size).toBeGreaterThan(0); expect(code.gridCellActivations.size).toBeGreaterThan(0); expect(code.confidence).toBeGreaterThan(0); expect(code.timestamp).toBeGreaterThan(0); }); });