From 51cff7b0f348aac8feb7f5e5dc52a780bd6cbbc0 Mon Sep 17 00:00:00 2001 From: Federico Pasqua Date: Tue, 14 Jul 2026 16:50:54 +0200 Subject: [PATCH] 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. --- ...0_model_contract_and_historical_options.md | 244 ++++++++++++++++++ ...01_project_foundation_and_configuration.md | 175 +++++++++++++ plans/02_mathematical_core_and_oracles.md | 167 ++++++++++++ plans/03_cpu_planar_simulation_engine.md | 158 ++++++++++++ plans/04_raylib_visualization_workbench.md | 145 +++++++++++ plans/05_gpu_resources_and_fft_proof.md | 156 +++++++++++ .../06_complete_base_solver_and_dimensions.md | 141 ++++++++++ plans/07_multiscale_backend.md | 163 ++++++++++++ plans/08_spherical_backend.md | 153 +++++++++++ plans/09_delayed_time_backend.md | 148 +++++++++++ plans/10_reference_and_analysis_tools.md | 127 +++++++++ .../11_performance_portability_and_release.md | 173 +++++++++++++ plans/README.md | 172 ++++++++++++ 13 files changed, 2122 insertions(+) create mode 100644 plans/00_model_contract_and_historical_options.md create mode 100644 plans/01_project_foundation_and_configuration.md create mode 100644 plans/02_mathematical_core_and_oracles.md create mode 100644 plans/03_cpu_planar_simulation_engine.md create mode 100644 plans/04_raylib_visualization_workbench.md create mode 100644 plans/05_gpu_resources_and_fft_proof.md create mode 100644 plans/06_complete_base_solver_and_dimensions.md create mode 100644 plans/07_multiscale_backend.md create mode 100644 plans/08_spherical_backend.md create mode 100644 plans/09_delayed_time_backend.md create mode 100644 plans/10_reference_and_analysis_tools.md create mode 100644 plans/11_performance_portability_and_release.md create mode 100644 plans/README.md diff --git a/plans/00_model_contract_and_historical_options.md b/plans/00_model_contract_and_historical_options.md new file mode 100644 index 0000000..8d3a706 --- /dev/null +++ b/plans/00_model_contract_and_historical_options.md @@ -0,0 +1,244 @@ +# Macrostep 00 — Model contract and retained historical options + +## Objective + +Create the permanent in-repository source of truth for the rewrite. Freeze the new deterministic behavior and exactly three retained historical options: RK4 relaxation reference, packed-unitary FFT, and sphere model. After this macrostep, normal implementation work must not depend on repeatedly reading `/home/fpasqua/Nextcloud/VecchiProgetti/SmoothLifeAll`. + +## Dependencies + +None. + +## Required outputs + +- `docs/model-contract.md`: exact mathematics and update semantics. +- `docs/historical-options.md`: the three retained options, their exact semantics, constraints, and rejected historical behavior. +- `docs/legacy-source-map.md`: provenance with source file, line range, and source-file hash. +- `tests/fixtures/legacy/preset_rows.jsonl`: schema-neutral bootstrap capture of every accepted legacy row. +- `tests/fixtures/contract/`: small deterministic scalar/field fixtures. + +## Phase 0.1 — Freeze the shared mathematical contract + +### Substep 0.1.1 — State, topology, and indexing + +Record these invariants verbatim in `docs/model-contract.md`: + +- State is a scalar `A ∈ [0,1]` after every committed update. +- Base domains are periodic: a 1-D circle, 2-D torus, or 3-D torus. +- Storage is x-fast row-major. Define and test one canonical index mapping. +- Signed periodic offset for even extent `N` is `i` for `i < N/2`, otherwise `i-N`. +- Sphere is a closed spherical surface; delayed time is a 2-D spatial torus with circular temporal history. + +### Substep 0.1.2 — Sampled kernels + +Freeze the exact base construction: + +```text +ri = ra / rr +w = ra / rb +L(r;a,w) = 0 when r < a-w/2 + 1 when r > a+w/2 + (r-a)/w + 1/2 otherwise +KD(r) = 1 - L(r;ri,w) +KR(r) = L(r;ri,w) * (1-L(r;ra,w)) +M = circular_convolution(A,KD) / sum(KD) +N = circular_convolution(A,KR) / sum(KR) +``` + +Document that weights are sampled at lattice points. Generate the complete nonzero support and warn when radii are unsuitable for the domain. The historical component cutoff is not retained. + +Record the known 2-D check for `ra=10, rr=3, rb=10`: + +```text +sum(KR) ≈ 279.216312 +sum(KD) ≈ 35.524035 +``` + +### Substep 0.1.3 — All rule curves + +Use conventional `TAU = 2π`; the legacy shader variable called `pi` actually stores tau. + +Freeze rising curves 0–7: + +```text +0 hard: x >= a ? 1 : 0 +1 linear: compact linear transition over a±e/2 +2 Hermite: u²(3-2u), u=(x-a+e/2)/e, compactly clamped +3 sine: 0.5*sin((TAU/2)*(x-a)/e)+0.5, compactly clamped +4 logistic: 1/(1+exp(-4(x-a)/e)) +5 atan: atan((x-a)*(TAU/2)/e)/(TAU/2)+0.5 +6 atan/cos: (1.1*atan((x-a)/e)/(TAU/4)*cos(1.4(x-a))+1)/2 +7 overshoot: (logistic-0.5)*(1+exp(-(x-a)²/e²))+0.5 +``` + +For types 0–7, `W(n;a,b)=P(n,a,sn)*(1-P(n,b,sn))`. Hard windows are exactly `[a,b)`. Types 8 and 9 are complete windows: + +```text +base = logistic(n,a,sn) * (1-logistic(n,b,sn)) +mid = (a+b)/2 +type 8 = base*(1-0.2*exp(-(20*(n-mid))²)) +type 9 = base*(1+0.2*exp(-(20*(n-mid))²)) +``` + +The mixer uses only curves 0–7 at center `0.5` and width `sm`. Curves 6/7 and resulting targets may overshoot; clamp only at the integration/commit points specified below. + +### Substep 0.1.4 — Four rule constructions + +Freeze: + +```text +B = W(N;b1,b2) +D = W(N;d1,d2) +Q = selected mixer at M +1: S = mix(B,D,M) +2: S = mix(B,D,Q) +3: S = W(N, mix(b1,d1,M), mix(b2,d2,M)) +4: S = W(N, mix(b1,d1,Q), mix(b2,d2,Q)) +``` + +## Phase 0.2 — Freeze dynamics and integration + +### Substep 0.2.1 — Base dynamics + +```text +mode 0 / Discrete: A' = clamp(S) +mode 1 / Growth: dA/dt = 2S-1 +mode 2 / Relaxation: dA/dt = S-A +``` + +The base discrete path ignores `dt` and selected integrator. Modes 3/4 found in old keyboard code are experimental and excluded from the supported contract unless later added with explicit names. + +### Substep 0.2.2 — Integrators and clamp points + +- Euler: `clamp(A + dt*k1)`. +- AB3: deterministic Euler first step, AB2 second step, AB3 thereafter: `(23k_n-16k_{n-1}+5k_{n-2})/12`. +- RK4: clamp every intermediate state and the final state. +- `Rk4RelaxationReference::StageState` is the default: every relaxation stage uses `S(stage)-stage`. +- `Rk4RelaxationReference::StepOrigin` is the retained historical option: `k1=S(A0)-A0`; intermediate `k2..k4` compute neighborhoods/targets from their clamped stage but subtract `A0`. +- The RK4 reference field exists structurally only inside relaxation+RK4 configuration. It is absent for discrete, growth, Euler, and AB3 rather than carried and ignored. +- Preserve AB history only for presentation, inspection, pause, and scheduler changes. +- Invalidate it for reset, ordinary state load, initializer/seed, rule, dynamics, timestep, integrator, kernel geometry, historical-option selection, topology, shape, variant, or backend changes. Switching away from and later back to AB3 never revives old derivatives. +- An exact continuation checkpoint may restore AB history only when its complete validated model/backend-independent arithmetic descriptor matches. + +Undefined AB history is discarded. This list is the authoritative history-invalidation policy used by every later macrostep. + +### Substep 0.2.3 — FFT algorithms + +Freeze one local `FftAlgorithm` option for planar and multiscale convolution: + +- `Standard` (default): conventional unscaled forward transform, inverse scaled by `1/sample_count`, then sampled-kernel normalization. +- `LegacyPackedUnitary`: power-of-two 1-D/2-D/3-D GPU path retaining adjacent-real packing, half-width x complex spectra, historical bit-reversal/twiddle plan stages, unitary butterfly scaling, real/complex conversion, and spectral correction `sqrt(sample_count)/kernel_sum`. + +The legacy FFT is a complete algorithm backend, not a global compatibility mode. It uses the same complete kernels and safe ping-pong resource layer as the new implementation. Old OpenGL compatibility syntax, working-directory shaders, framebuffer feedback, and resource behavior are discarded. An explicit legacy FFT request on CPU or unsupported GPU hardware fails clearly; it never silently substitutes `Standard`. A small CPU stage oracle and fixtures validate its packing, plans, scaling, spectra, and convolution. + +## Phase 0.3 — Freeze variant contracts + +### Substep 0.3.1 — Multiscale + +Record all six combinations in a 2×3 matrix: + +- Independent inputs: each scale receives `(ring_i(A), disk_i(A))`. +- Chained inputs: `(ring_0,ring_1)`, `(ring_1,ring_2)`, `(ring_2,disk_2)`. +- Sequential: update and clamp between scales, recomputing from the current state. +- Ordered clamped sum: evaluate all responses from one snapshot, add/clamp each in scale order. +- Mean increment: evaluate from one snapshot, add the arithmetic mean once, then clamp. + +The new implementation supports growth and corrected relaxation. It rejects discrete dynamics because the three composition names do not define an unambiguous target aggregator; adding it later requires an explicit target-aggregation enum and fixtures. + +Sequential composition always recomputes every required input from the current state. Shared-snapshot methods always use one original state. Relaxation names that current or original reference state explicitly. Additive mode-0 responses, stale chained fields, texture feedback, and undefined mode-2 sources are discarded. + +### Substep 0.3.2 — Sphere + +Freeze: + +- six `K×K` active faces, legacy default `K=128`, internal radius `R=K/2`; +- direction map `normalize(face_normal + tan(uπ/4)face_u + tan(vπ/4)face_v)`; +- area-weighted sample accumulation; +- distance `R*acos(clamp(dot(a,b),-1,1))`; +- `ri=ra/3`, transition widths `1`; +- planar-to-geodesic conversion `R*acos(1-ra²/(2R²))`; +- spherical cap area `2πR²(1-cos(r/R))`; +- direct replacement and fixed `A+0.1(2S-1)` modes. + +Freeze one local `SphereModel` option: + +- `Corrected` (default): complete edge/corner mapping and per-center normalization by the actual sum of `cell_area*kernel_weight`, preserving a constant field. +- `Legacy`: original six-face atlas geometry, side gutters with masked corner sectors, analytic disk normalization `cap(ri)`, analytic ring normalization `cap(ra)-cap(ri)`, original radius conversion/search stencil, and original discrete/fixed-`0.1` smooth dynamics. + +Both models use clamped dot products, explicit initialization, and ping-pong writes. Unclamped `acos`, texture feedback, and undefined atlas contents are discarded. + +### Substep 0.3.3 — Delayed time + +Freeze: + +- periodic x/y field and history depth 16; +- `ri=ra/3`, both transition widths `1`, sampled stencil normalization; +- `head` is the next layer to overwrite and `latest=wrap(head-1,depth)`; +- causal nearest-layer selection is `wrap(latest-floor(distance+0.5),depth)`, so delay zero reads the latest committed state; +- direct replacement or `latest+0.1(2S-1)`, then clamp. + +The historical head anomaly is discarded and has no configuration option. + +## Phase 0.4 — Preset and fixture capture + +### Substep 0.4.1 — Schema-neutral bootstrap capture + +Before the Rust schema exists, use a tiny reviewed extraction script to copy accepted source rows verbatim into JSONL with source path, line number, parsed columns, description, and source hash. This is evidence capture, not the final application importer. Expected counts are: + +- main catalogue: 188 valid rows; +- SDL catalogue: 187 rows, largely duplicate and containing drift; +- multiscale catalogue: 12 rows = 4 triplets; +- sphere catalogue: 1 row; +- DT catalogue: 29 rows. + +Do not deduplicate the evidence and do not run legacy executables. Macrostep 01 converts this frozen capture into the versioned schema and performs deliberate deduplication. + +### Substep 0.4.2 — Freeze migration defaults absent from rows + +Commit a mapping table so every imported row becomes a complete run: + +- Base: shape `1024`/`512²`/`64³` by dimension, Euler, standard FFT, seed `1`, cleared C++-inspired periodic splats, palette 2, and 3-D volume style 2. Because Euler is selected, no RK4-reference field is stored; creating relaxation+RK4 later defaults that newly applicable field to `StageState`. +- SDL rows: same model mapping, source-tagged and deduplicated against main rows; no separate backend. +- Multiscale: `512²`, sequential composition, independent kernels, growth/relaxation only, standard FFT, seed `1`, cleared base-style splats, and palette 7. +- Sphere: `K=128`, `R=K/2`, seed `1`, cleared then seeded overlays, and palette 1. Generate a corrected-default preset and a separately named `SphereModel::Legacy` preset from the historical row. +- DT: no historical fixed shape existed because it followed the window; choose and record `512²`, depth 16, causal delay, seed `1`, a seeded box field replicated into all layers, and palette 7. Record this initializer/shape as an intentional modern replacement. + +The table must distinguish source facts from chosen deterministic replacements. + +### Substep 0.4.3 — Freeze initializer algorithms + +- Base splats: clear to zero; choose continuous uniform centers; radius uniform in `[0.5ra,ra)`; count `floor(domain_volume / product(min(2ra,axis_extent)))+1`; paint periodic interval/disk/ball samples to one. Use ChaCha with a specified draw order. +- Sphere overlays: clear first; perform 1,000 draws with random face/center, radius 2–7, and random binary value. +- DT boxes: build one seeded field from 1,000 rectangles with width and height independently 10–19, then replicate it to all history layers. Use one documented boundary policy; do not retain gradual filling or undefined layers. + +Commit exact seeded fixture arrays so later PRNG upgrades cannot silently change tests. + +### Substep 0.4.4 — Golden fixtures + +Commit compact fixtures for: + +- scalar curve boundaries and overshoot; +- a rule-surface grid spanning all valid enum combinations; +- small asymmetric 1-D/2-D/3-D fields; +- raw and normalized kernels; +- direct convolution outputs plus legacy packed plans/stages/unitary scaling; +- Euler/AB/RK synthetic derivatives, including both RK4 relaxation references; +- all six corrected multiscale combinations; +- source-frozen corrected/legacy sphere `M/N/S/next` fields at face centers, edges, and masked corners for both update modes, in addition to face transforms, normalization, and area totals; +- DT layer-coded history and radial delay shells. + +Use explicit arrays for essential goldens, not only PRNG seeds. + +## Phase 0.5 — Source retirement protocol + +1. Hash every consulted legacy source/config file and store the hashes in `docs/legacy-source-map.md`. +2. Record source paths and relevant line ranges. +3. Mark the specification plus the new contract as the implementation authority. +4. Future legacy consultation requires a concrete discrepancy, and its finding must be copied back into the contract with provenance. +5. The application, build, tests, and importer outputs must not require the legacy path. + +## Exit gate + +- Every formula, constant, mode, topology, retained historical option, and discarded defect has a local documented decision. +- Preset counts/grouping reconcile with the source catalogues. +- Fixtures are readable without legacy tools. +- A new implementer can build any mandatory backend using only this repository. diff --git a/plans/01_project_foundation_and_configuration.md b/plans/01_project_foundation_and_configuration.md new file mode 100644 index 0000000..3b7bcbd --- /dev/null +++ b/plans/01_project_foundation_and_configuration.md @@ -0,0 +1,175 @@ +# Macrostep 01 — Project foundation and configuration + +## Objective + +Turn the empty Rust binary into a maintainable, headless-capable library plus raylib application shell. Establish schema, validation, error handling, assets, deterministic run identity, and CI before implementing simulation behavior. + +## Dependencies + +Macrostep 00 complete. + +## Phase 1.1 — Establish package and feature boundaries + +### Substep 1.1.1 — Cargo features + +Keep one package initially. Define: + +```text +default = [app, gpu] +app = raylib application, UI, and renderers +gpu = app + low-level OpenGL/rlgl acceleration +tools = optional analysis executables +``` + +`src/lib.rs` must compile with no raylib imports under `cargo test --no-default-features`. `src/main.rs` is a thin executable boundary. + +### Substep 1.1.2 — Evaluate and pin dependencies + +Select current mutually compatible releases and commit `Cargo.lock`: + +- `raylib` for context/window/input/drawing; +- `serde` and `toml` for schema; +- `clap` for startup/headless options; +- `thiserror` in the library and optionally `anyhow` in binaries; +- `tracing` plus a subscriber; +- `rand_chacha` and `rand_core` for deterministic initialization; +- `rustfft`/complex support for later convolution; +- optional `rayon` for CPU parallelism; +- `directories` for user data locations; +- development: `approx`, `proptest`, `criterion`, and a snapshot tool only if fixtures remain reviewable. + +Do not add a dependency when a small, tested local type is clearer. + +### Substep 1.1.3 — Module skeleton + +Create the module boundaries listed in `plans/README.md`. Keep `gpu`, `app`, `render`, and `ui` behind features. Add module-level documentation describing ownership and forbidden dependencies. + +## Phase 1.2 — Define the versioned configuration schema + +### Substep 1.2.1 — Typed model schema + +Create string-backed enums and structs for: + +- `VariantConfig::{Planar,Multiscale,Sphere,DelayedTime}`; +- `RuleConfig` and all curve/construction enums; +- `Dynamics::{Discrete,Growth,Relaxation}`; +- `Integrator::{Euler,AdamsBashforth3,RungeKutta4}`; +- `Rk4RelaxationReference::{StageState,StepOrigin}`; +- `FftAlgorithm::{Standard,LegacyPackedUnitary}`; +- `SphereModel::{Corrected,Legacy}`; +- shapes, resolution, initializer, seed, and optional recommended presentation. + +There is no general compatibility profile. Use a tagged time-evolution schema so `Rk4RelaxationReference` exists only in the `Relaxation + RungeKutta4` branch; it is structurally absent for every other dynamics/integrator combination. Place `FftAlgorithm` only in planar/multiscale GPU compute configuration and `SphereModel` only in sphere configuration. + +Use `schema_version = 1`. Keep model settings separate from app preferences. + +### Substep 1.2.2 — Validation + +Validation returns field-specific, actionable errors and rejects: + +- NaN/infinity; +- nonpositive radius, radius ratios, transition widths, smoothing widths, or timestep; +- invalid/zero shape extents; +- unsupported dynamics/integrator combinations (the tagged schema makes an irrelevant RK4 reference unrepresentable); +- statically invalid `LegacyPackedUnitary` combinations such as CPU backend, non-power-of-two shape, or unsupported dimension; +- empty scales or a non-three-scale imported multiscale preset; +- impossible history depth or sphere face size. + +Split validation into two stages. Macrostep 01 performs schema/static validation without a graphics context. Macrostep 05 adds runtime capability validation for texture limits, float FBOs, resource counts, memory, and actual legacy-FFT support; loading may be statically valid yet fail a requested GPU construction with an actionable runtime error. + +Do **not** reject reversed birth/death intervals: legacy catalogues contain them and the exact window formula defines their behavior. Emit warnings for risky but defined conditions such as radius near half the periodic extent or nonnested chained scales. + +### Substep 1.2.3 — Stable identity and provenance + +Every preset has: + +- stable slug/UUID; +- display name and description; +- variant and schema version; +- source provenance and optional original row; +- tags; +- deterministic default seed; +- relevant localized historical-option values; +- recommended shape/backend/presentation. + +Define a normalized run descriptor suitable for logs, state exports, and bug reports. + +## Phase 1.3 — Preset library and persistence + +### Substep 1.3.1 — Bundled and user locations + +- Embed or package bundled presets independently of the working directory. +- Load user presets from the platform configuration directory. +- Never mutate bundled files. +- Save settings atomically through temp-file + rename. +- Preserve unknown newer schema versions by refusing destructive writes. + +### Substep 1.3.2 — Schema-backed legacy conversion + +Consume Macrostep 00's frozen JSONL evidence and migration-default table to generate final versioned presets: + +- 15-column base rows; +- groups of three multiscale rows; +- 11-column sphere/DT rows. + +The converter must report accepted/rejected entries, apply every absent-field default explicitly, preserve source rows/descriptions/numeric precision, and deduplicate only by a documented normalized key. A direct legacy-text parser may exist as a separately tested maintenance command, but generation and normal runtime loading use the committed evidence, not the external tree. Verify expected source counts, multiscale grouping, generated counts, and a manifest hash. + +### Substep 1.3.3 — Command-line contract + +Support at least: + +```text +--preset +--config +--variant +--backend +--fft +--rk4-relaxation +--sphere-model +--seed +--shape <...> +--steps +--headless +--export-state +--list-presets +--validate-config +``` + +CLI overrides apply after preset validation and produce a new validated run descriptor. + +## Phase 1.4 — Error, logging, and asset policy + +### Substep 1.4.1 — Errors + +Define nonpanicking library errors for config, allocation, backend capability, shader compilation, state import, and numerical validation. The app converts them into a visible error panel/toast and a structured log. + +### Substep 1.4.2 — Logging + +Log application version, OS, selected preset, seed, shape, backend, FFT algorithm, RK4 relaxation reference when relevant, sphere model when relevant, and later GPU capabilities. Avoid per-frame logs. A user must be able to copy a compact diagnostic report. + +### Substep 1.4.3 — Resource lookup + +Essential shaders should be embedded with `include_str!` or packaged under a compile-time-known resource root. Development overrides are optional and explicit. No normal launch path assumes the repository is the current directory. + +## Phase 1.5 — Quality baseline + +- Add `rustfmt` and strict project-appropriate Clippy settings. +- Unit-test schema defaults, every enum, validation paths, round trips, atomic writes, and CLI precedence. +- Add CI jobs for formatting, Clippy, headless tests, and application compilation. +- Record the supported Rust toolchain policy; current project toolchain is Rust 1.97 with edition 2024. + +## Deliverables + +- Headless library skeleton and feature-gated app skeleton. +- Versioned schema, validator, preset library, importer, and CLI. +- Deterministic run descriptor, finalized preset catalogue, and structured errors/logging. +- CI quality baseline. + +## Exit gate + +- `cargo test --no-default-features` passes without initializing raylib. +- `cargo test --all-features` and application build pass. +- Every bundled preset validates and round-trips without numeric drift. +- Invalid fields identify their exact path and reason. +- Launch and preset listing work from outside the repository directory. +- The legacy tree is not accessed at runtime. diff --git a/plans/02_mathematical_core_and_oracles.md b/plans/02_mathematical_core_and_oracles.md new file mode 100644 index 0000000..00bf6f4 --- /dev/null +++ b/plans/02_mathematical_core_and_oracles.md @@ -0,0 +1,167 @@ +# Macrostep 02 — Mathematical core and deterministic oracles + +## Objective + +Implement the shared SmoothLife mathematics as a pure, independently testable Rust library. Build slow, clear oracles before any FFT or GPU implementation. + +## Dependencies + +Macrosteps 00–01 complete. + +## Phase 2.1 — Field, shape, and topology primitives + +### Substep 2.1.1 — Validated shapes and storage + +Implement validated 1-D/2-D/3-D shapes and `Field` with: + +- x-fast contiguous storage; +- checked public indexing and optimized internal indexing; +- coordinate/index conversion; +- periodic wrapping that is correct for negative coordinates; +- iterators over logical coordinates; +- explicit shape compatibility checks. + +Keep arithmetic and storage generic only where it aids tests; production state is `f32`, oracle calculations are `f64`. + +### Substep 2.1.2 — Inspection data vocabulary + +Define stable channel IDs and metadata for: + +- state `A`; +- disk density `M` and ring density `N`; +- target `S`; +- derivative/increment; +- next state; +- raw/normalized `KD` and `KR`; +- later per-scale, history, seam, and area channels. + +A snapshot states shape, value range, semantic units, generation, and whether data is borrowed or copied. Do not expose raylib textures from the core API. + +## Phase 2.2 — Exact scalar rule engine + +### Substep 2.2.1 — Curves + +Implement one function per named rising curve plus complete-window types 8/9. Handle compact support boundaries exactly, especially hard `[a,b)` behavior. Avoid a generic formula that obscures the special windows. + +### Substep 2.2.2 — Mixers and rule constructions + +Implement typed dispatch for all four rule constructions. Provide: + +```text +target(rule, n, m) -> f32/f64 +dynamics(target, state, mode) -> target-or-derivative +``` + +Do not clamp target values; some curve choices legitimately overshoot. Validate finite inputs and detect nonfinite outputs in debug/test instrumentation. + +### Substep 2.2.3 — Rule-surface sampler + +Implement a headless sampler over `(N,M) ∈ [0,1]²` with configurable resolution. It becomes both a fixture generator and the visualization source; the renderer must not duplicate rule mathematics. + +## Phase 2.3 — Kernel construction + +### Substep 2.3.1 — Geometry + +Implement softened Euclidean disk/ring generation for all base dimensions using signed wrapped offsets. Return: + +- raw samples; +- normalization sum accumulated in `f64`; +- normalized samples; +- support bounds and warnings. + +Reject a zero/nonfinite sum. Raw-kernel cache keys include shape, dimension, `ra`, `rr`, and `rb`; spectrum caches additionally include the selected FFT algorithm. + +### Substep 2.3.2 — Direct periodic convolution + +Implement an intentionally slow `f64` circular convolution for small fields. Favor clarity and asymmetric fixtures over performance. Provide separate disk/ring evaluation and a combined neighborhood result. + +### Substep 2.3.3 — Kernel properties + +Test: + +- nonnegative weights for normal linear kernels; +- expected symmetry; +- known sums for the default `L` geometry; +- constant-field invariant `M=N=c`; +- impulse output equals the shifted normalized kernel; +- translation equivariance; +- x/y/z orientation on nonsymmetric states. + +## Phase 2.4 — Integrator framework + +### Substep 2.4.1 — Derivative-provider boundary + +Define an integrator around a callback/trait that evaluates the complete state-dependent derivative. RK4 must be able to request four full neighborhood/rule evaluations; it is not a pointwise postprocess. + +### Substep 2.4.2 — Required methods + +Implement: + +- discrete replacement, independent of `dt` and numerical integrator; +- Euler; +- AB3 with Euler then AB2 startup; +- RK4 with clamped intermediate states and both relaxation references: default `StageState` and retained historical `StepOrigin`. + +Store AB generation count and derivative history explicitly. Implement the authoritative invalidation matrix from Macrostep 00—including integrator changes—and test every row. + +### Substep 2.4.3 — Optional reference methods + +Implement iterative implicit trapezoid and AB4 only under a reference/tools module. The trapezoid method uses a clamped Euler predictor and bounded fixed-point iteration with a convergence tolerance. These methods do not appear in the normal application integrator menu. + +## Phase 2.5 — Initializers and replay fixtures + +Implement deterministic: + +- zero and constant; +- impulse and hand-authored matrix; +- seeded noise; +- source-inspired interval/disk/ball splats using ChaCha and one explicit wrap policy. + +Separate `reset-and-fill` from `overlay-splats`. Define two different serialization contracts: + +- **Restart state:** externally visible field plus shape/run metadata. Loading starts a new continuation and resets integrator history. For delayed time, an explicit load policy (for example replicate into all layers) is required. +- **Exact checkpoint:** complete continuation state: all current/staging data required by the variant, generation, integrator and AB derivative history/startup count, DT history layers/head, relevant FFT/RK4/sphere option values, and deterministic RNG stream state when future overlay actions must continue identically. Backend-specific caches/textures are rebuilt rather than serialized. + +Tests use committed arrays for critical goldens so a PRNG-library change cannot rewrite truth unnoticed. + +## Phase 2.6 — Testing strategy + +### Scalar tests + +- Every curve at center and support boundaries. +- Hard-window upper endpoint exclusion. +- Type 8/9 midpoint factors. +- Types 6/7 overshoot samples. +- All `4×10×8` rule selector combinations on a compact surface grid. + +### Integrator tests + +- Synthetic scalar/vector ODE convergence. +- Exact Euler → AB2 → AB3 startup. +- History invalidation after every warm/cold edit. +- Default relaxation RK stages subtract each stage state. +- `StepOrigin` fixtures prove that intermediate targets use their stage neighborhoods while subtracting the step's original state. +- State remains finite and clamped after commit. + +### Numerical tolerances + +- Contract `f64` scalar fixtures: `≤1e-12` where operations permit. +- `f32` scalar fixtures: initial target `≤2e-6`. +- Direct field fixtures: document absolute and aggregate error separately. + +Do not use long chaotic trajectories as unit goldens. + +## Deliverables + +- Raylib-free field, rule, kernel, direct convolution, integrator, and initializer modules. +- Rule-surface and inspection channel producers. +- Deterministic unit/property fixtures. + +## Exit gate + +- All contract scalar samples and selector combinations pass. +- Constant and impulse convolution invariants pass in 1-D/2-D/3-D. +- Kernel sums are finite and positive. +- Integrators show expected order on a controlled ODE. +- No public API can construct an invalid shape or unvalidated model config. +- The full macrostep passes under Miri or the chosen sanitizer for supported pure-Rust code, if practical. diff --git a/plans/03_cpu_planar_simulation_engine.md b/plans/03_cpu_planar_simulation_engine.md new file mode 100644 index 0000000..19eaeef --- /dev/null +++ b/plans/03_cpu_planar_simulation_engine.md @@ -0,0 +1,158 @@ +# 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 00–02 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 05–06, 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: + +```text +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: + +```text +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. diff --git a/plans/04_raylib_visualization_workbench.md b/plans/04_raylib_visualization_workbench.md new file mode 100644 index 0000000..26cc332 --- /dev/null +++ b/plans/04_raylib_visualization_workbench.md @@ -0,0 +1,145 @@ +# Macrostep 04 — Raylib visualization workbench + +## Objective + +Deliver the first useful interactive product: a portable, resize-safe raylib laboratory that runs the CPU backend and makes the rule, kernels, neighborhoods, and update logic visible. + +## Dependencies + +Macrosteps 00–03 complete. + +## Phase 4.1 — Application lifecycle and scheduler + +### Substep 4.1.1 — Raylib ownership + +Initialize and own raylib on the main thread. Keep handles out of the mathematical core. Establish explicit startup, running, backend-rebuild, and shutdown states so partial resource failures do not corrupt the model. + +### Substep 4.1.2 — Decoupled timing + +Implement: + +- render FPS independent of a fixed updates-per-second simulation clock; +- pause, single-step, reset, and an explicit finite `advance N steps` command that is not tied to rendering; +- bounded catch-up to avoid a spiral of death; +- headless benchmarking outside the render loop rather than an uncapped frame-driven mode; +- model `dt` independent of wall-clock tick duration. + +Animations and camera movement are time-based, not frame-count-based. + +### Substep 4.1.3 — Unified action map + +Map keyboard, mouse, and UI widgets to one `Action` enum. Retain practical legacy aliases (`p`, `c`, `x/y`, parameter pairs, preset cycling), but do not encode behavior directly in key handlers. Add a searchable/help overlay. + +## Phase 4.2 — Shared presentation primitives + +### Substep 4.2.1 — Scalar texture uploader + +Convert CPU scalar fields to reusable raylib textures without allocating every frame. Start with a portable normalized or packed upload path; retain original `f32` values in the model. Make filtering (`nearest` default, optional linear) explicit. + +### Substep 4.2.2 — Palettes + +Implement named versions of all seven legacy palettes in one shared Rust/GLSL definition: + +1. phase hue on black; +2. white on black; +3. black on white; +4. value rainbow; +5. brown/green; +6. gold/brown; +7. phase-shifted value rainbow. + +Sanitize palette inputs and show a legend/range. Palette phase changes in units per second. + +### Substep 4.2.3 — Cameras + +- 2-D uses a coherent `Camera2D`, cursor-centered wheel zoom, drag pan, reset, and fit-to-view. +- 1-D and 3-D placeholders use their own presentation state; do not overload simulation coordinates. +- Window resize changes presentation only, never simulation shape or state. + +## Phase 4.3 — Model and logic views + +### Substep 4.3.1 — Live state + +Render the selected field at correct aspect ratio with periodic coordinate indicators. Display generation, update rate, render FPS, shape, seed, preset, dynamics, integrator, and backend. + +### Substep 4.3.2 — Read-only inspection + +Provide a tab/grid selector for: + +- `A`, `M`, `N`, `S`, derivative/increment, and proposed next state; +- raw/normalized disk and ring kernels; +- rule surface `S(N,M)` with labeled axes and current `(N,M)` probe; +- radial kernel profile and numeric value-under-cursor. + +Inspection never modifies state. Keep `c` as an optional “next primary view” shortcut. + +### Substep 4.3.3 — Compare layout + +Support at least a two-pane mode, for example `A | S`, `M | N`, or `kernel | radial profile`. All panes refer to the same committed generation and show stale-generation warnings if an async backend is introduced later. + +## Phase 4.4 — Configuration UI + +Build a collapsible raylib-native panel (or a deliberately selected raygui binding after a compatibility spike) with sections: + +- run/preset/variant; +- domain and initializer; +- rule intervals and curves; +- dynamics/integrator/timestep and RK4 relaxation reference when applicable; +- kernel geometry; +- backend, FFT algorithm, and performance; +- view/palette/camera; +- capture and diagnostics. + +Classify edits visibly: + +- **Hot:** presentation and pointwise rule edits; apply immediately. +- **Warm:** kernel geometry/timestep/integrator; rebuild caches and invalidate integration history as specified. +- **Cold:** shape, topology, variant, or backend; require transactional recreate/apply. + +Provide sliders plus precise numeric entry. Show validation inline; never silently clamp model parameters to UI ranges. + +## Phase 4.5 — Presets, sessions, and capture + +### Substep 4.5.1 — Preset browser + +Filter by variant/dimension/tags, show provenance and notes, and indicate modified (“dirty”) parameters. Applying a preset is transactional and logs the resulting run descriptor. + +### Substep 4.5.2 — Persistence + +Persist user preferences separately from model presets. Add “save as user preset,” not append-to-bundled-file behavior. Save enough precision for exact round trips. + +### Substep 4.5.3 — Exports + +Provide: + +- viewport PNG, optionally with HUD; +- native field image with active palette; +- restart-state export (field plus metadata, numerical history resets on load); +- exact continuation checkpoint with integrator/variant history; +- metadata sidecar containing run descriptor and generation. + +Use collision-safe timestamp/sequence names in the platform pictures/data directory. + +## Phase 4.6 — Robustness and UX tests + +- Resize/minimize/fullscreen/high-DPI smoke tests. +- Launch from arbitrary working directories. +- Repeated valid/invalid warm and cold edits. +- Pause and single-step accuracy. +- Screenshot/state export while paused and running. +- Keyboard focus does not alter parameters while numeric input is active. +- Visible fallback if texture/shader creation fails. + +## Deliverables + +- Portable raylib application using the CPU planar backend. +- Discoverable controls, inspectors, preset browser, and exports. +- Stable action, camera, palette, and presentation abstractions for later variants. + +## Exit gate + +- A user can launch, choose a preset, reset with a seed, run/pause/step, edit parameters, and inspect every base pipeline channel. +- Headless and interactive CPU runs produce identical model states for equal commands. +- Resize and fullscreen never reset simulation. +- No inspection mode destroys or advances state. +- The application works outside the repository and reports failures visibly. diff --git a/plans/05_gpu_resources_and_fft_proof.md b/plans/05_gpu_resources_and_fft_proof.md new file mode 100644 index 0000000..6350c92 --- /dev/null +++ b/plans/05_gpu_resources_and_fft_proof.md @@ -0,0 +1,156 @@ +# Macrostep 05 — GPU resources and 2-D FFT proof + +## Objective + +Build a narrow, safe GPU layer under the raylib context and prove both selectable FFT algorithms against CPU oracles: the standard default and retained `LegacyPackedUnitary`. Do not implement the complete simulator until resource safety, stage fidelity, and numerical parity are demonstrated. + +## Dependencies + +Macrosteps 00–04 complete. + +## Phase 5.1 — Capability and backend policy + +### Substep 5.1.1 — Capability report + +Probe and record: + +- OpenGL and GLSL versions; +- maximum 2-D texture size, texture units, and draw buffers; +- `R32F` and `RG32F` texture/render-target support; +- framebuffer completeness; +- timer-query availability; +- estimated resource budget. + +`Backend::Auto` with `FftAlgorithm::Standard` falls back to CPU with a visible explanation. `LegacyPackedUnitary` is an explicit GPU-only request; unsupported capabilities or shapes fail clearly and never silently substitute the standard algorithm. + +### Substep 5.1.2 — Portability target + +Primary path: desktop OpenGL 3.3 core-compatible GLSL. Do not copy legacy compatibility constructs (`gl_TexCoord`, `ftransform`, `gl_FragColor`, implicit shader versions). GLES/Web is a later secondary target. + +## Phase 5.2 — Isolated resource layer + +### Substep 5.2.1 — Unsafe boundary + +Place all raw OpenGL/`rlgl` operations in `src/gpu/resource/`. Public wrappers are RAII-managed, non-cloneable owners of: + +- texture IDs and format/extent metadata; +- framebuffers and attachment ownership; +- shader programs and uniform locations; +- fullscreen pass geometry; +- optional timer queries. + +Every creation checks errors/completeness. Every custom pass flushes/restores raylib state according to a documented protocol. + +### Substep 5.2.2 — Ping-pong discipline + +Make sampling a current render target impossible through the safe pass API. A pass declares read textures and a distinct write target; debug mode asserts no alias. This prevents legacy feedback-loop defects across all later variants. + +### Substep 5.2.3 — Shader assets + +Embed release shaders and fail shader compilation/link with source name plus complete log. Support explicit development overrides only. Add shader preprocessing for shared curve/palette code if it produces deterministic, debuggable output. + +## Phase 5.3 — GPU data layouts + +Use 2-D textures as the portable baseline: + +- scalar fields: `R32F`; +- standard full-complex fields: `RG32F` at logical extent; +- legacy packed fields: `RG32F` at the historical half-x packed extent; +- 1-D later: one row; +- 2-D: direct layout; +- 3-D later: tiled z-slice atlas. + +Define exact texel-center and logical-to-physical mappings. Compute shaders and native 3-D render targets may be optional optimizations, never the only correctness path. + +## Phase 5.4 — Standard 2-D FFT implementation + +### Substep 5.4.1 — Standard algorithm spike + +Select Stockham autosort or a conventional staged radix-2 butterfly after comparing pass count, addressing clarity, and driver portability. Use integer `texelFetch`; never rely on filtering or normalized-coordinate rounding. + +### Substep 5.4.2 — Transform passes + +Implement: + +- real-to-complex copy; +- x and y forward stages; +- x and y inverse stages; +- exactly one `1/(Nx·Ny)` inverse scale; +- round-trip readback harness. + +Cache twiddles/plans by shape. Require power-of-two GPU extents initially and report this distinction from the more flexible CPU backend. + +### Substep 5.4.3 — Spectral convolution + +Upload or generate kernel spectra, multiply state spectrum by disk/ring spectra, inverse transform, and normalize by sampled sums consistent with CPU convention. Reuse the state forward FFT for both kernels. + +## Phase 5.5 — Legacy packed-unitary 2-D FFT + +### Substep 5.5.1 — CPU stage oracle + +Implement a small, clear CPU oracle for adjacent-real packing, packed-spectrum conversion, historical plan entries, unitary butterflies, and inverse unpacking. It exists for fixtures and diagnosis, not as a production CPU backend. + +### Substep 5.5.2 — Modern GPU port of the historical algorithm + +Retain the algorithmic behavior while rewriting its infrastructure: + +- adjacent x samples packed into real/imaginary components; +- historical half-x complex layout and conjugate/Nyquist handling; +- bit-reversal and twiddle plan stages for x/y; +- forward/inverse unitary scaling at each stage; +- ping-pong FFT scratch textures; +- convolution multiplier `sqrt(Nx·Ny)/kernel_sum`. + +Use GLSL 330, integer texel addressing, embedded shaders, checked resources, and the common safe pass API. Do not copy compatibility-profile GLSL or resource hazards. + +### Substep 5.5.3 — Algorithm-specific constraints + +Require power-of-two extents and enough texture/FBO resources. Keep standard and legacy plans, spectra, and scratch caches separate. Changing `FftAlgorithm` is a cold transactional rebuild and invalidates integration history. + +## Phase 5.6 — Numerical proof harness + +For each algorithm and test field, read back explicit stages: + +- input complex copy; +- forward spectrum; +- inverse round trip; +- disk/ring spectral products; +- `M` and `N`. + +Compare to CPU with max absolute, mean absolute, and L2 error. Include zero, constant, impulse, checkerboard, random seeded, and asymmetric patterns at multiple small powers of two. + +Initial targets: + +- standard round-trip max error `≤1e-4`; +- standard convolution max error `≤2e-4` on agreed fixtures; +- legacy packed stage outputs match the CPU stage fixtures within documented `f32` tolerances; +- legacy final convolution agrees with direct/standard CPU convolution within `2e-4` on agreed fixtures; +- constant-field density error is small enough to preserve the documented tolerance. + +Tolerances must be measured and recorded per GPU/driver class before broadening; never hide systematic normalization errors behind a loose bound. + +## Phase 5.7 — Lifecycle and failure testing + +- Recreate FFT resources repeatedly across sizes. +- Simulate allocation/shader failures and preserve the CPU backend. +- Check for GL errors and incomplete FBOs in debug validation mode. +- Verify no resource growth after repeated switches. +- Confirm no synchronous readback in the normal frame path. +- Preflight memory estimates before allocation and retain the prior valid backend on failure. + +## Deliverables + +- GPU capability report and automatic fallback policy. +- Auditable unsafe/RAII resource layer. +- Validated standard and legacy packed-unitary 2-D GPU FFT/convolution proofs. +- Legacy packing/plan/unitary CPU stage oracle. +- Per-algorithm stage-comparison harness and initial GPU benchmark metadata. + +## Exit gate + +- Standard CPU/GPU round trip and convolution tolerances pass on the reference environment. +- Legacy packing, plans, scaling, round trip, spectra, and convolution pass their stage/final tolerances. +- Resource alias checks prevent read/write feedback. +- Shader and allocation failures are actionable and non-destructive. +- Repeated recreation shows no incomplete framebuffer or resource leak. +- GPU simulation work does not begin until the 2-D proof is stable. diff --git a/plans/06_complete_base_solver_and_dimensions.md b/plans/06_complete_base_solver_and_dimensions.md new file mode 100644 index 0000000..79e7c03 --- /dev/null +++ b/plans/06_complete_base_solver_and_dimensions.md @@ -0,0 +1,141 @@ +# Macrostep 06 — Complete base solver and dimensional rendering + +## Objective + +Complete CPU/GPU parity for the main SmoothLife family and provide intentional visualizations for 1-D, 2-D, and 3-D. This macrostep finishes the base model before special variants are added. + +## Dependencies + +Macrosteps 00–05 complete. + +## Phase 6.1 — GPU rule and integration pipeline + +### Substep 6.1.1 — Shared GLSL rule + +Port all typed curves, windows, mixers, and four constructions. Keep formula structure parallel to Rust and use integer/enum specialization rather than float-equality selectors. Add a GPU rule-surface test over all valid combinations. + +### Substep 6.1.2 — Dynamics + +Implement distinct outputs: + +- target `S`; +- growth derivative `2S-1`; +- relaxation derivative `S-A`. + +Do not conflate target and increment. Preserve channels for inspection. + +### Substep 6.1.3 — Integrators + +- Discrete: target-to-next pass. +- Euler: ping-pong update. +- AB3: initialized derivative textures plus explicit startup generation. +- RK4: full FFT/neighborhood/rule evaluation at each clamped stage, with selectable `StageState` or retained historical `StepOrigin` relaxation reference. + +Reset histories on the same events as CPU. Never sample a write target. Compare both RK4 references to CPU fixtures. + +## Phase 6.2 — Logical atlas for all dimensions + +### Substep 6.2.1 — Layout + +Use the established 2-D texture abstraction: + +- 1-D: `N×1` logical field; +- 2-D: `Nx×Ny`; +- 3-D: z-slices tiled in a near-square atlas with explicit padding. + +Create one CPU/GPU-tested mapper from `(x,y,z)` to atlas texel. Padding is initialized, ignored by transforms, and excluded from metrics. + +### Substep 6.2.2 — 1-D and 3-D FFT stages + +- Standard 1-D runs x stages only; standard 3-D runs x/y within slices and z across mapped slices. +- Extend `LegacyPackedUnitary` from its 2-D proof to historical 1-D and 3-D packing, plans, stage order, unitary scaling, and `sqrt(sample_count)` convolution correction. +- Verify DC/Nyquist, conjugate reconstruction, packing, and wrap addressing with asymmetric impulses for both algorithms. +- Reuse algorithm-specific plans and buffers; include full-complex versus packed/atlas overhead in memory estimates. + +### Substep 6.2.3 — Transactional backend switching + +Allow CPU↔GPU and standard↔legacy-FFT switches through explicit state transfer. Preserve generation and state; rebuild algorithm-specific kernels/plans and reset integrator history unless an exact transferable history format is implemented. `LegacyPackedUnitary` remains GPU-only and rejects unsupported transitions. Show the consequence before applying. + +## Phase 6.3 — 1-D visualization + +Implement two views: + +1. current scalar profile; +2. explicit space-time history raster. + +The history raster is a CPU/GPU ring buffer whose rows advance only on committed simulation steps. It does not depend on uncleared window backbuffers. Support history length, scroll direction, pause, resize, palette, and generation labels. + +## Phase 6.4 — 2-D production view + +Complete: + +- periodic pan and fit/zoom behavior; +- state and all inspection channels; +- native-resolution capture; +- optional interpolation only as a display choice; +- pixel probe showing `A,M,N,S,k,next` for the same coordinate/generation. + +The production 2-D target is the first performance profile: 512² Euler should remain interactive on the designated machine, with simulation and rendering times reported separately. + +## Phase 6.5 — 3-D visualization + +### Substep 6.5.1 — Slice inspection first + +Provide axial/coronal/sagittal slices, slice index controls, montage, and numeric probes. This is the correctness view and fallback if volume shaders fail. + +### Substep 6.5.2 — Orbit camera and volume box + +Use an orbit/arcball camera with dolly, pan, reset, and optional time-based autorotation. Keep periodic volume offset separate from camera transform. + +### Substep 6.5.3 — Progressive ray marcher + +Implement, test, and expose quality controls for: + +1. density accumulation (legacy style 2 equivalent); +2. simple integral and fog; +3. threshold/depth fog; +4. depth darkening; +5. gradient coloring; +6. jittered Laplacian coloring. + +Use atlas-aware manual sampling, early opacity termination, and configurable step size/density/brightness/threshold. Start from legacy values (`0.5`, `0.25`, `4`, `0.99`) but do not hard-code them. Clamp/sanitize palette inputs. + +## Phase 6.6 — Parity and performance gates + +### Stage parity + +Compare standard CPU, standard GPU, and legacy packed GPU against their appropriate stage oracles: + +- kernels, packing, plans, and spectra; +- `M`, `N`, `S`, derivative; +- every integrator stage, including both RK4 relaxation references; +- final one-step state in each dimension. + +Initial final-state target: max difference `≤5e-4` on agreed fixtures. Use aggregate statistics and spectrum bands, not exact hashes, for longer chaotic runs. + +### Performance profiles + +Record designated reference targets without making CI hardware-dependent: + +- 512² Euler: goal ≥60 updates/s; +- 64³ Euler: goal ≥10 updates/s with responsive rendering; +- 3-D renderer: goal ≥30 render FPS at default quality. + +If targets fail, preserve correctness, lower recommended defaults, and file measured optimization work rather than silently skipping simulation steps. + +## Deliverables + +- Complete standard GPU base pipeline with CPU fallback and selectable legacy packed-unitary GPU pipeline. +- 1-D profile/history, 2-D production field, 3-D slices and volume renderer. +- CPU/GPU state transfer and all base inspection channels. +- Imported and validated base preset catalogue. + +## Exit gate + +- Every supported base preset can be selected and run with compatible dimension/dynamics/integrator settings. +- Standard CPU/GPU parity and legacy packed-unitary stage/final tolerances pass in 1-D/2-D/3-D. +- Both RK4 relaxation references pass one-step CPU/GPU fixtures. +- 1-D history advances exactly once per committed generation. +- 3-D slices and ray marcher agree on sampled values. +- Unsupported allocations fail transactionally and preserve the prior simulation. +- No application behavior depends on legacy shader files or executables. diff --git a/plans/07_multiscale_backend.md b/plans/07_multiscale_backend.md new file mode 100644 index 0000000..8826ffb --- /dev/null +++ b/plans/07_multiscale_backend.md @@ -0,0 +1,163 @@ +# Macrostep 07 — Multiscale backend + +## Objective + +Implement the three-scale concept as a first-class corrected 2-D backend with explicit neighborhood and composition semantics, per-scale inspection, and standard/legacy-FFT GPU support. + +## Dependencies + +Macrosteps 00–06 complete. + +## Scope decisions + +- Mandatory scope is three scales on a periodic 2-D domain. +- The historical 1-D/3-D infrastructure was nonfunctional because integration existed only in 2-D; do not claim support there. +- Generalizing to `n` scales is acceptable internally, but imported fixtures remain exactly three. + +## Phase 7.1 — Typed semantic model + +Define independent enums: + +```text +KernelInterpretation + IndependentDiskRing + ChainedBands + +Composition + Sequential + OrderedClampedSum + MeanIncrement +``` + +Each `ScaleConfig` owns radius/ratios, `dt`, dynamics, and rule. Dimension/shape belongs to the common domain, not each scale. + +Validate positive geometry, valid rules, exactly three scales for imported presets, growth/relaxation dynamics only, and descending/nested scales for chained bands. Nonnested bands are defined but produce a warning explaining their meaning. + +## Phase 7.2 — Neighborhood evaluation + +### Substep 7.2.1 — Independent kernels + +For each scale from one requested state snapshot: + +```text +N_i = ring_i(A) +M_i = disk_i(A) +S_i = rule_i(N_i,M_i) +``` + +Cache six kernel spectra. In shared-snapshot compositions, perform one state forward FFT and six inverse products. + +### Substep 7.2.2 — Chained bands + +Compute only: + +```text +R0 = ring_0(A) +R1 = ring_1(A) +R2 = ring_2(A) +D2 = disk_2(A) +inputs = [(R0,R1), (R1,R2), (R2,D2)] +``` + +Explain in UI that this represents adjacent radial bands cleanly when `inner_0≈outer_1` and `inner_1≈outer_2`. Do not calculate unused `disk_0/disk_1` in this mode. + +### Substep 7.2.3 — Response encoding + +Keep three concepts separate: + +```text +target F_i +growth increment dt_i*(2F_i-1) +relaxation increment dt_i*(F_i-A_reference) +``` + +Multiscale accepts only growth and corrected relaxation. It rejects discrete dynamics because these three composition names do not uniquely define how several targets replace one state. A future discrete mode requires a new explicit target-aggregation enum and fixtures; additive target-as-increment behavior is discarded. + +## Phase 7.3 — Composition policies + +### Substep 7.3.1 — Sequential + +For independent kernels: + +```text +state = A +for scale i: + evaluate scale i from state + state = clamp(state + increment_i) +``` + +Recompute every required neighborhood from the current state after each update. This is order-dependent. Chained sequential never reuses stale rings from an earlier state. + +### Substep 7.3.2 — Ordered clamped sum + +Evaluate all increments from original `A`, then: + +```text +state = clamp(A+r0) +state = clamp(state+r1) +state = clamp(state+r2) +``` + +Do not replace this with one final clamp; mixed-sign increments make them different. + +### Substep 7.3.3 — Mean increment + +Evaluate from original `A`, then: + +```text +A' = clamp(A + (r0+r1+r2)/3) +``` + +Average increments after each scale's own `dt`, not targets. + +## Phase 7.4 — CPU implementation and tests + +Build on the CPU planar convolution cache. Add mocked-neighborhood unit tests before full FFT tests: + +- chained input mapping; +- response encoding (`A=.4,F=.75,dt=.1` gives growth `.05`, relaxation `.035`); +- ordered clamps (`A=.9`, responses `[.3,-.8,.3]` gives `.5`); +- mean gives approximately `.8333333` for the same responses; +- scale-order dependence and full chained recomputation; +- discrete-dynamics validation rejection. + +Then run all six kernel/composition combinations against committed one-step fixtures. + +## Phase 7.5 — GPU implementation + +- Reuse the selected base FFT (`Standard` or `LegacyPackedUnitary`) and rule passes. +- Share one forward FFT in both shared-snapshot compositions. +- Sequential modes recompute only what their semantics require. +- Ping-pong state and integration targets; no read/write feedback. +- Cache spectra by scale and invalidate only geometry-dependent entries. +- Assert expected pass counts in instrumentation tests. + +Initial standard CPU/GPU one-step target is max error `≤7e-4`; the legacy packed GPU path must also pass its algorithm-specific stage and final tolerances. + +## Phase 7.6 — Workbench integration + +Provide: + +- three simultaneously visible scale tabs/cards; +- active-scale edits and explicit linked edits; +- kernel interpretation and composition selectors with formula help; +- per-scale `M/N/S/increment` channels; +- combined increment and clamp-stage views; +- scale-color overlay and radial-band diagram; +- clear validation for unsupported discrete dynamics and warnings for nonnested chained radii; +- imported triplet preset browser preserving group identity. + +## Deliverables + +- CPU and GPU multiscale 2-D backend. +- All six kernel/composition combinations for growth/relaxation, using either selectable GPU FFT algorithm. +- Per-scale inspectors and imported four legacy triplet groups. + +## Exit gate + +- All mocked and end-to-end composition fixtures pass. +- Tests prove sequential recomputation/order dependence and original-snapshot behavior. +- Chained mode requests only three rings plus the smallest disk. +- Shared-snapshot GPU modes use one state forward FFT. +- Standard CPU/GPU and legacy-packed GPU one-step tolerances pass. +- Additive discrete, stale chained inputs, undefined relaxation sources, and texture feedback are absent. diff --git a/plans/08_spherical_backend.md b/plans/08_spherical_backend.md new file mode 100644 index 0000000..3fe36c6 --- /dev/null +++ b/plans/08_spherical_backend.md @@ -0,0 +1,153 @@ +# Macrostep 08 — Spherical backend + +## Objective + +Implement SmoothLife on a closed sphere with a tested corrected default and one coherent retained `SphereModel::Legacy`, backed by CPU oracles, GPU simulation, and a modern raylib renderer. + +## Dependencies + +Macrosteps 00–06 complete. Macrostep 07 is not technically required, but execute in index order for a single team. + +## Phase 8.1 — Cube-sphere geometry model + +### Substep 8.1.1 — Face frames and directions + +Define six typed face frames with a single orientation table. For each face-cell center: + +```text +direction = normalize(normal + tan(uπ/4)*axis_u + tan(vπ/4)*axis_v) +``` + +Use configurable `K`, with legacy `K=128` and internal `R=K/2`. Store direction, area, face, and coordinates in CPU structures; upload immutable geometry once. + +### Substep 8.1.2 — Cell areas + +Compute each spherical quadrilateral area from two spherical triangles or a proven equivalent. Test: + +- every area finite/positive; +- face symmetry; +- total area approaches `4πR²` within a recorded discretization tolerance. + +### Substep 8.1.3 — Seam mapping + +Implement `SphereModel` as one local enum: + +- `Corrected` (default): direction-based projection across every edge and corner; materialize and snapshot-test the mapping. +- `Legacy`: original 24 side-gutter transforms and invalid corner gutters as one inseparable part of the historical sphere model. + +Do not expose independent seam/normalization compatibility toggles. Neither model samples and renders to the same atlas; both build a distinct initialized padded sampling atlas from current state. + +## Phase 8.2 — Spherical neighborhood oracle + +### Substep 8.2.1 — Radius conversion + +Freeze and implement: + +```text +ri_planar = ra/3 +widths = 1 +r_geo = R*acos(clamp(1-r_planar²/(2R²),-1,1)) +cap_area(r) = 2πR²*(1-cos(r/R)) +legacy search bound = ceil(2ra) +corrected search bound = complete nonzero softened support +``` + +Report invalid chord radii instead of producing NaN. + +### Substep 8.2.2 — Direct neighborhood + +For each active cell: + +1. read center direction `a`; +2. visit candidates from the padded atlas/mapping; +3. compute `distance=R*acos(clamp(dot(a,b),-1,1))`; +4. multiply candidate state by candidate spherical cell area; +5. accumulate softened disk/ring weights; +6. normalize according to the selected complete sphere model: + - `Corrected`: divide each numerator by the per-center sum of the same `cell_area*kernel_weight` terms actually visited; + - `Legacy`: divide disk by `2πR²(1-cos(ri/R))` and ring by `2πR²[(1-cos(ra/R))-(1-cos(ri/R))]`, regardless of softened boundaries or masked corner samples. + +The CPU implementation may be slow and use reduced `K` for exhaustive tests; clarity and seam correctness are primary. Constant-field uniformity is required for `Corrected`; historical deviations near legacy masked corners are expected fixtures. + +### Substep 8.2.3 — Dynamics + +Both sphere models support only: + +- discrete replacement `clamp(S)`; +- fixed smooth update `clamp(A+0.1*(2S-1))`. + +Do not expose base relaxation, configurable `dt`, FFT, AB3, or RK4. Future experimental sphere dynamics require a separately named model rather than extending `Legacy`. + +## Phase 8.3 — Deterministic initialization + +Always clear all active and gutter storage. Implement seeded sphere splats with explicit reset versus overlay operations. Provide face-coded, constant, impulse, and great-circle test initializers. Never preserve undefined initial texture contents. + +## Phase 8.4 — GPU direct solver + +### Substep 8.4.1 — Atlas resources + +Use separate current, padded-sampling, and next `R32F` targets plus immutable direction/area data. Fill gutters via explicit passes or CPU-generated mapping, then run one direct neighborhood pass over active tiles and swap. + +### Substep 8.4.2 — Stencil strategy + +Start with a bounded GLSL loop specialized/cached by face size and maximum radius. Precompute valid offset metadata where it reduces `sqrt`, branch, or mapping cost without changing semantics. Recompile only on geometry changes, not rule edits. + +### Substep 8.4.3 — Parity + +First compare each CPU model to Macrostep 00's independent source-frozen `M/N/S/next` fixtures at centers, edges, and masked corners for both update modes. Then compare GPU to its validated CPU model. Initial one-step max-error target is `≤1e-3`; CPU/GPU agreement alone is insufficient. + +## Phase 8.5 — Sphere presentation + +Generate one indexed cube-sphere mesh with independent UVs per face. Add: + +- an explicit `Corrected`/`Legacy` sphere-model selector with a concise semantic comparison; +- transactional model switching: construct the complete seam map, normalization data, padded atlas, and shader resources before commit; preserve active-face state and generation when `K` is unchanged; retain the previous model on failure; never share model-specific caches; +- orbit/arcball camera and time-based autorotation; +- grid overlay; +- all shared palettes; +- optional two-sided legacy red/blue styling; +- active atlas, padded atlas, direction, area, seam, and geodesic-distance views; +- face labels and edge-orientation debug mode. + +Keep rendering geometry separate from simulation resolution so mesh tessellation can change without altering state. + +## Phase 8.6 — Verification and performance + +### Geometry/seam tests + +- all 24 directed edge mappings and corner transitions; +- cross-edge-and-back round trip; +- shared-edge direction equality; +- rotational consistency under cube symmetries; +- total area and constant-field neighborhoods; +- no `acos` NaN. + +### Resource tests + +- no texture feedback; +- all gutters explicitly initialized; +- framebuffer completeness after rebuild; +- repeated `Corrected↔Legacy` switching agrees with a freshly constructed destination model, preserves state/generation, and never mixes seam or normalization caches; +- failed switches preserve the previous working model; +- rule edits do not rebuild geometry. + +### Performance target + +On the designated GPU, `K=128`, `ra=10` should target p95 step time below 33 ms for both models. If either fails, ship a lower interactive default while keeping `SphereModel::Legacy` selectable and document the measured cost (roughly 165 million candidate iterations per step before optimizations). + +## Deliverables + +- CPU oracles for `SphereModel::{Corrected,Legacy}`. +- One coherent retained legacy sphere model, not independent compatibility flags. +- GPU sphere backend and raylib sphere renderer. +- Sphere-specific inspection and seam diagnostic tools. + +## Exit gate + +- Face orientation, area, edge, and corner tests pass. +- Both CPU models match independent source-frozen end-to-end fixtures for both update modes. +- Constant state produces uniform neighborhoods for `Corrected`; `Legacy` analytic/masked-corner deviations match committed fixtures. +- CPU/GPU one-step parity passes at centers, edges, and corners for both models. +- Transactional model-switch lifecycle tests pass without mixed caches or state loss. +- Default sphere preset is rotatable, inspectable, and deterministic. +- No undefined atlas contents, feedback loop, or unclamped `acos` remains. diff --git a/plans/09_delayed_time_backend.md b/plans/09_delayed_time_backend.md new file mode 100644 index 0000000..99e1fbb --- /dev/null +++ b/plans/09_delayed_time_backend.md @@ -0,0 +1,148 @@ +# Macrostep 09 — Delayed-time backend + +## Objective + +Implement the distance-dependent delayed-time experiment as a deterministic, configurable 2-D backend with explicit history indexing, CPU oracle, accelerated GPU path, history diagnostics, and decoupled simulation/window resolution. + +## Dependencies + +Macrosteps 00–06 complete; follow the roadmap order after Macrostep 08. + +## Phase 9.1 — Explicit history model + +### Substep 9.1.1 — Storage and indexing + +Represent history as `depth × height × width` with default depth 16 and a circular `head` denoting the next layer to overwrite. Define helpers: + +```text +latest = wrap(head-1, depth) +sample(distance) = wrap(latest-floor(distance+0.5), depth) +``` + +Tests, UI, and shader must use the same integer helpers. Spatial x/y addressing is periodic. Window resize never changes simulation resolution by default. + +### Substep 9.1.2 — Causal policy + +Use one policy only: delay zero reads `latest`, and increasing rounded distance walks backward from it. Smooth dynamics also use `latest` as their base. The historical next-overwrite-head anomaly is discarded and is not configurable. + +Use explicit integer layer selection; do not blur time through normalized 3-D texture interpolation. + +## Phase 9.2 — Delayed neighborhood oracle + +### Substep 9.2.1 — Stencil + +Implement: + +```text +ri = ra/3 +inner width = outer width = 1 +search radius = ceil(ra+0.5) +``` + +For each spatial offset, precompute: + +- `(dx,dy)`; +- Euclidean distance; +- integer delay layer offset; +- disk and ring weights. + +Normalize by numerically summing this exact discrete stencil, not analytic area. + +### Substep 9.2.2 — CPU evaluation + +For each output point, wrap x/y, choose the causal history layer, accumulate `M/N`, evaluate the shared rule, then: + +```text +discrete: next = clamp(S) +smooth: next = clamp(history[latest] + 0.1*(2S-1)) +``` + +Commit next into `history[head]`, then advance `head`. Separate `preview()` from `commit()` so pause semantics are explicit. + +### Substep 9.2.3 — Pause and reset + +Pause freezes output and head. Reset initializes every layer; recompute-without-commit and stale/undefined storage are not supported. + +## Phase 9.3 — Initialization and interaction + +Provide deterministic modes: + +- all layers zero; +- one seeded frame replicated to all layers; +- independently seeded layers; +- populate one layer as an explicit analysis operation; +- source-inspired seeded boxes applied through a documented all-layer policy; +- import a restart state under an explicit layer-fill policy; +- import/export an exact checkpoint containing all history layers, `head`, generation, run descriptor, and RNG state. + +The seeded box initializer uses width/height in `10..19` and one documented boundary policy, then initializes all layers explicitly. Keep reset and later overlay actions distinct; do not retain gradual history filling. + +## Phase 9.4 — GPU history representation + +### Substep 9.4.1 — Choose after capability spike + +Preferred portable path is a tiled 2-D history atlas (default `4×4`) plus separate output/current targets. A texture array is an optional optimized path behind the same tested index abstraction. + +Atlas requirements: + +- integer tile/texel fetch; +- no interpolation bleed; +- dimensions preflighted against maximum texture size; +- clear ownership of padding; +- distinct read and write targets. + +### Substep 9.4.2 — Rule pass and commit + +Run the direct stencil pass using precomputed offsets/weights/delays (uniform buffer, lookup texture, or generated shader according to measured limits). Copy/blit output into the `head` tile only after all reads complete, then rotate the logical head. Never sample the atlas tile while writing it. + +### Substep 9.4.3 — CPU/GPU parity + +Read back `M`, `N`, output, and selected history tiles for small tests. Initial one-step max-error target: `≤1e-3`. + +## Phase 9.5 — Workbench integration + +Add: + +- current committed state and computed preview; +- history timeline with selectable layer, age, and physical tile; +- radial delay map showing which distance uses which age; +- `M/N/S/increment` inspection; +- head/latest indicators; +- history initialization controls; +- direct/smooth mode selector; +- DT preset browser and model-resolution controls independent of window size. + +Parameter edits state whether they preserve or reinitialize history. Rule-only edits may preserve state but must produce a reproducible run descriptor; radius or depth changes are cold rebuilds. + +## Phase 9.6 — Verification + +### History tests + +1. Fill each layer with its index and verify every radial delay. +2. Test boundaries around `distance=n±0.5`. +3. Test head wrap `15→0`. +4. Verify smooth base is `head-1`. +5. Place one layer impulse and observe only the expected radial shell. +6. Verify x/y wrapping at all edges/corners. +7. Verify pause leaves head/state unchanged. +8. Verify every reset initializes all layers. +9. Verify atlas and CPU layouts select identical values. + +### Performance target + +At 512² and `ra≈12`, target p95 GPU step below 33 ms on the designated machine after offset/weight/delay precomputation. Keep CPU for correctness and reduced-resolution fallback. High-resolution cost limits must be visible before allocation. + +## Deliverables + +- CPU delayed-history oracle and GPU backend. +- One explicit causal indexing policy. +- Imported DT catalogue with named presets. +- History/radial-delay workbench views, restart-state export, and exact continuation checkpoints. + +## Exit gate + +- All layer, radial shell, wrap, pause, and reset tests pass. +- CPU/GPU one-step tolerance passes. +- Window resize does not reset history. +- No atlas bleed, uninitialized layer, or read/write alias exists. +- Every DT preset uses the causal latest-relative delay policy and is reproducible. diff --git a/plans/10_reference_and_analysis_tools.md b/plans/10_reference_and_analysis_tools.md new file mode 100644 index 0000000..0f9762a --- /dev/null +++ b/plans/10_reference_and_analysis_tools.md @@ -0,0 +1,127 @@ +# Macrostep 10 — Reference and analysis tools + +## Objective + +Turn the trusted core into reproducible scientific/diagnostic tools. These tools validate numerical choices and make hidden model behavior understandable; only the comparison harness is required for v1. The inverse-design rule lab is optional. + +## Dependencies + +Macrosteps 00–09 complete for a full-system comparison. The numerical harness can begin after Macrostep 03. + +## Phase 10.1 — Numerical integration comparison + +### Substep 10.1.1 — Headless experiment format + +Define a versioned experiment file containing: + +- preset and explicit initial-state fixture; +- backend/precision; +- integrators and timesteps; +- exact start/end/step-count convention; +- reference selection; +- output metrics and snapshot cadence. + +Use exact step counts; do not inherit the Matlab `for t=0:dt:end` extra-update ambiguity. + +### Substep 10.1.2 — Integrators + +Compare: + +- Euler; +- iterative implicit trapezoid (Euler predictor, clamped fixed-point iteration, bounded count/tolerance); +- AB3 with Euler/AB2 startup; +- RK4 with clamped stages under both `StageState` and retained historical `StepOrigin` relaxation references; +- optional AB4. + +Use the same convolution/rule provider for every method. Record derivative evaluation count and wall time as well as error. + +### Substep 10.1.3 — Metrics and reports + +Compute max, L1, L2, normalized L2, histogram distance, and optional spectrum-band differences against a chosen high-resolution reference. Export CSV/JSON plus plots or plot-ready data. + +Treat the legacy `result.txt` values as historical trend evidence, not bitwise goldens: source parameters and timestep sweeps drifted, and the Matlab loop advanced an extra step. Acceptance is that higher-order methods converge consistently at small `dt`, not exact recreation of every printed number. + +## Phase 10.2 — Backend comparison tool + +Create a command that runs one serialized state through the relevant implementations and compares: + +- standard CPU versus standard GPU FFT; +- legacy packed GPU stages versus its CPU stage oracle and direct convolution; +- both RK4 relaxation references; +- both sphere models against their CPU oracles; +- kernels, `M/N/S`, every integration stage, final state, and later aggregate metrics. + +It should stop at the first stage exceeding tolerance and emit both fields for visual diff in the workbench. Include GPU/driver metadata. + +## Phase 10.3 — Preset health sweep + +For every bundled preset: + +1. validate schema and localized historical-option constraints; +2. allocate at a reduced smoke-test shape where valid; +3. reset deterministically; +4. run a short fixed step count; +5. assert all values finite and committed state in `[0,1]`; +6. record min/max/mean/variance and warnings; +7. ensure every inspection channel can be requested. + +Do not assert that chaotic patterns match a screenshot. The sweep detects crashes, NaNs, stale resources, and schema drift. + +## Phase 10.4 — Visualization analysis overlays + +Add optional workbench overlays sourced from core data: + +- CPU/GPU absolute-difference heatmap; +- update/clamp saturation mask; +- occupancy histogram; +- radial kernel profile; +- 2-D Fourier magnitude preview; +- multiscale contribution stack; +- sphere seam error/area distortion; +- delayed-time radial age map. + +Keep expensive analysis paused/on-demand; never alter simulation state. + +## Phase 10.5 — Optional Glider Constructor rule lab + +This is explicitly nonblocking for the simulator release. If approved, implement behind `tools`: + +- 80×80 toroidal symmetric drawing canvas; +- selectable integer vertical displacement; +- 500×500 quantized `(N,M)` lookup assignment; +- conflict count/heatmap when one bin demands both outputs; +- test simulation using the derived lookup; +- import/export for pattern and lookup. + +Keep lookup rules separate from analytic `RuleConfig`; they are a distinct rule-provider type. Document differences from the legacy aid: no bundled glider fixture existed, undefined bins defaulted to `0.5`, and analytic rather than sampled normalization was used. + +## Phase 10.6 — Reproducibility + +Every tool output includes: + +- application/git version; +- schema/preset ID; +- serialized initial-state hash; +- backend and precision; +- seed, shape, generation, timestep, and integrator; +- CPU thread count or GPU/driver identity; +- relevant FFT algorithm, RK4 relaxation reference, and sphere model; +- command line/experiment file hash. + +Outputs are collision-safe and can be rerun from a generated manifest. + +## Deliverables + +- Numerical integration experiment runner and reports. +- Stage-aware CPU/GPU comparison tool. +- Complete bundled-preset health sweep. +- On-demand analysis overlays. +- Optional inverse-design rule lab only if separately accepted. + +## Exit gate + +- Integration experiments are exact-step reproducible. +- Small-timestep convergence order/trends are sensible and documented. +- CPU/GPU comparison identifies the first divergent stage. +- Every mandatory bundled preset passes the health sweep or is explicitly quarantined with a reason. +- Optional rule lab cannot silently masquerade as an analytic SmoothLife preset. diff --git a/plans/11_performance_portability_and_release.md b/plans/11_performance_portability_and_release.md new file mode 100644 index 0000000..77a4d01 --- /dev/null +++ b/plans/11_performance_portability_and_release.md @@ -0,0 +1,173 @@ +# Macrostep 11 — Performance, portability, and release + +## Objective + +Harden the complete simulator into a measurable, portable, supportable release. Optimize only verified bottlenecks while preserving CPU/GPU stage parity and deterministic replay. + +## Dependencies + +All mandatory behavior in Macrosteps 00–09 complete. Required analysis tooling from Macrostep 10 complete. + +## Phase 11.1 — Benchmark suite and budgets + +### Substep 11.1.1 — CPU benchmarks + +Benchmark in release mode: + +- curve/rule surface evaluation; +- kernel generation; +- direct oracle at small sizes; +- 1-D/2-D/3-D FFT and convolution; +- Euler, AB3, and RK4 base steps, including both RK4 relaxation references; +- all multiscale policies; +- reduced sphere and DT oracle steps; +- state upload/export. + +### Substep 11.1.2 — GPU timings + +Use timer queries where reliable and separate: + +- standard and legacy packed-unitary FFT stages; +- algorithm-specific kernel multiplication/inverses; +- rule/integration, including both RK4 relaxation references; +- multiscale passes under each supported FFT algorithm; +- corrected and legacy sphere stencils; +- delayed-time stencil/commit; +- 3-D ray marching; +- UI/render cost. + +Avoid `glFinish()` in normal operation. Record p50/p95 and warm-up methodology. + +### Substep 11.1.3 — Baseline policy + +Commit benchmark metadata for designated hardware/software. Flag median regressions above 10–15% for review, but keep hardware-dependent gates out of ordinary CI. Correctness tolerances remain blocking everywhere. + +## Phase 11.2 — Measured optimization + +### CPU + +- reuse plans, spectra, and scratch buffers; +- parallelize transform lines and pointwise passes after deterministic tests; +- improve cache locality and avoid unnecessary complex copies; +- vectorize only with readable fallback and measured benefit. + +### GPU + +- reuse state forward transforms; +- fuse only pointwise passes whose separate inspection output can still be produced on demand; +- cache shader specializations and uniform locations; +- precompute sphere/DT stencil metadata; +- adapt raymarch quality independently from simulation quality; +- never introduce per-frame allocation/readback. + +Every optimization requires before/after stage parity plus benchmark evidence. + +## Phase 11.3 — Memory and resource management + +- Estimate CPU RAM and GPU VRAM before every cold rebuild. +- Include state, histories, RK/AB buffers, spectra, atlas padding, render targets, and capture staging. +- Enforce configurable soft/hard budgets. +- Fall back to the previous valid configuration on allocation failure. +- Expose a resource report in the diagnostics panel. +- Stress repeated backend/variant/resolution switching and verify stable resource counts. + +Recommended interactive profiles should be realistic; do not advertise legacy shortcut sizes such as 512³ when memory/performance makes them unusable. + +## Phase 11.4 — Portability matrix + +### Primary tier + +- Linux desktop; +- Windows desktop; +- macOS supported raylib/OpenGL path, with limitations documented. + +Target OpenGL 3.3 core-compatible behavior and CPU fallback where float-FBO requirements fail. Web/GLES remains secondary until separately implemented and tested. + +### CI + +Run: + +- formatting and Clippy with the declared toolchain; +- all headless tests on primary OSes; +- raylib application compilation on primary OSes; +- bundled preset/schema validation; +- shader compilation/static validation; +- hidden-window Mesa/Xvfb GPU smoke tests on Linux when stable; +- packaging smoke tests from directories unrelated to the repository. + +Document driver-specific tolerances instead of accepting arbitrary output drift. + +## Phase 11.5 — Operational hardening + +### Substep 11.5.1 — File behavior + +- user config/data/captures use platform directories; +- atomic settings/preset writes; +- collision-safe captures; +- no writes beside the executable; +- clear migration/backup policy for future schema versions. + +### Substep 11.5.2 — Failure behavior + +Test missing/corrupt config, invalid preset, shader failure, unsupported GPU, OOM/preflight rejection, minimized window, resize storms, and failed state import. Standard auto mode falls back to CPU when possible and displays why; explicit `LegacyPackedUnitary` fails clearly rather than changing algorithms. + +### Substep 11.5.3 — Diagnostics + +A copyable report includes version, OS, raylib/OpenGL/GLSL, backend, FFT algorithm, relevant RK4 reference or sphere model, capabilities, preset/run descriptor, memory estimate, and recent errors. Logs rotate or remain bounded. + +## Phase 11.6 — Documentation and packaging + +Write: + +- project README with screenshots and quick start; +- mathematical model and retained historical-options guide; +- controls/UI reference; +- configuration schema with examples for every variant; +- CPU/GPU backend and tolerance explanation; +- performance and memory tuning guide; +- troubleshooting and driver fallback guide; +- contributor architecture/testing guide; +- release notes listing intentional differences from legacy. + +Package binaries, embedded/packaged shaders, preset catalogues, licenses, and example configs. Verify clean-machine installation and launch. + +## Phase 11.7 — Final acceptance matrix + +### Functional + +- Base 1-D/2-D/3-D: modes 0/1/2 and Euler/AB3/RK4. +- Multiscale 2-D: both neighborhood interpretations and all three compositions. +- Retained options: both RK4 relaxation references and both FFT algorithms where supported. +- Sphere: complete `Corrected` and `Legacy` models with discrete/fixed-smooth dynamics. +- DT: one causal 16-layer distance-delay model with both update modes. +- Every backend exposes its required logic channels. + +### Numerical + +- Direct↔standard CPU↔standard GPU tolerances pass, and legacy packed GPU stages/final convolution pass their dedicated CPU-oracle tolerances. +- State remains finite and committed values remain `[0,1]`. +- Deterministic reset/replay works for CPU; GPU is reproducible within documented tolerance. +- Retained historical options use safe deterministic infrastructure; no undefined historical behavior exists in any path. + +### Performance/resource + +- No steady-state allocation or readback. +- Reference profiles meet recorded responsiveness targets or ship with lower documented defaults. +- Memory preflight and transactional failure paths work. + +### Product + +- Presets, controls, captures, state replay, and diagnostics are discoverable. +- Launch never depends on the old repository or current working directory. +- Primary-platform packages pass smoke tests. + +## Deliverables + +- Baselines and optimized implementations with preserved parity. +- Primary-platform CI/build/package pipeline. +- Complete user/contributor documentation. +- Signed-off functional/numerical/performance acceptance matrix. + +## Exit gate + +Release only when every mandatory matrix row is implemented, tested, and documented; all bundled presets validate; CPU fallback can execute every simulation variant using its CPU-supported standard options; explicit `LegacyPackedUnitary` requests remain GPU-only and fail rather than substitute; GPU acceleration passes reference-profile smoke tests; and no blocking diagnostic, resource leak, undefined feedback path, or runtime dependency on legacy files remains. diff --git a/plans/README.md b/plans/README.md new file mode 100644 index 0000000..bd85fe5 --- /dev/null +++ b/plans/README.md @@ -0,0 +1,172 @@ +# SmoothLife Rust/raylib reimplementation plan + +## Mission + +Reimplement the legacy SmoothLife collection as one modern Rust 2024 application using raylib for the window, input, and presentation. The result is a configurable simulation laboratory, not a line-by-line port. It must expose the internal logic of every simulator through inspectable fields while preserving the documented mathematics and making legacy defects explicit rather than accidental. + +This plan is implementation-oriented: execute the macrosteps in order and use each exit gate as the prerequisite for the next step. Later work should rely on the in-repository contract and tests produced by Macrostep 00, not repeatedly reopen the legacy tree. + +The original source position is ~/Nextcloud/VecchiProgetti/SmoothLifeAll/ + +## Required release scope + +| Legacy component | New application responsibility | +| --- | --- | +| `SmoothLife/` | Periodic 1-D, 2-D, and 3-D model; discrete/growth/relaxation dynamics; Euler, AB3, and RK4; both RK4 relaxation references; standard and legacy packed-unitary FFTs; inspection and 3-D rendering. | +| `SmoothLifeSDL/` | Subsumed by the portable raylib shell. Its one-pass Euler behavior is covered by the base Euler path, not a separate simulator. | +| `SmoothLifeMultiscale/` | Corrected three-scale 2-D growth/relaxation model, two neighborhood interpretations, three composition policies, and either GPU FFT algorithm. | +| `SmoothLifeSphere/` | Corrected sphere default plus one coherent retained legacy sphere model; both use safe deterministic resources. | +| `SmoothLifeDT/` | Periodic 2-D field with initialized 16-frame circular history and one causal radius-dependent delay policy. | +| FreeBasic/Matlab | Independent CPU oracles, FFT/integrator validation, and a numerical comparison tool. | +| `GliderConstructor.bas` | Optional post-v1 inverse-design tool; it is not a general simulation backend and does not block the main release. | + +## Product principles + +1. **Pure core, graphical shell.** The model must run headlessly without raylib. Rendering consumes snapshots and inspection channels; it does not own simulation truth. +2. **CPU oracle before GPU optimization.** Every GPU pass is checked against a deterministic CPU implementation. +3. **One shared rule implementation.** All variants use the same typed rule configuration and equivalent Rust/GLSL formulas. +4. **Inspectable by design.** `A`, `M`, `N`, target `S`, derivative/increment, kernels, scale outputs, history layers, and topology diagnostics are first-class channels. +5. **Historical simulation behavior is exceptional and local.** There is no general legacy engine or compatibility profile. Only the explicitly retained RK4 relaxation reference, packed-unitary FFT, and sphere model are selectable; all other simulation behavior follows the new deterministic design. +6. **Deterministic replay and continuation.** A run is identified by schema version, preset ID, seed, shape, backend, only the localized historical options relevant to that run, and step count. Restart-state files reset numerical history; exact checkpoints additionally store AB history, DT history/head, generation, and deterministic RNG state. +7. **No runtime dependency on the old project.** Legacy catalogues are imported once and committed in the new schema. +8. **No steady-state allocation or readback.** Buffers and plans are reused; GPU readback is only for tests and explicit exports. + +## Intended repository shape + +```text +smoothlife/ +├── Cargo.toml +├── src/ +│ ├── lib.rs # raylib-free public core +│ ├── main.rs # application entry point +│ ├── config/ # schema, validation, preset library/import +│ ├── field/ # shapes, storage, indexing, inspection data +│ ├── math/ # curves, rules, kernels +│ ├── integration/ # discrete, Euler, AB3, RK4 +│ ├── convolution/ # direct oracle and FFT implementations +│ ├── simulation/ # common commands and backend facade +│ ├── variants/ # planar, multiscale, sphere, delayed time +│ ├── gpu/ # isolated rlgl/OpenGL resources and passes +│ ├── app/ # scheduler, actions, lifecycle +│ ├── render/ # palettes, 1-D/2-D/3-D/sphere rendering +│ └── ui/ # panels, HUD, help, notifications +├── assets/ +│ ├── presets/ +│ └── shaders/ +├── tests/ +├── benches/ +└── plans/ +``` + +Start as one Cargo package. Make raylib and GPU code optional behind features so `cargo test --no-default-features` exercises the mathematical core without a graphics context. Create a workspace only if later standalone tools justify it. + +## Core data flow + +```text +validated preset + deterministic initializer + │ + ▼ + state A + │ + topology-specific neighborhood + │ + M (disk), N (ring) + │ + common target S(N,M) + │ + dynamics → derivative/increment + │ + selected integration + │ + clamp and commit A' + │ + inspection snapshot → raylib renderer/UI +``` + +The special variants replace only the neighborhood/topology and update policy layers: + +- **Multiscale:** several `(M,N,S)` pipelines plus a composition policy. +- **Sphere:** direct geodesic, area-weighted neighborhoods on a cube-sphere. +- **Delayed time:** each radial offset selects a spatially shifted history layer. + +## Configuration model + +Use strict, versioned TOML with string enums and a tagged variant: + +```text +Preset +├── identity/provenance +├── VariantConfig +│ ├── Planar +│ ├── Multiscale +│ ├── Sphere +│ └── DelayedTime +├── RuleConfig (one or one per scale) +├── DynamicsConfig +├── InitializerConfig +└── recommended presentation +``` + +Keep model presets distinct from user preferences (window, palette, camera, key bindings). Bundled presets are immutable; user presets and captures live in platform-specific user directories. + +## Historical options policy + +The new deterministic implementation is always the baseline: complete kernel support, initialized state, Euler → AB2 → AB3 startup, explicit ping-pong writes, corrected multiscale evaluation, causal delayed history, fixed simulation scheduling, and strict configuration validation. + +Exactly three historical choices remain: + +```text +Rk4RelaxationReference + StageState # default: S(stage)-stage + StepOrigin # historical: S(stage)-state_at_step_start + +FftAlgorithm + Standard # default: conventional normalized FFT + LegacyPackedUnitary + +SphereModel + Corrected # default: complete seams and sampled normalization + Legacy # original atlas/seam and analytic-cap model +``` + +These are independent, local settings—not a general compatibility profile. `LegacyPackedUnitary` retains packed real/complex storage, half-width x spectra, historical butterfly/plan stages, unitary scaling, and the matching `sqrt(N)/kernel_sum` correction. `SphereModel::Legacy` retains the original cube-atlas geometry, side-gutter/corner masking, analytic normalization, radius conversion, direct stencil, and fixed smooth update. + +Even these options use safe deterministic infrastructure. The project never preserves undefined AB buffers, uninitialized textures, texture feedback loops, unclamped `acos`, platform `rand()` streams, stale multiscale fields, additive-discrete multiscale behavior, or the delayed-time head anomaly. + +## Delivery milestones + +| Milestone | Macrosteps | User-visible result | +| --- | --- | --- | +| R0: frozen contract | 00 | All required behavior and source provenance live in this repository. | +| R1: first useful simulator | 01–04 | Deterministic CPU SmoothLife with a professional raylib 2-D workbench and inspectors. | +| R2: accelerated base model | 05–06 | CPU/GPU base parity, 1-D history, 2-D field, 3-D slices/volume, complete base presets. | +| R3: all historical models | 07–09 | Multiscale, sphere, and delayed-time backends selectable in one application. | +| R4: release candidate | 10–11 | Reference tooling, benchmarks, packaging, portability, and complete documentation. | + +## Macrostep index + +1. [Macrostep 00 — Model contract and retained historical options](00_model_contract_and_historical_options.md) +2. [Macrostep 01 — Project foundation and configuration](01_project_foundation_and_configuration.md) +3. [Macrostep 02 — Mathematical core and deterministic oracles](02_mathematical_core_and_oracles.md) +4. [Macrostep 03 — CPU planar simulation engine](03_cpu_planar_simulation_engine.md) +5. [Macrostep 04 — Raylib visualization workbench](04_raylib_visualization_workbench.md) +6. [Macrostep 05 — GPU resources and 2-D FFT proof](05_gpu_resources_and_fft_proof.md) +7. [Macrostep 06 — Complete base solver and dimensional rendering](06_complete_base_solver_and_dimensions.md) +8. [Macrostep 07 — Multiscale backend](07_multiscale_backend.md) +9. [Macrostep 08 — Spherical backend](08_spherical_backend.md) +10. [Macrostep 09 — Delayed-time backend](09_delayed_time_backend.md) +11. [Macrostep 10 — Reference and analysis tools](10_reference_and_analysis_tools.md) +12. [Macrostep 11 — Performance, portability, and release](11_performance_portability_and_release.md) + +## Definition of “macrostep complete” + +A macrostep is complete only when: + +- every required phase is implemented; +- its tests and diagnostics pass in debug and release where relevant; +- its deliverables are committed; +- its exit gate is demonstrated, not merely asserted; +- documentation and schema examples are updated in the same change; +- unresolved deviations are recorded as explicit issues with an owner and blocking status. + +Do not begin optimization before the corresponding oracle and stage-level comparisons exist.