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

总览 · ← 返回运行 20261003-093415-search-t1-r2-D-s1

节点 n23

lowrank_shape v2:协方差方向引导的型内细胞选择(不改表达)叠加组成基线(两阶段频率趋势外推 / 单输入心脏解剖先验),只改变哪些细胞被输出。

运行?一次完整的自动搜索或 Agent 会话,有自己的锁定配置和证据包。20261003-093415-search-t1-r2-D-s1
父节点n21
子节点—
操作?种子:人写的起点;改进:在父节点上改;草稿:从头写;修复:修父节点的报错。改进
状态已打分
分数搜索目标分 55.18(+4.9) · X3 52.46(+3.5) · proxy10 60.64(+7.7) · 3 次复测均分 54.65
审查未审查
用时?从运行开始到结束(或到现在)的挂钟时间。19 分
程序版本741fd36006d0e411a122efe9fc3134b89f37e5ce (programs.git)

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

来自 programs.git 741fd36006:solution/METHOD.md

lowrank_shape v2:协方差方向引导的型内细胞选择(不改表达)叠加组成基线(两阶段频率趋势外推 / 单输入心脏解剖先验),只改变哪些细胞被输出。

方法

父节点 21 证明 ΔΣ 仿射变形单调有害(mmd_u/variogram 齐降),本版按 PLAN 把协方差信息从"变换残差"改为"引导型内细胞选择",并补上单输入退路(父在 proxy10 退化为 copy_last,-10.69 分)。

组成基线(已验证杠杆,节点 3/7/13/16/20;单输入部分直接调用 src.task1_temporal.reweight):

  • 两输入阶段:逐类型频率趋势外推 f_pred = f1 + T·(f1−f0),T = min(Δt_target/Δt_input, 1.5)(T_CLIP,节点 16 的调参结论),夹到 ≥0 后归一,最大余数法分配 n_out。只用时间差,视图无关。
  • 单输入阶段:心脏解剖组成先验(heart×1.6、edge×0.25、剔 Neural Tube),来自 harness 提供的 reweight.type_weights(上一轮 run 的已验证规则,proxy 55.97)。

家族机制(lowrank_shape,选择而非变形):

  • 两阶段(X3/final):两阶段合并 top-2000 HVG、z-score、randomized SVD 取 15 PC;池化全部细胞分别用 Ledoit-Wolf 估 Σ0、Σ1,ΔΣ=Σ1−Σ0 取 |λ| top-3 特征向量 u_k;对每个有效型(两阶段各 ≥30 细胞)末阶段细胞打分 s_i = Σ_k |λ_k|·((z_i−mean_type)·u_k),权重 w_i = 1 + λ_sel·rank_norm(s_i)(λ_sel=0.3),Efraimidis-Spirakis 键做型内加权无放回抽样(配额超池时按 w 有放回)。
  • 单输入(proxy10):单阶段 15 PC;每型(≥30 细胞)Ledoit-Wolf 协方差最大特征向量为型内主变异轴(成熟度代理);轴方向用增殖签名定向(正端=增殖低=更成熟)。知识来源:分化伴随细胞周期下调是通用发育生物学知识;增殖基因表(Mki67/Top2a/Cdk1/Ccnb1/Ccnb2/Pcna/Mcm2/Mcm5/Rrm2/Birc5/Cdc20/Tk1)为通用注释,非保留阶段测量。权重 w_i = 1 + λ_mat·rank_norm(proj),λ_mat=0.3。
  • 输出全部是末阶段真实细胞的原始稀疏表达,不改任何表达值。

关闭机制对照:VEC_MECH_OFF=1 → 所有型内权重=1(同一组成配额下均匀抽取),其余流程不变。

查分结果(A 半,seed 0)

配置X3proxy10
父节点 21 提交(α=0)49.0052.98
v2 纯选择、无组成基线(λ_sel=0.3/λ_mat=0.15)48.1853.14
v2 组成基线 + 机制关54.2059.04
v2 组成基线 + 机制开(λ_sel=0.3, λ_mat=0.15)53.9359.86
v2 组成基线 + 机制开(λ_sel=0.1)53.71—
v2 组成基线 + 机制开(λ_mat=0.3,提交配置)53.9360.11

节点分(A 半估计):(2×53.93+60.11)/3 ≈ 55.99,父 50.32。

机制生效证据

  • X3:4 个有效型(IFT-CM 489、OFT/RV-CM 391、SV-CM 176、Unknown 437),w_std/mean≈0.0755(均匀时为 0);ΔΣ top-3 |λ| = 23.1/18.9/5.0。组成基线大幅改变输出:IFT-CM 配额 30.7%、Endocardium 25.8%、V-CM 16.0%(末阶段实测分别 22.5%/14.0%/8.7%),SV-CM/Endothelium 趋势降为 0。
  • proxy10:17 个型全部有权重,w_std/mean≈0.0403;成熟度轴与增殖签名的相关 −0.40~+0.63(定向后正端=低增殖)。
  • 四组分变化(开 vs 关):X3 de_score 13.25=13.25、de_direction 13.29 vs 13.28、mmd_u 17.11 vs 17.27、variogram 10.28 vs 10.40 —— 机制在 X3 上效应≈0(−0.27,噪声内);proxy10 四项全部小幅同向改善(+0.07/+0.07/+0.60/+0.09,合计 +0.82~+1.07),方向一致但幅度在 ~2 分噪声内。

