Layer 1 complete: E3-E6 + E2 analysis add-ons
Finishes the Layer 1 analytical core. All six experiments run with honest, publication-quality figures; 71 tests green. - E3 region-matched grounding: `grounding.exercised` knob + per-region tail survival. Matched holds the exercised region's tail (0.49) where uniform spreads thin and lets it collapse (0.07). - E4 multi-teacher recombination: `run_coverage` runner. Union coverage matches U(K_T,rho,q) exactly. Finding: mean-mixture distillation shows NO surviving benefit (a conservation law — 1/K_T dilution cancels the union gain); a union-preserving max-merge (M2N2-style) does. E4 reports both operators. - E5 QD vs greedy: greedy drives fixation (H~0.01); QD holds H at 0.48-0.88, rising with the novelty exponent. - E6 re-mint gate: `arm` multi-override sweep. Re-minting a collapsed lineage locks in divergence of KL-to-original; gating on diversity prevents it. - E2 analysis add-ons (from the companion work order, numbers verified): new analysis.py (reduce_to_stationary, critical_grounding with bootstrap CI -> g*=0.048, 95% CI [0.047,0.050]); tail_band_metrics + per-band logging; the E2 figure rebuilt as a 2x2 (defined g*+CI, g=0 flagged as a finite-time artifact, tail item-vs-mass, per-rarity-band panel). Uses truth-mass-weighted tail coverage rather than the raw (martingale) tail_mass. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
a6eb9b7512
commit
1721d047fa
42 changed files with 1938 additions and 135 deletions
|
|
@ -14,10 +14,13 @@ import numpy as np
|
|||
import pandas as pd
|
||||
|
||||
from .config import LineageCfg
|
||||
from .metrics import forward_kl, heterozygosity, per_region, support_size, tail_mass
|
||||
from .metrics import (forward_kl, heterozygosity, per_region, support_size,
|
||||
tail_band_metrics, tail_mass)
|
||||
from .step import StepCtx, allocate_m, generation_step
|
||||
from .truth import make_true_distribution, uniform_init
|
||||
|
||||
N_BANDS = 4 # rarity bands for per-band tail-survival logging (blueprint pred. 4)
|
||||
|
||||
|
||||
def run_lineage(cfg: Mapping[str, Any] | LineageCfg, seed: int) -> pd.DataFrame:
|
||||
"""Run one lineage and return per-generation metrics.
|
||||
|
|
@ -52,8 +55,10 @@ def run_lineage(cfg: Mapping[str, Any] | LineageCfg, seed: int) -> pd.DataFrame:
|
|||
raise ValueError(f"unknown init {cfg.truth.init!r} (expected uniform|truth)")
|
||||
|
||||
p_star_eff = p_star_orig.copy() # grounding reference; may be re-minted (E6)
|
||||
exercised = cfg.dynamics.grounding.exercised
|
||||
exercised = np.asarray(exercised) if exercised is not None else None
|
||||
m_vector = allocate_m(cfg.dynamics.grounding.m, cfg.truth.R,
|
||||
cfg.dynamics.grounding.policy)
|
||||
cfg.dynamics.grounding.policy, exercised)
|
||||
step_ctx = StepCtx(
|
||||
n=cfg.dynamics.n,
|
||||
m_vector=m_vector,
|
||||
|
|
@ -83,12 +88,29 @@ def run_lineage(cfg: Mapping[str, Any] | LineageCfg, seed: int) -> pd.DataFrame:
|
|||
"head_support": int(np.sum(p[head_mask] > eps)),
|
||||
"tail_frac_alive": (float(np.mean(p[tail_mask] > eps)) if n_tail else 0.0),
|
||||
"head_frac_alive": (float(np.mean(p[head_mask] > eps)) if n_head else 0.0),
|
||||
# Truth-mass-weighted tail coverage: share of the tail's TRUE mass carried by
|
||||
# still-alive items. Bounded, monotone in grounding, and the honest "mass
|
||||
# rescued" companion to tail_frac_alive (raw tail_mass is a drift martingale).
|
||||
"tail_truth_mass_alive": (
|
||||
float(p_star_orig[tail_mask][p[tail_mask] > eps].sum()
|
||||
/ p_star_orig[tail_mask].sum()) if n_tail else 0.0),
|
||||
}
|
||||
if n_tail >= N_BANDS: # per-rarity-band survival (band 0 = rarest); see metrics
|
||||
fa, _ = tail_band_metrics(p, p_star_orig, tail_mask, n_bands=N_BANDS,
|
||||
alive_eps=eps)
|
||||
for b in range(N_BANDS):
|
||||
row[f"band{b}_alive"] = fa[b]
|
||||
if cfg.truth.R > 1: # per-region columns only when there is >1 region
|
||||
for r, v in per_region(heterozygosity, p, regions).items():
|
||||
row[f"H_region_{r}"] = v
|
||||
for r, v in per_region(tail_mass, p, regions, tail_mask).items():
|
||||
row[f"tail_region_{r}"] = v
|
||||
# per-region tail-item survival (E3's honest metric: how much of each
|
||||
# region's rare tail is kept alive, not just its martingale mass)
|
||||
for r in range(cfg.truth.R):
|
||||
region_tail = (regions == r) & tail_mask
|
||||
row[f"tailalive_region_{r}"] = (
|
||||
float(np.mean(p[region_tail] > eps)) if region_tail.any() else 0.0)
|
||||
rows.append(row)
|
||||
|
||||
record(0, p)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue