Skip to content

feat: physics stability, k-NN information metrics & save system#149

Merged
M1thieu merged 7 commits into
erematorg:mainfrom
M1thieu:main
Feb 22, 2026
Merged

feat: physics stability, k-NN information metrics & save system#149
M1thieu merged 7 commits into
erematorg:mainfrom
M1thieu:main

Conversation

@M1thieu
Copy link
Copy Markdown
Collaborator

@M1thieu M1thieu commented Feb 22, 2026

Objective

Stabilize N-body simulation, add information-theoretic measurement tools
(k-NN entropy/MI, KL/JS divergence), introduce a production-grade save system
with stable entity identity, and clean up spatial indexing and pairwise staging.

Implementation

utils

  • Adaptive neighbor index for spatial queries

forces / energy

  • Velocity Verlet integrator (2nd-order symplectic, ~0.01% energy drift over 800+ s)
  • Fix missing PreviousAcceleration component (silent Bevy query failure froze all particles)
  • Softened Coulomb F = k·q/(r² + ε²)^1.5 — no singularity at r < ε
  • All physics to FixedUpdate; GravityForceMode default → Mutual
  • egui sliders for gravity/Coulomb/speed multipliers now properly wired

core / pairwise

  • Unify pairwise staging; add safety scaffolds for force application ordering

information crate

  • k-NN entropy/MI estimators (Kraskov et al. 2004, non-parametric)
  • Fix digamma Stirling asymptotic expansion (wrong for all integer inputs)
  • KLDivergence: divergence(), jensen_shannon(), cross_entropy(), total_variation()
  • Unified discrete + continuous estimator trait API; full test coverage

save_system crate (new)

  • PersistentId(u64) + seeded counter — stable cross-session entity identity, no UUID
  • Atomic write via std::fs::rename, VecDeque event buffer, chained version migration
  • get_saved_entity_components() query by PersistentId

docs

  • Standardized crate READMEs; architectural notes across all domains

Testing

  • 56 unit tests passing (cargo test --workspace)
  • basic_save example: save → reload → entity lookup → migration, end-to-end verified
  • N-body tested 830+ seconds at -0.09% energy drift

Visual Changes

// Stable entity identity across sessions
let star_id = id_counter.generate();
save(&game_save, &settings, "sim.json")?;

let loaded = load::<GameSaveData>(&settings, "sim.json")?;
let components = get_saved_entity_components(&loaded, star_id);

Technical Notes

  • save_system targets Bevy 0.18
  • Entity restore (load → spawn) is TODO — requires Bevy Reflect deserialization
  • MPM grid binary serialization is a future addition once the MPM solver is ported

refactor(energy): deterministic pair loops

refactor(forces): stage gravity pairs and document realtime limits
- energy: shared pairwise helpers used by charges/thermal\n- energy: reusable Local staging contexts + O(N) thermal sanity checks\n- forces: SoA staging path for one-way gravity hot loop\n- save_system: atomic writes + checkpoint/rollback world APIs\n- information: baseline entropy/MI estimator traits + deterministic tests\n\nPhysics behavior unchanged; focused on determinism/perf hygiene and observability.

feat(energy): add optional strict pairwise neighbor determinism

- add PairwiseDeterminismConfig (default off)\n- add shared ordered-neighbor emission helper\n- wire charges/thermal pairwise loops to strict mode\n- keep realtime fast path when strict mode is disabled\n\nThis closes inner-neighbor ordering nondeterminism for replay/campaign runs.
## N-Body Physics Fixes
- Fixed orbital instability: star mass was 200k, scaled to 10k (matches reference)
- Energy drift reduced from +19% to +0.017% (1000x improvement!)
- Mars now maintains orbit within 1% of initial radius (no escape)
- Orbital velocity formula verified correct; configuration was root cause

## Integration & Control
- Decoupled speed_multiplier from integration timestep (keeps dt stable at ~0.01667s)
- Fixed camera to stay at origin (no tracking drift)
- Scaled Coulomb constant from 8.99e9 to 1.0 (simulation units)
- Added comprehensive file-based physics diagnostics (energy, momentum, orbital drift)