验证过 / 没验证

  • 已验证:组成基线是主要增益来源(两视图各 +5 分);家族选择机制在单输入路径上有小而一致的正效应(λ_mat 0.15→0.3 单调升),在两阶段路径上中性;λ_sel 0.1/0.3 无差别。
  • 未验证:ΔΣ top-3 方向是否真是发育趋势(PLAN risks#1;选择版即使方向是噪声也只重排细胞、不放大表达,损害上限远小于父节点的仿射变形);T_CLIP=1.5 直接沿用节点 16 的调参,未在本程序上重扫;final 视图(E8.5+E9.5→E10.5,标签词汇不同)未跑过,但代码路径与 X3 相同、只用时间差和标签。
  • 确定性:所有随机来自 np.random.default_rng(seed),randomized_svd 用 random_state=seed。纯 CPU(EXECUTION.json gpu:false),X3 视图 ~10 s、proxy 视图 ~17 s,峰值内存 <4 GB。

调研员的计划

名称lowrank_shape v2:协方差方向引导的型内选择(替代仿射变换)
动机父节点 21 的正 α 仿射变换在 X3 上使 mmd_u 0.033→0.052、variogram 0.00156→0.00227(cell_state/covariation 齐降),根因是每型 133–489 细胞在 30 维下 ΔΣ 为噪声。同时 proxy10 退化为 copy_last 导致比节点 3 低 10.69 分(52.98 vs 63.66)。最弱组 de_recovery 46.67(X3 de_score skill 0.448,低于地板)。结构问题:(1) 把噪声 ΔΣ 当变换方向用,(2) 单输入无机制。修复:将协方差信息从'变换残差'改为'引导型内细胞选择',并为单输入提供基于型内协方差的成熟度选择退路。
做法步骤:
1. 读输入阶段(同父节点流程)。两阶段时:合并选 top-2000 HVG、z-score、randomized SVD 取 15 个 PC(降维减噪,父用 30)。
2. 两阶段路径(X3):
a) 全型合并估全局 ΔΣ(池化所有型细胞,有效样本量千级),取 |λ| top-3 特征向量 u1–u3 作为全局变化方向;
b) 对每个有效型(≥30 细胞),计算该型末阶段细胞在 u1–u3 上的投影得分 s_i = Σ |λ_k|·(z_i·u_k);
c) 型内加权无放回抽样:权重 w_i = 1 + λ_sel · rank_norm(s_i),λ_sel=0.3 初值(搜索 0.1–0.5),使'变化方向前端'细胞被多选;总抽样数不变(保型间组成);
d) 可选微变换(默认关):对 top-1 方向,α_micro=0.02 仿射(仅当全局 ΔΣ top-1 |λ| 超过 100 次置换 95% 分位时启用),特征值裁剪 [0.98, 1.02]。
3. 单输入路径(proxy10):
a) 单阶段 PCA(top-2000 HVG,15 PC);
b) 每型 Ledoit-Wolf 估协方差,取最大特征向量作为型内主变异轴(成熟度代理);
c) 型内加权抽样:权重偏向主变异轴正端(λ_mat=0.15 初值,搜索 0.05–0.3),模拟节点 3 的 maturity selection 但用协方差结构定义轴;
d) 若型内细胞 < 30,退化为均匀分层抽样。
4. 输出:选中细胞的原始稀疏表达,不做任何表达修改(保零值结构、保共变)。
5. 关闭机制对照:VEC_MECH_OFF=1 → 所有权重=1,退化为均匀分层抽样(= 父节点 α=0 行为)。
6. vec-score 快速筛选:先在 X3 上跑 λ_sel=0.3 一次(2 min),看 mmd_u 和 de_score 是否同向改善;再跑 proxy10 λ_mat=0.15 一次;若两组均 ≥ 父 +1 分再扫 λ 范围。
7. 内存/时间:15 PC × 2000 HVG,每步 < 500 MB;预计总运行 < 30 s。
风险1) 全局 ΔΣ top-3 方向仍可能是噪声(池化后样本量增大但不保证方向正确)——Engineer 应检查投影得分的型内分布是否有双峰/偏态,若近似对称则说明方向无信息,λ_sel 应降到 0.1 或关闭;2) 加权选择可能轻微改变型内表达分布,导致 variogram 小幅恶化——若 X3 variogram skill 降 > 0.02 则回退 λ_sel;3) 单输入成熟度轴方向可能选反(最大特征向量无方向性)——用型内基因-细胞相关或增殖签名方向确定正负;4) 总查分次数:X3 开关对照 2 次 + proxy10 对照 2 次 + λ 扫描 2–3 次 ≈ 7 次,留余量给复跑。

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

对比:父节点版本 a14a13b7fa。改动的文件:solution/METHOD.md +41 −55、solution/run.py +206 −196

diff --git a/solution/METHOD.md b/solution/METHOD.mdindex 8cf4510..0e6f758 100644--- a/solution/METHOD.md+++ b/solution/METHOD.md@@ -1,55 +1,41 @@-lowrank_shape 最小实现:Ledoit-Wolf 型内协方差低秩外推仿射变形;X3 上开/关对照显示机制单调有害(cell_state、covariation 齐降),故默认 α=0(关闭),负结果如实上报。--# lowrank_shape(节点 21,draft)--## 方法(完全按 PLAN family=lowrank_shape 实现)--1. 读全部输入阶段(`view_io.inputs_by_time`,官方面板顺序)。输出细胞 = 最后输入阶段按-   celltype 分层比例抽样到 `target_n_cells`(保组成,不改比例)。-2. ≥2 个输入阶段且 α>0 时启用机制:-   - 两阶段合并选方差 top 2500 HVG(逐块稠密计算基因矩,不整表稠密);按合并均值/方差 z-score;-   - randomized SVD(`random_state=seed`,确定性)取 30 个 PC 载荷 V(拟合每阶段最多抽 12000 细胞);-   - 有效类型 = 两阶段都有且各 ≥30 细胞的 celltype 标签(含 "Unknown";无标签场景未出现,未启用 KMeans 分支);-   - 每型:`sklearn.covariance.LedoitWolf` 估 30 维 PCA 坐标协方差 Σ0、Σ1;ΔΣ=Σ1−Σ0 特征分解,-     取 |λ| top-10 重建 ΔΣ_lr;Σ_pred = Σ1 + α·ΔΣ_lr,特征值裁剪 ≥1e-4;-     A = Σ_pred^{1/2} Σ1^{−1/2}(eigh);-   - 输出中该型细胞:z_new = mean1 + A(z−mean1),x_new = (V^T z_new + r)·sd + mu(r=原残差),夹 ≥0;-   - 非 HVG 基因、无效类型细胞:原样复制最后输入阶段。-3. 单输入阶段(proxy 视图):无 ΔΣ 可估,机制关闭,输出 = 末阶段分层子样(PLAN 步骤 7 的退路)。--参数:n_hvg=2500, n_pcs=30, k=10, min_cells=30, eigen_clip=1e-4,均按 PLAN 初值;α 见下。-知识来源:无生物学先验被写入程序(纯统计方法,不用通路/谱系/文献知识;prior/、external/ 未读取)。-视图无关:不读视图路径/文件名/board 字段,不用绝对时间(α 为常数),伪装视图下输出逐元素相同。--## 机制生效证据(α=0.3 在 X3 上,stderr JSON)--- 有效类型 4 个:IFT-CM(133/489)、OFT/RV-CM(327/391)、SV-CM(238/176)、Unknown(377/437);-  实际被修改细胞 448/652(69%,即全部属于有效类型的输出细胞)。-- ΔΣ 前 10 特征值能量占比 0.95–0.99(低秩近似充分,但也提示 ΔΣ 可能被少数方向/噪声主导)。-- 型内协方差 Frobenius 比 1.33–1.96(形状确实被改变,机制在运行)。-- 基因空间最大均值漂移 0.05–1.55 log 单位(PCA 空间均值严格不动;漂移来自夹 ≥0,SV-CM 最大)。-- 四组分变化(X3,A 半,同一 subsample 流程):-  | 配置 | de_recovery | direction | cell_state | covariation | 总分 |-  |---|---|---|---|---|---|-  | 关(α=0,=copy 末阶段子样) | 44.54 | 49.87 | 51.06 | 49.74 | 48.87 |-  | 开 α=0.1 | 44.17 | 49.87 | 38.09 | 43.38 | 43.61 |-  | 开 α=0.3 | 43.80 | 49.49 | 36.37 | 39.25 | 42.08 |-  | 开 α=0.3 + 稀疏解码(仅改原非零位) | 42.74 | 50.50 | 21.67 | 27.73 | 35.36 |-  proxy10(单输入,机制恒关):53.24。--## 结论(负结果)--机制按计划实现并确实在运行(上表证据),但方向性预测失败:正 α 外推使型内分布膨胀-(mmd_u 0.033→0.052,variogram 0.00156→0.00227),恰是 PLAN 预期改善的 cell_state、-covariation 两组单调恶化;DE 两组基本不动(均值保持符合设计);α 越小损失越小但始终为负,-且损害在 α=0.1 已大部分出现(非线性),说明主害不是解码稠密化而是协方差膨胀本身——-两阶段型内协方差差 ΔΣ 在 X3 的细胞数(每型百级)下更可能是采样噪声/技术差异而非发育趋势-(PLAN risks #1 命中)。稀疏解码变体更差,排除“稠密化破坏共变”的解释。-据此默认 α=0(同节点 18 的处理):提交程序 = 分层子样 copy_last。-复现机制:`LOWRANK_ALPHA=0.3 python run.py ...`;对照:`VEC_MECH_OFF=1`。--## 验证过 / 未验证--- 验证:proxy、X3 两视图跑通 + vec-check ok;seed 0 复跑逐元素一致(determinism);X3 开/关对照 4 组配置各 1 次查分(共 5 次查询)。-- 未验证:α<0(收缩方向)——不在 PLAN 搜索范围且等于按评分反向调参,未做;k、n_pcs 未扫(α 单调有害,扫其余超参无意义);final 视图(E8.5+E9.5 双输入,机制会启用)未跑——本节点无权访问,代码路径与 X3 相同(每阶段拟合抽样上限 12000 细胞控制内存/时间)。-- 运行时间:X3 ~40 s、proxy ~10 s,纯 CPU(EXECUTION.json gpu=false),远低于 limits。+lowrank_shape v2:协方差方向引导的型内细胞选择(不改表达)叠加组成基线(两阶段频率趋势外推 / 单输入心脏解剖先验),只改变哪些细胞被输出。++## 方法++父节点 21 证明 ΔΣ 仿射变形单调有害(mmd_u/variogram 齐降),本版按 PLAN 把协方差信息从"变换残差"改为"引导型内细胞选择",并补上单输入退路(父在 proxy10 退化为 copy_last,-10.69 分)。++**组成基线**(已验证杠杆,节点 3/7/13/16/20;单输入部分直接调用 `src.task1_temporal.reweight`):+- 两输入阶段:逐类型频率趋势外推 `f_pred = f1 + T·(f1−f0)`,`T = min(Δt_target/Δt_input, 1.5)`(T_CLIP,节点 16 的调参结论),夹到 ≥0 后归一,最大余数法分配 n_out。只用时间差,视图无关。+- 单输入阶段:心脏解剖组成先验(heart×1.6、edge×0.25、剔 Neural Tube),来自 harness 提供的 `reweight.type_weights`(上一轮 run 的已验证规则,proxy 55.97)。++**家族机制(lowrank_shape,选择而非变形)**:+- 两阶段(X3/final):两阶段合并 top-2000 HVG、z-score、randomized SVD 取 15 PC;池化全部细胞分别用 Ledoit-Wolf 估 Σ0、Σ1,ΔΣ=Σ1−Σ0 取 |λ| top-3 特征向量 u_k;对每个有效型(两阶段各 ≥30 细胞)末阶段细胞打分 `s_i = Σ_k |λ_k|·((z_i−mean_type)·u_k)`,权重 `w_i = 1 + λ_sel·rank_norm(s_i)`(λ_sel=0.3),Efraimidis-Spirakis 键做型内加权无放回抽样(配额超池时按 w 有放回)。+- 单输入(proxy10):单阶段 15 PC;每型(≥30 细胞)Ledoit-Wolf 协方差最大特征向量为型内主变异轴(成熟度代理);轴方向用增殖签名定向(正端=增殖低=更成熟)。**知识来源**:分化伴随细胞周期下调是通用发育生物学知识;增殖基因表(Mki67/Top2a/Cdk1/Ccnb1/Ccnb2/Pcna/Mcm2/Mcm5/Rrm2/Birc5/Cdc20/Tk1)为通用注释,非保留阶段测量。权重 `w_i = 1 + λ_mat·rank_norm(proj)`,λ_mat=0.3。+- 输出全部是末阶段真实细胞的原始稀疏表达,不改任何表达值。++**关闭机制对照**:`VEC_MECH_OFF=1` → 所有型内权重=1(同一组成配额下均匀抽取),其余流程不变。++## 查分结果(A 半,seed 0)++| 配置 | X3 | proxy10 |+|---|---|---|+| 父节点 21 提交(α=0) | 49.00 | 52.98 |+| v2 纯选择、无组成基线(λ_sel=0.3/λ_mat=0.15) | 48.18 | 53.14 |+| v2 组成基线 + 机制关 | 54.20 | 59.04 |+| v2 组成基线 + 机制开(λ_sel=0.3, λ_mat=0.15) | 53.93 | 59.86 |+| v2 组成基线 + 机制开(λ_sel=0.1) | 53.71 | — |+| v2 组成基线 + 机制开(λ_mat=0.3,提交配置) | 53.93 | 60.11 |++节点分(A 半估计):(2×53.93+60.11)/3 ≈ 55.99,父 50.32。++## 机制生效证据++- X3:4 个有效型(IFT-CM 489、OFT/RV-CM 391、SV-CM 176、Unknown 437),w_std/mean≈0.0755(均匀时为 0);ΔΣ top-3 |λ| = 23.1/18.9/5.0。组成基线大幅改变输出:IFT-CM 配额 30.7%、Endocardium 25.8%、V-CM 16.0%(末阶段实测分别 22.5%/14.0%/8.7%),SV-CM/Endothelium 趋势降为 0。+- proxy10:17 个型全部有权重,w_std/mean≈0.0403;成熟度轴与增殖签名的相关 −0.40~+0.63(定向后正端=低增殖)。+- 四组分变化(开 vs 关):X3 de_score 13.25=13.25、de_direction 13.29 vs 13.28、mmd_u 17.11 vs 17.27、variogram 10.28 vs 10.40 —— 机制在 X3 上效应≈0(−0.27,噪声内);proxy10 四项全部小幅同向改善(+0.07/+0.07/+0.60/+0.09,合计 +0.82~+1.07),方向一致但幅度在 ~2 分噪声内。++## 验证过 / 没验证++- 已验证:组成基线是主要增益来源(两视图各 +5 分);家族选择机制在单输入路径上有小而一致的正效应(λ_mat 0.15→0.3 单调升),在两阶段路径上中性;λ_sel 0.1/0.3 无差别。+- 未验证:ΔΣ top-3 方向是否真是发育趋势(PLAN risks#1;选择版即使方向是噪声也只重排细胞、不放大表达,损害上限远小于父节点的仿射变形);T_CLIP=1.5 直接沿用节点 16 的调参,未在本程序上重扫;final 视图(E8.5+E9.5→E10.5,标签词汇不同)未跑过,但代码路径与 X3 相同、只用时间差和标签。+- 确定性:所有随机来自 `np.random.default_rng(seed)`,randomized_svd 用 `random_state=seed`。纯 CPU(EXECUTION.json gpu:false),X3 视图 ~10 s、proxy 视图 ~17 s,峰值内存 <4 GB。diff --git a/solution/run.py b/solution/run.pyindex 54d81e8..3148a00 100644--- a/solution/run.py+++ b/solution/run.py@@ -1,15 +1,31 @@-"""lowrank_shape: Ledoit-Wolf shrinkage covariance low-rank extrapolation.--Family: lowrank_shape (PLAN). Mechanism: within each valid cell type, estimate-stage-0/stage-1 covariance of the 30-d PCA coordinates (Ledoit-Wolf shrinkage),-take the top-k low-rank part of dSigma = Sigma1 - Sigma0, extrapolate-Sigma_pred = Sigma1 + alpha * dSigma_lr, and map stage-1 cells by the affine-shape transform A = Sigma_pred^(1/2) Sigma1^(-1/2) centered at the type mean.-Means are unchanged; only the within-type distribution shape changes.-Single input stage: no dSigma available -> mechanism off, output = copy of the-last input stage (subsampled).--Control switch: env VEC_MECH_OFF=1 forces alpha=0 (identity transform).+"""lowrank_shape v2: covariance-direction-guided within-type cell selection+on top of a data-driven composition base.++Family: lowrank_shape (PLAN). Family mechanism: use low-rank covariance+structure to *score and select* which last-stage cells enter the output+(parent node 21 showed the affine shape deformation itself monotonically+harms mmd_u/variogram). No cell's expression is modified.++Base composition (proven lever, nodes 3/13/16/20, src.task1_temporal.reweight):+- two input stages: per-type frequency trend extrapolation+  f_pred = f1 + T*(f1 - f0), T = min(dt_target/dt_input, 1.5), clipped >= 0.+- single input stage: heart-dissection anatomical prior (heart types x1.6,+  edge types x0.25, Neural Tube dropped) from reweight.type_weights.++Family mechanism (selection within each type):+- two stages: pooled Ledoit-Wolf Sigma0/Sigma1 in shared 15-d PCA space,+  dSigma top-3 |eigen| directions u_k; per valid type (>=30 cells both+  stages) score s_i = sum_k |lam_k| * ((z_i - mean_type) . u_k), weights+  w_i = 1 + lambda_sel * rank_norm(s_i); weighted sampling w/o replacement.+- single stage: per type Ledoit-Wolf covariance in 15-d PCA, top+  eigenvector = dominant within-type axis, oriented so that its positive+  end has lower proliferation-signature score (general developmental+  knowledge: differentiation down-regulates cell cycle); weights+  w_i = 1 + lambda_mat * rank_norm(proj_i).++Control: env VEC_MECH_OFF=1 -> all within-type weights 1 (uniform take+within the same composition quotas; isolates the family mechanism).+Env knobs: LAM_SEL (0.3), LAM_MAT (0.15), T_CLIP (1.5). """  from __future__ import annotations@@ -25,37 +41,33 @@ from scipy import sparse  sys.path.insert(0, str(Path(__file__).resolve().parent)) -from src.task1_temporal import view_io  # noqa: E402  (harness puts modeling/ on PYTHONPATH)--N_HVG = 2500-N_PCS = 30-# PLAN initial alpha = 0.3. On/off control on X3 (weight 2): alpha=0.3 -> 42.08,-# alpha=0.1 -> 43.61, off (alpha=0) -> 48.87; cell_state and covariation (the two-# groups the mechanism targets) both got monotonically worse with alpha.-# Negative result: default 0.0 (same policy as node 18). Re-enable for tests with-# env LOWRANK_ALPHA=0.3; env VEC_MECH_OFF=1 forces the identity control.-ALPHA = 0.0-K_LOW_RANK = 10+from src.task1_temporal import view_io  # noqa: E402+from src.task1_temporal import reweight  # noqa: E402++N_HVG = 2000+N_PCS = 15+LAM_SEL = 0.3+LAM_MAT = 0.3+T_CLIP = 1.5 MIN_CELLS_PER_TYPE = 30-EIGEN_CLIP = 1e-4 FIT_CAP_PER_STAGE = 12000+PROLIF_GENES = ["Mki67", "Top2a", "Cdk1", "Ccnb1", "Ccnb2", "Pcna",+                "Mcm2", "Mcm5", "Rrm2", "Birc5", "Cdc20", "Tk1"]   def log(obj):     print(json.dumps(obj), file=sys.stderr, flush=True)  -def gene_moments(adatas):-    """Per-gene mean and E[x^2] over the concatenation of stages (chunked)."""-    n_genes = adatas[0].shape[1]+def gene_moments(Xs):+    n_genes = Xs[0].shape[1]     s = np.zeros(n_genes, dtype=np.float64)     s2 = np.zeros(n_genes, dtype=np.float64)     n = 0-    for a in adatas:-        X = (a.X if hasattr(a, "X") else a).tocsr()+    for X in Xs:+        X = X.tocsr()         for i0 in range(0, X.shape[0], 2048):-            B = X[i0:i0 + 2048]-            Bd = np.asarray(B.todense(), dtype=np.float64)+            Bd = np.asarray(X[i0:i0 + 2048].todense(), dtype=np.float64)             s += Bd.sum(axis=0)             s2 += (Bd * Bd).sum(axis=0)             n += Bd.shape[0]@@ -64,53 +76,53 @@ def gene_moments(adatas):     return mean, var  -def stratified_subsample(labels, n_out, rng):-    """Proportional stratified sample of row indices, deterministic given rng."""-    n = len(labels)-    if n_out >= n:-        return np.arange(n)-    idx = []-    types = np.unique(labels)-    quotas = {}-    acc = 0.0-    for t in types:-        c = int((labels == t).sum())-        q = int(np.floor(c * n_out / n))-        acc += c * n_out / n - q-        quotas[t] = q-    # distribute leftover by largest fractional remainder, deterministic order-    rem = n_out - sum(quotas.values())-    frac = []-    for t in types:-        c = int((labels == t).sum())-        frac.append((-(c * n_out / n - np.floor(c * n_out / n)), t))-    frac.sort()-    for _, t in frac[:rem]:-        quotas[t] += 1-    for t in types:-        rows = np.flatnonzero(labels == t)-        q = min(quotas[t], len(rows))-        if q > 0:-            idx.append(np.sort(rng.choice(rows, size=q, replace=False)))-    return np.sort(np.concatenate(idx)) if idx else np.arange(0)---def mat_sqrt_parts(S, floor):-    """eigh-based: return (U, sqrt(eig clipped at floor)) for S PSD-ish."""-    w, U = np.linalg.eigh((S + S.T) / 2.0)-    w = np.maximum(w, floor)-    return U, np.sqrt(w)---def lowrank_extrapolate(S0, S1, alpha, k):-    dS = S1 - S0-    w, U = np.linalg.eigh((dS + dS.T) / 2.0)-    order = np.argsort(-np.abs(w))-    keep = order[:k]-    dS_lr = (U[:, keep] * w[keep]) @ U[:, keep].T-    S_pred = S1 + alpha * dS_lr-    energy = float(w[keep] ** 2 @ np.ones(len(keep)) / max((w ** 2).sum(), 1e-12))-    return S_pred, energy+def fit_pca(adatas, fit_idx, seed):+    from sklearn.utils.extmath import randomized_svd+    gmean, gvar = gene_moments([a.X[fit_idx[i]] for i, a in enumerate(adatas)])+    hvg = np.argsort(-gvar)[:N_HVG]+    hvg = hvg[gvar[hvg] > 1e-12]+    mu = gmean[hvg]+    sd = np.maximum(np.sqrt(gvar[hvg]), 1e-8)+    Z = []+    for i, a in enumerate(adatas):+        B = np.asarray(a.X[fit_idx[i]][:, hvg].todense(), dtype=np.float32)+        Z.append((B.astype(np.float64) - mu) / sd)+    Z = np.vstack(Z)+    Z -= Z.mean(axis=0, keepdims=True)+    n_pcs = int(min(N_PCS, Z.shape[0] - 1, Z.shape[1] - 1))+    _, _, Vt = randomized_svd(Z, n_components=n_pcs, n_oversamples=20,+                              random_state=seed)+    return hvg, mu, sd, Vt.T.copy()+++def to_coords(X, hvg, mu, sd, V):+    B = np.asarray(X[:, hvg].todense(), dtype=np.float32).astype(np.float64)+    return ((B - mu) / sd) @ V+++def rank_norm(s):+    n = len(s)+    if n <= 1:+        return np.zeros(n)+    order = np.argsort(s, kind="stable")+    r = np.empty(n, dtype=np.float64)+    r[order] = np.arange(n, dtype=np.float64)+    return r / (n - 1)+++def weighted_take(X, rows, k, w, rng):+    if rows.size == 0 or k <= 0:+        return None+    if k > rows.size:+        p = None+        if w is not None:+            p = np.maximum(w, 1e-9)+            p = p / p.sum()+        return X[rng.choice(rows, size=k, replace=True, p=p)]+    if w is None:+        return X[rng.choice(rows, size=k, replace=False)]+    keys = -np.log(np.maximum(rng.random(rows.size), 1e-12)) / np.maximum(w, 1e-9)+    return X[rows[np.argsort(keys, kind="stable")[:k]]]   def main():@@ -120,136 +132,134 @@ def main():     ap.add_argument("--seed", type=int, required=True)     args = ap.parse_args() -    view = args.data     rng = np.random.default_rng(args.seed)-    manifest = view_io.load_manifest(view)-    genes = view_io.panel_genes(view, manifest)-    n_panel = len(genes)+    manifest = view_io.load_manifest(args.data)+    genes = view_io.panel_genes(args.data, manifest)      mech_off = os.environ.get("VEC_MECH_OFF", "0") == "1"-    alpha = 0.0 if mech_off else float(os.environ.get("LOWRANK_ALPHA", ALPHA))+    lam_sel = 0.0 if mech_off else float(os.environ.get("LAM_SEL", LAM_SEL))+    lam_mat = 0.0 if mech_off else float(os.environ.get("LAM_MAT", LAM_MAT))+    t_clip = float(os.environ.get("T_CLIP", T_CLIP))      inputs = view_io.inputs_by_time(manifest)-    a_last = view_io.read_stage(view, inputs[-1], genes, missing="fill")+    a_last = view_io.read_stage(args.data, inputs[-1], genes, missing="fill")     labels_last = view_io.labels_of(a_last)     n_out = view_io.target_n_cells(manifest, a_last.n_obs, cap=manifest["max_cells"])-    out_rows = stratified_subsample(labels_last, n_out, rng)+    X = a_last.X.tocsr() -    two_stage = len(inputs) >= 2 and alpha > 0.0-    X_out = a_last.X.tocsr()[out_rows]+    two_stage = len(inputs) >= 2+    stats = {"path": "two_stage" if two_stage else "single_stage",+             "mech_off": mech_off, "lam_sel": lam_sel, "lam_mat": lam_mat}+    weights = {}   # type -> weight array over that type's rows in a_last      if two_stage:-        a_prev = view_io.read_stage(view, inputs[-2], genes, missing="fill")+        a_prev = view_io.read_stage(args.data, inputs[-2], genes, missing="fill")         labels_prev = view_io.labels_of(a_prev)-        adatas = [a_prev, a_last]--        # PCA fit on subsamples of both stages-        fit_idx = []-        for a in adatas:-            r = np.random.default_rng(args.seed + 7)-            if a.n_obs > FIT_CAP_PER_STAGE:-                fit_idx.append(r.choice(a.n_obs, size=FIT_CAP_PER_STAGE, replace=False))-            else:-                fit_idx.append(np.arange(a.n_obs))--        gmean, gvar = gene_moments([a.X[fit_idx[i]] for i, a in enumerate(adatas)])-        hvg = np.argsort(-gvar)[:N_HVG]-        hvg = hvg[gvar[hvg] > 1e-12]-        mu = gmean[hvg]-        sd = np.sqrt(gvar[hvg])-        sd = np.maximum(sd, 1e-8)--        # z-scored stacked fit matrix-        Zfit = []-        for i, a in enumerate(adatas):-            B = np.asarray(a.X[fit_idx[i]][:, hvg].todense(), dtype=np.float32)-            Zfit.append((B - mu) / sd)-        Zfit = np.vstack(Zfit).astype(np.float64)-        Zfit -= Zfit.mean(axis=0, keepdims=True)-        # randomized SVD -> loadings V (n_hvg x n_pcs), deterministic-        from sklearn.utils.extmath import randomized_svd-        n_pcs = int(min(N_PCS, Zfit.shape[0] - 1, Zfit.shape[1] - 1))-        _, _, Vt = randomized_svd(Zfit, n_components=n_pcs, n_oversamples=20,-                                  random_state=args.seed)-        V = Vt.T.copy()-        del Zfit, Vt--        def coords(X_hvg_dense):-            Zc = (X_hvg_dense - mu) / sd-            return Zc @ V, Zc--        # valid types: >= MIN_CELLS in both stages-        types = sorted(set(labels_prev) & set(labels_last))-        valid = [t for t in types-                 if int((labels_prev == t).sum()) >= MIN_CELLS_PER_TYPE-                 and int((labels_last == t).sum()) >= MIN_CELLS_PER_TYPE]--        from sklearn.covariance import LedoitWolf--        Z1_all = np.asarray(a_last.X[:, hvg].todense(), dtype=np.float32).astype(np.float64)-        Z0_all = np.asarray(a_prev.X[:, hvg].todense(), dtype=np.float32).astype(np.float64)-        z1_all, Zc1_all = coords(Z1_all)-        z0_all, _ = coords(Z0_all)-        del Z0_all, Z1_all--        new_hvg = np.asarray(X_out[:, hvg].todense(), dtype=np.float32).astype(np.float64)-        out_labels = labels_last[out_rows]-        stats = {"types": {}, "n_cells_changed": 0}--        for t in valid:-            m0 = labels_prev == t-            m1 = labels_last == t-            S0 = LedoitWolf().fit(z0_all[m0]).covariance_-            S1 = LedoitWolf().fit(z1_all_t := z1_all[m1]).covariance_-            mean1 = z1_all_t.mean(axis=0)-            S_pred, energy = lowrank_extrapolate(S0, S1, alpha, K_LOW_RANK)-            Up, sp = mat_sqrt_parts(S_pred, EIGEN_CLIP)-            U1, s1 = mat_sqrt_parts(S1, 1e-6)-            A = (Up * sp) @ Up.T @ (U1 * (1.0 / s1)[None, :]) @ U1.T--            rows_out = np.flatnonzero(out_labels == t)-            if rows_out.size == 0:-                continue-            z = z1_all[rows_out]-            r = ((Zc1_all[rows_out]) - z @ V.T)-            z_new = mean1 + (z - mean1) @ A.T-            Zc_new = z_new @ V.T + r-            recon = np.maximum(Zc_new * sd + mu, 0.0)-            if os.environ.get("DECODE_SPARSE", "0") == "1":-                orig = new_hvg[rows_out]-                recon = np.where(orig > 0, recon, 0.0)-            new_hvg[rows_out] = recon-            stats["n_cells_changed"] += int(rows_out.size)--            # evidence: mean shift in gene space (should be tiny), cov Frobenius ratio-            x_old = np.asarray(a_last.X[rows_out][:, hvg].todense(), dtype=np.float64)-            x_new = new_hvg[rows_out]-            mean_shift = float(np.abs(x_new.mean(0) - x_old.mean(0)).max())-            zt = z - mean1-            cov_emp_after = (zt @ A.T).T @ (zt @ A.T) / max(zt.shape[0] - 1, 1)-            frob_ratio = float(np.linalg.norm(cov_emp_after) / max(np.linalg.norm(S1), 1e-12))-            stats["types"][t] = {-                "n0": int(m0.sum()), "n1": int(m1.sum()),-                "dS_topk_energy": round(energy, 3),-                "max_abs_mean_shift_genespace": round(mean_shift, 4),-                "cov_frob_ratio_vs_S1": round(frob_ratio, 3),-            }-        log({"mechanism": "lowrank_shape", "alpha": alpha, "k": K_LOW_RANK,-             "n_valid_types": len(valid), "stats": stats})--        # rebuild output matrix with modified HVG columns-        hvg_block = sparse.csr_matrix(np.asarray(new_hvg, dtype=np.float32))-        non_hvg_mask = np.ones(n_panel, dtype=bool)-        non_hvg_mask[hvg] = False-        non_hvg_idx = np.flatnonzero(non_hvg_mask)-        combined = sparse.hstack([X_out[:, non_hvg_idx].tocsc(), hvg_block.tocsc()]).tocsc()-        cols = np.concatenate([non_hvg_idx, hvg])-        inv = np.argsort(cols)-        X_out = combined[:, inv].tocsr()+        t_prev, t_last, t_tgt = inputs[-2]["time"], inputs[-1]["time"], manifest["target"]["time"]+        dt_in = t_last - t_prev+        T = min((t_tgt - t_last) / dt_in, t_clip) if dt_in > 0 else 0.0+        stats["T"] = round(float(T), 3)++        # ---- composition base: frequency trend extrapolation ----+        types = [str(t) for t in np.unique(labels_last)]+        n0, n1 = len(labels_prev), len(labels_last)+        f1 = np.array([(labels_last == t).sum() for t in types], dtype=np.float64) / n1+        f0 = np.array([(labels_prev == t).sum() for t in types], dtype=np.float64) / n0+        fpred = np.clip(f1 + T * (f1 - f0), 0.0, None)+        fpred /= max(fpred.sum(), 1e-12)+        alloc = reweight.largest_remainder(fpred, n_out)+        stats["alloc_frac"] = {t: round(float(a / max(n_out, 1)), 3)+                               for t, a in zip(types, alloc) if a > 0}++        # ---- family mechanism: pooled covariance-change directions ----+        if lam_sel > 0.0:+            fit_rng = np.random.default_rng(args.seed + 7)+            fit_idx = [np.arange(a.n_obs) if a.n_obs <= FIT_CAP_PER_STAGE else+                       fit_rng.choice(a.n_obs, size=FIT_CAP_PER_STAGE, replace=False)+                       for a in (a_prev, a_last)]+            hvg, mu, sd, V = fit_pca([a_prev, a_last], fit_idx, args.seed)+            Z0 = to_coords(a_prev.X, hvg, mu, sd, V)+            Z1 = to_coords(a_last.X, hvg, mu, sd, V)+            del a_prev+            from sklearn.covariance import LedoitWolf+            S0 = LedoitWolf().fit(Z0).covariance_+            S1 = LedoitWolf().fit(Z1).covariance_+            dS = (S1 - S0)+            dS = (dS + dS.T) / 2.0+            lam, U = np.linalg.eigh(dS)+            order = np.argsort(-np.abs(lam))[:3]+            U3, lam3 = U[:, order], np.abs(lam[order])+            stats["global_dS_top3_abs_eig"] = [round(float(x), 3) for x in lam3]+            valid = [t for t in types+                     if int((labels_prev == t).sum()) >= MIN_CELLS_PER_TYPE+                     and int((labels_last == t).sum()) >= MIN_CELLS_PER_TYPE]+            for t in valid:+                rows = np.flatnonzero(labels_last == t)+                zc = Z1[rows] - Z1[rows].mean(axis=0, keepdims=True)+                s = (zc @ U3) @ lam3+                w = 1.0 + lam_sel * rank_norm(s)+                weights[t] = w+                stats["types"] = stats.get("types", {})+                stats["types"][t] = {"n": int(rows.size),+                                     "w_std_over_mean": round(float(w.std() / w.mean()), 4)}     else:-        log({"mechanism": "lowrank_shape", "alpha": 0.0, "note": "single input or mech off: copy last stage"})--    view_io.write_prediction(X_out.tocsr(), genes, args.out, seed=args.seed)+        # ---- composition base: heart anatomical prior (proven, reweight.py) ----+        types = [str(t) for t in np.unique(labels_last) if str(t) not in reweight.DROP_TYPES]+        counts = np.array([(labels_last == t).sum() for t in types], dtype=np.float64)+        w_types = reweight.type_weights(types, reweight.HEART_WEIGHT, reweight.EDGE_WEIGHT)+        alloc = reweight.largest_remainder(counts * w_types, n_out)++        # ---- family mechanism: within-type maturity axis ----+        if lam_mat > 0.0:+            fit_rng = np.random.default_rng(args.seed + 7)+            n = a_last.n_obs+            fit_idx = [np.arange(n) if n <= FIT_CAP_PER_STAGE else+                       fit_rng.choice(n, size=FIT_CAP_PER_STAGE, replace=False)]+            hvg, mu, sd, V = fit_pca([a_last], fit_idx, args.seed)+            Z1 = to_coords(a_last.X, hvg, mu, sd, V)+            gene_index = {g: i for i, g in enumerate(genes)}+            pg = [gene_index[g] for g in PROLIF_GENES if g in gene_index]+            stats["n_prolif_genes_found"] = len(pg)+            if pg:+                P = np.asarray(a_last.X[:, pg].todense(), dtype=np.float64)+                prolif = ((P - P.mean(axis=0)) / np.maximum(P.std(axis=0), 1e-8)).mean(axis=1)+            else:+                prolif = np.zeros(n)+            from sklearn.covariance import LedoitWolf+            stats["types"] = {}+            for t in types:+                rows = np.flatnonzero(labels_last == t)+                if rows.size < MIN_CELLS_PER_TYPE:+                    continue+                Zt = Z1[rows]+                Zc = Zt - Zt.mean(axis=0, keepdims=True)+                S = LedoitWolf().fit(Zc).covariance_+                lam, U = np.linalg.eigh((S + S.T) / 2.0)+                u = U[:, int(np.argmax(lam))]+                proj = Zc @ u+                p = prolif[rows]+                c = float(np.corrcoef(proj, p)[0, 1]) if proj.std() > 1e-9 and p.std() > 1e-9 else 0.0+                if np.isfinite(c) and c > 0:+                    proj = -proj+                w = 1.0 + lam_mat * rank_norm(proj)+                weights[t] = w+                stats["types"][t] = {"n": int(rows.size), "corr_axis_prolif": round(c, 3),+                                     "w_std_over_mean": round(float(w.std() / w.mean()), 4)}++    blocks = []+    for t, k in zip(types, alloc):+        k = int(k)+        if k <= 0:+            continue+        rows = np.flatnonzero(labels_last == t)+        B = weighted_take(X, rows, k, weights.get(t), rng)+        if B is not None:+            blocks.append(B)+    X_out = sparse.vstack(blocks, format="csr").astype(np.float32)+    X_out.eliminate_zeros()+    log(stats)++    view_io.write_prediction(X_out, genes, args.out, seed=args.seed)     log({"n_cells": int(X_out.shape[0]), "nnz": int(X_out.nnz), "out": args.out})  

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

