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:
@@ -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()
|
||||
|
||||
Reference in New Issue
Block a user