mirror of
https://github.com/logos-blockchain/research.git
synced 2026-08-07 19:53:10 +00:00
103 lines
5.8 KiB
Markdown
103 lines
5.8 KiB
Markdown
# tsi-sim-mc — Cryptarchia TSI simulator (multicore build)
|
||
|
||
> **This is the multicore-optimised, reviewed copy of `../tsi-sim/`.** The original is left
|
||
> untouched. Versus the original it adds: a **sparse lottery sampler** (~30–100× faster per
|
||
> epoch), a **hardened multicore sweep** (loky + single-thread BLAS), an **opt-in parallel
|
||
> chunked lottery**, an optional **spec fixed-point mode**, corrected figures, config
|
||
> validation, and a larger test suite. See "Performance & reproducibility" below.
|
||
|
||
Monte-Carlo simulation framework used to choose safe values for the **uncle-reference**
|
||
parameters of Cryptarchia's Total Stake Inference (TSI):
|
||
|
||
- `U` — max uncles referenced per block (`MAX_UNCLES`); `U=0` is the no-uncle baseline.
|
||
- `W` — uncle reference window in slots (spec default 300).
|
||
- swept against network size `N`, stake distribution `S` (uniform / Pareto), and
|
||
network **latency** `L` (in slots — deliberately *not* `D`, which denotes the stake estimate).
|
||
|
||
It measures how well the inferred total active stake `D` tracks the true total stake, and
|
||
whether uncle references recover the active slots that network latency loses to forks.
|
||
|
||
> This lives under a `raw/` docs path, so it is invisible to the repository's
|
||
> markdown-lint CI. It is a standalone Python package with its own tooling.
|
||
|
||
## Model
|
||
|
||
Reduced **canonical-chain-with-orphans** model: we simulate the global winning-slot
|
||
sequence (stake-weighted φ lottery), build a real block tree with latency- and
|
||
multi-winner-induced forks, resolve the canonical chain (honest longest-chain), let
|
||
canonical blocks reference uncles per the spec's selection rules, and count TSI density
|
||
`m = honest-chain blocks + deduplicated referenced uncles` in the measurement window.
|
||
All honest nodes converge to the same deep chain (k-finality), so a single per-epoch
|
||
`D` is faithful. A full per-node model is the planned next phase (`per_node_dest` flag
|
||
scaffolds it).
|
||
|
||
See the sibling spec `../` and `../../cryptarchia-total-stake-inference.md` for the math.
|
||
|
||
## Quick start
|
||
|
||
```bash
|
||
make install # create .venv and install (editable) with dev deps
|
||
make test # unit tests + fast theory checks
|
||
make verify # simulator vs closed-form analytic checks
|
||
make smoke # tiny scaled-k sweep + figures (end-to-end smoke test)
|
||
make sweep figures # full scaled-k parameter sweep + academic figures
|
||
```
|
||
|
||
Outputs: `results/*.parquet` (one row per config×epoch) and `figures/*.{pdf,png}`
|
||
(both git-ignored).
|
||
|
||
## Scale
|
||
|
||
True constants (`k=2160`, `f=1/30`) give 648,000-slot epochs. Mean accuracy is provably
|
||
`k`-invariant (only variance scales `~1/T`), so sweeps use a **scaled `k`**
|
||
(`configs/default.yaml`); the final accuracy/variance figures re-run at true `k`
|
||
(`configs/fullscale.yaml`, `make sweep-fullscale`). `configs/smoke.yaml` is a tiny dev grid.
|
||
|
||
## Performance & reproducibility
|
||
|
||
- **Sparse lottery (the main win).** The number of slots a node wins is `Binomial(n_slots,
|
||
p_i)` and the won slots are a uniform distinct subset — distributionally identical to an
|
||
independent Bernoulli per slot, but without the dense `(n_nodes, n_slots)` array that was
|
||
~95% of runtime. Full-scale (`k=2160`) epoch: **~3.3 s → ~0.1 s (~30×)**; at `k=256`,
|
||
**~0.39 s → ~0.009 s (~40×)**.
|
||
- **Multicore across configs (the main lever).** `run_trajectory` is a pure function of a
|
||
hash-seeded, immutable `SimConfig`, so the sweep is order-independent and embarrassingly
|
||
parallel. `run_sweep` uses joblib's process-based **loky** backend with
|
||
`inner_max_num_threads=1` (and the Makefile pins `*_NUM_THREADS=1`) to use all cores
|
||
without BLAS oversubscription. `--n-jobs -1` (default) uses every core; `--batch-size 1`
|
||
suits the small heavy full-scale grid. Measured on a 14-core box, the full scaled-`k`
|
||
sweep (`configs/default.yaml`, 3888 configs) runs in **~58 s parallel vs ~561 s serial
|
||
(9.7×)**.
|
||
- **Opt-in within-config parallelism.** `lottery_chunks > 1` splits the per-slot lottery
|
||
across slot-chunks with independent `SeedSequence.spawn` children. After the sparse fix the
|
||
lottery is a small fraction of an epoch, so this rarely helps — it exists for a single
|
||
isolated config with an enormous `n_slots`. **Reproducibility caveat:** the chunked stream
|
||
differs from the serial stream and *changes with `n_chunks`*, so `lottery_chunks` must be a
|
||
pinned, recorded parameter, never derived from the core count.
|
||
- **RNG reproducibility.** Every draw is a deterministic spawn off `SeedSequence(hash(config))`
|
||
— child 0 draws stake, child `e+1` drives epoch `e`, which spawns lottery/aux sub-streams.
|
||
Results are identical regardless of parallel scheduling order. The sparse sampler consumes
|
||
the RNG differently from the original dense one, so committed baselines here were
|
||
regenerated against the sparse sampler.
|
||
|
||
## Faithfulness notes (from review)
|
||
|
||
- `update_D(..., fixed_point=True)` mirrors the spec's integer `f`-truncation
|
||
(`int(f·1000)/1000 = 0.033`), reproducing the on-chain estimator's ~1% systematic
|
||
overestimate. Default `False` keeps the exact-`f`, analysis-faithful behaviour.
|
||
- TSI counts *blocks* (wins), so at full uncle recovery the estimate equilibrates at the
|
||
**block-count ceiling** `-ln(1-f)/f ≈ 1.017`, not 1.0 — a deterministic overshoot, not
|
||
noise. Figures overlay this ceiling; `theory.block_count_ceiling` computes it.
|
||
|
||
## Layout
|
||
|
||
```
|
||
src/tsi_sim/ constants config rng stake lottery latency blocktree uncles tsi epoch
|
||
engine metrics theory sweep verify plotting/{style,figures,make_figures}
|
||
scripts/ run_sweep.py make_figures.py verify.py (thin shims; installed as
|
||
tsi-sweep / tsi-figures / tsi-verify)
|
||
configs/ smoke.yaml default.yaml fullscale.yaml
|
||
tests/ test_{lottery,uncles,tsi_counting,blocktree,config,rng,stake,theory,
|
||
latency,theory_convergence}.py
|
||
```
|