"""Exact authored-law enumeration; not experiments or empirical confidence intervals."""
import unittest
from fractions import Fraction as F
from itertools import product
from finite_value import evaluate
class Tests(unittest.TestCase):
 def check_bounds(self,row):
  self.assertGreaterEqual(row['gain'],0);self.assertLessEqual(row['gain'],1-row['v0']);self.assertLessEqual(row['gain'],row['expected_tv']);self.assertLessEqual(float(row['gain']),row['pinsker_ceiling']+1e-12)
 def test_tight_perfect_signal(self):
  law={(0,w,w):F(1,2)for w in [0,1]};u={a:{(0,w):F(a==w)for w in [0,1]}for a in [0,1]};d=evaluate(law,u);self.check_bounds(d);self.assertEqual(d['gain'],F(1,2));self.assertEqual(d['gain'],d['expected_tv'])
 def test_independent_signal_zero_value(self):
  law={(0,z,w):F(1,4)for z,w in product([0,1],repeat=2)};u={a:{(0,w):F(a==w)for w in [0,1]}for a in [0,1]};d=evaluate(law,u);self.assertEqual(d['gain'],0);self.assertEqual(d['conditional_information_nats'],0)
 def test_information_irrelevant_to_action(self):
  law={(0,n,(t,n)):F(1,4)for t,n in product([0,1],repeat=2)};u={a:{(0,(t,n)):F(a==t)for t,n in product([0,1],repeat=2)}for a in [0,1]};d=evaluate(law,u);self.check_bounds(d);self.assertEqual(d['gain'],0);self.assertGreater(d['conditional_information_nats'],0)
 def test_positive_signal_value_can_be_less_than_charge(self):
  law={(0,z,w):F(3,8)if z==w else F(1,8)for z,w in product([0,1],repeat=2)};u={a:{(0,w):F(a==w)for w in [0,1]}for a in [0,1]};d=evaluate(law,u);self.check_bounds(d);self.assertEqual(d['gain'],F(1,4));self.assertLess(d['gain']-F(1,3),0)
 def test_all_small_binary_joint_laws(self):
  n=0
  for counts in product(range(5),repeat=4):
   if sum(counts)!=4:continue
   law={(0,z,w):F(k,4)for (z,w),k in zip(product([0,1],repeat=2),counts)};u={a:{(0,w):F(a==w)for w in [0,1]}for a in [0,1]};self.check_bounds(evaluate(law,u));n+=1
  self.assertEqual(n,35)
 def test_learned_comparison_is_not_bayes_increment(self):
  law={(w,0,w):F(1,2)for w in [0,1]};u={a:{(w,w):F(a==w)for w in [0,1]}for a in [0,1]};d=evaluate(law,u);self.assertEqual(d['gain'],0)
  # Coarse learned rule deliberately chooses 1-X; fine learned rule chooses X.
  learned0=F(0);learned1=F(1);self.assertGreater(learned1-learned0,d['gain']);self.assertEqual(learned1-learned0,d['gain']+(d['v0']-learned0)-(d['v1']-learned1))
 def test_conditioning_can_remove_signal_value(self):
  law={(w,w,w):F(1,2)for w in [0,1]};u={a:{(w,w):F(a==w)for w in [0,1]}for a in [0,1]};d=evaluate(law,u);self.check_bounds(d);self.assertEqual(d['v0'],1);self.assertEqual(d['gain'],0)
if __name__=='__main__':unittest.main()
