Files
smoothlife/plans/03_cpu_planar_simulation_engine.md
Federico Pasqua 51cff7b0f3 Add detailed phase plans for foundational macrosteps
- Macrostep 00: Model contract and retained historical options.
- Macrostep 01: Project foundation and configuration, including schema, presets, CLI, and CI setup.
- Macrostep 02: Mathematical core implementation and deterministic oracles.
- Macrostep 03: CPU-based planar simulation engine, FFT backend, and headless runner.

Provides exhaustive objectives, phase breakdowns, validation policies, and deliverables for each macrostep.
2026-07-14 16:50:54 +02:00

6.1 KiB
Raw Permalink Blame History

Macrostep 03 — CPU planar simulation engine

Objective

Build the first complete deterministic SmoothLife simulator using the pure core and a conventional CPU FFT. Support headless stepping and all base dimensions before introducing GPU complexity.

Dependencies

Macrosteps 0002 complete.

Phase 3.1 — FFT convolution backend

Substep 3.1.1 — Transform convention

Implement the default FftAlgorithm::Standard CPU path with a standard library FFT. The retained LegacyPackedUnitary algorithm is a GPU backend planned in Macrosteps 0506, with only a small CPU stage oracle for tests. Define and test the standard convention:

  1. unscaled forward transform;
  2. spectral multiplication;
  3. inverse scaled exactly by 1/(Nx·Ny·Nz);
  4. divide by sampled kernel sum, or pre-normalize kernels once.

Never apply sqrt(sample_count) in the standard path; that correction belongs only to LegacyPackedUnitary.

Substep 3.1.2 — Separable N-D transforms

Implement transforms along each active axis with reusable plans and scratch buffers. Start with full complex storage for clarity. If real-to-complex optimization is later added, retain the full-complex implementation as the reference.

Requirements:

  • arbitrary validated extents supported by the chosen FFT library on CPU;
  • no x/y/z transposition ambiguity;
  • cached plans keyed by shape;
  • no steady-state allocations;
  • serial correctness before Rayon parallelism.

Substep 3.1.3 — Spectral kernel cache

Build/cache spectra only when shape or kernel geometry changes. Keep disk/ring spectra, sums, and source parameters together so stale kernels cannot be paired with a new config.

Phase 3.2 — Planar backend pipeline

Substep 3.2.1 — Backend state

The planar CPU backend owns:

  • current and next state;
  • M, N, target, and derivative channels;
  • disk/ring kernels and spectra;
  • FFT work buffers/plans;
  • integrator and AB history;
  • generation and timing counters;
  • run descriptor and deterministic initializer state.

Substep 3.2.2 — Euler/discrete step

Implement the complete stage pipeline:

FFT(A)
→ multiply by KDF/KRF
→ inverse + normalize to M/N
→ evaluate S
→ discrete replacement or Euler derivative update
→ clamp and swap

Expose each stage through inspection without forcing a copy when the CPU owns the field.

Substep 3.2.3 — AB3 and RK4

  • AB3 performs one derivative evaluation per step and rotates initialized history.
  • RK4 performs the full convolution/rule pipeline at each clamped stage and supports both StageState and historical StepOrigin relaxation references.
  • Discrete mode bypasses both methods.
  • Parameter commands use Macrostep 00's full invalidation matrix: only presentation/inspection/pause/scheduler edits preserve history; rule, dynamics, timestep, integrator, kernel, historical-option selection, state/initializer, topology, shape, variant, and backend edits invalidate it.

Phase 3.3 — Simulation command facade

Define a small object-safe facade or enum dispatch with commands such as:

step(count)
pause/single-step handled by app, not backend
reset(initializer, seed)
apply_hot(rule edit)
rebuild_warm(kernel edit)
recreate_cold(shape/variant edit)
load/export restart state
load/export exact checkpoint
inspection(channel)
metrics()

Apply warm/cold changes transactionally: build and validate new resources first, then replace the live backend. Preserve the prior valid simulation if rebuilding fails.

Phase 3.4 — Headless runner

Implement CLI execution that can:

  • choose preset/shape/seed/mode/integrator;
  • run exact step counts;
  • export restart state, exact continuation checkpoints, and inspection channels;
  • print checksums, min/max/mean/variance, occupancy histogram, and elapsed time;
  • compare two state files with max, L1, and L2 error.

The headless path and interactive path must call the same backend methods.

Phase 3.5 — Determinism and parallelism

  1. Establish single-thread deterministic fixtures.
  2. Add Rayon only around independent transform lines or pointwise passes.
  3. Ensure reductions affecting normalization use a defined order or precomputed kernel sums.
  4. Document whether multi-threaded execution is bit-identical or tolerance-equivalent.
  5. Include thread count and CPU backend version in benchmark metadata, not in mathematical run identity unless output differs.

Phase 3.6 — Verification

Stage-level tests

  • FFT round trip: zero, constant, impulse, checkerboard, and asymmetric matrices.
  • FFT convolution against direct f64 oracle in all dimensions.
  • Default kernel-sum checks.
  • One-step output for every dynamics/integrator combination, including both RK4 relaxation references.
  • Stage snapshots for M, N, S, derivative, and committed state.

Deterministic scenario tests

Run fixed states for 1, 2, and 10 steps. Compare arrays for CPU serial mode and aggregate metrics for allowed parallel differences. Include representative 1-D, 2-D discrete, 2-D growth, 2-D relaxation, and 3-D presets.

Allocation tests

Use a counting allocator or benchmark instrumentation to prove no allocation during steady-state Euler/AB/RK stepping after warm-up.

Performance baseline, not optimization gate

Record release-build timings for:

  • 1-D 1024 and 8192;
  • 2-D 128² and 512²;
  • 3-D 32³ and 64³;
  • Euler versus RK4.

These measurements establish later GPU speedup and regression baselines. Correctness is the exit gate; do not distort architecture to hit a premature number.

Deliverables

  • CPU FFT convolution backend.
  • Complete base planar simulator in 1-D/2-D/3-D.
  • Headless runner, state import/export, metrics, and comparisons.
  • Stage-level fixtures and baseline report.

Exit gate

  • FFT convolution matches the direct oracle within 2e-5 on agreed small fields.
  • All base one-step fixtures pass in 1-D/2-D/3-D.
  • Seed + preset + shape + backend + step count reproduces output.
  • RK4 invokes four complete derivative pipelines; AB history startup/reset is deterministic.
  • No steady-state heap allocation occurs after warm-up.
  • Headless state and metrics can be consumed without raylib.