Restructure: descriptive tier and experiment names, paper/manuscript

- paper/pnas -> paper/manuscript (venue-neutral)
- configs/layer1 -> configs/inheritance, src/knowledge -> src/inheritance
  (imported as `inheritance`), make layer1 -> make inheritance; layer2 alias dropped
- inheritance and trained-network bundles named after the manuscript figure
  they feed (fig2_grounding_sweep, figS3_rebaselining, ...), or descriptively
  where they feed none; configs keep their `experiment:` value so parquet
  hashes are unchanged, only output.dir moves
- figure scripts, SI figure sources, notebooks, REPRODUCING.md, README and the
  SI Methods/tables updated; make clean no longer deletes tracked manifests;
  reproduce.sh hashes the s{seed}/ layouts too

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Y64o8FKP7rCuXzC48pxpMm
This commit is contained in:
Giorgio Gilestro 2026-09-13 17:00:40 +01:00
parent 84124de143
commit ab3dc10587
240 changed files with 477 additions and 476 deletions

View file

@ -6,7 +6,7 @@ single master seed, and returns long-form results. ``save_artifacts`` writes the
contract: ``results.parquet`` + ``resolved_config.yaml`` + ``manifest.json``. Figures are
regenerated separately from ``results.parquet`` alone.
CLI: python -m knowledge.experiment configs/layer1/E2.yaml
CLI: python -m inheritance.experiment configs/inheritance/fig2_grounding_sweep.yaml
"""
from __future__ import annotations
@ -427,7 +427,7 @@ def run_and_save(config_path: str | Path) -> Path:
def main(argv: list[str] | None = None) -> None:
parser = argparse.ArgumentParser(description="Run a Layer-1 experiment from a YAML config.")
parser.add_argument("config", help="Path to configs/layer1/EX.yaml")
parser.add_argument("config", help="Path to configs/inheritance/EX.yaml")
args = parser.parse_args(argv)
out_dir = run_and_save(args.config)
print(f"wrote artifacts to {out_dir}/")

View file

@ -2,7 +2,7 @@
``run_lineage`` is the core driver every experiment builds on. It accepts a plain nested
mapping (the scientific-validation conformance tests pass one directly) or a
:class:`~knowledge.config.LineageCfg`, and returns a tidy DataFrame with one row per
:class:`~inheritance.config.LineageCfg`, and returns a tidy DataFrame with one row per
generation (0..T inclusive) carrying every blueprint-2.3 metric, global and per-region.
"""

View file

@ -3,7 +3,7 @@
Trains one LoRA specialist per task family on a small open-weight base, then evaluates the base,
each specialist, and their weight-space **merges** (soup vs ties) on a held-out mixed test set.
Produces a tidy long-form results frame and the standard artifact triple (via
``knowledge.experiment.save_artifacts``), recording model/adapter provenance in the manifest.
``inheritance.experiment.save_artifacts``), recording model/adapter provenance in the manifest.
The claim under test (the real-LLM image of E8): a model recombined from decorrelated specialists is
better than any single specialist overall, and the sharper signature competent across *all*
@ -20,7 +20,7 @@ import numpy as np
import pandas as pd
import yaml
from knowledge.experiment import save_artifacts
from inheritance.experiment import save_artifacts
from .directed import sample_merge_weights, select_winners
from .evaluate import evaluate, generate, load_model

View file

@ -3,7 +3,7 @@
Realises the Layer-1 (``knowledge``) Wright-Fisher abstractions in *real trained
generative models* on a fully-synthetic sandbox whose ground-truth ``p*`` is known
exactly. A model's knowledge is measured as its output distribution over ``K`` discrete
*modes* (via an oracle), so the same metrics (``knowledge.metrics``), the same closed
*modes* (via an oracle), so the same metrics (``inheritance.metrics``), the same closed
forms, and the same experiments carry over a neural collapse curve can be overlaid on
a Layer-1 analytic curve.

View file

