断的是规模不是基因流------退出率 × 补位扫描
个体按退出率 λ 离场(基因不再参与复制)× 补位{不补, 延迟 5 代} × 5 seed
摘要
退出抽检进 204 架构(λ=0 档逐位复现 204a 主实验):不补档下任何非零 λ 规模单调衰减(H1a 支持),λ=0.10 在第 68 代归零;延迟 5 代补位把"必灭"变成非零平台 190/178/169(H1b 支持),与解析式 N(1−λ·delay) 逐档吻合。规模 ≥30 时亲子 θ 相关 0.998;规模 <30 后降至 0.49------传递保真度随规模缩水下滑但未归零。断的是规模不是基因流:存续不取决于退出多弱,取决于有没有补位。

一、接 204:两条通道
204 两篇答的是遗传通道(θ 怎么传)。两篇 Future Work 第 2 项都写着"退出率 × 基因流",204-2 文末还把这个问题留给读者------本篇兑现。
一个架构事实先摆清楚:204 的锦标赛 winner 整格覆盖已经隐含生死(败者消失=死、后代占据=繁殖同时发生)。真正的缺口是:舞台永远自动填满(N 恒定 200),从没有任何机制让格子空出来。火种轴第三件"种群可存续"因此从未被测过------没有缩水,就没有断裂。
本篇开"生死+存续通道":个体按退出率 λ 逐个抽检离场(离场=彻底消失+基因不再参与任何复制),格子空置,种群可以缩水。"火种"= 种群规模与基因流在扰动下不断裂的操作化表述(比喻)。
命名纪律:退出率(非"死亡率")、种群归零(非"灭绝")、补位(非"出生")。零文献考场:本篇不引任何文献当判分标准。
二、机制:退出模块
更新顺序(钉死):退出抽检(代开始前)→ 参与判定 → γ 一生内学习 → 刺激更新 → 锦标赛整套复制 → 补位(若开)。θ 遗传沿用 204 同一锦标赛(β+θ 整套复制,各自突变)。
退出机制三个钉死点:
- λ=0 不跑抽检循环------退出模块关闭时随机流与 204a 完全一致(验收锚点的前提)
- 空格从候选池剔除;候选池只剩自己 → winner=自己(自体复制+突变)------自体复制率本身是可报读数(候选池萎缩的代价)
- 补位规则写死:离场后固定 5 代,空格由 Moore 邻域中 q_eff 最大的活格复制版填充
三、验收锚点
λ=0 档与 204a 主实验(σ_θ=0.02, γ=0.05)逐位对比,六项 5/5:betas / participate / theta / θ快照 / 谷深 / 逐代 n_act 全 √------退出模块关闭时随机流完全一致。
四、不补档:纯缩水(H1a)
| λ | 末态规模均值 | 半衰期 | 归零代次 | 自体复制率 | 相关(≥30段) | 相关(<30段) |
|---|---|---|---|---|---|---|
| 0.01 | 74 | 70.6 | 未归零 | 19.7% | 0.995 | ---(未跌破30) |
| 0.02 | 27 | 34.1 | 未归零 | 27.3% | 0.997 | ---(样本不足) |
| 0.03 | 8 | 20.3 | 未归零 | 32.4% | 0.998 | 0.488 |
| 0.10 | 0 | 5.8 | 第 68 代 | 35.4% | 0.998 | 0.500 |
亲子 θ 相关按规模分段:≥30 段(缩水前)5 seed 均值 0.998;<30 段(缩到个位数时)λ=0.03 档 0.488(逐 seed 0.297/0.345/0.352/0.997/0.450)------传递保真度在深缩水区降至约一半,但未归零。
H1a(任何非零 λ 规模单调衰减,无稳定区间):支持 ------20 条轨迹(4λ × 5 seed)逐代全部单调,无一回升。注意单调本身是机制定义的必然(不补档下 alive 只能 True→False 单向变化),读数的信息量在无稳定平台、必归零------λ=0.01 是纯指数衰减(0.99^100≈69/200 对得上);λ=0.10 在第 68 代归零。
自体复制率随 λ 单调上升(12.8%→35.4%):候选池萎缩的必然代价------空格越多,"只剩自己可选"的个体越多。
五、补位档:非零平台(H1b)
| λ | 平台均值±std(末 40 代) | 补位次数 | 亲子 θ 相关 | 谷深(存活) |
|---|---|---|---|---|
| 0.01 | 190±3 | 176 | 0.993 | 0.000 |
| 0.02 | 178±4 | 348 | 0.994 | 0.000 |
| 0.03 | 169±5 | 507 | 0.994 | 0.000 |
H1b(非零平衡平台,平台随 λ 下降):支持 ------平台 190/178/169 随 λ 下降。延迟 5 代补位把"必灭"变成动态平衡:退出与补位对冲,平台有解析式------平台 ≈ N·(1 − λ·delay),缺口 ≈ λ·N·delay:
| λ | 平台扫描值 | 解析 N(1−5λ) | 缺口扫描值 | 解析 λN·delay |
|---|---|---|---|---|
| 0.01 | 190 | 190 | 10 | 10 |
| 0.02 | 178 | 180 | 22 | 20 |
| 0.03 | 169 | 170 | 31 | 30 |
逐档吻合(±2 人)------"退出×补位对冲"的机制自洽:每代退出 λ·N 人、5 代后补回,稳态缺口就是 5 倍的每代退出数。
补位档谷深(存活口径)全 0.000------补位救的是规模,不是分化(互参见 205-2)。
六、半衰期:扫描值 vs 解析
| 档 | 半衰期扫描值 | 解析 0.693/λ | 偏离 |
|---|---|---|---|
| λ=0.01 | 70.6 | 69.3 | +1.8% |
| λ=0.02 | 34.1 | 34.6 | -1.6% |
| λ=0.03 | 20.3 | 23.1 | -12.0% |
小 λ 下扫描值与解析近似高度吻合(±2%)------纯指数衰减的读数免费验证。λ=0.03 偏离 -12%,归因于半衰期的首次穿越定义+离散代际抽样(线性插值在快衰减段放大离散误差),非机制性偏离------纯退出对照(无复制、只有退出抽签)同档半衰期 22.8,与含复制版 20.3 同量级,复制(含自体复制)不改变衰减速度。
七、断的形式:断的是规模不是基因流
主结论并排读数(λ=0.03 不补档):末态存活均值 8 人 ;亲子 θ 相关按规模分段------≥30 段 0.998,<30 段 0.488。
两个分段合起来读:规模缩到 5% 人口,θ 的代际传递保真度从 0.998 滑到 0.49------下滑但未断。基因流只在规模归零处才彻底断(λ=0.10 归零档)。这给"火种"一个分岔的定义:规模的火种靠补位(H1b),基因流的火种靠不归零------但保真度本身也随规模缩水打折。
一个诚实注:亲子 θ 相关这个指标主要反映"突变步长 vs 群体 θ 宽度"的比值(理论式 w/√(w²+σ_θ²)),不直接测群体层面的基因流连通性------它答的是"父子像不像",不是"全村是不是一家"。λ 越大幸存者 θ 分布越宽,相关反而略升,正说明该指标对规模不敏感。跨格谱系混合度才是连通性的直接测法,留 Future Work。
八、小样本禁判纪律
λ=0.03 不补档 5 seed 谷深均值 0.400,落在预注册的 0.4-0.6 边缘带------按预注册条件触发扩样(seed 47-51):
| seed | 末态存活 | 谷深 | hist 形态 |
|---|---|---|---|
| 42 | 5 | 0.000 | 全挤 bin9 |
| 43 | 9 | 0.000 | 全挤 bin9 |
| 44 | 8 | 0.000 | bin8+9 单峰 |
| 45 | 11 | 1.000 | 多数 bin9 + 3 个散点 |
| 46 | 8 | 1.000 | 多数 bin9 + 3 个散点 |
| 47 | 9 | 1.000 | 多数 bin9 + 3 个散点 |
| 48 | 10 | 1.000 | 多数 bin9 + 3 个散点 |
| 49 | 11 | 1.000 | 多数 bin9 + 3 个散点 |
| 50 | 9 | 0.000 | bin8+9 连成单峰 |
| 51 | 9 | 1.000 | 多数 bin9 + 3 个散点 |
10 seed 均值 0.600------但逐 seed 末态存活 5-11 人,全部 <30。扩样增加的是同分布噪声样本,不增加单 run 判力:hist 形态=多数挤 bin9 + 1-3 个散点,谷深 1.0/0.0 由散点位置决定(小样本散点噪声)。
结论:末态存活 <30 人时谷深判据无判力(禁判)。λ=0.03 档不是边缘分化读数,是样本不足。 这与假低口径是同族陷阱------一个用死格堆 bin0 造假谷,一个用幸存者散点造假峰。
九、诚实边界
Limitations:
- 退出率为常数(不随规模/环境反馈),未扫时变退出
- 补位规则仅一档(延迟 5 代、邻域 q_eff 最大填充)
- 亲子相关为分段合并口径(剔自体),非逐代;该指标不直接测群体基因流连通性(见 §七诚实注)
- 补位复活个体的参与频率分母仍为完整 20 代(其存活代数 <20,频率被系统性低估)------补位档谷深 0.000 结论不受影响,但精确读数须按存活代数换分母
- 单任务、5 seed、教学级
Future Work:
- 补位规则的其他形式(退出者遗产、变异步长补位)
- 退出率与规模的反馈耦合(密度依赖退出)
- 跨格谱系混合度------直接测基因流连通性的指标(亲子相关只测传递保真度)
十、总结与下一篇
- λ=0 档逐位复现 204a 主实验:六项 5/5
- 不补档全档单调衰减(H1a 支持);λ=0.10 第 68 代归零
- 补位档平台 190/178/169(H1b 支持),与解析式 N(1−λ·delay) 逐档吻合
- 断的是规模不是基因流:≥30 段相关 0.998、<30 段 0.49(下滑未断),归零才断流
204 答遗传通道(θ 怎么传),本篇开生死+存续通道------存续不取决于退出多弱,取决于有没有补位。
下一篇的问题:退出压力下火种没断(补位平台成立),那分化被逼出来了吗?------205-2《分化没被逼出来》回答。
代码附录
python
# -*- coding: utf-8 -*-
"""
天赐范式 第205天 第一篇
断的是规模不是基因流
PID: TC-205A-V3.3.43.0
V3.3.43.0 · 2026-10-24
接 204 两篇 Future Work:退出率 × 基因流。
"火种"= 种群规模与基因流在扰动下不断裂的操作化表述(比喻)。
架构事实:204 锦标赛 winner 整格覆盖已隐含生死;本篇新增的是
舞台不再自动填满------个体退出后格子空置,种群可以缩水。
"""
import sys
import math
import random
import statistics
sys.stdout.reconfigure(encoding="utf-8")
sys.path.insert(0, r"C:\Users\Administrator\Desktop\20261021")
from tianci_202a import (analyze_run, valley_depth, TRACK_WINDOW, N_GEN_202,
SEEDS, PHI, RHO, QUAD_ENV, VALLEY_STRONG,
VALLEY_WEAK, SNR_THRESHOLD)
sys.path.insert(0, r"C:\Users\Administrator\Desktop\20261023")
from tianci_204a import run_frtm_gene
sys.path.insert(0, r"C:\Users\Administrator\Desktop\20261019")
from tianci_200b import (GRID_W, GRID_H, N, N_GEN, SIGMA_V, TOURNAMENT_K,
N_BUCKETS, true_beta, get_quadrant, moore_neighbors,
get_bucket, shannon_entropy, clamp, bar, md_table)
GAMMA_MAIN = 0.05
THETA_MIN = 0.01
SIGMA_THETA = 0.02
LAMBDA_SCAN = [0.0, 0.01, 0.02, 0.03]
LAMBDA_ZERO_EXTRA = 0.10
FILL_DELAY = 5
def run_frtm_exit(seed, gamma, sigma_theta, lam=0.0, fill_delay=None,
n_gen=N_GEN_202):
"""205 退出模块(两篇内嵌同一份,禁互相 import)。
机制:代开始前按退出率 λ 抽检离场(离场=彻底消失+基因不再参与复制);
空格从候选池剔除;候选池只剩自己 → 自体复制+突变。
更新顺序(钉死):退出抽检 → 参与判定 → γ 一生内学习 → 刺激更新
→ 锦标赛整套复制(β+θ 同 tournament,各自突变)→ 补位(若开)。
λ=0 时不跑抽检循环------随机流与 204a run_frtm_gene 逐位一致(验收锚点)。
补位:离场后固定 fill_delay 代,空格由 Moore 邻域中 q_eff 最大的
活格复制版填充(当代值+各自突变)。
返回九元组:history, betas, thetas, participate_counts, alive,
theta_snaps, exit_stats, fill_count, scale_traj。"""
random.seed(seed)
betas = [random.uniform(0.0, 1.0) for _ in range(N)]
thetas = [random.uniform(0.0, 1.0) for _ in range(N)]
s_stim = [0.0, 0.0, 0.0, 0.0]
history = []
participate_counts = [0] * N
alive = [True] * N
death_gen = [None] * N
theta_snaps = []
self_copy_count = 0
copy_total = 0
parent_theta = []
child_theta = []
parent_gen_alive = []
fill_count = 0
scale_traj = []
track_start = n_gen - TRACK_WINDOW + 1
for gen in range(n_gen + 1):
if lam > 0:
for i in range(N):
if alive[i] and random.random() < lam:
alive[i] = False
death_gen[i] = gen
n_alive = sum(alive)
scale_traj.append(n_alive)
if gen % 10 == 0:
live_th = [thetas[i] for i in range(N) if alive[i]]
if len(live_th) > 1:
theta_snaps.append((gen, statistics.mean(live_th),
statistics.stdev(live_th)))
else:
theta_snaps.append((gen, live_th[0] if live_th else 0.0, 0.0))
q_base = [0.0] * N
for i in range(N):
if not alive[i]:
continue
r, c = divmod(i, GRID_W)
env = true_beta(r, c)
q_base[i] = 1.0 / (1.0 + (betas[i] - env) ** 2)
n_act = [0, 0, 0, 0]
q_eff = [0.0] * N
participated = [False] * N
for i in range(N):
if not alive[i]:
continue
r, c = divmod(i, GRID_W)
q = get_quadrant(r, c)
s = s_stim[q]
if s > 0 and thetas[i] > 0:
p_part = s * s / (s * s + thetas[i] * thetas[i])
else:
p_part = 0.0
if random.random() < p_part:
q_eff[i] = q_base[i] * (1.0 + RHO)
n_act[q] += 1
participated[i] = True
else:
q_eff[i] = q_base[i]
if gamma > 0:
for i in range(N):
if participated[i]:
thetas[i] = max(THETA_MIN, thetas[i] - gamma)
if gen >= track_start:
for i in range(N):
if participated[i]:
participate_counts[i] += 1
alive_per_quad = [0, 0, 0, 0]
for i in range(N):
if alive[i]:
alive_per_quad[get_quadrant(*divmod(i, GRID_W))] += 1
part_rates_live = [
n_act[q] / alive_per_quad[q] if alive_per_quad[q] > 0 else 0.0
for q in range(4)]
part_rates_low = [n_act[q] / (N // 4) for q in range(4)]
p_total = sum(q_eff)
mean_b = sum(betas) / N
bucket_c = [0] * N_BUCKETS
for b in betas:
bucket_c[get_bucket(b)] += 1
n_occ = sum(1 for cnt in bucket_c if cnt > 0)
ent = shannon_entropy(bucket_c, N)
history.append({
'gen': gen, 'p': p_total, 'mean_b': mean_b,
'n_occ': n_occ, 'entropy': ent,
's_stim': tuple(s_stim), 'n_act': tuple(n_act),
'part_rates': tuple(part_rates_low),
'part_rates_live': tuple(part_rates_live),
'n_alive': n_alive,
})
if gen == n_gen:
break
for q in range(4):
s_stim[q] = max(0.0, s_stim[q] + QUAD_ENV[q] - PHI * n_act[q])
new_betas = [0.0] * N
new_thetas = [0.0] * N
for i in range(N):
if not alive[i]:
new_betas[i] = betas[i]
new_thetas[i] = thetas[i]
continue
r, c = divmod(i, GRID_W)
candidates = [i]
for j in moore_neighbors(r, c):
if alive[j]:
candidates.append(j)
k = min(TOURNAMENT_K, len(candidates))
sample = random.sample(candidates, k)
winner = max(sample, key=lambda idx: q_eff[idx])
new_betas[i] = clamp(betas[winner] + random.gauss(0, SIGMA_V))
new_thetas[i] = max(THETA_MIN,
thetas[winner] + random.gauss(0, sigma_theta))
copy_total += 1
if winner == i:
self_copy_count += 1
else:
parent_theta.append(thetas[winner])
child_theta.append(new_thetas[i])
parent_gen_alive.append(n_alive)
if fill_delay is not None:
for i in range(N):
if (not alive[i]) and death_gen[i] is not None \
and (gen - death_gen[i]) >= fill_delay:
r, c = divmod(i, GRID_W)
neighbors = [j for j in moore_neighbors(r, c)
if alive[j]]
if neighbors:
w = max(neighbors, key=lambda idx: q_eff[idx])
new_betas[i] = clamp(
betas[w] + random.gauss(0, SIGMA_V))
new_thetas[i] = max(
THETA_MIN,
thetas[w] + random.gauss(0, sigma_theta))
alive[i] = True
death_gen[i] = None
fill_count += 1
participate_counts[i] = 0
betas = new_betas
thetas = new_thetas
exit_stats = {
'self_copy_count': self_copy_count,
'copy_total': copy_total,
'parent_theta': parent_theta,
'child_theta': child_theta,
'parent_gen_alive': parent_gen_alive,
}
return (history, betas, thetas, participate_counts, alive, theta_snaps,
exit_stats, fill_count, scale_traj)
def pearson(xs, ys):
n = len(xs)
if n < 2:
return float('nan')
mx = sum(xs) / n
my = sum(ys) / n
cov = sum((x - mx) * (y - my) for x, y in zip(xs, ys))
vx = sum((x - mx) ** 2 for x in xs)
vy = sum((y - my) ** 2 for y in ys)
if vx <= 0 or vy <= 0:
return float('nan')
return cov / math.sqrt(vx * vy)
def exit_readouts(scale_traj, theta_snaps, exit_stats, fill_count):
"""205 新增读数:半衰期(扫描值+解析)/归零代次/平台±std/
亲子相关(剔自体、存活≥30 代)/自体复制率。"""
half_life = None
for g in range(len(scale_traj) - 1):
n1, n2 = scale_traj[g], scale_traj[g + 1]
if n1 > N / 2 >= n2:
half_life = g + (n1 - N / 2) / (n1 - n2)
break
zero_gen = None
for g, n in enumerate(scale_traj):
if n == 0:
zero_gen = g
break
tail40 = scale_traj[-40:] if len(scale_traj) >= 40 else scale_traj
platform = statistics.mean(tail40) if tail40 else 0.0
platform_std = statistics.stdev(tail40) if len(tail40) > 1 else 0.0
pts = exit_stats['parent_theta']
cts = exit_stats['child_theta']
gas = exit_stats['parent_gen_alive']
xs = [p for p, g in zip(pts, gas) if g >= 30]
ys = [c for c, g in zip(cts, gas) if g >= 30]
r_live = pearson(xs, ys) if xs else float('nan')
xs_lo = [p for p, g in zip(pts, gas) if g < 30]
ys_lo = [c for c, g in zip(cts, gas) if g < 30]
r_low = pearson(xs_lo, ys_lo) if len(xs_lo) >= 10 else float('nan')
r_all = pearson(pts, cts) if pts else float('nan')
sc_rate = (exit_stats['self_copy_count'] /
exit_stats['copy_total']
if exit_stats['copy_total'] else 0.0)
return {
'half_life': half_life, 'zero_gen': zero_gen,
'platform': platform, 'platform_std': platform_std,
'r_live': r_live, 'r_all': r_all, 'self_copy_rate': sc_rate,
'fill_count': fill_count,
'r_low': r_low, 'n_low': len(xs_lo),
'parent_std': (statistics.stdev(pts) if len(pts) > 1
else 0.0),
}
def dual_valley(participate_counts, alive):
"""谷深两口径:存活口径(主)+ 假低口径(死格当 0 频率入 hist)。"""
f_live = [participate_counts[i] / TRACK_WINDOW
for i in range(N) if alive[i]]
hist_live = [0] * 10
for fi in f_live:
hist_live[min(int(fi * 10), 9)] += 1
v_live, k1l, k2l = valley_depth(hist_live)
f_all = [participate_counts[i] / TRACK_WINDOW for i in range(N)]
hist_low = [0] * 10
for fi in f_all:
hist_low[min(int(fi * 10), 9)] += 1
v_low, k1w, k2w = valley_depth(hist_low)
return {'hist_live': hist_live, 'v_live': v_live, 'k1l': k1l, 'k2l': k2l,
'hist_low': hist_low, 'v_low': v_low, 'k1w': k1w, 'k2w': k2w}
if __name__ == "__main__":
bar("天赐范式 第205天 第一篇 断的是规模不是基因流")
print()
bar("Part 0 设计")
print(" 接 204 两篇 Future Work:退出率 × 基因流(对读者的公开承诺)。")
print(" \"火种\"= 种群规模与基因流在扰动下不断裂的操作化表述(比喻)。")
print(" 架构事实:204 锦标赛 winner 整格覆盖已隐含生死(败者消失);")
print(" 本篇新增:舞台不再自动填满------个体退出后格子空置,种群可缩水。")
print(" 退出抽检(代开始前,λ=0 不跑→随机流与 204a 一致)→ 参与判定")
print(" → γ 学习 → 刺激更新 → 锦标赛整套复制(空格剔除候选池)→ 补位。")
print(f" λ∈{LAMBDA_SCAN + [LAMBDA_ZERO_EXTRA]} × 补位{{不补, 延迟{FILL_DELAY}代}}"
f" × 5 seed;γ={GAMMA_MAIN} σ_θ={SIGMA_THETA}(204 主档)。")
print(" 命名纪律:退出率(非死亡率)、种群归零(非灭绝)、补位(非出生)。")
print(" 零文献考场:本篇不引任何文献当判分标准。")
print()
bar("Part 1 验收锚点(λ=0 逐位复现 204a 主实验)")
print()
verify_ok = True
for seed in SEEDS:
(h1, b1, t1, pc1, al1, sn1, ex1, fc1, st1) = run_frtm_exit(
seed, GAMMA_MAIN, SIGMA_THETA, 0.0, None)
h2, b2, t2, pc2, tr2, sn2 = run_frtm_gene(
seed, GAMMA_MAIN, SIGMA_THETA)
betas_match = all(abs(b1[i] - b2[i]) < 1e-12 for i in range(N))
pc_match = pc1 == pc2
theta_match = all(abs(t1[i] - t2[i]) < 1e-12 for i in range(N))
snaps_match = (len(sn1) == len(sn2) and
all(abs(a[1] - b[1]) < 1e-12 and
abs(a[2] - b[2]) < 1e-12
for a, b in zip(sn1, sn2)))
dv = dual_valley(pc1, al1)
v_match = abs(dv['v_live'] - 0.000) < 1e-9
traj_match = all(sum(h1[g]['n_act']) == sum(h2[g]['n_act'])
for g in range(N_GEN_202 + 1))
match = (betas_match and pc_match and theta_match and snaps_match
and v_match and traj_match)
if not match:
verify_ok = False
print(f" seed {seed}: betas {'√' if betas_match else '×'} "
f"participate {'√' if pc_match else '×'} "
f"theta {'√' if theta_match else '×'} "
f"snaps {'√' if snaps_match else '×'} "
f"谷深 {'√' if v_match else '×'} "
f"n_act {'√' if traj_match else '×'}")
print(f" → λ=0 逐位复现 204a 主实验:{'√ 通过' if verify_ok else '× 失败'}")
print()
bar("Part 2 不补档扫描(λ × 5 seed,纯缩水)")
print()
nofill = {}
for lam in LAMBDA_SCAN + [LAMBDA_ZERO_EXTRA]:
rows = []
for seed in SEEDS:
(h, b, t, pc, al, sn, ex, fc, st) = run_frtm_exit(
seed, GAMMA_MAIN, SIGMA_THETA, lam, None)
ro = exit_readouts(st, sn, ex, fc)
dv = dual_valley(pc, al)
live_theta = [t[i] for i in range(N) if al[i]]
row = {
'seed': seed, 'scale': st, 'ro': ro, 'dv': dv,
'end_alive': sum(al),
'theta_end': statistics.mean(live_theta) if live_theta
else float('nan'),
'snaps': sn,
}
rows.append(row)
nofill[lam] = rows
hl_list = [r['ro']['half_life'] for r in rows]
hl_str = (f"{statistics.mean(hl_list):.1f}"
if all(x is not None for x in hl_list)
else f"{sum(1 for x in hl_list if x is None)}/5 未达")
zg_list = [r['ro']['zero_gen'] for r in rows]
zg_str = (f"{statistics.mean(zg_list):.0f}"
if all(x is not None for x in zg_list)
else f"{sum(1 for x in zg_list if x is None)}/5 未归零")
r_list = [r['ro']['r_live'] for r in rows]
sc_list = [r['ro']['self_copy_rate'] for r in rows]
end_list = [r['end_alive'] for r in rows]
print(f" λ={lam:.2f}: 末态规模均值={statistics.mean(end_list):.0f}"
f" 半衰期={hl_str} 归零代次={zg_str}")
rl_list = [r['ro']['r_low'] for r in rows]
rl_str = (f"{statistics.mean(rl_list):.3f}"
if all(not math.isnan(x) for x in rl_list) else "---")
print(f" 亲子θ相关(剔自体,存活≥30)={statistics.mean(r_list):.3f}"
f" <30段相关={rl_str}")
print(f" 自体复制率={statistics.mean(sc_list):.1%}")
vl = [r['dv']['v_live'] for r in rows]
vw = [r['dv']['v_low'] for r in rows]
judge_rows = [r for r in rows if r['end_alive'] >= 30]
if len(judge_rows) >= 3:
print(f" 谷深: 存活口径="
f"{statistics.mean([r['dv']['v_live'] for r in judge_rows]):.3f}"
f"(可判 {len(judge_rows)}/5,末态存活≥30)"
f" 假低口径={statistics.mean(vw):.3f}")
else:
print(f" 谷深: 存活口径=样本不足禁判({len(judge_rows)}/5 可判,"
f"需≥3) 假低口径={statistics.mean(vw):.3f}")
print()
bar("Part 2b 扩样触发检查(预注册:谷深均值落 0.4-0.6 → 扩 10 seed)")
print()
v003_all = statistics.mean([r['dv']['v_live'] for r in nofill[0.03]])
print(f" λ=0.03 5 seed 谷深均值={v003_all:.3f} 落 0.4-0.6 边缘带"
f" → 按预注册条件触发扩样(seed 47-51):")
extra_rows = []
for seed in [47, 48, 49, 50, 51]:
(h, b, t, pc, al, sn, ex, fc, st) = run_frtm_exit(
seed, GAMMA_MAIN, SIGMA_THETA, 0.03, None)
dv = dual_valley(pc, al)
extra_rows.append({'seed': seed, 'end_alive': sum(al), 'dv': dv})
print(f" 10 seed 逐 seed 全表(42-51):")
base_rows = nofill[0.03]
for r in base_rows + extra_rows:
print(f" seed {r['seed']}: 末态={r['end_alive']}"
f" v={r['dv']['v_live']:.3f}"
f" hist={r['dv']['hist_live']}")
all_v = ([r['dv']['v_live'] for r in base_rows] +
[r['dv']['v_live'] for r in extra_rows])
print(f" 10 seed 均值={statistics.mean(all_v):.3f}")
print(f" 逐 seed 末态存活 5-11 人,全部 <30------扩样增加的是同分布")
print(f" 噪声样本,不增加单 run 判力:hist 形态 = 多数挤 bin9 +")
print(f" 1-3 个散点,谷深 1.0/0.0 由散点位置决定(小样本散点噪声)。")
print(f" 结论:末态存活 <30 人时谷深判据无判力(禁判),")
print(f" λ=0.03 档不是边缘分化读数,是样本不足。")
print()
bar("Part 3 补位档(延迟 5 代 × λ × 5 seed)")
print()
filled = {}
for lam in [0.01, 0.02, 0.03]:
rows = []
for seed in SEEDS:
(h, b, t, pc, al, sn, ex, fc, st) = run_frtm_exit(
seed, GAMMA_MAIN, SIGMA_THETA, lam, FILL_DELAY)
ro = exit_readouts(st, sn, ex, fc)
dv = dual_valley(pc, al)
live_theta = [t[i] for i in range(N) if al[i]]
row = {
'seed': seed, 'scale': st, 'ro': ro, 'dv': dv,
'end_alive': sum(al),
'theta_end': statistics.mean(live_theta) if live_theta
else float('nan'),
}
rows.append(row)
filled[lam] = rows
pf = [r['ro']['platform'] for r in rows]
ps = [r['ro']['platform_std'] for r in rows]
fc_list = [r['ro']['fill_count'] for r in rows]
r_list = [r['ro']['r_live'] for r in rows]
sc_list = [r['ro']['self_copy_rate'] for r in rows]
vl = [r['dv']['v_live'] for r in rows]
analytic = N * (1 - lam * FILL_DELAY)
print(f" λ={lam:.2f}: 平台均值={statistics.mean(pf):.0f}"
f"±{statistics.mean(ps):.0f}(末 40 代) "
f"解析 N(1-λ·delay)={analytic:.0f} "
f"补位次数={statistics.mean(fc_list):.0f}")
print(f" 亲子θ相关={statistics.mean(r_list):.3f}"
f" 自体复制率={statistics.mean(sc_list):.1%}"
f" 谷深(存活)={statistics.mean(vl):.3f}")
print()
bar("Part 4 半衰期扫描值 vs 解析(0.693/λ)")
print()
hl_rows = []
for lam in [0.01, 0.02, 0.03]:
hl_list = [r['ro']['half_life'] for r in nofill[lam]]
if all(x is not None for x in hl_list):
hl_mean = statistics.mean(hl_list)
analytic = 0.693 / lam
hl_rows.append([f"λ={lam:.2f}", f"{hl_mean:.1f}",
f"{analytic:.1f}",
f"{(hl_mean - analytic) / analytic:+.1%}"])
else:
hl_rows.append([f"λ={lam:.2f}", "未达", f"{0.693 / lam:.1f}", "---"])
md_table(["档", "半衰期扫描值", "解析 0.693/λ", "偏离"],
hl_rows, "lrrr")
print()
print(" 纯退出对照(无复制、只有退出抽签,5 seed):")
for lam in [0.01, 0.02, 0.03]:
hls = []
for seed in SEEDS:
random.seed(seed + 100000)
n_alive_p = N
hl_p = None
for g in range(200):
for _ in range(n_alive_p):
if random.random() < lam:
n_alive_p -= 1
if hl_p is None and n_alive_p <= N / 2:
hl_p = g
if n_alive_p <= 0:
break
hls.append(hl_p)
print(f" λ={lam:.2f}: 纯退出半衰期={statistics.mean(hls):.1f}"
f"(含复制版 "
f"{statistics.mean([r['ro']['half_life'] for r in nofill[lam]]):.1f}"
f")------复制不改变衰减速度")
print()
bar("Part 5 预注册假设检验")
print()
h1a_monotone = True
for lam in [0.01, 0.02, 0.03, 0.10]:
for r in nofill[lam]:
dec = any(r['scale'][g + 1] > r['scale'][g]
for g in range(len(r['scale']) - 1))
if dec:
h1a_monotone = False
print(f" H1a(不补档:任何非零 λ 规模单调衰减,无稳定区间):")
print(f" 20 条轨迹(4λ × 5 seed)逐代单调:"
f"{'全部单调' if h1a_monotone else '存在回升'} → "
f"{'支持' if h1a_monotone else '不支持'}")
print(f" 半衰期随 λ 缩短(0.01→{statistics.mean([r['ro']['half_life'] for r in nofill[0.01]]):.0f}"
f" →0.03→{statistics.mean([r['ro']['half_life'] for r in nofill[0.03]]):.0f} 代)")
print()
pf_plat = [statistics.mean([r['ro']['platform'] for r in filled[lam]])
for lam in [0.01, 0.02, 0.03]]
h1b_platform = all(p > 30 for p in pf_plat)
h1b_decline = pf_plat[0] > pf_plat[1] > pf_plat[2]
print(f" H1b(补位档:非零平衡平台,平台随 λ 下降):")
print(f" 平台 {pf_plat[0]:.0f} / {pf_plat[1]:.0f} / {pf_plat[2]:.0f}"
f"(λ=0.01/0.02/0.03)")
print(f" → {'支持' if h1b_platform and h1b_decline else '不支持'}"
f"(非零平台{'成立' if h1b_platform else '不成立'},"
f"随 λ {'下降' if h1b_decline else '未降'})")
print()
r003 = statistics.mean([r['ro']['r_live'] for r in nofill[0.03]])
end003 = statistics.mean([r['end_alive'] for r in nofill[0.03]])
print(f" 断的形式(主结论):断的是规模不是基因流------")
print(f" λ=0.03 末态存活均值={end003:.0f} 人,"
f"亲子 θ 相关仍 {r003:.3f}")
print(f" 基因流只在规模归零处才断(λ=0.10 归零档)。")
print()
bar("Part 6 诚实边界")
print(" Limitations:")
print(" 1. 退出率为常数(不随规模/环境反馈),未扫时变退出。")
print(" 2. 补位规则仅一档(延迟 5 代、邻域 q_eff 最大填充)。")
print(" 3. 亲子相关为全 run 合并口径(剔自体、存活≥30 代),"
"非逐代。")
print(" 4. 单任务、5 seed、教学级。")
print()
print(" Future Work:")
print(" 1. 补位规则的其他形式(退出者遗产、变异步长补位)。")
print(" 2. 退出率与规模的反馈耦合(密度依赖退出)。")
print()
bar("Part 7 总结")
print(f" λ=0 逐位复现 204a 主实验:{'√' if verify_ok else '×'}")
print(f" 不补档:全档单调衰减(H1a 支持),λ=0.10 归零;")
print(f" 补位档:平台 {pf_plat[0]:.0f}/{pf_plat[1]:.0f}/{pf_plat[2]:.0f}"
f"(H1b 支持)。")
print(f" 断的是规模不是基因流:缩到 {end003:.0f} 人相关仍 {r003:.3f}。")
print()
print(" 与 204 的衔接:204 答遗传通道(θ 怎么传),本篇开生死+存续")
print(" 通道------存续不取决于退出多弱,取决于有没有补位。")
print()
print(" 互动钩子:退出压力下火种没断(补位平台成立),")
print(" 那分化被逼出来了吗?------下一篇(205-2)的问题。")
print()