用到的知识库条目

编号标题出处
k041Within-stage pseudotime and graph toolkit offline: scanpy DPT/PAGA/Leiden, Palantir, CellRank 210.1186/s13059-019-1663-x (PAGA); 10.1038/s41587-019-0068-4 (Palantir); 10.1038/s41592-024-02303-9 (CellRank 2)
k031Offline OT toolkit in the sandbox: moscot TemporalProblem, wot OTModel, POT, geomloss10.1038/s41586-024-08453-2 (moscot); 10.1016/j.cell.2019.01.006 (Waddington-OT)
k018Damped per-type shift: shrinkage alpha on the observed deltanotes/plan/cards/T1.md

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

改了什么把父节点的 ΔΣ 仿射变形换成两层:(1) 组成基线——两阶段用逐型频率趋势外推 f1+T·(f1−f0)(T≤1.5),单输入用心脏解剖先验(调 src.task1_temporal.reweight);(2) 家族机制——15-PC 空间池化 Ledoit-Wolf 协方差的 ΔΣ top-3 方向(单输入用型内最大特征向量、增殖签名定向)给型内细胞打分做加权抽样(λ_sel=0.3、λ_mat=0.3),输出全是末阶段真实细胞的原始表达,不改任何表达值。
各组分数的变化cell_state:变好 +6.31(51.56→57.87):proxy10 mmd_u 0.03999→0.03181、得分 +2.97;X3 mmd_u 0.03177→0.02814、+1.35。与简报事实 5 一致:组成改动与真实变化同向时四项齐升,mmd_u 收益最大。
covariation:小幅变好 +2.00(49.95→51.95):proxy10 variogram 0.001203→0.001064、得分 +0.85;X3 +0.17(在噪声内)。只重排真实细胞、不改表达,共变结构未受损。
de_recovery:变好 +4.99(46.67→51.66):proxy10 de_score 原始值 0.0126→0.1619、得分 +1.36;X3 -0.169→-0.013、+1.19。按 Engineer 的开/关对照,增益主要来自组成基线而非家族选择机制。
direction:变好 +5.28(52.79→58.07):proxy10 de_direction 原始值 0.1745→0.3239、得分 +2.47;X3 -0.0011→0.0725、+0.745。同样主要由组成基线贡献。
family_idlowrank_shape
假设是否成立unclear
经验
  1. 在单输入路径退化为 copy_last 的程序上,补一个已验证的组成先验(本例心脏解剖 reweight:heart×1.6、edge×0.25、剔 Neural Tube)可使 proxy10 从 52.98 升到 60.11,是当前最可靠的单视图杠杆。
  2. 两阶段路径上,逐型频率趋势外推(T=min(Δt_target/Δt_input,1.5))在 X3 带来约 +5 分且四项同向改善,重现了'组成变化同向即有效'的规律;押错方向会四项齐降,故只适用于有真实时间差的输入。
  3. 把低秩协方差信息从'仿射变形残差'改为'型内选择权重'后,即使 ΔΣ 方向仍是噪声,损害上限也很小(选择只重排真实细胞,X3 开/关差 −0.27,在噪声内),不会像父节点变形版那样使 mmd_u/variogram 崩坏——这是安全但收益未证实的形态。
  4. 家族机制的开/关差在两视图都在 T1≈2 分噪声内(X3 −0.27、proxy10 +0.8~1.1),+4.86 的榜分增益应归因于组成基线;没有开/关对照就会把 reweight 收益误记到 lowrank_shape 头上。
  5. proxy10 上 λ_mat 0.15→0.3 单调 +0.8(59.04→59.86→60.11),提示增殖签名定向的成熟度选择方向可能对,但幅度需更大 λ 或更强轴定义才能超出噪声;λ_sel 0.1/0.3 无差别。
