Virtual Embryo Challenge更新于 10-03 19:58(北京时间) / 每 5 分钟更新

总览 · ← 返回运行 20261003-171955-search-t2-embryo-interp-chain-12h

节点 n35 终选程序?按该运行锁定的规则最终选出的程序;可能是候选节点,也可能由护栏回退到基线。在终选来历上

NO_CHANGE: 相关特征子空间投影位移(k=25–200 五档全部噪声内,retention≥0.94 结构性空转);备选 RESID 残余双峰坍缩、迭代残差核扩散、逐类型 asym、within 核亦全部证否

运行?一次完整的自动搜索或 Agent 会话,有自己的锁定配置和证据包。20261003-171955-search-t2-embryo-interp-chain-12h
父节点n34
子节点n37
操作?种子:人写的起点;改进:在父节点上改;草稿:从头写;修复:修父节点的报错。改进
状态已打分
分数搜索目标分 63.23(+0.0) · proxy 63.23(+0.0)
审查通过 检查1(越界读取):未发现问题。数据读取全部经 view_io.load_manifest/read_stage(args.data,...)(run.py:1290-1300),prior 文件用 os.path.join(view,'prior',...)(run.py:338,456),无绝对路径、'..'、/mnt、/home、data/raw、downloads 或 src/common/evaluation,无联网代码。; 检查2(硬编码目标统计量):未发现问题。全文无长数字常量、无写死的类型比例/细胞数/基因列表;相关核、类型均值差、残余分离、RMS 等均从输入现场计算(cor…
用时?从运行开始到结束(或到现在)的挂钟时间。41 分
程序版本5c4da635ff210522d529a56ea8364e224f3b89ad (programs.git)

方法说明?节点程序自带的 METHOD.md:这个程序做了什么、为什么。

来自 programs.git 5c4da635ff:solution/METHOD.md

NO_CHANGE: 相关特征子空间投影位移(k=25–200 五档全部噪声内,retention≥0.94 结构性空转);备选 RESID 残余双峰坍缩、迭代残差核扩散、逐类型 asym、within 核亦全部证否

结论

提交的 run.py 默认输出与父节点 34 逐位一致(X/data、indices、indptr、obsm、seed 的 sha256 全部相同;--ablate mechanism 亦逐位一致,已验证)。PLAN 指定的机制(EIGPROJ)已实现并按 PLAN 的判据证否;按任务书要求又实现了 4 个针对同一弱项(cell_state / variogram)的备选机制,共 17 个配置、18 次查分,无一超过父节点基线 +0.3(A 半,seed 0),故按 NO_CHANGE 提交,所有机制代码保留在 run.py 中、默认关闭(env 开关见下),供后续节点复用。

基线(proxy A 半,seed 0,与父节点 34 逐位一致的输出)

board 62.36;raw:de_score 0.2857 / de_direction 0.3852 / mmd_u 0.01161 / variogram 0.01342 / nbhd 0.05066 / d2_shape 0.0047 / occupancy_dice 0.8066 / scale_log_ratio 0.0162。(父节点 docstring 中 asym=0.85 的网格值也是 62.36,交叉印证默认输出 = 父节点。)

1. PLAN 机制 EIGPROJ:实现与证否(5 次查分 + 1 次基线)

实现(按 PLAN):对括号两阶段全细胞的基因-基因 Pearson 相关矩阵 C(498×498,np.linalg.eigh,按 |λ| 取前 k 个特征向量 V_k),在不对称相关扩散之后、软权重之前,对每个共有类型的 Δ' 做 Δ''=V_k(V_kᵀΔ'),再经原有 PROJ_NORM 重归一到 ||Δ||。两侧(a 全量、b 衰减 η(1−asym)=0.15)都投影。T2_EIGPROJ_K,k=0 或 ≥498 跳过。

机制生效证据(PLAN mechanism_evidence 逐条核对):

  • 投影保留率 ||Δ''||/||Δ'||:k=25/50/100/150/200 → 0.959/0.963/0.969/0.974/0.980,全部高于 PLAN 的证据带 0.6–0.95 → 判据本身已宣告投影近似空转;
  • 方向改变角:16.5°/15.6°/14.4°/13.0°/11.4°(在 5–30° 带内但偏小端);
  • variogram raw:0.01337/0.01337/0.01332/0.01333/0.01339,对比基线 0.01342,改善 ≤0.0001,远低于 PLAN 要求的 ≥0.0005(目标 ≤0.0125 完全未达);
  • de_direction raw:0.3803–0.3818 vs 基线 0.3852,恶化 0.003–0.005,超过 PLAN 的 <0.001 容忍线。
kboardvariogram rawmmd_u rawnbhd raw
0(=父节点)62.360.013420.011610.05066
2562.240.013370.011800.05118
5062.240.013370.011700.05137
10062.370.013320.011490.05091
15062.430.013330.011390.05053
20062.410.013390.011440.05049

证否的结构性原因(供后续节点参考,勿再沿此方向):(I+ηC) 与 V_kV_kᵀ 可交换(同为 C 的特征基上的对角算子),扩散 Δ+ηCΔ 已把 Δ 集中到 C 的主特征方向(谱权 (1+ηλᵢ)),事后再投影到同一矩阵的前 k 特征空间只能移除 ≤6% 的能量(k=25 时也只移除 4%)——投影与扩散不是独立约束,PLAN 的前提("加性校正保留了 Δ 中与 C 正交的分量")在数学上不成立。k<25 的档位按 PLAN 风险条款跳过(k=50 时 de_dir=0.3816<0.39)。

2. 备选机制(针对同一弱项 cell_state / variogram,均已实现、均证否)

诊断动机:全管线跑完后,输出内每个共有类型中 a 来源与 b 来源细胞的残余质心分离仍达 within-type std 的 0.55–0.76 倍(run.py stderr 的 resid_sep_rel_before=0.629),即混合双峰是 variogram/mmd 低于地板的直接嫌疑。

2a. RESID 残余双峰坍缩(T2_RESID_GAMMA/TAU/SIDE/LAMBDA,8 次查分)

测出输出内的残余分离 s=μ_out(b)−μ_out(a),用与主管线相同的解码(软权重 w=clip(|s|/0.15,0,1)、nnz-only、clip≥0)坍缩 γ 比例;both-sides 时系数 c_a=γ·n_b/(n_a+n_b)、c_b=γ·n_a/(n_a+n_b) 保持合并均值不动(DE 指标结构性不受扰)。

  • both γ=0.5 → 62.27;γ=1.0 → 62.14;γ=0.5+λ=6 → 62.26;γ=1.0+λ=6 → 61.79;a-only γ=0.5 → 60.90;a-only γ=1.0 → 56.58(dp 被移动、de_score 0.2857→0.1786,证实"保均值"设计必要)。
  • 一致规律:mmd_u 显著改善(0.01161→0.01081,+0.22 分,全树从未有机制做到)但 neighborhood_mmd 一致恶化(0.05066→0.05296…0.05655,−0.27…−0.67 分),净负。结论:残余双峰并非 nbhd/variogram 能吃的免费午餐——把 a/b 两群细胞的表达拉近会破坏表达-位置配对(两群细胞坐标不同)。零率不变(0.9584→0.9586),排除稀疏结构解释。
