dsfb-add — Algebraic Deterministic Dynamics Sweep
dsfb-add is the empirical sweep and figure-generation companion for the Algebraic Deterministic Dynamics (ADD) stack. It runs deterministic lambda sweeps, exports structural observables as CSV, and feeds a Colab notebook that regenerates the paper-facing figures from those CSVs.
At a high level, the crate does three things:
- It evolves four deterministic toy models across a shared lambda grid.
- It writes reproducible sweep outputs into
output-dsfb-add/<timestamp>/at the repo root. - It provides the numerical substrate for the ADD paper's figures: cross-layer response curves, transport transition summaries, structural-law fits, robustness checks, and finite-size scaling diagnostics.
The stack it sweeps is:
- Algebraic Echo Theory (AET)
- Topological Charge Propagation (TCP)
- Resonance Lattice Theory (RLT)
- Invariant Word-Length Thermodynamics (IWLT)
Citation
Primary paper for this crate:
- de Beer, R. (2026). Algebraic Deterministic Dynamics (ADD): A Non-Stochastic Structural Extension of DSFB (v1.0). Zenodo. DOI: 10.5281/zenodo.18830567
Zenodo record:
Suggested BibTeX:
Motivation
ADD extends the deterministic style of DSFB upward into structural dynamics. Instead of using stochastic primitives as the default language for memory, disorder, spread, and irreversibility, the ADD paper frames those effects through exact evolution rules on words, graphs, and trajectory-generated complexes.
dsfb-add is the empirical side of that argument. It is not a full physics engine and it does not claim microscopic fidelity. Its job is narrower and more useful for the paper: it provides a deterministic numerical laboratory in which the four layers can be swept together, perturbed in a controlled way, compared across finite trajectory lengths, and summarized with a small number of interpretable structural observables.
In practice that means the crate can answer questions like:
- how echo growth changes across lambda,
- how invariant word-length entropy tracks that echo growth,
- where the resonance transport transition occurs,
- how persistent-topology summaries respond across the same sweep,
- whether the AET-IWLT structural law survives deterministic rule perturbations,
- and whether those claims stabilize as
steps_per_runincreases.
Mathematical Model
The ADD paper defines a common deterministic template for all four layers. The abstract state evolves by
S_{k+1} = Φ(S_k),
with a discrete invariant
I(S_{k+1}) = I(S_k),
and a monotone structural functional
L(S_{k+1}) >= L(S_k).
dsfb-add is the numerical sweep implementation of that idea. It does not attempt to symbolically prove the paper's theorems inside Rust; instead it instantiates deterministic toy models whose exported diagnostics are direct empirical proxies for the functionals defined in the paper.
Algebraic Echo Theory (AET)
In the paper, AET works on words in a free monoid G* with a terminating, confluent rewriting system R. The echo of a word is its normal form,
Echo(w) = NF(w),
and the echo length is
L_AET(w) = len(Echo(w)).
The paper's AET evolution is left-multiplicative:
w_{k+1} = NF(g* w_k),
with increment sequence
Delta_k = L_k+1 - L_k,
L_k = L_AET(w_k),
and asymptotic survival rate
sigma = lim inf_{n -> inf} (1 / n) sum_{k=0}^{n-1} Delta_k.
In dsfb-add, the aet module implements exactly this style of deterministic word evolution on a small alphabet with terminating, confluent local rules. The exported sweep statistics are empirical summaries of the paper's L_AET dynamics:
-
echo_slope(lambda)is the finite-run slope estimateecho_slope ~= (L_final - L_initial) / steps_per_run -
avg_increment(lambda)is the finite-run average of the incrementsavg_increment = (1 / N) sum Delta_k.
So the AET CSVs are a sampled lambda-family of the paper's echo-length growth law.
Topological Charge Propagation (TCP)
In the paper, TCP starts from a deterministic trajectory, builds a filtration of simplicial complexes,
K_{alpha_1} subseteq K_{alpha_2} whenever alpha_1 <= alpha_2,
and defines the topological charge vector
Q(alpha) = (beta_0(K_alpha), beta_1(K_alpha), beta_2(K_alpha), ...).
The paper also uses the Euler-characteristic identity
chi(K_alpha) = sum_{k >= 0} (-1)^k beta_k(K_alpha),
and a topological-disorder functional of the form
L_TCP(t) = sum_k w_k * #{persistent classes in dimension k with lifetime >= delta}.
dsfb-add keeps persistent homology itself in the notebook rather than in Rust. The Rust crate exports deterministic point clouds for each lambda and each deterministic run window, and the notebook computes the paper-facing PH summaries:
betti1_mean(lambda)betti1_std(lambda)total_persistence_mean(lambda)total_persistence_std(lambda)
The smooth TCP observable used in the figures is total persistence, which is the notebook's empirical surrogate for the paper's L_TCP.
Resonance Lattice Theory (RLT)
In the paper, RLT evolves on a locally finite resonance graph G = (V, E) with deterministic dynamics
v_{k+1} = Psi(v_k).
From an initial configuration v_0, the reachable component is
C(v_0) = { v in V | v = Psi^(k)(v_0) for some k >= 0 },
and the resonance spread is
L_RLT(v_0) = |C(v_0)|.
The paper further defines escape rate
lambda(v_0) = lim inf_{n -> inf} (1 / n) d_G(v_0, v_n),
and resonance expansion ratio
rho(v_0, n) = |V_n| / (n + 1),
rho(v_0) = lim inf_{n -> inf} rho(v_0, n),
where V_n = {v_0, ..., v_n} is the visited set up to time n.
The rlt module exports finite-run deterministic proxies for these exact paper objects:
escape_rate(lambda)is the sampled version oflambda(v_0)expansion_ratio(lambda)is the sampled version ofrho(v_0, n)rlt_examples/...csvstores representative bounded and expanding trajectories
The crate also exports the paper-facing phase-boundary summary:
lambda_star = first lambda with expansion_ratio >= 0.5
lambda_0_1 = first lambda with expansion_ratio >= 0.1
lambda_0_9 = first lambda with expansion_ratio >= 0.9
transition_width = lambda_0_9 - lambda_0_1
These are the deterministic transport-transition metrics used by the notebook's RLT scaling plots and hero figure annotation.
Invariant Word-Length Thermodynamics (IWLT)
In the paper, IWLT defines the equivalence class of a history word under a rewriting system as
[w] = { u in E* | u is reachable from w by finitely many rewrites },
and the word-length entropy as the minimal representative length
S_IWLT(w) = min_{u in [w]} len(u).
The evolution is append-only,
w_{k+1} = w_k e_{i_{k+1}},
and the paper proves existence of the entropy-density limit
s_inf = lim_{k -> inf} S_IWLT(w_k) / k.
Under the paper's local-irreversibility assumptions, IWLT obeys the deterministic entropy-density law
S_IWLT(w_k) >= (m - BC) k,
s_inf >= m - BC > 0.
The iwlt module implements a deterministic append-and-reduce history system in exactly this spirit. Its exported diagnostics are finite-run empirical surrogates of the paper quantities:
-
entropy_density(lambda)is the sampled estimateentropy_density ~= S_IWLT(w_final) / steps_per_run -
avg_increment(lambda)is the mean per-step increase in the minimal representative length.
Cross-Layer Structural Law
The main empirical claim tested by this crate is that the AET and IWLT functionals lock together numerically across the same lambda sweep. Concretely, for every run length N, the notebook merges
echo_slope(lambda)from AET, andentropy_density(lambda)from IWLT,
then fits the linear law
entropy_density ~= a * echo_slope + b.
From that fit it computes:
-
Pearson correlation,
-
Spearman rank correlation,
-
regression slope
a, -
intercept
b, -
R^2, -
mean-squared residual,
-
and the dimensionless ratio
entropy_density / echo_slope.
This is the structural-law pipeline behind aet_iwlt_law_summary.csv, the finite-size scaling summaries, the residual diagnostics, the universality comparison, and the bottom panel of fig_hero_add_stack.png.
What The Crate Actually Computes
Putting the paper mathematics and the Rust implementation together:
- the Rust crate generates deterministic trajectories, words, and graph walks parameterized by lambda and optional multiple
steps_per_runvalues, - the CSVs store finite-run samples of
L_AET,S_IWLT, TCP persistence summaries, and RLT spread/escape observables, - perturbed sweeps test whether those laws are stable under small deterministic rule changes,
- and the notebook reconstructs the paper-facing diagnostics from those exported deterministic samples.
So the crate is not merely a plotting harness. It is the executable empirical realization of the paper's algebraic-topological stack: the place where the formal quantities from AET, TCP, RLT, and IWLT are turned into concrete sweep data, regression summaries, phase-boundary estimates, and final figures.
Architecture
The crate is split into four simulation modules plus shared configuration, output, and orchestration code.
aet: deterministic word evolution on a finite alphabet with terminating, confluent local rewrite rules. It tracks irreducible echo length growth and average increment statistics.tcp: deterministic 2D trajectory generation indexed by lambda. Rust writes per-lambda point clouds and coarse topological proxies; the Colab notebook can then compute richer persistent-homology diagnostics from those point clouds.rlt: deterministic walks on a synthetic resonance lattice. It measures graph escape rate and expansion ratio from the visited component.iwlt: append-only symbolic evolution with local length-non-increasing rewrites. It tracks minimal representative length, entropy density, and average increment.config: definesSimulationConfig, including the lambda sweep bounds, step count, seed, and per-subtheory toggles.output: createsoutput-dsfb-add/<timestamp>/usingchrono::Utc::now()and writes sweep, phase-boundary, and robustness CSV files.sweep: orchestrates baseline and perturbed sweeps, optional multi-Nruns, phase-boundary extraction, and robustness summaries.analysis/rlt_phase: extractslambda_star, transition brackets, and transition width from the RLT expansion curve.
SimulationConfig::lambda_grid() produces evenly spaced lambda values on [lambda_min, lambda_max]. With the default configuration the sweep is deterministic and reproducible across runs because each sub-theory derives all pseudo-random choices from random_seed and the lambda index.
If multi_steps_per_run is populated, the crate repeats the full sweep for every requested trajectory length. This is what supports the paper's finite-size scaling story: the exact same lambda grid and deterministic rules are re-run at multiple N, and the notebook then measures how regression slope, R^2, residual variance, and phase-boundary location stabilize.
The crate also depends on the workspace dsfb crate. That dependency is used to build a small deterministic drive signal shared across the ADD toy models, so the sweep remains aligned with the DSFB repository's observer-first philosophy without modifying any existing DSFB source code.
Code-Level Walkthrough
The crate is intentionally split so the Rust side handles deterministic data generation and the notebook side handles heavier plotting and PH post-processing.
Library Entry Points
The main library entry point is:
;
This is the simplest API when embedding dsfb-add from another Rust program: pass a SimulationConfig, let the crate create a fresh timestamped output directory, and write the full sweep there.
The lower-level entry point used by the binary is:
;
This is the better choice when you want explicit control over where outputs are written or when integrating ADD sweeps into a larger orchestration layer.
CLI Binary
The binary target is:
dsfb_add_sweep
It accepts:
--config path/to/config.json--steps-per-run-list 512,5000,10000,20000
If a config.json exists in the current working directory, it is loaded automatically. Otherwise the binary uses SimulationConfig::default().
SimulationConfig Parameters
SimulationConfig is the central contract for the crate. Its fields are:
num_lambda: number of lambda samples in the sweep gridlambda_min,lambda_max: inclusive sweep bounds used bylambda_grid()steps_per_run: fallback single run length when no multi-Nsweep is requestedmulti_steps_per_run: optional list of run lengths for finite-size scaling; if non-empty this takes precedence oversteps_per_runrandom_seed: deterministic seed for all pseudo-random branch choicesenable_aet,enable_tcp,enable_rlt,enable_iwlt: per-layer switches that allow focused runs
Default values are chosen to make the crate useful out of the box:
num_lambda = 360lambda_min = 0.0lambda_max = 1.0steps_per_run = 512multi_steps_per_run = [512, 5000, 10000, 20000]
That means the default binary run is already a finite-size scaling experiment across four trajectory lengths. For a one-off local production run, you can override this with:
What Each Rust Module Does
src/aet.rsimplements the AET word-evolution sweep and its perturbed variantsrc/iwlt.rsimplements the IWLT append-and-reduce entropy sweep and its perturbed variantsrc/rlt.rsimplements deterministic resonance walks, phase-transition proxies, and example trajectoriessrc/tcp.rsimplements deterministic 2D trajectory generation and exports multi-run point clouds for notebook-side PHsrc/analysis/rlt_phase.rsextractslambda_star, transition-width brackets, and related phase-boundary quantitiessrc/analysis/structural_law.rsfits the AET-IWLT structural law and computes the confidence interval used in downstream summariessrc/output.rsowns CSV schema definitions and file-writing helperssrc/sweep.rsis the orchestration layer: it loops over enabledsteps_per_runvalues, runs baseline and perturbed sweeps, aggregates summaries, and writes the full output setsrc/bin/dsfb_add_sweep.rsis the CLI wrapper aroundSimulationConfigloading and sweep execution
Progress Reporting
The sweep binary emits percentage-based progress updates while it runs. This is especially useful for large local finite-size runs where steps_per_run may extend up to 100000 or higher.
The progress tracker reports:
- the current subsystem,
- whether the run is baseline or perturbed,
- the current
steps_per_run, - and the overall percentage through the entire ADD job.
Running The Sweep
From the repo root:
Optional config override:
Finite-size scaling run:
If config.json exists in the current working directory, the binary loads it automatically. Otherwise it uses SimulationConfig::default().
By default the crate now runs a finite-size scaling sweep across:
51250001000020000
and writes per-N files with _N<steps> suffixes, while also keeping unsuffixed canonical CSVs for the reference run. If --steps-per-run-list is provided, those values override the configured sweep list for that run.
Each run creates:
output-dsfb-add/<YYYY-MM-DDTHH-MM-SSZ>/
inside the workspace root and writes the requested CSV outputs there.
Why The Crate Is Split Between Rust And Colab
The Rust crate is responsible for deterministic generation, reproducibility, and explicit CSV schemas. The notebooks are responsible for figure production, persistent-homology post-processing, and exploratory views that would be awkward or heavyweight to maintain directly in Rust.
That split is intentional:
- Rust owns deterministic execution and file layout.
- CSVs provide stable interchange points for the paper workflow.
- Colab owns presentation, diagnostics, and final publication figures.
This design keeps the core ADD experiment reproducible from the command line while still making the paper's figure pipeline easy to rerun in the cloud.
Using The Colab Notebook
Workflow:
- Run the Rust sweep locally so the CSV files, point clouds, and trajectory examples are generated.
- Zip, upload, or sync
output-dsfb-add/<timestamp>/into your Colab environment, or let the notebook generate a fresh run in Colab. - Open
crates/dsfb-add/dsfb_add_sweep.ipynbusing the Colab badge in the main repo README. - Set
OUTPUT_DIRonly if you intentionally want an existing run directory; otherwise the notebook can bootstrap a fresh one. - Run the notebook cells to regenerate all PNG figures and derived summary CSVs in the same directory as the sweep outputs.
The notebook is structured so Rust remains the authoritative simulation layer and Colab remains the analysis and figure-generation layer. The Rust side produces deterministic sweeps and structural summaries; the notebook performs the paper-facing regression, finite-size scaling, residual diagnostics, universality comparison, and hero-figure assembly.
For Colab specifically, the notebook uses a minimal reproducible default sweep profile of 512 when it bootstraps a fresh Rust run. A dropdown near the top of the notebook selects the active steps_per_run value for both bootstrap and figure display, and it defaults to 512 so free CPU sessions remain practical. If you want the full production profile in Colab, set RUST_MULTI_STEPS = [512, 5000, 10000, 20000, 50000, 100000] in the notebook before running the bootstrap cell. If you run the large multi-N sweep locally and upload the results, that same dropdown lets you switch the displayed analysis to any available N without editing the plotting code.
For the completed local production run currently present in this workspace, use the dedicated replay notebook:
crates/dsfb-add/dsfb_add_results_replay.ipynb
That notebook is preconfigured for:
- timestamp:
2026-03-01T18-19-22Z - expected archive:
output-dsfb-add/dsfb-add-2026-03-01T18-19-22Z.zip
Its default behavior is analysis-only:
RUN_RUST_SWEEP_IN_COLAB = FalseOUTPUT_DIR = /content/output-dsfb-add/2026-03-01T18-19-22Z
Upload that zip in Colab, run the helper cell upload_and_unpack_replay_zip(), and then run the remainder of the notebook. The same steps_per_run dropdown can then switch between 512, 5000, 10000, 20000, 50000, and 100000 using the uploaded local results.
Outputs
Expected runtime files:
aet_sweep.csvaet_sweep_perturbed.csvaet_sweep_N<steps>.csvaet_sweep_perturbed_N<steps>.csvtcp_sweep.csvtcp_sweep_N<steps>.csvrlt_sweep.csvrlt_sweep_perturbed.csvrlt_sweep_N<steps>.csvrlt_sweep_perturbed_N<steps>.csviwlt_sweep.csviwlt_sweep_perturbed.csviwlt_sweep_N<steps>.csviwlt_sweep_perturbed_N<steps>.csvtcp_points/lambda_<idx>_run_<r>.csvtcp_points_N<steps>/lambda_<idx>_run_<r>.csvrlt_examples/trajectory_bounded_lambda_<idx>.csvrlt_examples/trajectory_expanding_lambda_<idx>.csvrlt_examples_N<steps>/trajectory_bounded_lambda_<idx>.csvrlt_examples_N<steps>/trajectory_expanding_lambda_<idx>.csvrlt_phase_boundary.csvcross_layer_thresholds.csvtcp_phase_alignment.csvrobustness_metrics.csvaet_iwlt_law_summary.csvaet_iwlt_scaling_summary.csvaet_iwlt_diagnostics_summary.csvtcp_ph_summary.csv(written by the Colab notebook after persistent-homology post-processing)
Expected notebook figure outputs:
fig_aet_echo_slope_vs_lambda.pngfig_aet_robustness.pngfig_iwlt_entropy_density_vs_lambda.pngfig_iwlt_robustness.pngfig_rlt_escape_rate_vs_lambda.pngfig_rlt_expansion_ratio_vs_lambda.pngfig_rlt_expansion_ratio_vs_lambda_zoom.pngfig_rlt_robustness.pngfig_rlt_trajectory_bounded.pngfig_rlt_trajectory_expanding.pngfig_tcp_betti1_mean_vs_lambda.pngfig_tcp_total_persistence_vs_lambda.pngfig_aet_iwlt_structural_law.pngfig_aet_iwlt_universality.pngfig_aet_iwlt_scaling_slope_vs_N.pngfig_aet_iwlt_scaling_r2_vs_N.pngfig_aet_iwlt_scaling_resid_vs_N.pngfig_aet_iwlt_residuals_vs_echo.pngfig_aet_iwlt_residual_hist.pngfig_aet_iwlt_ratio_vs_lambda.pngfig_aet_iwlt_ratio_hist.pngfig_aet_iwlt_loglog.pngfig_cross_layer_summary_vs_lambda.pngfig_rlt_phase_lambda_star_vs_N.pngfig_rlt_phase_width_vs_N.pngfig_rlt_phase_sharpness_vs_N.pngfig_rlt_vs_aet_threshold.pngfig_rlt_vs_iwlt_threshold.pngfig_tcp_phase_alignment_vs_N.pngfig_hero_add_stack.png
tcp_sweep.csv includes coarse Rust-side topological proxies (betti0, betti1, l_tcp) plus radius statistics. The notebook augments those proxies with ripser-based H1 summary statistics computed from the exported per-lambda run clouds, with total persistence treated as the main smooth TCP observable.
The perturbed sweep CSVs are small deterministic robustness experiments: they nudge the update laws without changing the overall structural regime picture. The Rust sweep now writes the core numerical summaries directly:
aet_iwlt_law_summary.csvcontains the linear AET-IWLT fit perNand per mode, includingR^2, residual variance, and slope confidence interval.aet_iwlt_scaling_summary.csvisolates the baseline finite-size scaling branch acrossN.aet_iwlt_diagnostics_summary.csvstores residual and ratio statistics perN.rlt_phase_boundary.csvstoreslambda_star, the 0.1-0.9 transition width, and a finite-difference sharpness estimate.cross_layer_thresholds.csvrecords the AET and IWLT structural values at the RLT transport transition.tcp_phase_alignment.csvrecords how the TCP peak observables align with the RLT phase transition.robustness_metrics.csvcompresses baseline-vs-perturbed deltas for the structural law and the RLT transition.
The notebook then turns those summaries into paper-ready figures, adds PH-derived TCP summaries, overlays diagnostics, and rebuilds the fully annotated hero figure.
Taken together, the outputs are meant to support the numerical section of the ADD paper:
- baseline and perturbed sweeps show the main structural response,
- multi-
Nruns show finite-size convergence, - phase-boundary summaries quantify the RLT transport transition,
- structural-law summaries quantify the AET-IWLT coupling,
- and the hero figure condenses the stack into a single paper-facing panel.
Publishability Notes
The crate is intended to be publishable on crates.io as a normal Rust package:
- it exposes a reusable library API,
- it ships a documented CLI binary,
- it includes the notebooks that consume the exported CSVs,
- and it depends on the published
dsfbcrate rather than on unpublished workspace-only internals.
The crate is therefore usable in two ways:
- as a command-line experiment runner for ADD paper reproduction, and
- as a library dependency for projects that want to orchestrate ADD sweeps programmatically.
Relationship To The DSFB / ADD Papers
The DSFB crate provides the deterministic observer philosophy already present in this monorepo. The ADD paper extends that philosophy into structural dynamics: irreducible word growth, deterministic topological complexity, resonance spread, and entropy production without stochastic assumptions.
dsfb-add turns that argument into a repeatable experiment. Its outputs are the empirical curves used to study echo slopes, entropy densities, resonance spreads, and topology-vs-lambda structure for the ADD stack.