exp: 轮次46-47——select=pre(打分地平线=被执行前缀终点)正向,两 seed 复现

2 s 误差比逐题符号检验 s0 192好/64差 p=4.9e-16、s1 191/65 p=1.5e-15;时限内(≤1.3×老师)
0.2656→0.3320(+6.64pp)、0.2969→0.3398(+4.30pp);行程比 −0.171/−0.171;碰撞仍 0、超 VMAX 仍 0。
到达只 +5/+3 题(McNemar p=0.42/0.68 ⇒ 噪声),故不改默认口径、作可选口径入库。
代价:到达题末态误差 0.22→0.42 mm(判据壳 1 mm 内,余量 4.6×→2.4×),两 seed 都涨。

对照可比性先证:控制臂 tie0 与轮次42 round42_K8cb1 的 22/22 键逐位相同 ⇒ 该配方跨窗口确定性
复现,本轮起新杠杆可用单臂对已落盘控制。

实现:select='pre' 用 fut[:,:,commit_n-1] 的终点误差(同一次 goal_err 只换点集);两条可手算正对照
(前缀好/末端差 vs 末端好/前缀差 ⇒ 两口径必须选相反候选) + 不变式(commit_n=16 时与 endpoint 同选);
49 项测试绿;n=16 冒烟证非惰性。候选表同步修准:backoff/ep_waste 两行状态改判掉,#29/#30 登记。
This commit is contained in:
cbb
2026-10-21 00:57:08 +08:00
parent 72c8835229
commit 3c250c7df3
8 changed files with 602 additions and 2 deletions
+50
View File
@@ -966,5 +966,55 @@ class TieByClearanceTest(unittest.TestCase):
self.assertTrue(all(isinstance(s, int) and isinstance(t, int) for s, t in seen))
class PreHorizonTest(unittest.TestCase):
"""#29:`select='pre'` 按「这一轮真会执行到的位置」打分;`endpoint` 按整条地平线末端打分。
夹具是两条刻意做成「前缀好但末端差」/「末端好但前缀差」的候选,期望值可手算。"""
class StubModel:
act_scale = 1.0
def __init__(self, act):
self.act = act
def sample_k(self, feat, K, z, steps=1):
B = feat.shape[0]
return (self.act.expand(B, K, 16, 6).clone(), torch.zeros(B, device=feat.device),
torch.zeros(B, 13, device=feat.device))
class NearKin:
def clamp_box(self, q):
return q
def gaps(self, q, cap):
return {'gm': torch.ones(q.shape[0], 49)}
def run1(self, select, commit_n=2):
# 候选0:前 2 步各 +0.2(前缀 0.4),随后 14 步 −0.4/14 ⇒ 地平线末端回到 0
# 候选1:16 步各 +0.05 ⇒ 前缀只有 0.1,但地平线末端 0.8
c0 = [0.2, 0.2] + [-(0.4 / 14.0)] * 14
c1 = [0.05] * 16
acts = torch.stack([torch.tensor([[v, 0, 0, 0, 0, 0] for v in c0], dtype=torch.float32),
torch.tensor([[v, 0, 0, 0, 0, 0] for v in c1], dtype=torch.float32)])
self.assertEqual(tuple(acts.shape), (2, 16, 6)) # 夹具自证:第 0 轴才是唯一有内容的轴
err = lambda kin, q, T, R: (((0.9 - q[:, 0]).clamp(min=0.0)) * 1000.0, torch.zeros(q.shape[0]))
with patch('ml.sim.closed_loop.features', return_value=torch.zeros(1, 83)), \
patch('ml.sim.closed_loop.goal_err', side_effect=err):
_, per = rollout(self.StubModel(acts), self.NearKin(), [{'q0': [0] * 6, 'T': [1, 0, 0]}], 'cpu',
K=2, safety=False, max_sec=0.04, return_traj=True, use_sub=False,
select=select, replan='empty', commit_n=commit_n)
return per
def test_pre_and_endpoint_pick_opposite(self):
p_end = self.run1('endpoint')
self.assertAlmostEqual(float(p_end['traj'][0, 1, 0]), 0.05 * 1.2, places=5) # 末端 0.8 ⇒ 选候选1
p_pre = self.run1('pre')
self.assertAlmostEqual(float(p_pre['traj'][0, 1, 0]), 0.2 * 1.2, places=5) # 前缀 0.4 ⇒ 选候选0
self.assertNotAlmostEqual(float(p_end['traj'][0, 1, 0]), float(p_pre['traj'][0, 1, 0]), places=3)
def test_pre_equals_endpoint_when_commit_is_the_whole_horizon(self):
"""不变式:commit_n=16 = 整条地平线 ⇒ pre 的索引落到末端,必须与 endpoint 选同一条。"""
p = self.run1('pre', commit_n=16)
self.assertAlmostEqual(float(p['traj'][0, 1, 0]), 0.05 * 1.2, places=5)
if __name__ == '__main__':
unittest.main()