2b. ITERDIFF 迭代残差核扩散(父节点建议 #1,T2_ITERDIFF_ENABLE/ETA2,2 次查分)

两遍管线:第一遍输出后按型内残差重算相关核 C2(与 C 的余弦仅 0.48,确是不同的核),第二遍用 C2 做方向校正。η2=1.0 → 61.90(variogram 0.01378 反而变差);η2=2.0 → 62.30(de_score 0.2857→0.3214 是唯一亮点,但 nbhd 0.05295、variogram 0.01353 均恶化)。证否。

2c. ASYMPT 逐类型不对称(父节点建议 #2,T2_ASYMPT_ZETA/CAP,2 次查分)

asym_type = clip(0.85 + ζ·(||Δ_type||/median −1), 0, 0.95)。ζ=+0.3 → 62.35(asym 实际范围 0.74–0.91);ζ=−0.3 → 62.29。均噪声内。证否。

2d. within 型内残差核(T2_PROJ_CORR_KERNEL=within,1 次查分)

扩散核换成两阶段型内残差相关(去掉组成结构)→ 61.80,variogram 0.01381 恶化。全细胞核(含组成结构)才是对的方向。证否。

验证过什么 / 没验证什么

  • 验证:默认输出与 --ablate 输出逐位一致且与父节点行为一致(哈希对比);vec-check 通过;seed 0/1/2 均能跑通、确定;全程 1.6 s / <1 GB。所有统计量(相关核、残余分离、类型范数)均从视图输入现场计算,无硬编码、无绝对时间依赖(只用 t 与时间差),满足视图无关。
  • 未验证:所有配置只在 proxy A 半 seed 0 上筛过(个别双配置);没有任何配置达到"双 seed 确认"门槛(≥+0.3),故未花 seed 1/2 查分;B 半行为未测。
  • 生物学知识来源:本节点全部机制均为输入数据的现场统计(基因-基因相关、类型均值差、特征分解),未使用任何外部生物学知识条目或保留阶段信息。

查分账目(18/20)

基线×2(其中 1 次为重复,浪费)、EIGPROJ k 网格×5、RESID×6、ITERDIFF×2、ASYMPT×2、within×1。

给后续节点的建议

  1. variogram(skill≈0.39,低于地板)对类型级 Δ 方向的一切修正都不敏感(CORRPROJ 是唯一动过它的机制,η≈1 已饱和);对细胞级分布的修正(RESID)会先伤 nbhd。它可能与 nbhd 存在结构冲突:任何把两群细胞表达拉近的操作都同时降 mmd_u 和升 nbhd。若再攻 cell_state,应找只降 mmd_u 不动表达-位置配对的路径(例如按空间邻域条件化地坍缩:只坍缩空间上已混居的 a/b 细胞对——RESID 代码已就位,加一个邻域条件即可试)。
  2. de_score 在 ITERDIFF η2=2.0 下 0.2857→0.3214(+0.18 分)是本次唯一超噪声的单项收益,但被 nbhd/variogram 恶化淹没;若单独把"残差核扩散"只用于 DE 通道(如叠加 TSHIFT/PBPROJ 式的伪批量校正而不动细胞级位移),可能变现。
  3. 本父节点(34)在 A 半 62.3 附近是一个尖锐局部最优:17 个新配置全部 ≤ +0.07。继续在位移方向/幅度上找增益的期望值很低。

调研员的计划

名称相关特征子空间投影位移:去除Δ中与组织共变结构正交的分量以修复variogram
动机父节点34的variogram skill仅0.407(低于地板0.5,得分5.09/12.5),是全树最弱单项指标,说明位移管线主动破坏了基因-基因共变结构。cell_state组51.51是四组最低。节点31的相关扩散(Δ+ηCΔ)将variogram raw从0.01382降至0.01300(skill 0.391→0.407),方向正确但力度不足:加性校正保留了Δ中与C正交的分量,该分量在位移后产生虚假基因间变异。所有直接操控方差的尝试(VARISO节点17/19、共变重着色节点21)均失败,因为它们改变表达幅度而非位移方向。本方案从位移方向入手,用投影而非加性校正,是未试过的结构改动。
做法在父节点34的相关扩散步骤之后、软权重之前,新增特征子空间投影:(1) 对括号两阶段全细胞计算基因-基因Pearson相关矩阵C(~498×498,已有);(2) 对C做特征分解,取前k个特征向量组成V_k(498×k);(3) 对每个共有类型的扩散后位移Δ'执行投影 Δ''=V_k(V_k^T·Δ'),再重归一化到||Δ'||;(4) 投影后的Δ''进入后续管线(support=0.15、w_g、λ=6、α=5、β=0.2、asym=0.85)不变。参数:k的初值与搜索范围——k∈{50,100,150,200}(498基因面板),预期最优在100-150(捕获主要共变模式但不过度约束)。vec-score快速筛选:每个k只跑seed 0,看variogram raw(目标:从0.01296降至≤0.0125)和board;若variogram raw改善≥0.0005且de_score/de_direction/neighborhood_mmd raw恶化均<0.001,再跑seed 1/2确认。单输入阶段退路:无括号对时走分层copy,投影不参与(与父节点一致)。实现注意:特征分解用numpy.linalg.eigh(对称矩阵),取绝对值最大的前k个特征值对应的特征向量;投影是矩阵乘法,498维向量×(498×k)矩阵,计算量可忽略。
风险1) k过小(<50)时Δ被过度约束,位移方向偏离真实时间变化,de_score/de_direction下降——Engineer应在k=50时检查de_dir raw,若<0.39则跳过更小k。2) C的顶部特征向量可能由少数高变基因主导,投影后Δ集中在这些基因上,反而加剧不均衡——检查投影后Δ的基因支持集是否仍覆盖≥30个基因。3) variogram对稀疏结构(93%零值)敏感,投影可能改变哪些基因被clip到0——检查投影后nnz比例变化,若>2%则需加nnz保护。4) 收益可能仍在噪声内(<1分)——用双seed确认,若board差<0.5则停止。

代码改动?这个节点的程序和父节点程序的逐行差别:绿色是新增,红色是删除。

对比:父节点版本 e5d7615f0a。改动的文件:solution/METHOD.md +49 −46、solution/run.py +267 −13

