LightNest / tests /test_sequential_patch_rl.py
LIghtJUNction's picture
Cursor
Add the October 17 experiment source without the result archives.
3f69d68 verified
Raw History Blame Contribute Delete
2.99 kB
import random
import unittest
from unittest.mock import patch
import torch
from lightnest import rv32
from lightnest.learned_patch import MAX_WINDOW
from lightnest.sequential_patch_rl import arithmetic, make_task, passes, rollout, terminal_reward
class FixedPolicy(torch.nn.Module):
def __init__(self, position):
super().__init__(); self.position=position; self.calls=0
self.weight=torch.nn.Parameter(torch.tensor(1.))
def forward(self,c,b):
self.calls+=1
scores=torch.full((len(c),257),-30.)+self.weight*0
scores[:,self.position]=self.weight*30
return scores,torch.ones((len(c),256,8))*self.weight
class SequentialTests(unittest.TestCase):
def test_oracle(self):
self.assertEqual(arithmetic((4,2,1),'sub'),1)
self.assertEqual(arithmetic((2147483647,1,1),'add'),-2147483647)
def test_generator_bounds_and_independent_execution(self):
for split in ('train','unseen_bias','three_op_combined'):
for seed in range(40):
t=make_task(random.Random(seed),split)
self.assertLessEqual(len(t.binary),MAX_WINDOW)
# Test-only assembler repair never enters policy or training reward.
target='sub' if 'to sub' in t.command or 'with sub' in t.command else 'add'
words=[int.from_bytes(t.binary[i:i+4],'little') for i in range(0,len(t.binary),4)]
words=[((w & ~(127<<25)) | ((32 if target=='sub' else 0)<<25)) if w&127==51 else w for w in words]
repaired=b''.join(w.to_bytes(4,'little') for w in words)
self.assertTrue(passes(repaired,t.cases))
def test_none_and_budget(self):
t=make_task(random.Random(3)); p=FixedPolicy(MAX_WINDOW)
out,edits,h,_=rollout(p,[t.command],[t.binary])
self.assertEqual(out,[t.binary]); self.assertEqual(edits,[0]); self.assertEqual(p.calls,1)
p=FixedPolicy(0)
with patch('lightnest.sequential_patch_rl.rv32.simulate',side_effect=AssertionError('oracle reached policy')):
_,_,h,lp=rollout(p,[t.command],[t.binary],sample=True)
self.assertEqual(p.calls,3); self.assertEqual(len(h[0]),3)
lp.sum().backward(); self.assertIsNotNone(p.weight.grad)
def test_input_bounds(self):
p=FixedPolicy(0)
for n in (0,4):
with self.assertRaises(ValueError): rollout(p,['x'],[b'1234'],max_proposals=n)
with self.assertRaises(ValueError): rollout(p,['x'],[b'x'*257])
def test_terminal_reward(self):
binary=b''.join(w.to_bytes(4,'little') for w in (rv32.addi('x10','x0',7),rv32.EBREAK))
cases=[([1,2],7)]
self.assertEqual(terminal_reward(binary,binary,cases,0),1)
self.assertEqual(terminal_reward(binary,binary,cases,1),-1)
self.assertEqual(terminal_reward(binary,binary,[([1,2],8)],0),-1)
with self.assertRaises(ValueError): terminal_reward(binary,binary,[],0)
if __name__=='__main__': unittest.main()