/** * Memory-as-Physics engine for Hippo. * * Pure math module: forces, Velocity Verlet integration, physics-based scoring, * and cluster amplification. No I/O — all state is passed in and returned. * * Memories are particles on the unit hypersphere in embedding space (384-dim). * Forces act on them: query gravity (retrieval), inter-memory attraction, * conflict repulsion, and drag (consolidation). Nearby high-scoring memories * amplify each other via constructive interference. */ import type { EmotionalValence } from './memory.js'; import type { PhysicsConfig } from './physics-config.js'; export interface PhysicsParticle { memoryId: string; position: number[]; velocity: number[]; mass: number; charge: number; temperature: number; lastSimulation: string; } export interface ScoredPhysicsResult { memoryId: string; baseScore: number; clusterAmplification: number; finalScore: number; } export interface SystemEnergy { kinetic: number; potential: number; total: number; } export interface SimulationStats { particleCount: number; avgVelocityMagnitude: number; maxVelocityMagnitude: number; energy: SystemEnergy; substepsRun: number; } export declare function vecDot(a: number[], b: number[]): number; export declare function vecNorm(v: number[]): number; export declare function vecScale(v: number[], s: number): number[]; export declare function vecAdd(a: number[], b: number[]): number[]; export declare function vecSub(a: number[], b: number[]): number[]; export declare function vecZero(dim: number): number[]; /** Normalize to unit length. Returns zero vector if magnitude < epsilon. */ export declare function vecNormalize(v: number[]): number[]; /** Clamp vector magnitude to maxMag. */ export declare function vecClampMagnitude(v: number[], maxMag: number): number[]; export declare function computeMass(strength: number, retrievalCount: number): number; export declare function computeCharge(valence: EmotionalValence): number; export declare function computeTemperature(ageDays: number, temperatureDecay: number): number; /** * F1: Query gravity (retrieval-time, virtual — does not update position). * Returns scalar force magnitude for ranking. * * F_query(i) = G_Q * mass(i) * max(0, cosine(pos_i, query))^2 */ export declare function queryGravityMagnitude(particle: PhysicsParticle, queryEmbedding: number[], G_query: number): number; /** * Momentum bonus: how aligned is the particle's velocity with the query direction? * Returns a value in [0, 1]. */ export declare function velocityAlignmentBonus(particle: PhysicsParticle, queryEmbedding: number[]): number; /** * F2: Inter-memory attraction force vector (consolidation-time). * Attractive force from particle j on particle i. * * F_attract(i,j) = G_M * m_i * m_j * max(0, cosine(i,j))^3 * direction(j→i in embedding space) * * Direction is computed as the component of (pos_j - pos_i) that lies tangent to the * unit sphere at pos_i (since we normalize positions back to the sphere after integration). */ export declare function attractionForce(pi: PhysicsParticle, pj: PhysicsParticle, G_memory: number): number[]; /** * F3: Conflict repulsion force vector (consolidation-time). * Repulsive force pushing i away from j. * * F_repel(i,j) = K_R * m_i * m_j / max(0.01, cosine_distance(i,j))^2 * where cosine_distance = 1 - cosine_similarity */ export declare function repulsionForce(pi: PhysicsParticle, pj: PhysicsParticle, K_repulsion: number): number[]; /** * F4: Drag force vector (consolidation-time). * F_drag(i) = -drag * velocity(i) / max(1, effective_half_life(i)) * * effectiveHalfLife should be passed in from the memory's current half_life_days. */ export declare function dragForce(particle: PhysicsParticle, drag: number, effectiveHalfLife: number): number[]; export interface ForceContext { /** Map of memory ID -> list of conflicting memory IDs */ conflictPairs: Map>; /** Map of memory ID -> effective half-life days */ halfLives: Map; config: PhysicsConfig; } /** * Run the full physics simulation for one sleep cycle. * Mutates particles in place. Returns simulation statistics. */ export declare function simulate(particles: PhysicsParticle[], ctx: ForceContext): SimulationStats; export declare function computeSystemEnergy(particles: PhysicsParticle[], G_memory: number): SystemEnergy; /** * Score all particles against a query embedding using physics-based ranking. * Does NOT modify particle positions (virtual force computation). */ export declare function physicsScore(particles: PhysicsParticle[], queryEmbedding: number[], config: PhysicsConfig, /** Cross-ingest-stable tie key per memoryId (typically the memory's * content, supplied by the caller which has entries in scope). Without * it ties fall to memoryId -- per-instance only, which lets the * cluster_top_k amplification set vary across fresh ingests. */ tieKeyOf?: (memoryId: string) => string): ScoredPhysicsResult[]; /** * Nudge a particle's position toward (good outcome) or away from (bad outcome) * the query embedding. Respects temperature: new memories respond more. * Mutates particle in place. */ export declare function applyOutcomeFeedback(particle: PhysicsParticle, queryEmbedding: number[], good: boolean, feedbackAlpha: number): void; //# sourceMappingURL=physics.d.ts.map