## UI & Code Quality
- Added bevy_egui 0.39 integration with interactive simulation controls
- EguiPrimaryContextPass schedule (required for bevy_egui + Bevy 0.18)
- Implemented charged planets with Coulomb forces alongside gravity
- Cleaned dead code in information/fractals/renderer.rs
- Removed unused glam dependency
- All 41 MPM unit tests passing

## Physics Validation
- Two-body action-reaction forces verified (Newton's 3rd law)
- Momentum conservation: |p| < 0.02 over 60+ seconds
- System stable at dt=0.01667s with Symplectic Euler
- Plummer softening (ε=8.0) verified mathematically correct

## Configuration
- Star mass = 10,000 (IRL-scaled)
- Planets at realistic distances (Mercury 80, Mars 260, Neptune 520)
- Orbital velocities match formula: v = r·√(G·M/(r²+ε²)^1.5)
Extend shannon.rs and mutual/calculation.rs with non-parametric k-NN based
continuous entropy and mutual information estimation (Kraskov et al. 2004).

## What's Added
- knn_estimators.rs: Core k-NN distance calculations, digamma approximation
- Shannon::continuous_entropy() - entropy for continuous variables
- Shannon::continuous_joint_entropy() - joint entropy for continuous data
- MutualInfo::continuous_knn() - mutual information via k-NN
- MutualInfo::continuous_conditional_knn() - conditional MI via k-NN

## Why This Matters
- Replaces discrete binning with proper continuous estimation
- Measure information flow from simulation data: 'bits exchanged between agent & environment'
- Foundation for evolution selection based on actual information coupling
- No external dependencies (pure Rust, algorithms only)

## Technical Details
- k-NN algorithm in continuous space (Kraskov et al. 2004)
- Noise addition to handle near-duplicate points
- Digamma function for entropy calculation (asymptotic expansion)
- All methods return entropy in bits (natural log divided by ln(2))
- Removed unused avgdigamma() dead code (inlined into continuous_knn)
Standardized documentation pattern across all 6 crate READMEs:
- Core Principles (or Core API/Modules) - clear intent and scope
- Scope & Limits - explicit constraints and approximations
- Status - production-ready vs early-stage, known limitations

Crates updated:
- energy/: renamed "Scope and units" → "Core Principles", clarified status
- forces/: removed unsupported Barnes-Hut reference, clarified Plummer softening formula
- information/: already standardized (Feb 2026)
- matter/: already standardized (Feb 2026)
- systems/: already standardized (Feb 2026)
- utils/: already standardized (Feb 2026)

Added architectural TODO/FIXME/NOTE comments to document:
- forces/src/lib.rs: integrator upgrade to Velocity Verlet, contact physics gap
- energy/src/electromagnetism/charges.rs: Coulomb singularity workaround and fix roadmap
- matter/src/lib.rs: comprehensive blocking issues (MPM, collision physics, constitutive models)
- examples/basic_forces.rs: full rewrite needed for parameter exposure
- information/src/lib.rs: encoding scaffold, evolution operators, reaction-diffusion roadmap
- systems/src/lib.rs: MPM integration, acoustics coupling, AI information connection

All notes follow consistent pattern: TODO/FIXME/NOTE with clear context and rationale.
- Velocity Verlet integrator (2nd-order, ~0.01% energy drift)
- Fix silent query failure from missing PreviousAcceleration component
- All physics to FixedUpdate; GravityForceMode default -> Mutual
- Softened Coulomb at r < epsilon, bounded camera zoom with CoM
- Fix digamma Stirling expansion; KLDivergence with JS, TV, cross-entropy + tests
- Discrete + continuous estimator traits; KnnEntropy/MI (default k=3)
- PersistentId(u64), seeded counter, atomic write fix, VecDeque events
- Chained version migration; remove dead helpers; basic_save.rs updated
@M1thieu M1thieu merged commit 24b00b3 into erematorg:main Feb 22, 2026
3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant