AUREOLE-R-v3 / legacy /code /test_theory.py
PureOne's picture
AUREOLE-R 3.0.0-hf.1: standalone public research release
9d6c005 verified
Raw
History Blame Contribute Delete
4.05 kB
"""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):
# E[(B-a)^2] = 1+a^2, uniquely minimized at a=0.
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)