import unittest,itertools,tempfile from pathlib import Path import numpy as np from aureole.certificates import CertificateMemory,visibility_certificate,enclosure from aureole.innovation import prepare,eliminate,exact_risk_two,covariance from aureole.renderer import Scene,receiver_grid,light_grid class InnovationTests(unittest.TestCase): def test_covariance_contraction_all_readouts(self): rng=np.random.default_rng(121) for _ in range(200): q=rng.dirichlet(np.ones(9));r=rng.normal(size=(9,5)) a=np.arange(3);u=np.arange(3,9);mass=q[a].sum() old=covariance(r,q) new=covariance(r[u],q[u]/(1-mass)) self.assertGreaterEqual(np.linalg.eigvalsh((1-mass)*old-new).min(),-1e-10) def test_exact_two_draw_enumeration(self): rng=np.random.default_rng(12) for k in (3,4,6): q=rng.dirichlet(np.ones(k));f=rng.uniform(size=(k,3));h=rng.normal(size=(k,3)) outcomes=[];weights=[] for a,b in itertools.permutations(range(k),2): y1=h.sum(0)+(f[a]-h[a])/q[a] h2=h.copy();h2[a]=f[a] y2=h2.sum(0)+(f[b]-h2[b])/(q[b]/(1-q[a])) outcomes.append((y1+y2)/2);weights.append(q[a]*q[b]/(1-q[a])) outcomes=np.array(outcomes);weights=np.array(weights) np.testing.assert_allclose(weights@outcomes,f.sum(0),atol=1e-12) risk=np.sum(weights[:,None]*(outcomes-f.sum(0))**2)/3 self.assertAlmostEqual(risk,exact_risk_two(f[None],h[None],q[None])[0],places=11) def test_exact_completion_fixed_budget(self): f=np.arange(9,dtype=float).reshape(1,3,3) used=[] def oracle(rows,j):used.extend(j.tolist());return f[rows,j] y,_=eliminate(np.zeros_like(f),np.full((1,3),1/3),oracle,3,np.random.default_rng(3)) np.testing.assert_array_equal(y,f.sum(1));self.assertEqual(len(set(used)),3) def test_no_rays_on_complete_state(self): h=np.ones((4,3,2)) def oracle(*args):raise AssertionError('Should not trace') y,steps=eliminate(h,np.zeros((4,3)),oracle,2,np.random.default_rng(3)) np.testing.assert_array_equal(y,h.sum(1));self.assertEqual(steps,[]) def test_false_zero_support_rejected_by_audit(self): with self.assertRaises(ValueError):exact_risk_two(np.ones((1,3,1)),np.zeros((1,3,1)),np.array([[.5,.5,0]])) def test_upper_uniform_endpoint_never_selects_zero_support(self): class UpperRng: def random(self,n):return np.full(n,np.nextafter(1.0,0.0)) q=np.zeros((1000,7));q[:,:5]=np.random.default_rng(41).dirichlet(np.ones(5),size=1000) def oracle(rows,j): self.assertTrue(np.all(j<5));return np.ones((len(rows),1)) result,steps=eliminate(np.zeros((1000,7,1)),q,oracle,2,UpperRng()) self.assertTrue(np.isfinite(result).all()) self.assertTrue(np.all(steps[0][1]!=steps[1][1])) def test_known_only_control_and_support(self): b=np.ones((1,4,3));v=np.array([[0.,1.,0.,0.]]) h,q=prepare(b,np.full((1,4),.6),v,np.array([[True,True,False,False]]),np.ones((1,4))) np.testing.assert_array_equal(q,[[0,0,.5,.5]]) np.testing.assert_allclose(h[0,:,0],[0,1,.6,.6]) def test_invalid_budget_and_proposal(self): with self.assertRaises(ValueError):eliminate(np.ones((1,3,1)),np.full((1,3),1/3),lambda *x:None,True,np.random.default_rng()) with self.assertRaises(ValueError):eliminate(np.ones((1,3,1)),np.array([[0,.1,.1]]),lambda *x:None,1,np.random.default_rng()) def test_float_oracle_matches_independent_quadratic(self): rng=np.random.default_rng(987) for sid in range(800,820): scene=Scene.create(sid) p=rng.uniform([-1,-1,0],[1,1,0],(200,3));l=rng.uniform([-.9,-.9,2.2],[.9,.9,2.2],(200,3)) v,_=visibility_certificate(scene,p,l) np.testing.assert_array_equal(v,scene.visibility(p,l)) def test_moving_and_spatial_certificates_no_false_acceptance(self): rng=np.random.default_rng(982) for sid in range(820,830): scene=Scene.create(sid);p=receiver_grid(8,12);l=light_grid(4) mem=CertificateMemory(p,l,scene.spheres) ids=np.repeat(np.arange(len(p)),len(l));j=np.tile(np.arange(len(l)),len(p)) v,m=visibility_certificate(scene,p[ids],l[j]);mem.commit(ids,j,v,m) for _ in range(12): g=scene.spheres.copy();g[:,:3]+=rng.uniform(-.035,.035,(3,3));g[:,3]*=rng.uniform(.96,1.04,3) moved=Scene(sid,g);mem.begin_geometry(g) query=p+rng.uniform(-.012,.012,p.shape);query[:,2]=0 values,known=mem.lookup(np.arange(len(p)),query) truth=moved.visibility(query[:,None,:],l[None,:,:]) self.assertTrue(np.all(values[known]==truth[known])) def test_unreported_motion_is_not_protected(self): scene=Scene.create(833);p=receiver_grid(16,20);l=light_grid(6) mem=CertificateMemory(p,l,scene.spheres) ids=np.repeat(np.arange(len(p)),len(l));j=np.tile(np.arange(len(l)),len(p)) v,m=visibility_certificate(scene,p[ids],l[j]);mem.commit(ids,j,v,m) values,known=mem.lookup(np.arange(len(p))) changed=scene.changed().visibility(p[:,None,:],l[None,:,:]) self.assertGreater(np.count_nonzero(known & (values!=changed)),0) def test_epoch_resets_while_margin_can_survive(self): s=Scene.create(20);p=receiver_grid(4,5);l=light_grid(2) a=CertificateMemory(p,l,s.spheres);b=CertificateMemory(p,l,s.spheres,mode='epoch') ids=np.arange(len(p));j=np.zeros(len(p),int);v,m=visibility_certificate(s,p,l[j]) for mem in (a,b):mem.commit(ids,j,v,m) g=s.spheres.copy();g[0,0]+=1e-7 for mem in (a,b):mem.begin_geometry(g) self.assertGreater(a.lookup(ids)[1].sum(),0);self.assertEqual(b.lookup(ids)[1].sum(),0) def test_enclosure_covers_all_binary_completions(self): b=np.arange(1,10,dtype=float).reshape(1,3,3);v=np.array([[1.,0.,0.]]);known=np.array([[True,False,False]]) lo,hi=enclosure(b,v,known) for a,c in itertools.product((0,1),repeat=2): y=(b*np.array([1,a,c])[None,:,None]).sum(1) self.assertTrue((y>=lo).all() and (y<=hi).all()) def test_roundtrip_and_namespace(self): s=Scene.create(31);p=receiver_grid(3,4);l=light_grid(2) a=CertificateMemory(p,l,s.spheres,'alpha');ids=np.arange(len(p));j=np.zeros(len(p),int) v,m=visibility_certificate(s,p,l[j]);a.commit(ids,j,v,m) with tempfile.TemporaryDirectory() as d: path=Path(d)/'memory.npz';a.save(path);b=CertificateMemory.load(path,'alpha') np.testing.assert_array_equal(a.lookup(ids)[1],b.lookup(ids)[1]) with self.assertRaises(ValueError):CertificateMemory.load(path,'beta') def test_motion_budget_is_conservative_on_return(self): s=Scene.create(12);a=CertificateMemory(receiver_grid(2,2),light_grid(2),s.spheres) g=s.spheres.copy();g[0,0]+=.2;a.begin_geometry(g);a.begin_geometry(s.spheres) self.assertGreaterEqual(a.budget,.4-1e-14) def test_readout_cross_covariance_is_psd(self): rng=np.random.default_rng(22);r=rng.normal(size=(7,12));q=rng.dirichlet(np.ones(7)) self.assertGreaterEqual(np.linalg.eigvalsh(covariance(r,q)).min(),-1e-10) if __name__=='__main__':unittest.main()