diff --git a/solution/METHOD.md b/solution/METHOD.mdindex 6a15712..096be85 100644--- a/solution/METHOD.md+++ b/solution/METHOD.md@@ -1,61 +1,64 @@-不对称相关扩散:a 侧位移用全量 Δ'=renorm(Δ+η·C·Δ),b 侧衰减到 η(1−asym)=0.15(asym=0.85),保护近目标细胞的表达-位置配对;--ablate 逐位还原父节点 31。+NO_CHANGE: 相关特征子空间投影位移(k=25–200 五档全部噪声内,retention≥0.94 结构性空转);备选 RESID 残余双峰坍缩、迭代残差核扩散、逐类型 asym、within 核亦全部证否 -## 方法(family T2EI-01,PLAN 字面实现)+## 结论 -父节点 31 的 CORRPROJ 对 a/b 两侧施加相同的方向校正 Δ'=renorm(Δ+η·C·Δ|_{|Δ|≥0.15})(C=括号两阶段全细胞基因-基因 Pearson 相关,η=1)。本节点引入 asym∈[0,1](`T2_PROJ_ASYM`,提交默认 0.85):+提交的 `run.py` 默认输出与父节点 34 **逐位一致**(X/data、indices、indptr、obsm、seed 的 sha256 全部相同;`--ablate mechanism` 亦逐位一致,已验证)。PLAN 指定的机制(EIGPROJ)已实现并按 PLAN 的判据证否;按任务书要求又实现了 4 个针对同一弱项(cell_state / variogram)的备选机制,共 17 个配置、18 次查分,无一超过父节点基线 +0.3(A 半,seed 0),故按 NO_CHANGE 提交,所有机制代码保留在 run.py 中、默认关闭(env 开关见下),供后续节点复用。 -- a 侧(较早括号阶段)细胞位移用全量扩散 Δ'_a(η_a=1);-- b 侧(较晚阶段、已接近目标)用衰减扩散 Δ'_b(η_b=η·(1−asym)=0.15);-- 两侧各自的 Δ' 再经父节点的软权重 w_g=clip(|Δ|/0.25,0,1)、λ=6 逐细胞投影加权、α=5 位移、β=0.2 NN 配对收缩,管线其余部分逐位不变;-- asym=0 时两侧共用同一 Δ'(同一对象),输出与父节点 31 逐位一致(本地 digest 验证);`--ablate mechanism` 即 asym=0。-- `T2_PROJ_ASYM_SIDE=a` 为反向对照(衰减 a 侧、b 侧全量)。+## 基线(proxy A 半,seed 0,与父节点 34 逐位一致的输出) -坐标、细胞抽取、各向异性整形(aniso γ=0.5)均未动。单输入阶段(无括号对)退路不变:分层 copy,asym 不参与。无新增生物知识条目:相关核完全由视图内两个输入阶段现场计算。+board **62.36**;raw:de_score 0.2857 / de_direction 0.3852 / mmd_u 0.01161 / variogram 0.01342 / nbhd 0.05066 / d2_shape 0.0047 / occupancy_dice 0.8066 / scale_log_ratio 0.0162。(父节点 docstring 中 asym=0.85 的网格值也是 62.36,交叉印证默认输出 = 父节点。) -## 机制生效证据(PLAN mechanism_evidence 四项)+## 1. PLAN 机制 EIGPROJ:实现与证否(5 次查分 + 1 次基线) -1. **neighborhood_mmd raw**(A 半 proxy,seed 0;asym=0 基线 0.05158):0.25→0.05142,0.5→0.05116,0.75→0.05070,**0.85→0.05066**,0.9→0.05083,1.0→0.05540。最优改善 0.00092 ≥ PLAN 有效阈值 0.0005。seed 1:0.05201→0.05074;seed 2:0.04988→0.04890,三种子方向一致。-2. **mmd_u raw**:0.01222(asym=0)→ 0.01161(asym=0.85),父节点 31 的 mmd_u 微损被逆转(A 半口径)。-3. **Δ'_a 与 Δ'_b 的方向差**:cos(Δ,Δ'_a) 均值 0.8616 vs cos(Δ,Δ'_b) 均值 0.9321,差 0.070 > 0.02 要求;作用于全部 10 个共有类型的 b 侧 2000 个细胞的位移方向。-4. **ablation**:`--ablate mechanism` 输出与父节点 31 的 seed-0 预测逐位一致(.X 与 spatial_3D 字节级 digest 相同)。+实现(按 PLAN):对括号两阶段全细胞的基因-基因 Pearson 相关矩阵 C(498×498,`np.linalg.eigh`,按 |λ| 取前 k 个特征向量 V_k),在不对称相关扩散之后、软权重之前,对每个共有类型的 Δ' 做 Δ''=V_k(V_kᵀΔ'),再经原有 PROJ_NORM 重归一到 ||Δ||。两侧(a 全量、b 衰减 η(1−asym)=0.15)都投影。`T2_EIGPROJ_K`,k=0 或 ≥498 跳过。 -## 查分记录(共 13 次,余 2;A 半,board 为八项 points 之和)+机制生效证据(PLAN mechanism_evidence 逐条核对):+- 投影保留率 ||Δ''||/||Δ'||:k=25/50/100/150/200 → **0.959/0.963/0.969/0.974/0.980**,全部高于 PLAN 的证据带 0.6–0.95 → 判据本身已宣告投影近似空转;+- 方向改变角:16.5°/15.6°/14.4°/13.0°/11.4°(在 5–30° 带内但偏小端);+- variogram raw:0.01337/0.01337/0.01332/0.01333/0.01339,对比基线 0.01342,改善 ≤0.0001,**远低于 PLAN 要求的 ≥0.0005**(目标 ≤0.0125 完全未达);+- de_direction raw:0.3803–0.3818 vs 基线 0.3852,恶化 0.003–0.005,超过 PLAN 的 <0.001 容忍线。 -| # | 配置 | seed | board | nbhd raw | mmd_u raw | variogram raw | de_dir raw | de_score raw |-|---|---|---|---|---|---|---|---|---|-| 1-2 | asym=0(=父节点,基线校准;重复 1 次浪费额度) | 0 | 62.06 | 0.05158 | 0.01222 | 0.013474 | 0.3813 | 0.2857 |-| 3 | asym=0.25 | 0 | 62.11 | 0.05142 | 0.01215 | 0.013445 | 0.3814 | 0.2857 |-| 4 | asym=0.5 | 0 | 62.18 | 0.05116 | 0.01203 | 0.013403 | 0.3817 | 0.2857 |-| 5 | asym=0.75 | 0 | 62.31 | 0.05070 | 0.01177 | 0.013377 | 0.3816 | 0.2857 |-| 6 | asym=1.0 | 0 | 61.20 | 0.05540 | 0.01362 | 0.014745 | 0.3812 | 0.3214 |-| 7 | asym=0.85 | 0 | 62.36 | 0.05066 | 0.01161 | 0.013420 | — | — |-| 8 | asym=0.9 | 0 | 62.34 | 0.05083 | 0.01158 | 0.013560 | — | — |-| 9 | asym=0.85, side=a(反向) | 0 | 61.53 | 0.05477 | 0.01216 | 0.013539 | — | — |-| 10 | asym=0.85 + CLIPAWARE_TH=0.05 | 0 | 55.80 | 0.07325 | 0.01981 | 0.029699 | 0.3548 | 0.2143 |-| 11 | asym=0(基线) | 1 | 61.56 | 0.05201 | 0.01173 | 0.013803 | — | — |-| 12 | asym=0.85 | 1 | 61.89 | 0.05074 | 0.01111 | 0.013817 | — | — |-| 13 | η=1.25/asym=0.88 | 0 | 62.38 | 0.05058 | 0.01162 | 0.013424 | — | — |-| 14 | η=1.5/asym=0.9 | 0 | 62.38 | 0.05053 | 0.01165 | 0.013424 | — | — |-| 15 | η=2.0/asym=0.925 | 0 | 62.39 | 0.05047 | 0.01166 | 0.013424 | — | — |-| 16 | η=2.0/asym=0.925 | 1 | 61.92 | 0.05052 | 0.01115 | — | — | — |-| 17 | asym=0.85 | 2 | 62.46 | 0.04890 | 0.01097 | — | — | — |-| 18 | asym=0(基线) | 2 | 62.16 | 0.04988 | 0.01151 | — | — | — |+| k | board | variogram raw | mmd_u raw | nbhd raw |+|---|---:|---:|---:|---:|+| 0(=父节点) | 62.36 | 0.01342 | 0.01161 | 0.05066 |+| 25 | 62.24 | 0.01337 | 0.01180 | 0.05118 |+| 50 | 62.24 | 0.01337 | 0.01170 | 0.05137 |+| 100 | 62.37 | 0.01332 | 0.01149 | 0.05091 |+| 150 | **62.43** | 0.01333 | 0.01139 | 0.05053 |+| 200 | 62.41 | 0.01339 | 0.01144 | 0.05049 | -(编号 1-2 为同一预测的两次查分;实际消耗 18/20 额度。)+**证否的结构性原因(供后续节点参考,勿再沿此方向)**:(I+ηC) 与 V_kV_kᵀ 可交换(同为 C 的特征基上的对角算子),扩散 Δ+ηCΔ 已把 Δ 集中到 C 的主特征方向(谱权 (1+ηλᵢ)),事后再投影到同一矩阵的前 k 特征空间只能移除 ≤6% 的能量(k=25 时也只移除 4%)——投影与扩散不是独立约束,PLAN 的前提("加性校正保留了 Δ 中与 C 正交的分量")在数学上不成立。k<25 的档位按 PLAN 风险条款跳过(k=50 时 de_dir=0.3816<0.39)。 -## 结论与选择+## 2. 备选机制(针对同一弱项 cell_state / variogram,均已实现、均证否) -- asym 在 0→0.85 单调改善、0.85 处峰、1.0 处崩(b 侧完全无扩散时邻域配对反而变差:两侧位移方向差过大,交界处表达不连续,PLAN 风险 1 在 asym=1 兑现)。三种子配对差 +0.30/+0.34/+0.29 board,收益通道全部是 neighborhood_mmd(+0.05~0.11 points)与 mmd_u(+0.04~0.06),与 PLAN 预期一致。-- 提高 η 同时保持 η_b=0.15(η=1.25/1.5/2.0)只在噪声内微增(+0.02~0.03 board,nbhd raw 差 0.0002 < 0.0005 显著阈值),按 PLAN 保持 η=1 单参数改动。-- **提交配置**:asym=0.85、side=b、η=1、support=0.15(代码默认值,无需环境变量)。-- **clip-aware attenuation(PLAN 辅助修正)被证否**:TH=0.05 时 board 55.80(−6.3),mmd_u 0.0198、variogram 0.0297 均崩——衰减位移使本应被 clip≥0 整流的近零对被保留在原值,破坏了位移管线赖以工作的稀疏整流结构。未再试更低阈值(PLAN 风险注明 <0.02 预期无效,且 0.05 已显示方向性错误而非力度问题)。-- 反向(衰减 a 侧)61.53 劣于基线,交叉验证了机制的方向特异性:需要保护的是 b 侧。+诊断动机:全管线跑完后,输出内每个共有类型中 a 来源与 b 来源细胞的残余质心分离仍达 within-type std 的 **0.55–0.76 倍**(run.py stderr 的 `resid_sep_rel_before`=0.629),即混合双峰是 variogram/mmd 低于地板的直接嫌疑。 -## 验证过 / 未验证+### 2a. RESID 残余双峰坍缩(`T2_RESID_GAMMA/TAU/SIDE/LAMBDA`,8 次查分)+测出输出内的残余分离 s=μ_out(b)−μ_out(a),用与主管线相同的解码(软权重 w=clip(|s|/0.15,0,1)、nnz-only、clip≥0)坍缩 γ 比例;both-sides 时系数 c_a=γ·n_b/(n_a+n_b)、c_b=γ·n_a/(n_a+n_b) 保持合并均值不动(DE 指标结构性不受扰)。+- both γ=0.5 → **62.27**;γ=1.0 → 62.14;γ=0.5+λ=6 → 62.26;γ=1.0+λ=6 → 61.79;a-only γ=0.5 → 60.90;a-only γ=1.0 → 56.58(dp 被移动、de_score 0.2857→0.1786,证实"保均值"设计必要)。+- 一致规律:**mmd_u 显著改善**(0.01161→0.01081,+0.22 分,全树从未有机制做到)但 **neighborhood_mmd 一致恶化**(0.05066→0.05296…0.05655,−0.27…−0.67 分),净负。结论:残余双峰并非 nbhd/variogram 能吃的免费午餐——把 a/b 两群细胞的表达拉近会破坏表达-位置配对(两群细胞坐标不同)。零率不变(0.9584→0.9586),排除稀疏结构解释。 -- 已验证:seed 0/1/2 三种子 A 半配对比较;ablate 与父节点逐位一致;vec-check 通过;运行 ~9s、内存 <1GB(限额 30min/28GB 内);对 seed 确定(default_rng)。-- 未验证:B 半正式分(A 半 +0.3 小于 T2 噪声 ~1,但三种子方向一致且 nbhd/mmd_u raw 改善均超阈值,机制真实性由 ablation 与方向特异性支撑);真实括号(E6.75→E8.0 之外的 t、共有类型数)下 asym=0.85 的最优性——t 变大时 b 侧离目标更远,最优 asym 可能偏小,但 0.5–0.9 区间在 A 半上平坦(62.18–62.36),预期不敏感;未做伪装视图重跑(改动不含任何视图路径/绝对时间依赖,asym 只依赖括号两侧的数据顺序)。+### 2b. ITERDIFF 迭代残差核扩散(父节点建议 #1,`T2_ITERDIFF_ENABLE/ETA2`,2 次查分)+两遍管线:第一遍输出后按型内残差重算相关核 C2(与 C 的余弦仅 0.48,确是不同的核),第二遍用 C2 做方向校正。η2=1.0 → **61.90**(variogram 0.01378 反而变差);η2=2.0 → 62.30(de_score 0.2857→0.3214 是唯一亮点,但 nbhd 0.05295、variogram 0.01353 均恶化)。证否。 -## 知识来源+### 2c. ASYMPT 逐类型不对称(父节点建议 #2,`T2_ASYMPT_ZETA/CAP`,2 次查分)+asym_type = clip(0.85 + ζ·(||Δ_type||/median −1), 0, 0.95)。ζ=+0.3 → **62.35**(asym 实际范围 0.74–0.91);ζ=−0.3 → 62.29。均噪声内。证否。 -无新增外部生物知识。相关核 C、逐类型 Δ、细胞抽取全部由视图 manifest 指定的两个输入阶段现场计算;未使用任何保留阶段/保留基因型的测量值。父节点沿用的通路先验接口(prior/ go_bp、reactome)在本节点默认路径(PROJ_MODE=corr)中不读取。+### 2d. within 型内残差核(`T2_PROJ_CORR_KERNEL=within`,1 次查分)+扩散核换成两阶段型内残差相关(去掉组成结构)→ **61.80**,variogram 0.01381 恶化。全细胞核(含组成结构)才是对的方向。证否。++## 验证过什么 / 没验证什么++- 验证:默认输出与 `--ablate` 输出逐位一致且与父节点行为一致(哈希对比);`vec-check` 通过;seed 0/1/2 均能跑通、确定;全程 1.6 s / <1 GB。所有统计量(相关核、残余分离、类型范数)均从视图输入现场计算,无硬编码、无绝对时间依赖(只用 t 与时间差),满足视图无关。+- 未验证:所有配置只在 proxy A 半 seed 0 上筛过(个别双配置);没有任何配置达到"双 seed 确认"门槛(≥+0.3),故未花 seed 1/2 查分;B 半行为未测。+- 生物学知识来源:本节点全部机制均为输入数据的现场统计(基因-基因相关、类型均值差、特征分解),未使用任何外部生物学知识条目或保留阶段信息。++## 查分账目(18/20)++基线×2(其中 1 次为重复,浪费)、EIGPROJ k 网格×5、RESID×6、ITERDIFF×2、ASYMPT×2、within×1。++## 给后续节点的建议++1. variogram(skill≈0.39,低于地板)对**类型级 Δ 方向**的一切修正都不敏感(CORRPROJ 是唯一动过它的机制,η≈1 已饱和);对**细胞级分布**的修正(RESID)会先伤 nbhd。它可能与 nbhd 存在结构冲突:任何把两群细胞表达拉近的操作都同时降 mmd_u 和升 nbhd。若再攻 cell_state,应找只降 mmd_u 不动表达-位置配对的路径(例如按空间邻域条件化地坍缩:只坍缩空间上已混居的 a/b 细胞对——RESID 代码已就位,加一个邻域条件即可试)。+2. de_score 在 ITERDIFF η2=2.0 下 0.2857→0.3214(+0.18 分)是本次唯一超噪声的单项收益,但被 nbhd/variogram 恶化淹没;若单独把"残差核扩散"只用于 DE 通道(如叠加 TSHIFT/PBPROJ 式的伪批量校正而不动细胞级位移),可能变现。+3. 本父节点(34)在 A 半 62.3 附近是一个尖锐局部最优:17 个新配置全部 ≤ +0.07。继续在位移方向/幅度上找增益的期望值很低。diff --git a/solution/run.py b/solution/run.pyindex 4d9377e..4dce15b 100644--- a/solution/run.py+++ b/solution/run.py@@ -8,7 +8,23 @@ exp(log r_a + SCALE_DAMP·t·Δlog r), and draws cells stratified by type: round(t·n) from the later stage, the rest from the earlier one. Coordinates travel with the cells. n is log-linear in t, clipped to the board range. -This node (34, PROJ_ASYM, family T2EI-01): the corr-diffusion direction+This node (35, NO_CHANGE, family T2EI-01): the PLAN mechanism (EIGPROJ:+project each type's diffused Δ' onto the top-k eigenvectors of the corr+kernel C, then renormalize) was implemented and falsified: post-diffusion+retention is 0.94-0.98 at every k in 25..200 because (I+ηC) and V_kV_k^T+commute — the diffusion already concentrates Δ into C's leading eigenspace,+so the projection is structurally a near no-op. Board deltas over the parent+(A half, seed 0): k=25/50/100/150/200 → −0.12/−0.12/+0.01/+0.07/+0.05,+variogram raw moves ≤0.0001 (target ≥0.0005). Four alternative mechanisms+targeting the same weakness (cell_state) were also falsified: RESID residual+sub-population collapse (mmd_u 0.01161→0.01081 but nbhd 0.05066→0.053+,+net −0.1..−5.8 over 6 configs), ITERDIFF residual-kernel second-pass+diffusion (61.90/62.30), per-type ASYMPT (62.35/62.29), within-type corr+kernel (61.80). All mechanisms stay in the code behind default-off env+flags; defaults reproduce parent node 34 bit-for-bit, and --ablate disables+them (identical output). See METHOD.md.++Parent node (34, PROJ_ASYM, family T2EI-01): the corr-diffusion direction correction is applied ASYMMETRICALLY by source side: the a-side (earlier bracket stage) displacement uses the full diffusion Δ'_a = renorm(Δ + η·C·Δ), the b-side (later stage, already close to the target) uses the attenuated@@ -162,6 +178,16 @@ PROJ_CORR_KERNEL = os.environ.get("T2_PROJ_CORR_KERNEL", "all") # side is attenuated ("b" default per PLAN, "a" for the reverse cross-check). PROJ_ASYM = float(os.environ.get("T2_PROJ_ASYM", "0.85")) PROJ_ASYM_SIDE = os.environ.get("T2_PROJ_ASYM_SIDE", "b")+# Eigenspace projection of the diffused displacement (EIGPROJ, family T2EI-01,+# this node 35): after the asymmetric corr diffusion (and its support+# restriction), each type's Δ' is projected onto the span of the top-k+# eigenvectors of C (by |eigenvalue|), Δ'' = V_k (V_k^T Δ'), then the existing+# norm-preservation renormalizes to ||Δ||. This removes the component of the+# displacement orthogonal to the tissue's dominant co-variation programs, which+# is where the displacement pipeline injects spurious gene-gene variation+# (variogram skill 0.407 < floor at the parent). k = 0 (or k >= n_genes, or+# --ablate) skips the projection and reproduces parent node 34 bit-for-bit.+EIGPROJ_K = int(os.environ.get("T2_EIGPROJ_K", "0")) # Clip-aware attenuation (optional auxiliary, PLAN): for gene-cell pairs whose # displaced value would fall below CLIPAWARE_TH (i.e. gets rectified/distorted # by the clip≥0), scale that pair's correction by clip(displaced/TH, 0, 1) so@@ -173,6 +199,43 @@ CLIPAWARE_TH = float(os.environ.get("T2_CLIPAWARE_TH", "0")) # to 5× the biological range, which is what collapses mmd_u) while keeping the # correlation structure the diffusion imprints. 0 = off (parent behavior). BRACKET_CLIP = float(os.environ.get("T2_BRACKET_CLIP", "0"))+# Residual sub-population collapse (RESID, family T2EI-01, this node 35's+# submitted mechanism after the PLAN eigenspace projection was falsified):+# after the full expression pipeline (displacement + pair shrinkage), the+# a-derived and b-derived output cells of each shared type still sit apart —+# measured residual type-mean separation is 0.55–0.76 × within-type std on the+# proxy, i.e. the pipeline leaves a strong two-subpopulation bimodality that a+# real intermediate stage does not have. RESID measures that residual+# separation s = μ_out(b-derived) − μ_out(a-derived) per type and collapses a+# fraction γ of it with the SAME decode the main displacement uses: per-cell+# soft gene weights w_g = clip(|s_g|/τ_r, 0, 1)^p (noise genes barely move),+# shift applied only to entries already expressed in the cell, clipped at 0.+# Side coefficients c_a = γ·n_b/(n_a+n_b), c_b = γ·n_a/(n_a+n_b) keep the+# pooled output mean fixed (dp / DE metrics structurally blind, coordinates+# untouched). γ = 0 (or --ablate) reproduces parent node 34 bit-for-bit.+RESID_GAMMA = float(os.environ.get("T2_RESID_GAMMA", "0"))+RESID_TAU = float(os.environ.get("T2_RESID_TAU", "0.15"))+RESID_P = float(os.environ.get("T2_RESID_P", "1.0"))+RESID_MIN_CELLS = int(os.environ.get("T2_RESID_MIN_CELLS", "10"))+# per-cell λ-style weighting inside the residual collapse (0 = constant shift)+RESID_LAMBDA = float(os.environ.get("T2_RESID_LAMBDA", "0"))+# which side moves in the residual collapse: both | a | b (node-34 lesson:+# protect the b-side cells that are already close to the target)+RESID_SIDE = os.environ.get("T2_RESID_SIDE", "both")+# Iterative (residual-kernel) correlation diffusion (ITERDIFF, family T2EI-01,+# node-34 next_suggestion #1): run the full pipeline once, recompute the gene-+# gene correlation kernel C2 from the WITHIN-TYPE RESIDUALS of the pass-1+# output cloud (what actually remains unexplained after displacement), then+# redo the whole pipeline with C2 in place of C for the direction correction+# (Δ'' = renorm(Δ + η2·C2·Δ), same support/asym/soft-weight decode). η2 = 0 or+# ITERDIFF_ENABLE=0 (or --ablate) keeps the single-step parent behavior.+ITERDIFF_ENABLE = os.environ.get("T2_ITERDIFF_ENABLE", "0") == "1"+ITERDIFF_ETA2 = float(os.environ.get("T2_ITERDIFF_ETA2", "1.0"))+# Per-type asymmetry (ASYMPT, node-34 next_suggestion #2): attenuated-side+# diffusion strength per type, asym_type = clip(asym + ζ·(||Δ_type||/median − 1),+# 0, cap). ζ = 0 (or --ablate) reproduces parent node 34 bit-for-bit.+ASYMPT_ZETA = float(os.environ.get("T2_ASYMPT_ZETA", "0"))+ASYMPT_CAP = float(os.environ.get("T2_ASYMPT_CAP", "0.95")) # Pseudobulk-level prior projection (PBPROJ, this node's submitted mechanism). # Motivation: the stratified (1−t, t) draw weights make the per-cell # displacement cancel EXACTLY in the output pseudobulk, so de_score /@@ -488,7 +551,15 @@ def pathway_boost_graded(abs_d: np.ndarray, M, k: int):     return boost, order[:k]  -def project_delta(d: np.ndarray, M, names, k: int, eta: float, corr: np.ndarray | None):+def eig_basis(corr: np.ndarray, k: int):+    """Top-k eigenvectors of the symmetric corr kernel, by |eigenvalue|."""+    evals, evecs = np.linalg.eigh(corr.astype(np.float64))+    order = np.argsort(-np.abs(evals), kind="stable")[:k]+    return np.ascontiguousarray(evecs[:, order])+++def project_delta(d: np.ndarray, M, names, k: int, eta: float, corr: np.ndarray | None,+                  eigV: np.ndarray | None = None):     """Direction-correct one type's Δ with the prior. Returns (Δ', info)."""     ad_ = np.abs(d).astype(np.float64)     if M is not None:@@ -506,11 +577,23 @@ def project_delta(d: np.ndarray, M, names, k: int, eta: float, corr: np.ndarray             # |Δ| < support keep their measured Δ (no recruited noise genes,             # no support/sign changes outside the DE set)             dp = np.where(np.abs(d64) >= PROJ_SUPPORT, dp, d64)+        eig_ret, eig_cos = None, None+        if eigV is not None:+            pre = dp+            dp = eigV @ (eigV.T @ pre)+            n_pre = np.linalg.norm(pre)+            n_post = np.linalg.norm(dp)+            eig_ret = float(n_post / max(n_pre, 1e-12))+            eig_cos = float(pre @ dp / max(n_pre * n_post, 1e-12))         if PROJ_NORM:             dp = dp * (np.linalg.norm(d64) / max(np.linalg.norm(dp), 1e-12))         dp = dp.astype(np.float32)         cos = float(d @ dp / max(np.linalg.norm(d.astype(np.float64)) * np.linalg.norm(dp.astype(np.float64)), 1e-12))-        return dp, {"cos": cos, "mode": "corr"}+        info = {"cos": cos, "mode": "corr"}+        if eig_ret is not None:+            info["eig_ret"] = eig_ret+            info["eig_cos"] = eig_cos+        return dp, info     return d, {"mode": "none"}  @@ -601,8 +684,29 @@ def type_aniso_reshape(coords, labs_out, ca, cb, la_all, lb_all, t: float):     return c, info  +def corr_from_residuals(X: np.ndarray, labels: np.ndarray) -> np.ndarray | None:+    """Gene-gene Pearson corr of within-type residuals of an arbitrary cloud."""+    X = np.asarray(X, dtype=np.float64)+    labels = np.asarray(labels).astype(str)+    parts = []+    for lab in np.unique(labels):+        m = labels == lab+        if m.sum() >= 10:+            parts.append(X[m] - X[m].mean(axis=0, keepdims=True))+    if not parts:+        return None+    R = np.vstack(parts)+    sd = R.std(axis=0)+    sd[sd < 1e-12] = np.inf+    C = (R.T @ R) / R.shape[0]+    C = C / np.outer(sd, sd)+    np.fill_diagonal(C, 0.0)+    return C.astype(np.float32)++ def mix_converge(stage_a, stage_b, t: float, params: dict, alpha: float, view: str | None = None,-                 proj_eta: float | None = None, proj_asym: float | None = None):+                 proj_eta: float | None = None, proj_asym: float | None = None,+                 eigproj_k: int | None = None, corr_override: np.ndarray | None = None):     t = float(t)     damp = float(params.get("scale_damp", 1.0))     align = str(params.get("align", "procrustes"))@@ -645,6 +749,8 @@ def mix_converge(stage_a, stage_b, t: float, params: dict, alpha: float, view: s         proj_cos, proj_boost = [], []         if eta != 0.0 and shared and view is not None:             def _kernel():+                if corr_override is not None:+                    return corr_override                 if PROJ_CORR_KERNEL == "within":                     k = corr_kernel_within(stage_a, stage_b)                     if k is not None:@@ -656,12 +762,24 @@ def mix_converge(stage_a, stage_b, t: float, params: dict, alpha: float, view: s                     proj_corr = _kernel()             elif PROJ_MODE == "corr":                 proj_corr = _kernel()+        # Eigenspace projection basis (EIGPROJ, this node): top-k eigenvectors+        # of the same corr kernel used by the diffusion. k >= n_genes spans the+        # full space (V V^T = I) and is treated as off, exactly like k = 0.+        eig_k = EIGPROJ_K if eigproj_k is None else int(eigproj_k)+        proj_eigV = None+        if eig_k > 0 and proj_corr is not None and eig_k < proj_corr.shape[0]:+            proj_eigV = eig_basis(proj_corr, eig_k)         proj_cos_att = []+        eig_rets, eig_coss = [], []          def _prep(d0: np.ndarray, eta_side: float, record: bool) -> np.ndarray:             d = d0             if eta_side != 0.0 and (proj_M is not None or proj_corr is not None):-                d, pinfo = project_delta(d, proj_M, proj_names, PROJ_K, eta_side, proj_corr)+                d, pinfo = project_delta(d, proj_M, proj_names, PROJ_K, eta_side, proj_corr,+                                         eigV=proj_eigV)+                if "eig_ret" in pinfo:+                    eig_rets.append(pinfo["eig_ret"])+                    eig_coss.append(pinfo["eig_cos"])                 if record:                     if "cos" in pinfo:                         proj_cos.append(pinfo["cos"])@@ -679,18 +797,40 @@ def mix_converge(stage_a, stage_b, t: float, params: dict, alpha: float, view: s                 d = np.where(np.abs(d) >= CONVERGE_MIN_DELTA, d, np.float32(0.0)).astype(np.float32)             return d +        # Per-type asymmetry (ASYMPT, node-34 next_suggestion #2): scale the+        # attenuated side's diffusion strength per type by how much that type+        # moves over the bracket: r = ||Δ_type|| / median(||Δ||),+        # asym_type = clip(asym + ζ·(r − 1), 0, cap). ζ = 0 (or --ablate)+        # reproduces the global-asym parent bit-for-bit.+        dnorms = {lab: float(np.linalg.norm((means_b[lab] - means_a[lab]).astype(np.float64)))+                  for lab in shared}+        dmed = float(np.median(list(dnorms.values()))) if dnorms else 0.0+        asym_pts = []         for lab in shared:             d0 = (means_b[lab] - means_a[lab]).astype(np.float32)-            if asym == 0.0 or eta_att == eta:+            if ASYMPT_ZETA != 0.0 and dmed > 0:+                r = dnorms[lab] / dmed+                a_t = float(np.clip(asym + ASYMPT_ZETA * (r - 1.0), 0.0, ASYMPT_CAP))+                eta_att_t = eta * (1.0 - a_t)+                asym_pts.append(a_t)+            else:+                eta_att_t = eta_att+            if asym == 0.0 or eta_att_t == eta:                 d_full = _prep(d0, eta, True)                 delta_a[lab] = d_full                 delta_b[lab] = d_full             elif asym_side == "b":                 delta_a[lab] = _prep(d0, eta, True)-                delta_b[lab] = _prep(d0, eta_att, False)+                delta_b[lab] = _prep(d0, eta_att_t, False)             else:-                delta_a[lab] = _prep(d0, eta_att, False)+                delta_a[lab] = _prep(d0, eta_att_t, False)                 delta_b[lab] = _prep(d0, eta, True)+        if asym_pts:+            conv["asympt_zeta"] = ASYMPT_ZETA+            conv["asympt_cap"] = ASYMPT_CAP+            conv["asympt_asym_mean"] = float(np.mean(asym_pts))+            conv["asympt_asym_min"] = float(np.min(asym_pts))+            conv["asympt_asym_max"] = float(np.max(asym_pts))         if eta != 0.0 and (proj_M is not None or proj_corr is not None):             conv["proj_eta"] = eta             conv["proj_mode"] = "pathway" if proj_M is not None else "corr"@@ -705,6 +845,12 @@ def mix_converge(stage_a, stage_b, t: float, params: dict, alpha: float, view: s             if proj_cos and proj_cos_att:                 conv["proj_cos_full_minus_att"] = float(np.mean(proj_cos) - np.mean(proj_cos_att))             conv["proj_boost_mean"] = float(np.mean(proj_boost)) if proj_boost else None+        if proj_eigV is not None and eig_rets:+            conv["eigproj_k"] = int(eig_k)+            conv["eigproj_retention_mean"] = float(np.mean(eig_rets))+            conv["eigproj_retention_min"] = float(np.min(eig_rets))+            conv["eigproj_cos_mean"] = float(np.mean(eig_coss))+            conv["eigproj_angle_deg_mean"] = float(np.degrees(np.arccos(np.clip(np.mean(eig_coss), -1.0, 1.0))))         if n_part:             conv["soft_enable"] = True             conv["soft_tau"] = SOFT_TAU@@ -938,6 +1084,74 @@ def mix_converge(stage_a, stage_b, t: float, params: dict, alpha: float, view: s                 variso_pb_maxshift=float(np.max(pbshifts)),             ) +    resid_info = {"resid_enable": bool(RESID_GAMMA != 0.0), "resid_gamma": RESID_GAMMA,+                  "resid_tau": RESID_TAU, "resid_p": RESID_P, "resid_n_types": 0,+                  "resid_sep_rel_before": None, "resid_sep_rel_after": None,+                  "resid_shift_norm_mean": None, "resid_zero_rate_before": None,+                  "resid_zero_rate_after": None}+    if RESID_GAMMA != 0.0 and ia.size and ib.size:+        labs_a_r = np.asarray(stage_a.labels).astype(str)[ia]+        labs_b_r = np.asarray(stage_b.labels).astype(str)[ib]+        shared_r = sorted(set(labs_a_r.tolist()) & set(labs_b_r.tolist()))+        rb, ra_, snorms, zr0, zr1 = [], [], [], [], []+        for lab in shared_r:+            ma = labs_a_r == lab+            mb = labs_b_r == lab+            na, nb = int(ma.sum()), int(mb.sum())+            if na < RESID_MIN_CELLS or nb < RESID_MIN_CELLS:+                continue+            A = xa[ma].astype(np.float64)+            B = xb[mb].astype(np.float64)+            s = B.mean(axis=0) - A.mean(axis=0)+            w = np.clip(np.abs(s) / max(RESID_TAU, 1e-12), 0.0, 1.0) ** RESID_P+            if RESID_SIDE == "a":+                ca_, cb_ = RESID_GAMMA, 0.0+            elif RESID_SIDE == "b":+                ca_, cb_ = 0.0, RESID_GAMMA+            else:+                ca_ = RESID_GAMMA * nb / (na + nb)+                cb_ = RESID_GAMMA * na / (na + nb)+            comb0 = np.vstack([A, B])+            sep0 = np.linalg.norm(s)+            spread = max(np.linalg.norm(comb0.std(axis=0)), 1e-12)+            ds = w * s+            if RESID_LAMBDA != 0.0:+                m_ = ds != 0+                if m_.any():+                    dm = ds[m_].astype(np.float64)+                    denom = float(dm @ dm) + CONVERGE_EPS+                    dev_a = A[:, m_].astype(np.float64) - A.mean(axis=0)[m_][None, :]+                    p_a = dev_a @ dm / denom+                    wa = np.clip(1.0 - RESID_LAMBDA * p_a, 0.2, 2.5)+                    dev_b = B[:, m_].astype(np.float64) - B.mean(axis=0)[m_][None, :]+                    p_b = dev_b @ dm / denom+                    wb = np.clip(1.0 + RESID_LAMBDA * p_b, 0.2, 2.5)+                else:+                    wa = np.ones(A.shape[0]); wb = np.ones(B.shape[0])+                Anew = np.clip(A + ca_ * wa[:, None] * ds[None, :], 0.0, None)+                Bnew = np.clip(B - cb_ * wb[:, None] * ds[None, :], 0.0, None)+            else:+                Anew = np.clip(A + ca_ * ds[None, :], 0.0, None)+                Bnew = np.clip(B - cb_ * ds[None, :], 0.0, None)+            Anew = np.where(A > 0, Anew, A)+            Bnew = np.where(B > 0, Bnew, B)+            xa[ma] = Anew.astype(np.float32)+            xb[mb] = Bnew.astype(np.float32)+            comb1 = np.vstack([Anew, Bnew])+            s1 = comb1[na:].mean(axis=0) - comb1[:na].mean(axis=0)+            rb.append(sep0 / spread)+            ra_.append(np.linalg.norm(s1) / spread)+            snorms.append(float(np.linalg.norm(w * s)))+            zr0.append(float((comb0 == 0).mean()))+            zr1.append(float((comb1 == 0).mean()))+            resid_info["resid_n_types"] += 1+        if rb:+            resid_info["resid_sep_rel_before"] = float(np.mean(rb))+            resid_info["resid_sep_rel_after"] = float(np.mean(ra_))+            resid_info["resid_shift_norm_mean"] = float(np.mean(snorms))+            resid_info["resid_zero_rate_before"] = float(np.mean(zr0))+            resid_info["resid_zero_rate_after"] = float(np.mean(zr1))+     expr = np.clip(np.vstack([xa, xb]), 0.0, None).astype(np.float32) if (ia.size or ib.size) else np.zeros((0, len(stage_a.genes)), np.float32)     clamp_info = {"bracket_clip": BRACKET_CLIP, "n_clamped_cells": 0}     if BRACKET_CLIP > 0 and expr.shape[0]:@@ -1049,6 +1263,7 @@ def mix_converge(stage_a, stage_b, t: float, params: dict, alpha: float, view: s     info.update(pbproj_info)     info.update(tshift_info)     info.update(clamp_info)+    info.update(resid_info)     info.update(         t=t, n=int(expr.shape[0]), rms_a=rms_a, rms_b=rms_b, target_rms=target_rms,         out_rms=rms_radius(coords), n_from_a=int(ia.size), n_from_b=int(ib.size), **conv, **pair_info,@@ -1062,10 +1277,15 @@ def main() -> None:     parser.add_argument("--out", required=True)     parser.add_argument("--seed", type=int, default=0)     parser.add_argument("--ablate", default=None,-                        help="mechanism-off control: 'mechanism' (or any name) sets PROJ_ASYM=0 "-                             "(both sides full diffusion), reproducing parent node 31 bit-for-bit")+                        help="mechanism-off control: 'mechanism' (or any name) disables this "+                             "node's mechanisms (RESID_GAMMA=0, EIGPROJ_K=0), reproducing "+                             "parent node 34 bit-for-bit")     args = parser.parse_args()-    proj_asym = 0.0 if args.ablate else None+    global RESID_GAMMA+    if args.ablate:+        RESID_GAMMA = 0.0+    proj_asym = None+    eigproj_k = 0 if args.ablate else None      manifest = load_manifest(args.data)     genes = panel_genes(args.data, manifest)@@ -1079,8 +1299,33 @@ def main() -> None:     stage_a = read_stage(args.data, a, genes)     stage_b = read_stage(args.data, b, genes)     params = board_params(manifest, "mix", PARAMS, args.seed)-    expr, coords, info = mix_converge(stage_a, stage_b, t, params, CONVERGE_ALPHA,-                                      view=args.data, proj_asym=proj_asym)+    iterdiff_info = {"iterdiff_enable": bool(ITERDIFF_ENABLE and not args.ablate),+                     "iterdiff_eta2": ITERDIFF_ETA2, "iterdiff_kernel_cos_vs_C": None}+    if ITERDIFF_ENABLE and not args.ablate:+        expr1, coords1, info1 = mix_converge(stage_a, stage_b, t, params, CONVERGE_ALPHA,+                                             view=args.data, proj_asym=proj_asym, eigproj_k=eigproj_k)+        rng_mix = np.random.default_rng(args.seed)+        ia_r, ib_r = mix_indices(stage_a.labels, stage_b.labels, t, int(info1["n"]), rng_mix)+        labs_out = np.concatenate([np.asarray(stage_a.labels).astype(str)[ia_r],+                                   np.asarray(stage_b.labels).astype(str)[ib_r]])+        C2 = corr_from_residuals(expr1, labs_out)+        if C2 is not None:+            C1 = corr_kernel(stage_a, stage_b, len(stage_a.genes)).astype(np.float64)+            n1 = np.linalg.norm(C1); n2 = np.linalg.norm(C2.astype(np.float64))+            iterdiff_info["iterdiff_kernel_cos_vs_C"] = float(+                (C1 * C2.astype(np.float64)).sum() / max(n1 * n2, 1e-12))+            expr, coords, info = mix_converge(stage_a, stage_b, t, params, CONVERGE_ALPHA,+                                              view=args.data, proj_asym=proj_asym,+                                              eigproj_k=eigproj_k, corr_override=C2,+                                              proj_eta=ITERDIFF_ETA2)+            info.update(iterdiff_info)+        else:+            expr, coords, info = expr1, coords1, info1+            info.update(iterdiff_info)+    else:+        expr, coords, info = mix_converge(stage_a, stage_b, t, params, CONVERGE_ALPHA,+                                          view=args.data, proj_asym=proj_asym, eigproj_k=eigproj_k)+        info.update(iterdiff_info)     keep = {k: info.get(k) for k in ("t", "n", "rms_a", "rms_b", "out_rms", "n_shared_types", "z_dot", "z_flipped",                                      "align", "alpha", "n_shared_types_converged", "within_type_std_rel",                                      "between_type_mean_dist_rel", "n_from_a", "n_from_b",@@ -1091,6 +1336,15 @@ def main() -> None:                                          "proj_cos_mean", "proj_cos_min", "proj_boost_mean",                                          "proj_asym", "proj_asym_side", "proj_eta_att",                                          "proj_cos_att_mean", "proj_cos_full_minus_att",+                                         "eigproj_k", "eigproj_retention_mean", "eigproj_retention_min",+                                         "eigproj_cos_mean", "eigproj_angle_deg_mean",+                                         "resid_enable", "resid_gamma", "resid_tau", "resid_p",+                                         "resid_n_types", "resid_sep_rel_before", "resid_sep_rel_after",+                                         "resid_shift_norm_mean", "resid_zero_rate_before",+                                         "resid_zero_rate_after",+                                         "iterdiff_enable", "iterdiff_eta2", "iterdiff_kernel_cos_vs_C",+                                         "asympt_zeta", "asympt_cap", "asympt_asym_mean",+                                         "asympt_asym_min", "asympt_asym_max",                                         "pbproj_enable", "pbproj_eta", "pbproj_k", "pbproj_src",                                         "pbproj_n_pathways", "pbproj_n_boosted", "pbproj_boost_max",                                         "pbproj_s_min", "pbproj_s_max", "pbproj_s_mean",

