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

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

节点 n21

lowrank_shape 最小实现:Ledoit-Wolf 型内协方差低秩外推仿射变形;X3 上开/关对照显示机制单调有害(cell_state、covariation 齐降),故默认 α=0(关闭),负结果如实上报。

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

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

来自 programs.git a14a13b7fa:solution/METHOD.md

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 流程): proxy10(单输入,机制恒关):53.24。
    配置de_recoverydirectioncell_statecovariation总分
    关(α=0,=copy 末阶段子样)44.5449.8751.0649.7448.87
    开 α=0.144.1749.8738.0943.3843.61
    开 α=0.343.8049.4936.3739.2542.08
    开 α=0.3 + 稀疏解码(仅改原非零位)42.7450.5021.6727.7335.36

结论(负结果)

机制按计划实现并确实在运行(上表证据),但方向性预测失败:正 α 外推使型内分布膨胀 (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: Ledoit-Wolf 收缩协方差低秩外推改变型内分布形状
动机当前最佳节点 7 的 covariation 53.94 和 de_recovery 52.79 是最弱两组;节点 16 covariation 仅 50.83。variogram(权重 20)奖励基因间共变结构,而已有尝试(节点 5/8/11/12)通过低维编码→基因空间解码改变表达,covariation 普遍在 42–50,说明解码过程破坏共变。节点 13 去掉表达位移后 X3 variogram 从 0.002305→0.00171(+1.64 分),证明保护原始共变结构的重要性。lowrank_shape 不改变均值(不影响 DE),只在低维空间修改型内协方差的低秩分量,然后加回原始残差,避免生成式解码的共变破坏。这是一个尚未被测试的机制方向。
做法步骤:
1. 数据准备:取两个输入阶段(E8.5、E9.5)的表达矩阵。选方差最大的 2500 个 HVG(基于合并两阶段的方差)。对 HVG 做 log1p 后按基因 z-score 标准化。对标准化后的矩阵做 PCA,保留前 30 个主成分(V 为 30×2500 载荷矩阵)。每个细胞保存 PCA 坐标 z 和基因空间残差 r = x_zscore − V^T z。
2. 细胞分组:使用输入数据中的细胞类型标签(若有)或对合并数据做 k=15 的 KMeans 聚类作为伪类型。只处理两阶段都有且每阶段 ≥ 30 个细胞的类型;其余细胞保持原值不变。
3. 收缩协方差估计(双输入路径):对每个有效类型,在 PCA 空间(30 维)分别计算两阶段的中心化坐标,用 sklearn.covariance.LedoitWolf 估计收缩协方差 Σ₀(30×30)和 Σ₁(30×30)。
4. 低秩协方差外推:ΔΣ = Σ₁ − Σ₀。对 ΔΣ 做特征分解,只保留绝对值最大的前 k=10 个特征值及对应特征向量,重建 ΔΣ_lr(低秩近似)。外推 Σ_pred = Σ₁ + α·ΔΣ_lr,α=0.3 为初始步长。对 Σ_pred 做特征值裁剪:任何 < 1e-4 的特征值替换为 1e-4,确保正定。
5. 仿射变换矩阵:A = Σ_pred^{1/2} @ Σ₁^{−1/2}(均为 30×30,通过特征分解计算矩阵平方根和逆平方根)。对 E9.5 该型的每个细胞:z_new = z_mean₁ + A @ (z − z_mean₁),其中 z_mean₁ 是该型在阶段 1 的 PCA 均值。基因空间输出:x_new_zscore = V^T z_new + r(加回原始残差),再反标准化回原始表达空间。
6. 非 HVG 基因和无效类型的细胞:直接复制最后一个输入阶段的值。
7. 单输入退路(proxy10):只有一个输入阶段时,无法估计 ΔΣ,变换取单位阵(A=I),输出 = 输入,机制完全关闭。

关键参数初值与搜索范围:
- n_hvg = 2500(固定)
- n_pcs = 30(固定)
- α(外推步长)= 0.3,搜索 [0.1, 0.5],步长 0.1;若 X3 分数下降则减小到 0.1
- k(低秩截断)= 10,搜索 [5, 15]
- min_cells = 30(每阶段每型最少细胞数)
- eigen_clip = 1e-4

vec-score 快速筛选:先在小样本(每型最多 500 细胞、500 HVG)上跑通流程,确认协方差确实被修改(Frobenius 范数变化 > 1%)。然后全量跑,用 vec-score 查分。比较 α=0(关闭)和 α=0.3(开启)的四组分差异,重点看 covariation 和 de_recovery。…
风险1. 协方差变化主要是采样噪声而非发育趋势:两阶段间型内协方差差异可能来自有限的细胞数。缓解:Ledoit-Wolf 收缩 + 低秩截断(只取前 10 个方向)+ 小步长 α=0.3。Engineer 应在小样本上先检查 ΔΣ 的特征值谱是否有明显信号(前几个特征值远大于其余),若全为噪声量级则机制可能无效。2. 仿射变换产生极端表达值:裁剪特征值后应检查输出表达的范围,若超出输入范围 3 倍标准差则触发警告。3. proxy10 上机制完全关闭,分数 ≈ copy_last(~52.75),节点分数主要依赖 X3 表现;若 X3 无改善则总分不会超过基线。4. 细胞类型分组不准确(标签缺失或聚类不当)导致协方差估计混杂不同细胞状态。Engineer 应检查每个有效类型的细胞数分布。5. PCA 残差加回后,非主成分方向的共变结构不变,可能限制了改善幅度。这是低秩约束的固有代价。

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

对比:这个提交的上一版(种子程序:相对空仓库)。改动的文件:solution/EXECUTION.json +1 −0、solution/METHOD.md +55 −0、solution/run.py +257 −0

diff --git a/solution/EXECUTION.json b/solution/EXECUTION.jsonnew file mode 100644index 0000000..9d5125c--- /dev/null+++ b/solution/EXECUTION.json@@ -0,0 +1 @@+{"gpu": false}diff --git a/solution/METHOD.md b/solution/METHOD.mdnew file mode 100644index 0000000..8cf4510--- /dev/null+++ b/solution/METHOD.md@@ -0,0 +1,55 @@+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。diff --git a/solution/run.py b/solution/run.pynew file mode 100644index 0000000..54d81e8--- /dev/null+++ b/solution/run.py@@ -0,0 +1,257 @@+"""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).+"""++from __future__ import annotations++import argparse+import json+import os+import sys+from pathlib import Path++import numpy as np+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+MIN_CELLS_PER_TYPE = 30+EIGEN_CLIP = 1e-4+FIT_CAP_PER_STAGE = 12000+++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]+    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 i0 in range(0, X.shape[0], 2048):+            B = X[i0:i0 + 2048]+            Bd = np.asarray(B.todense(), dtype=np.float64)+            s += Bd.sum(axis=0)+            s2 += (Bd * Bd).sum(axis=0)+            n += Bd.shape[0]+    mean = s / n+    var = np.maximum(s2 / n - mean * mean, 0.0)+    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 main():+    ap = argparse.ArgumentParser()+    ap.add_argument("--data", required=True)+    ap.add_argument("--out", required=True)+    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)++    mech_off = os.environ.get("VEC_MECH_OFF", "0") == "1"+    alpha = 0.0 if mech_off else float(os.environ.get("LOWRANK_ALPHA", ALPHA))++    inputs = view_io.inputs_by_time(manifest)+    a_last = view_io.read_stage(view, 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)++    two_stage = len(inputs) >= 2 and alpha > 0.0+    X_out = a_last.X.tocsr()[out_rows]++    if two_stage:+        a_prev = view_io.read_stage(view, 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()+    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)+    log({"n_cells": int(X_out.shape[0]), "nnz": int(X_out.nnz), "out": args.out})+++if __name__ == "__main__":+    main()

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

