Architecture¶
Layers¶
The computational core is pure and deterministic; everything that touches files, users or screens sits above it. The CLI and the GUI call the same services.
flowchart TB
subgraph interfaces["Interfaces"]
api["Python API"]
cli["CLI · erdr (typer)"]
gui["GUI · PySide6 (+ portable .exe)"]
end
subgraph services["Application services"]
runner["experiment runner"]
runs["run folders · manifests"]
analysis["readings · k sweeps"]
validate["workbook validation"]
export["exporters"]
end
subgraph core["Computational core (numpy, no I/O)"]
direction LR
pipe["normalizers → metrics → Step 1 (r, g, z, d) → Steps 2–6 → cases"]
end
config["config (pydantic)"]
data["data · schema · loaders · writers · catalogue"]
interfaces --> services --> core
services --> data
services --> config
core -. "plug-ins" .- registry["registries"]
| Package | Role |
|---|---|
erdr.core |
normalizers, metrics, Step 0 pipeline, sorted neighbours, the k rule, Step 1, Steps 2–6 with a replayable trace, Steps 1–5 as hyperspheres, readings, cases, plug-in registries |
erdr.config |
typed configuration (pydantic v2), presets, YAML/TOML/JSON, canonical hash |
erdr.data |
Dataset, loaders (extended layout, CSV, Excel, ERDR workbook, Parquet), writers, the datasets folder, built-in datasets |
erdr.services |
runner, run folders, readings comparison and k sweeps, dataset summaries, workbook validation |
erdr.export |
plain tables, CSV/JSON/Markdown/LaTeX, Excel, figures, HTML report, datasets |
erdr.cli |
the erdr command |
erdr.gui |
the desktop application (optional extra [gui]) |
The core imports only numpy, pydantic (plug-in parameter types) and its own modules; it never
reads a file. erdr.data.schema is pure as well.
Information flow¶
flowchart LR
X["X, types I/J, classes"] --> N["Step 0: normalizer<br/>(fitted on E₀)"]
N --> M["metric on the selected features<br/>ρ rounded to 1e-10"]
M --> O["sorted neighbours<br/>(ρ, index)"]
O --> C["Step 1: r, g, z, d<br/>static queue order"]
C --> L["Steps 2–5: queue → Sᵢ → L →<br/>block, Step 4 / Step 5"]
L --> R["Step 6: D, F = E₀ \ D"]
L --> T["trace: one record per iteration"]
T --> K["17 cases"]
C --> H["hyperspheres: enemy sphere and k-sphere<br/>of every object"]
T --> H2["the spheres around Sᵢ in every iteration<br/>(L = the sphere test)"]
The trace¶
run_erdr records per iteration only what changes — the selected object, L, the objects that
cover Sᵢ, those left out by readings A/B, the decision, the counter changes, the moves, the sizes
— so memory stays linear in m per iteration. ERDRResult.state_after(t) replays the records into
the full state of any iteration (in F, processed, g, d), queue_before(t) gives the queue of
Step 2 and counter_history() the counters after every iteration — exactly the blocks of the
sheets ERDR Iterations and ERDR Trace.
Exports and the GUI share one model¶
flowchart LR
R["ExperimentResult"] --> T["export.tables<br/>(plain tables with marks)"]
R --> F["export.figures<br/>(draw_* on axes)"]
T --> C["csv · json · markdown · latex"]
T --> X["xlsx (sheets like the workbook)"]
T --> H["html report"]
F --> H
F --> P["png · svg"]
T --> G["GUI table models"]
F --> G2["GUI figure canvas · hypersphere explorer"]
F --> A["figures/iteration-spheres.gif"]
A table cell carries a mark — what it means (class K1, training sample, selected object, counter
decreased, tie decided by r …), not how it looks — and a column header the kind of quantity it
holds (quantitative or nominal feature, class, r g z, d, parameter); export.theme gives every
mark its colours, so the GUI, the Excel writer, the HTML report, the figures and the console show
the same categories in the same colours (ADR-019). Figures are drawn on axes the caller provides, so the GUI embeds the very drawings
the exports save (ADR-012).
Extension points¶
Every exchangeable part is a plug-in chosen by name (Extending):
| Kind | Default | Built in |
|---|---|---|
| normalizers | min–max over E₀ | none, z-score, robust, max-abs, decimal scaling, rank, unit length |
| metrics | by dataset type (auto): Zhuravlev on heterogeneous data, Manhattan on quantitative, Hamming on nominal — the Zhuravlev distances on every type |
weighted Zhuravlev, HEOM, Gower (any features); Manhattan, Euclidean, Chebyshev, Minkowski, Canberra, cosine, Mahalanobis (set I); Hamming (set J) |
| dataset formats | detected from the file | extended .csv/.dat, CSV table, Excel table, ERDR workbook, Parquet (extra [parquet]) |
| export formats | all | CSV, JSON, Markdown, LaTeX, Excel, figures, HTML, datasets |
| built-in datasets | Heart-Disease (7, 13, 2) | Heart-Disease (270, 13, 2), the guide's example (7, 4, 2), every dataset of the type folders except TCGA_LUAD |
| readings | literal | A, B, C, scope of z — 16 combinations |
Plug-ins register in a Registry; external packages add them through the entry-point group
erdr.<kind> (erdr.metrics, erdr.normalizers, erdr.loaders, erdr.exporters). A plug-in's
parameter type also generates its form in the GUI.