调研来源?调研员查到并用到的知识条目和文献检索结果(只列标题和编号)。

用到的知识库条目

编号标题出处
k007Interval staging and held-out-window filtering of external datanotes/official/来件/virtualembryo.ai/rules.md
k023Time-split validation with a held-out intermediate or next time pointnotes/handover/02_知识学习路线.md
k025Spateo: rigid + non-rigid alignment and morphometric vector fields10.1016/j.cell.2024.10.011

分析结果?分析员写的 ANALYSIS.json:改了什么、各组分数怎么变、假设是否成立、经验和下一步建议。

改了什么NO_CHANGE 节点:实现了 PLAN 的 EIGPROJ(扩散后 Δ' 投影到相关核前 k 特征子空间,k=25–200)及 4 个针对 cell_state 的备选机制(RESID 残余双峰坍缩、ITERDIFF 残差核二遍扩散、逐类型 ASYMPT、within 型内核),全部在 A 半 seed 0 上证否后按默认关闭提交,输出与父节点 34 逐位一致(ablation 亦逐位相同),机制代码留在 run.py 的 env 开关后。
各组分数的变化cell_state:噪声内(实际为零):mmd_u raw 0.01093、variogram raw 0.01296 与父节点相同,得分 +0.00;目标弱项 variogram(skill 0.407,地板下)未被修复。
expression_change:噪声内(实际为零):de_score raw 0.3103、de_direction raw 0.3987 与父节点逐位相同,得分 +0.00。
local_spatial:零变化:neighborhood_mmd raw 0.04779 与父节点相同,+0.00。
shape_scale:零变化:d2_shape 0.00661 / occupancy_dice 0.8086 / scale_log_ratio 0.0099 均与父节点相同,+0.00。
family_idT2EI-01
假设是否成立否
经验
  1. 在相关扩散(Δ+ηCΔ)之后再对同一相关矩阵 C 做特征子空间投影是结构性空转:(I+ηC) 与 V_kV_kᵀ 在 C 的特征基上可交换,扩散已把 Δ 集中到主特征方向,k=25–200 的投影保留率均 ≥0.94、variogram raw 只动 ≤0.0001(要求 ≥0.0005)——不要叠加共享同一特征基的算子。
  2. 在位移管线输出的 a/b 双群细胞上做表达坍缩(RESID,both-sides 保合并均值)能拿到全树最佳 mmd_u 单项收益(raw 0.01161→0.01081),但 neighborhood_mmd 一致恶化(0.0507→0.053–0.057),净负:把坐标不同的两群细胞表达拉近必然破坏表达-位置配对,mmd_u 与 nbhd 在此结构性冲突。
  3. variogram(skill≈0.39,地板下)对类型级 Δ 方向的一切修正不敏感(EIGPROJ、ITERDIFF、within 核、逐类型 asym 全部证否),唯一动过它的是相关扩散本身且 η≈1 已饱和——别再在位移方向上做文章攻 cell_state。
  4. ITERDIFF η2=2.0 下 de_score raw 0.2857→0.3214(约 +0.18 分)是 17 个配置中唯一超噪声的单项收益,但被同配置的 nbhd/variogram 恶化淹没——收益通道和伤害通道可以用同一机制的不同输出层解耦。
  5. 父节点 34 在 A 半 ~62.3 是尖锐局部最优:17 个新配置(5 个 EIGPROJ k 档 + 12 个备选)无一超过 +0.07,位移方向/幅度空间的期望收益已耗尽。
  6. RESID a-only 变体(移动合并均值)使 de_score raw 0.2857→0.1786、board 崩到 56.58,验证'保合并均值'设计(c_a=γ·n_b/(n_a+n_b), c_b=γ·n_a/(n_a+n_b))对 DE 指标的结构性保护是必要的。
mechanism_active否
下一步建议
  1. 针对 expression_change:把 ITERDIFF 的残差核扩散(η2≈2)只接到伪批量/DE 通道(如叠加 TSHIFT/PBPROJ 式校正),不动细胞级位移,尝试变现 de_score +0.036 raw 的单项收益而不伤 nbhd。
  2. 针对 cell_state+local_spatial:在已有 RESID 代码上加空间邻域条件——只坍缩在坐标上已混居的 a/b 细胞对(如 kNN 中异源占比高于阈值的细胞),试图解耦 mmd_u 收益与 nbhd 伤害。
  3. 针对 shape_scale:occupancy_dice skill 0.424 低于地板(raw 0.8086)是形状组唯一地板下单项,且未被本链任何节点触碰——可试各向异性/占据分布层面的整形(现有 aniso γ 通道),预期 8.33 分权重下 skill 0.424→0.5+ 约值 +0.6 分。

对话摘要?每个角色和大模型对话的统计:轮数、工具调用、用时、token 数和最后的回答摘录;原始记录只给路径。

只给统计和最后回答的摘录;完整对话请到原始记录位置里列出的文件看。

分析员

角色?调研员写计划、工程师改代码、分析员解读分数、审查员检查作弊。分析员 alibaba-token-plan-cn/qwen3.8-max
调用次数1 次
轮数?大模型一共回复了几轮(每轮可以调用多个工具)。3
工具调用?大模型调用读文件、执行命令等工具的次数,按工具名统计。共 3 次:bash 1、read 1、write 1
用时不到 1 分
token 数?输入 / 输出(含思考)的 token 数,来自接口返回的用量。输入 22,501 · 输出 1,422 · 思考 569
任务(第一行)分析节点 n35 的打分结果,写 ANALYSIS.json
最后的回答(摘录)
ANALYSIS.json written
原始记录位置?完整对话记录在 Spark 上的文件路径;看板不复制原始内容。/home/spark-longxinyang/vec/runs/formal/20261003-171955-search-t2-embryo-interp-chain-12h/nodes/35/analyst.jsonl 17 KB
/home/spark-longxinyang/vec/runs/formal/20261003-171955-search-t2-embryo-interp-chain-12h/nodes/35/analyst.stderr

工程师

角色工程师 alibaba-token-plan-cn/qwen3.8-max
调用次数1 次
轮数82
工具调用共 82 次:bash 55、edit 26、write 1
用时36 分
token 数输入 154,190 · 输出 22,851 · 思考 44,153
任务(第一行)按计划修改程序:相关特征子空间投影位移:去除Δ中与组织共变结构正交的分量以修复variogram
最后的回答(摘录)
All done. Final verification passed: default output bit-for-bit identical to parent 34 and to `--ablate`, vec-check ok on seeds 0/1/2, deterministic, 1.6 s runtime, CPU-only.

**做了什么**:实现 PLAN 的 EIGPROJ(扩散后 Δ' 投影到相关核前 k 特征子空间,k=25–200 五档)并按 PLAN 判据证否——retention 0.94–0.98(远超证据带上限 0.95)、variogram raw 仅动 ≤0.0001(要求 ≥0.0005)、board 最好 +0.07(噪声内);根因是 (I+ηC) 与 V_kV_kᵀ 可交换,扩散已把 Δ 集中到同一特征空间,投影结构性空转。随后实现 4 个针对同一弱项(cell_state)的备选机制并各证否:RESID 残余双峰坍缩(6 配置:mmd_u 0.01161→0.01081 全树最佳单项收益,但 nbhd 0.0507→0.053–0.057 一致恶化,净负;a-only 变体崩到 56.6)、ITERDIFF 残差核二遍扩散(61.90/62.30)、逐类型 ASYMPT(62.35/62.29)、within 核(61.80)。

**查分结果**:18/20 次,基线 62.36(A 半,seed 0),17 个新配置全部 ≤62.43,无一达到 +0.3 确认门槛。按 NO_CHANGE 提交,机制代码保留(默认关闭),METHOD.md 首行为 `NO_CHANGE:` 并附完整证否账目。

**下一步最值得试**:(1) ITERDIFF η2=2 下 de_score 0.2857→0.3214 是本次唯一超噪声单项收益——把残差核扩散只接到伪批量/DE 通道(不动细胞级位移)可能变现;(2) RESID 的 mmd_u 收益真实但被 nbhd 抵消——加空间邻域条件(只坍缩空间上已混居的 a/b 细胞对)或可解耦两者;(3) variogram 对类型级 Δ 方向修正完全不敏感,别再在位移方向上做文章。
原始记录位置/home/spark-longxinyang/vec/runs/formal/20261003-171955-search-t2-embryo-interp-chain-12h/nodes/35/engineer.jsonl 440 KB
/home/spark-longxinyang/vec/runs/formal/20261003-171955-search-t2-embryo-interp-chain-12h/nodes/35/engineer.stderr

调研员

角色调研员 alibaba-token-plan-cn/qwen3.8-max
调用次数1 次
轮数1
工具调用共 0 次:—
用时4 分
token 数输入 20,364 · 输出 1,190 · 思考 7,783
任务(第一行)为节点 n35(改进,父节点 n34)写改进计划 PLAN.json
最后的回答(摘录)
{
  "name": "相关特征子空间投影位移:去除Δ中与组织共变结构正交的分量以修复variogram",
  "motivation": "父节点34的variogram skill仅0.407(低于地板0.5,得分5.09/12.5),是全树最弱单项指标,说明位移管线主动破坏了基因-基因共变结构。cell_state组51.51是四组最低。节点31的相关扩散(Δ+ηCΔ)将variogram raw从0.01382降至0.01300(skill 0.391→0.407),方向正确但力度不足:加性校正保留了Δ中与C正交的分量,该分量在位移后产生虚假基因间变异。所有直接操控方差的尝试(VARISO节点17/19、共变重着色节点21)均失败,因为它们改变表达幅度而非位移方向。本方案从位移方向入手,用投影而非加性校正,是未试过的结构改动。",
  "approach": "在父节点34的相关扩散步骤之后、软权重之前,新增特征子空间投影:(1) 对括号两阶段全细胞计算基因-基因Pearson相关矩阵C(~498×498,已有);(2) 对C做特征分解,取前k个特征向量组成V_k(498×k);(3) 对每个共有类型的扩散后位移Δ'执行投影 Δ''=V_k(V_k^T·Δ'),再重归一化到||Δ'||;(4) 投影后的Δ''进入后续管线(support=0.15、w_g、λ=6、α=5、β=0.2、asym=0.85)不变。参数:k的初值与搜索范围——k∈{50,100,150,200}(498基因面板),预期最优在100-150(捕获主要共变模式但不过度约束)。vec-score快速筛选:每个k只跑seed 0,看variogram raw(目标:从0.01296降至≤0.0125)和board;若variogram raw改善≥0.0005且de_score/de_direction/neighborhood_mmd raw恶化均<0.001,再跑seed 1/2确认。单输入阶段退路:无括号对时走分层copy,投影不参与(与父节点一致)。实现注意:特征分解用numpy.linalg.eigh(对称矩阵),取绝对值最大的前k个特征值对应的特征向量;投影是矩阵乘法,498维向量×(498×k)矩阵,计算量可忽略。",
  "expected_groups": ["cell_state"],
  "risks": "1) k过小(<50)时Δ被过度约束,位移方向偏离真实时间变化,de_score/de_direction下降——Engineer应在k=50时检查de_dir raw,若<0.39则跳过更小k。2) C的顶部特征向量可能由少数高变基因主导,投影后Δ集中在这些基因上,反而加剧不均衡——检查投影后Δ的基因支持集是否仍覆盖≥30个基因。3) variogram对稀疏结构(93%零值)敏感,投影可能改变哪些基因被clip到0——检查投影后nnz比例变化,若>2%则需加nnz保护。4) 收益可能仍在噪声内(<1分)——用双seed确认,若board差<0.5则停止。",
  "family_id": "T2EI-01",
  "mechanism": "将逐类型位移向量投影到基因-基因相关矩阵的前k个特征向量张成的子空间上,移除与组织共变结构正交的分量,使位移只沿协同变化的基因程序方向推动细胞,从而保护基因-基因共变结构(variogram)。",
  "vs_constant_shift": "常数位移对型内所有细胞施加相同向量;本机制改变的是位移方向本身——通过子空间投影去除与组织共变结构不一致的分量,不同型的Δ方向不同、投影结果不同,且型内逐细胞投影加权(λ=6)进一步调制幅度。这是方向约束,不是幅度平移。",
  "mechanism_evidence": "1) variogram raw变化:父节点0.01296,目标≤0.0125(改善≥0.0005);2) 投影保留率||Δ''||/||Δ'||:应在0.6-0.95之间,过低说明k太小;3) 逐型Δ方向改变角度:arccos(Δ'·Δ''/(|Δ'||Δ''|))均值应在5°-30°,为0则投影未生效;4) de_score/de_direction raw不应下降>0.01;5) 三种子配对比较确认方向一致。",
  "mechanism_off_control": "k设为基因总数(498)或设置环境变量T2_EIGPROJ_K=0跳过投影:此时V_k·V_k^T=I,Δ''=Δ',输出与父节点34逐位一致。用--ablate mechanism触发,验证digest相同。",
  "sources": []
}
原始记录位置/home/spark-longxinyang/vec/runs/formal/20261003-171955-search-t2-embryo-interp-chain-12h/nodes/35/researcher.jsonl 5 KB
/home/spark-longxinyang/vec/runs/formal/20261003-171955-search-t2-embryo-interp-chain-12h/nodes/35/researcher.stderr

审查员

角色审查员 alibaba-token-plan-cn/qwen3.8-max
调用次数1 次
轮数17
工具调用共 20 次:bash 11、read 7、grep 1、write 1
用时2 分
token 数输入 31,494 · 输出 2,387 · 思考 2,331
任务(第一行)审查节点 n35 的程序是否越界读取、写死目标、钻评分器漏洞
最后的回答(摘录)
REVIEW.json written
原始记录位置/home/spark-longxinyang/vec/runs/formal/20261003-171955-search-t2-embryo-interp-chain-12h/nodes/35/reviewer.jsonl 130 KB
/home/spark-longxinyang/vec/runs/formal/20261003-171955-search-t2-embryo-interp-chain-12h/nodes/35/reviewer.stderr