用到的知识库条目

编号标题出处
k012Official T1 scoring, output contract and adversarial controlsnotes/official/来件/virtualembryo.ai/task1-temporal.md; notes/official/来件/virtualembryo.ai/baselines.md
k032Neural ODE population dynamics from snapshots: TrajectoryNet, PRESCIENT, MIOFlow, scNODEarXiv:2002.04461 (TrajectoryNet); 10.1038/s41467-021-23518-w (PRESCIENT); arXiv:2206.14928 (MIOFlow); 10.1093/bioinformatics/btae393 (scNODE)
k010Flux Matching: learning non-score generative vector fieldsarXiv:2605.07319

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

改了什么按 PLAN 实现了 lowrank_shape(Ledoit-Wolf 型内协方差、ΔΣ top-10 低秩外推、仿射变形 A=Σ_pred^½Σ₁^−½,均值不动),但 X3 开/关对照显示正 α 单调有害(α=0→48.87、α=0.1→43.61、α=0.3→42.08),故提交配置默认 α=0,实际打分输出退化为末阶段分层子样 copy_last。
各组分数的变化cell_state:变坏:53.21→51.56(-1.65)。proxy10 mmd_u 0.0298→0.0400,得分 -3.87(copy 子样比父节点方法差);X3 mmd_u 0.0356→0.0318,得分 +1.19(在 ~2 分噪声边缘,不能算有效改善)。机制开启时 X3 上 mmd_u 反而 0.033→0.052,明确恶化。
covariation:变坏:54.21→49.95(-4.26)。proxy10 variogram 0.001028→0.001203,得分 -1.10;X3 0.001377→0.001558,得分 -0.73(噪声内)。机制开启时 X3 variogram 0.00156→0.00227,明确恶化——正是 PLAN 预期改善的分组。
de_recovery:变坏:49.78→46.67(-3.11)。全部来自 proxy10(de_score 0.268→0.0126,得分 -2.51,几乎落到地板 12.5);X3 持平(de_score -0.182→-0.169,得分 +0.09,噪声内)。机制在 proxy10 单输入下本就关闭,损失是相对父节点方法退化为 copy 所致,不是机制本身。
direction:变坏:57.77→52.79(-4.98)。proxy10 de_direction 0.360→0.174,得分 -3.20;X3 0.026→-0.001,得分 -0.27(噪声内)。同样归因于 proxy10 退化为 copy。
family_idlowrank_shape
假设是否成立否
经验
  1. 在每型仅百级细胞、两阶段技术背景可能不同的数据上(X3:4 个有效型、133–489 细胞/型),用 ΔΣ=Σ₁−Σ₀ 的低秩分量做正向外推(α=0.1–0.3)会膨胀型内分布:mmd_u 0.033→0.052、variogram 0.00156→0.00227,恰使目标分组 cell_state/covariation 单调恶化——ΔΣ 主要是采样噪声而非发育趋势(PLAN risks#1 命中)。
  2. 损害在 α=0.1 已出现大部分(48.87→43.61,α=0.3 仅再降到 42.08),说明主害是协方差膨胀本身而非幅度;且稀疏解码变体(只改原非零位)更差(35.36),排除'稠密化破坏共变'的解释。
  3. 任何在单输入视图(proxy10)下自动退化为 copy_last 的机制,都会相对有真实机制的父节点在 proxy10 上大幅失分(本例 -10.69),即使机制在双输入视图有效也可能总分为负;设计时应先估算退化路径的代价。
  4. 机制验证本身做得规范:开/关对照、Frobenius 比 1.33–1.96、ΔΣ top-10 能量 0.95+、被改细胞 448/652,证据齐全后才上报负结果并默认 α=0——这个流程值得沿用。
mechanism_active否
下一步建议
  1. 放弃 lowrank_shape 的正 α 协方差膨胀方向(对 covariation/cell_state 均有害);若再碰协方差类机制,先在小样本上检验 ΔΣ 前几个特征值是否显著超出置换/自助法噪声水平,不显著就不上全量。
  2. 转向树中已验证的组成/选择类杠杆(节点 7/16 的 composition_trend),针对 cell_state 和 direction 两组:X3 上 copy 基线 cell_state≈51 已近地板,增益应来自按发育趋势重采样细胞型比例,而非表达变换。
  3. 针对 de_recovery/direction:X3 的 de_score skill≈0.45(低于地板),说明纯 copy 在 DE 两项上系统性失分;可尝试在 copy 基础上叠加与两阶段 pb 差同向的小幅稀疏表达偏移(参考官方 E8.5→E9.5 演练中'组成变化+小偏移'的组合),先在 X3 单次查分验证方向再放大。

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

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

分析员

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

工程师

角色工程师 alibaba-token-plan-cn/qwen3.8-max
调用次数1 次
轮数27
工具调用共 41 次:bash 28、edit 11、write 2
用时19 分
token 数输入 64,332 · 输出 12,372 · 思考 13,755
任务(第一行)按计划修改程序:lowrank_shape: Ledoit-Wolf 收缩协方差低秩外推改变型内分布形状
最后的回答(摘录)
完成。节点 21(draft,family=lowrank_shape)总结:

**做了什么**:按 PLAN 完整实现 Ledoit-Wolf 型内协方差低秩外推仿射变形(HVG2500→PCA30→每型 Σ0/Σ1 收缩估计→ΔΣ top-10 低秩→A=Σ_pred^½Σ₁^−½,均值不动),含单输入退路和 `VEC_MECH_OFF`/`LOWRANK_ALPHA` 对照开关;proxy、X3 均跑通 vec-check,seed 确定性验证通过,纯 CPU。

**查分(5/20 次)**:X3 关(α=0)=48.87,开 α=0.1=43.61,α=0.3=42.08,α=0.3+稀疏解码=35.36;proxy10=53.24。机制证据齐全(448/652 细胞被改、Frobenius 比 1.33–1.96、ΔΣ top-10 能量 0.95+),但正 α 使 cell_state、covariation 单调恶化——PLAN risks#1 命中:百级细胞数下 ΔΣ 更像采样噪声而非发育趋势。已如实记录负结果,默认 α=0(同节点 18 先例),预估节点分 ≈ (53.2+2×48.9)/3 ≈ 50.3。

**下一步最值得试**:本方向可放弃正 α 协方差膨胀;树里更有效的仍是组成/选择类杠杆(节点 7/16 的 composition_trend),X3 上 copy 类基线 cell_state≈51 已近地板,想超过需在型内成熟度选择或跨数据集(Qiu)标签对齐上做文章,而非表达解码。
原始记录位置/home/spark-longxinyang/vec/runs/formal/20261003-093415-search-t1-r2-D-s1/nodes/21/engineer.jsonl 152 KB
/home/spark-longxinyang/vec/runs/formal/20261003-093415-search-t1-r2-D-s1/nodes/21/engineer.stderr

调研员

角色调研员 alibaba-token-plan-cn/qwen3.8-max
调用次数1 次
轮数1
工具调用共 0 次:—
用时6 分
token 数输入 14,356 · 输出 7,044 · 思考 8,192
任务(第一行)为节点 n21(草稿,父节点 nNone)写改进计划 PLAN.json,思路 lowrank_shape
最后的回答(摘录)
3 为初始步长。对 Σ_pred 做特征值裁剪:任何 < 1e-4 的特征值替换为 1e-4,确保正定。\n5. 仿射变换矩阵:A = Σ_pred^{1/2} @ Σ₁^{−1/2}(均为 30×30,通过特征分解计算矩阵平方根和逆平方根)。对 E9.5 该型的每个细胞:z_new = z_mean₁ + A @ (z − z_mean₁),其中 z_mean₁ 是该型在阶段 1 的 PCA 均值。基因空间输出:x_new_zscore = V^T z_new + r(加回原始残差),再反标准化回原始表达空间。\n6. 非 HVG 基因和无效类型的细胞:直接复制最后一个输入阶段的值。\n7. 单输入退路(proxy10):只有一个输入阶段时,无法估计 ΔΣ,变换取单位阵(A=I),输出 = 输入,机制完全关闭。\n\n关键参数初值与搜索范围:\n- n_hvg = 2500(固定)\n- n_pcs = 30(固定)\n- α(外推步长)= 0.3,搜索 [0.1, 0.5],步长 0.1;若 X3 分数下降则减小到 0.1\n- k(低秩截断)= 10,搜索 [5, 15]\n- min_cells = 30(每阶段每型最少细胞数)\n- eigen_clip = 1e-4\n\nvec-score 快速筛选:先在小样本(每型最多 500 细胞、500 HVG)上跑通流程,确认协方差确实被修改(Frobenius 范数变化 > 1%)。然后全量跑,用 vec-score 查分。比较 α=0(关闭)和 α=0.3(开启)的四组分差异,重点看 covariation 和 de_recovery。若总分差异 < 2 分,重复查分 3 次取均值确认。",
  "expected_groups": ["covariation", "cell_state"],
  "risks": "1. 协方差变化主要是采样噪声而非发育趋势:两阶段间型内协方差差异可能来自有限的细胞数。缓解:Ledoit-Wolf 收缩 + 低秩截断(只取前 10 个方向)+ 小步长 α=0.3。Engineer 应在小样本上先检查 ΔΣ 的特征值谱是否有明显信号(前几个特征值远大于其余),若全为噪声量级则机制可能无效。2. 仿射变换产生极端表达值:裁剪特征值后应检查输出表达的范围,若超出输入范围 3 倍标准差则触发警告。3. proxy10 上机制完全关闭,分数 ≈ copy_last(~52.75),节点分数主要依赖 X3 表现;若 X3 无改善则总分不会超过基线。4. 细胞类型分组不准确(标签缺失或聚类不当)导致协方差估计混杂不同细胞状态。Engineer 应检查每个有效类型的细胞数分布。5. PCA 残差加回后,非主成分方向的共变结构不变,可能限制了改善幅度。这是低秩约束的固有代价。",
  "family_id": "lowrank_shape",
  "mechanism": "在低维 PCA 空间用 Ledoit-Wolf 收缩估计两阶段型内协方差,取协方差差异的低秩分量外推一小步,以受限仿射变换改变中心化残差(形状),均值不变。",
  "vs_constant_shift": "常数位移给每个型的所有细胞加同一个向量,改变的是群体均值位置,不影响型内分布形状;lowrank_shape 不移动均值(变换以型均值为中心),改变的是型内协方差结构(分布的宽度、方向、共变模式)。常数位移主要影响 DE 指标(基因排序),lowrank_shape 主要影响 variogram(共变结构)和 mmd_u(分布形状),理论上不改变 DE。",
  "mechanism_evidence": "Engineer 应检查:1)变换前后每个有效类型的均值变化(应 < 0.01 标准差,证明均值未移动);2)变换前后型内协方差矩阵的 Frobenius 范数比(应偏离 1.0,证明形状确实改变);3)ΔΣ 前 10 个特征值占总能量的比例(若 > 60% 说明低秩近似合理);4)四组分各自变化:预期 covariation 改善、de_recovery 基本不变、direction 基本不变、cell_state 可能小幅变化;5)实际被修改的细胞数和比例(应为所有属于有效类型的细胞)。",
  "mechanism_off_control": "同一程序设 α=0(或等价地令 A=I 单位阵),此时 Σ_pred = Σ₁,变换为恒等映射,输出与输入完全相同。预期差别:关闭时输出 = 输入(逐元素相同),四组分与 copy_last 一致;开启时输出应不同,covariation 分组分数应有变化(改善或恶化)。若两者输出逐元素相同,说明机制未运行。"
}
```
原始记录位置/home/spark-longxinyang/vec/runs/formal/20261003-093415-search-t1-r2-D-s1/nodes/21/researcher.jsonl 24 KB
/home/spark-longxinyang/vec/runs/formal/20261003-093415-search-t1-r2-D-s1/nodes/21/researcher.stderr