@ -1,8 +1,8 @@
"""Resolved run configuration for a neural (Layer 1.5) lineage.
Mirrors the ``knowledge.config`` idiom exactly: frozen dataclasses with a ``from_dict``
that fills defaults and rejects unknown keys via ``knowledge.config._sub``. The grounding,
re-mint, and metrics blocks are *reused verbatim* from ``knowledge.config`` so the neural
Mirrors the ``inheritance.config`` idiom exactly: frozen dataclasses with a ``from_dict``
that fills defaults and rejects unknown keys via ``inheritance.config._sub``. The grounding,
re-mint, and metrics blocks are *reused verbatim* from ``inheritance.config`` so the neural
runner speaks the same schema as Layer 1 (grounding ``m``, the ``g -> m`` conversion, the
re-mint gate, and the KL/support floors are all identical). Only the data source
(``synthetic``) and the model (``model``) are neural-specific.
@ -14,7 +14,7 @@ import math
from dataclasses import dataclass, field, replace
from typing import Any, Mapping
from knowledge.config import GroundingCfg, MetricsCfg, RemintCfg, _sub
from inheritance.config import GroundingCfg, MetricsCfg, RemintCfg, _sub
@dataclass(frozen=True)
@ -22,7 +22,7 @@ class SyntheticCfg:
"""The fully-synthetic mode-truth and observation grammar.
The first seven fields are the Layer-1 ``TruthCfg`` knobs (they build ``p*`` over the
``K`` modes via ``knowledge.truth.make_true_distribution``). The remaining fields
``K`` modes via ``inheritance.truth.make_true_distribution``). The remaining fields
define how a mode is rendered to a categorical token sequence: an *identity* segment
that encodes the mode losslessly (read by the exact oracle) followed by a *style*
segment of within-mode stochastic tokens (so a real generative model has a

View file

@ -1,19 +1,19 @@
"""Metrics for a neural lineage — the *same* row schema as ``knowledge.lineage``.
"""Metrics for a neural lineage — the *same* row schema as ``inheritance.lineage``.
``measure_metrics`` takes a model's oracle-measured mode distribution ``p_hat`` and emits a
row with exactly the columns Layer 1 logs per generation (``knowledge.lineage.record``),
computed with the *same* ``knowledge.metrics`` functions. Identical columns are what let a
row with exactly the columns Layer 1 logs per generation (``inheritance.lineage.record``),
computed with the *same* ``inheritance.metrics`` functions. Identical columns are what let a
neural collapse curve be plotted on top of an analytic one, and let the same figure and
analysis code (``knowledge.analysis``) run unchanged.
analysis code (``inheritance.analysis``) run unchanged.
"""
from __future__ import annotations
import numpy as np
from knowledge.config import MetricsCfg
from knowledge.lineage import N_BANDS
from knowledge.metrics import (
from inheritance.config import MetricsCfg
from inheritance.lineage import N_BANDS
from inheritance.metrics import (
forward_kl,
heterozygosity,
per_region,
@ -27,7 +27,7 @@ def measure_metrics(p: np.ndarray, p_star_orig: np.ndarray, tail_mask: np.ndarra
regions: np.ndarray, R: int, metrics_cfg: MetricsCfg) -> dict:
"""Compute every per-generation metric for a measured mode distribution.
Mirrors ``knowledge.lineage.record`` field-for-field. ``forward_kl`` and the tail set
Mirrors ``inheritance.lineage.record`` field-for-field. ``forward_kl`` and the tail set
are always measured against the *original* truth, so a re-minted lineage that has lost
tails is penalised exactly as in Layer 1's E6.

View file

@ -1,6 +1,6 @@
"""Neural (Layer 1.5) experiment runner: sweep a grid x replicates, write artifacts.
Mirrors ``knowledge.experiment`` and reuses its sweep-expansion primitives
Mirrors ``inheritance.experiment`` and reuses its sweep-expansion primitives
(``_apply_param`` including the ``g -> m`` conversion and ``_set_by_path``), its
provenance helpers, and its output contract (``save_artifacts``). Only the per-run call and
the config key set differ: a neural run trains generative models rather than resampling a
@ -20,8 +20,8 @@ from typing import Any
import pandas as pd
import yaml
from knowledge.experiment import _apply_param, save_artifacts
from knowledge.seeding import spawn_seeds
from inheritance.experiment import _apply_param, save_artifacts
from inheritance.seeding import spawn_seeds
from .generation_loop import run_generative_lineage
@ -38,7 +38,7 @@ _EXTRA_LIBS = ("torch", "torchvision")
def expand_sweeps(cfg: dict) -> list[tuple[dict, dict]]:
"""Expand the sweep grid into (label, resolved_neural_cfg) pairs.
Identical semantics to ``knowledge.experiment.expand_sweeps`` (Cartesian product of the
Identical semantics to ``inheritance.experiment.expand_sweeps`` (Cartesian product of the
declared ``{param, values}`` entries, reusing ``_apply_param`` for the ``g -> m`` and
``arm`` special cases) but assembling the base from the neural config groups.
@ -129,7 +129,7 @@ def run_mnist_experiment(cfg: dict) -> tuple[pd.DataFrame, dict]:
Returns:
tuple[pd.DataFrame, dict]: Long-form results and the oracle-provenance manifest dict.
"""
from knowledge.config import _sub
from inheritance.config import _sub
from .config import MnistCfg, OracleCfg
from .mnist_data import assign_modes, load_mnist, make_mnist_truth, MnistSampler

View file

@ -1,4 +1,4 @@
"""The neural analogue of ``knowledge.lineage.run_lineage``.
"""The neural analogue of ``inheritance.lineage.run_lineage``.
Runs ``T`` generations of *train-a-model-on-the-previous-model's-samples*, the neural
image of the Wright-Fisher generational step. Each generation the pupil is trained on a
@ -6,7 +6,7 @@ pool of (i) ``n`` observations drawn from the parent model (drift) and (ii) ``m`
observations drawn from the grounding reference (immigration, ``g = m/(n+m)``), then its
oracle-measured mode distribution is logged with the *same* metric schema Layer 1 uses.
Grounding structure (proportional / uniform / matched over regions) and the re-mint gate
reuse ``knowledge.step`` and mirror ``run_lineage`` exactly, so a histogram-model lineage
reuse ``inheritance.step`` and mirror ``run_lineage`` exactly, so a histogram-model lineage
reproduces the analytic core and a neural-model lineage tests whether the same signs hold
in real weights.
"""
@ -18,9 +18,9 @@ from typing import Any, Mapping
import numpy as np
import pandas as pd
from knowledge.metrics import heterozygosity
from knowledge.step import allocate_m, structured_multinomial
from knowledge.truth import uniform_init
from inheritance.metrics import heterozygosity
from inheritance.step import allocate_m, structured_multinomial
from inheritance.truth import uniform_init
from .config import NeuralLineageCfg
from .evaluate import measure_metrics
@ -46,7 +46,7 @@ def run_generative_lineage(cfg: Mapping[str, Any] | NeuralLineageCfg,
Returns:
pd.DataFrame: One row per generation 0..T with the same metric columns as
``knowledge.lineage.run_lineage``.
``inheritance.lineage.run_lineage``.
"""
cfg = NeuralLineageCfg.from_dict(cfg)
syn = cfg.synthetic

View file

@ -20,7 +20,7 @@ from pathlib import Path
import numpy as np
from knowledge.truth import TrueDist, make_true_distribution
from inheritance.truth import TrueDist, make_true_distribution
from .config import MnistCfg

View file

@ -18,9 +18,9 @@ from typing import Any, Mapping
import numpy as np
import pandas as pd
from knowledge.config import MetricsCfg, _sub
from knowledge.step import allocate_m, structured_multinomial
from knowledge.truth import TrueDist, uniform_init
from inheritance.config import MetricsCfg, _sub
from inheritance.step import allocate_m, structured_multinomial
from inheritance.truth import TrueDist, uniform_init
from .config import MnistCfg, ModelCfg, NeuralDynamicsCfg
from .evaluate import measure_metrics
@ -54,7 +54,7 @@ def run_mnist_lineage(cfg: Mapping[str, Any], seed: int, oracle: Oracle,
mcfg = _sub(cfg["mnist"], MnistCfg)
model_cfg = _sub(cfg["model"], ModelCfg)
dyn_raw = dict(cfg.get("dynamics", {}))
from knowledge.config import GroundingCfg, RemintCfg
from inheritance.config import GroundingCfg, RemintCfg
dynamics = NeuralDynamicsCfg(
n=dyn_raw.get("n", NeuralDynamicsCfg.n),
grounding=_sub(dyn_raw.get("grounding", {}), GroundingCfg),

View file

@ -1,6 +1,6 @@
"""Multi-teacher recombination in real weights — the neural image of Layer-1 E4.
Layer-1 E4 (``knowledge.experiment.run_coverage``) showed the sharpest result of the study:
Layer-1 E4 (``inheritance.experiment.run_coverage``) showed the sharpest result of the study:
under **mean-mixture** distillation surviving tail coverage is *flat* in the teacher count
K_T (a conservation law averaging's 1/K_T dilution cancels the union gain), while a
**union-preserving max-merge** (à la M2N2) realises the benefit. This module tests whether
@ -26,9 +26,9 @@ import itertools
import numpy as np
import pandas as pd
from knowledge.config import _sub
from knowledge.seeding import spawn_seeds
from knowledge.teachers import make_correlated_teachers, make_retention_matrix
from inheritance.config import _sub
from inheritance.seeding import spawn_seeds
from inheritance.teachers import make_correlated_teachers, make_retention_matrix
from .config import ModelCfg, SyntheticCfg
from .models import make_model

View file

@ -1,7 +1,7 @@
"""The fully-synthetic sandbox: a known ``p*`` over modes + a lossless observation grammar.
The mode-truth (``p*``, regions, tail mask) comes straight from Layer 1's
``knowledge.truth.make_true_distribution`` so "mode", "region", and "tail" are *the same
``inheritance.truth.make_true_distribution`` so "mode", "region", and "tail" are *the same
objects* as in the analytic core. Each mode is rendered to a categorical token sequence:
* an **identity** segment of ``id_len`` base-``id_base`` digits that encodes the mode
@ -19,7 +19,7 @@ from __future__ import annotations
import numpy as np
from knowledge.truth import TrueDist, make_true_distribution
from inheritance.truth import TrueDist, make_true_distribution
from .config import SyntheticCfg