mechanism_activeunclear
下一步建议
  1. 针对 X3/final(两阶段):用节点 22 的生长/OT 组成权重替代频率趋势外推做基线(节点 22 X3 57.73 vs 本节点 52.46),并在本程序上重扫 T_CLIP(1.0/1.5/2.0)确认 1.5 是否仍最优。
  2. 针对 proxy10(单输入,de_recovery/cell_state):λ_mat 从 0.3 扩到 0.5–0.8,并把成熟度轴从'型内协方差最大特征向量+增殖签名定向'改为直接对每细胞算增殖签名得分做权重,检验选择效应能否超出 2 分噪声。
  3. 针对两阶段选择机制:先做 PLAN 步骤 2d 的置换检验(ΔΣ top-3 |λ| 对比 100 次置换 95% 分位),不显著时直接 λ_sel=0,把查分配额留给组成基线的调参。

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

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

分析员

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

工程师

角色工程师 alibaba-token-plan-cn/qwen3.8-max
调用次数1 次
轮数21
工具调用共 30 次:bash 22、write 3、edit 3、read 2
用时14 分
token 数输入 58,988 · 输出 14,064 · 思考 10,034
任务(第一行)按计划修改程序:lowrank_shape v2:协方差方向引导的型内选择(替代仿射变换)
最后的回答(摘录)
完成。提交配置 = 组成基线(两阶段频率趋势外推 T≤1.5 / 单输入心脏解剖先验)+ lowrank_shape 家族机制(协方差方向型内加权选择,λ_sel=0.3、λ_mat=0.3,不改表达),最终预测与已查分文件逐字节一致,两视图 vec-check 通过。

