| """Meaningful algebraic/counterexample checks, independent of the benchmark data.""" |
| import unittest |
| import numpy as np |
| from aureole_core import * |
|
|
|
|
| class TheoryChecks(unittest.TestCase): |
| def setUp(self): |
| self.rng=np.random.default_rng(20260919) |
| b=self.rng.normal(size=(7,7)); self.p=b@b.T+.2*np.eye(7) |
| c=self.rng.normal(size=(5,7)); self.w=c.T@c |
| self.h=self.rng.normal(size=7) |
|
|
| def test_value_matches_direct_risk_reduction(self): |
| _,p2=observe(np.zeros(7),self.p,self.h,2.,.6) |
| self.assertAlmostEqual(risk(self.p,self.w)-risk(p2,self.w),query_value(self.p,self.w,self.h,.6),places=10) |
|
|
| def test_update_psd_and_information_order(self): |
| _,p2=observe(np.zeros(7),self.p,self.h,2.,.6) |
| self.assertGreater(np.linalg.eigvalsh(p2).min(),0) |
| self.assertGreater(np.linalg.eigvalsh(self.p-p2).min(),-1e-10) |
|
|
| def test_batch_equals_sequential_independent_samples(self): |
| h=self.rng.normal(size=(3,7)); r=np.diag([.2,.5,.7]); p=self.p.copy() |
| for hi,ri in zip(h,np.diag(r)): _,p=observe(np.zeros(7),p,hi,0.,ri) |
| np.testing.assert_allclose(p,batch_covariance(self.p,h,r),atol=1e-10) |
|
|
| def test_task_additivity(self): |
| w1=np.diag([1.,2.,3.,0.,0.,0.,0.]); w2=self.w |
| self.assertAlmostEqual(query_value(self.p,w1+w2,self.h,.3),query_value(self.p,w1,self.h,.3)+query_value(self.p,w2,self.h,.3),places=10) |
|
|
| def test_future_metric_matches_explicit_loss(self): |
| a=self.rng.normal(size=(7,7))*.1; cs=[self.rng.normal(size=(4,7)) for _ in range(6)]; weights=.9**np.arange(6) |
| w=future_metric(a,cs,weights); x=self.rng.normal(size=7); total=0.; z=x.copy() |
| for c,weight in zip(cs,weights): total+=weight*np.linalg.norm(c@z)**2; z=a@z |
| self.assertAlmostEqual(total,x@w@x,places=10) |
|
|
| def test_transform_tail(self): |
| for rank in [0,1,4,7]: |
| u,e,p=transform_coding(self.p,self.w,rank) |
| self.assertAlmostEqual(risk(p,self.w),sum(e[rank:]),places=9) |
|
|
| def test_nuisance_query_expands_basis(self): |
| u=closed_observation_basis([np.eye(2)],[[1,0],[1,1]]) |
| self.assertEqual(u.shape[1],2) |
|
|
| def test_dynamic_closure(self): |
| a=np.array([[.9,1.,0.],[0,.8,0.],[0,0,.7]]) |
| u=closed_observation_basis([a],[[1,0,0]]) |
| self.assertEqual(u.shape[1],2) |
| np.testing.assert_allclose((np.eye(3)-u@u.T)@a.T@u,0.,atol=1e-10) |
|
|
| def test_projection_preserves_linear_future_channels(self): |
| a=np.array([[.9,1.,0.],[0,.8,0.],[0,0,.7]]); c=np.array([[1.,0.,0.]]) |
| u=closed_observation_basis([a],c); x=self.rng.normal(size=3); z=u.T@x |
| for _ in range(15): |
| np.testing.assert_allclose(c@x,c@u@z,atol=1e-9) |
| x=a@x; z=u.T@a@u@z |
|
|
| def test_sampling_not_generally_submodular(self): |
| p=np.eye(2); w=np.diag([1.,0.]); h1=np.array([1.,1.]); h2=np.array([0.,1.]) |
| _,p1=observe(np.zeros(2),p,h1,0,.1) |
| self.assertEqual(query_value(p,w,h2,.1),0.) |
| self.assertGreater(query_value(p1,w,h2,.1),.3) |
|
|
| def test_optical_area_mixture_passive_reciprocal(self): |
| ops=[] |
| for _ in range(4): |
| b=self.rng.random((6,6)); b=sym(b); b/=b.sum(0).max()*1.1; ops.append(b) |
| k=area_mixture(np.array(ops),[.1,.2,.3,.4]) |
| self.assertGreaterEqual(k.min(),0.); self.assertLessEqual(k.sum(0).max(),1.) |
| np.testing.assert_allclose(k,k.T) |
|
|
| def test_measurement_information_does_not_increase_while_absent(self): |
| q=np.diag(np.linspace(.01,.07,7)); p2=self.p+500*q |
| self.assertGreaterEqual(np.linalg.eigvalsh(p2-self.p).min(),0.) |
|
|
| def test_forgetting_has_nonnegative_bayes_risk(self): |
| _,posterior=observe(np.zeros(7),self.p,self.h,0.,.1) |
| self.assertGreaterEqual(risk(self.p-posterior,self.w),-1e-10) |
|
|
| def test_impossible_future_bit(self): |
| |
| for a in [-2.,-.5,0.,.5,2.]: self.assertAlmostEqual(.5*(1-a)**2+.5*(-1-a)**2,1+a*a) |
|
|
|
|
| if __name__=="__main__": unittest.main(verbosity=2) |
|
|