- 查分(A 半,seed 0,用 9/20 次):X3 49.00→53.93,proxy10 52.98→60.11,节点分 ≈55.99(父 50.32)。
- 开/关对照:增益主要来自组成基线(两视图各 +5);家族选择机制 proxy10 +0.8~+1.1(一致正向、噪声内)、X3 ≈0(-0.27,噪声内),已如实写入 METHOD.md。
- 下一步最值得试:X3 上用生长/OT 权重(节点 22 的 X3 57.73)替代频率趋势外推做组成基线,并在两阶段路径检验 ΔΣ 方向显著性后再启用选择。
原始记录位置/home/spark-longxinyang/vec/runs/formal/20261003-093415-search-t1-r2-D-s1/nodes/23/engineer.jsonl 137 KB
/home/spark-longxinyang/vec/runs/formal/20261003-093415-search-t1-r2-D-s1/nodes/23/engineer.stderr

调研员

角色调研员 alibaba-token-plan-cn/qwen3.8-max
调用次数1 次
轮数1
工具调用共 0 次:—
用时2 分
token 数输入 21,291 · 输出 1,521 · 思考 5,251
任务(第一行)为节点 n23(改进,父节点 n21)写改进计划 PLAN.json
最后的回答(摘录)
0 HVG、z-score、randomized SVD 取 15 个 PC(降维减噪,父用 30)。\n2. 两阶段路径(X3):\n  a) 全型合并估全局 ΔΣ(池化所有型细胞,有效样本量千级),取 |λ| top-3 特征向量 u1–u3 作为全局变化方向;\n  b) 对每个有效型(≥30 细胞),计算该型末阶段细胞在 u1–u3 上的投影得分 s_i = Σ |λ_k|·(z_i·u_k);\n  c) 型内加权无放回抽样:权重 w_i = 1 + λ_sel · rank_norm(s_i),λ_sel=0.3 初值(搜索 0.1–0.5),使'变化方向前端'细胞被多选;总抽样数不变(保型间组成);\n  d) 可选微变换(默认关):对 top-1 方向,α_micro=0.02 仿射(仅当全局 ΔΣ top-1 |λ| 超过 100 次置换 95% 分位时启用),特征值裁剪 [0.98, 1.02]。\n3. 单输入路径(proxy10):\n  a) 单阶段 PCA(top-2000 HVG,15 PC);\n  b) 每型 Ledoit-Wolf 估协方差,取最大特征向量作为型内主变异轴(成熟度代理);\n  c) 型内加权抽样:权重偏向主变异轴正端(λ_mat=0.15 初值,搜索 0.05–0.3),模拟节点 3 的 maturity selection 但用协方差结构定义轴;\n  d) 若型内细胞 < 30,退化为均匀分层抽样。\n4. 输出:选中细胞的原始稀疏表达,不做任何表达修改(保零值结构、保共变)。\n5. 关闭机制对照:VEC_MECH_OFF=1 → 所有权重=1,退化为均匀分层抽样(= 父节点 α=0 行为)。\n6. vec-score 快速筛选:先在 X3 上跑 λ_sel=0.3 一次(2 min),看 mmd_u 和 de_score 是否同向改善;再跑 proxy10 λ_mat=0.15 一次;若两组均 ≥ 父 +1 分再扫 λ 范围。\n7. 内存/时间:15 PC × 2000 HVG,每步 < 500 MB;预计总运行 < 30 s。",
  "expected_groups": ["cell_state", "de_recovery", "direction"],
  "risks": "1) 全局 ΔΣ top-3 方向仍可能是噪声(池化后样本量增大但不保证方向正确)——Engineer 应检查投影得分的型内分布是否有双峰/偏态,若近似对称则说明方向无信息,λ_sel 应降到 0.1 或关闭;2) 加权选择可能轻微改变型内表达分布,导致 variogram 小幅恶化——若 X3 variogram skill 降 > 0.02 则回退 λ_sel;3) 单输入成熟度轴方向可能选反(最大特征向量无方向性)——用型内基因-细胞相关或增殖签名方向确定正负;4) 总查分次数:X3 开关对照 2 次 + proxy10 对照 2 次 + λ 扫描 2–3 次 ≈ 7 次,留余量给复跑。",
  "family_id": "lowrank_shape",
  "mechanism": "用低秩协方差变化的主方向对型内细胞排序并加权选择(替代仿射变换),通过改变'哪些细胞被输出'来演化群体形状,不修改任何单个细胞的表达值。",
  "vs_constant_shift": "常数位移移动所有细胞的均值(改变表达量);本方法不改变任何细胞的表达,只改变哪些细胞被选入输出——通过协方差方向定义的选择权重改变群体的经验分布形状(方差、偏态、细胞状态位置),而非平移整个分布。",
  "mechanism_evidence": "1) 型内选择权重分布:报告 λ_sel>0 时权重 w_i 的 std/mean,若 ≈1 则机制未生效;2) 被选细胞与均匀抽样的重叠率:若 >95% 则选择无实际效果;3) 投影得分 s_i 的型内分布形状(偏度);4) X3 四组分各自变化:预期 mmd_u 改善(选到更'前进'的细胞)、de_score 改善(前端细胞表达更接近目标);5) 微变换若启用:报告实际被变换的细胞数和最大位移。",
  "mechanism_off_control": "VEC_MECH_OFF=1:所有选择权重设为 1(均匀分层抽样),微变换 α_micro=0,输出 = 父节点 α=0 的分层子样。预期差别:关闭时 X3 mmd_u/de_score 回到父节点水平(≈48.87);打开时 mmd_u 应降低(更好的细胞状态匹配)、de_score 应升高(前端细胞表达方向更对)。若开/关无差别,说明选择权重未实际改变输出组成。",
  "sources": []
}
原始记录位置/home/spark-longxinyang/vec/runs/formal/20261003-093415-search-t1-r2-D-s1/nodes/23/researcher.jsonl 6 KB
/home/spark-longxinyang/vec/runs/formal/20261003-093415-search-t1-r2-D-s1/nodes/23/researcher.stderr