import unittest
from fractions import Fraction as F
from decisions import *
from enzyme import CapacityFamily
from population import Population,TwoBandClass,ReadoutCalibration
from sandwich import BindingSite,SandwichSource,ObservationBudget,paper_certificates
from material_certificate import MaterialCertificate,DirectReserve
from amplification import AmplificationSource,IdentityChannel
from timing_certificate import timing_dual_certificate
from reporter import CofactorReactor,LinearRate,Reporter


class ScientificTests(unittest.TestCase):
    def test_scoped_reporting_preserves_nonanswers(self):
        c=Claim('fraction','equally weighted units','fixed task',F(2,3))
        self.assertEqual(DeterministicEnclosure(F(2,3),1,True).decide(c),'supported')
        self.assertEqual(DeterministicEnclosure(0,F(2,3),True).decide(c),'unresolved')
        self.assertEqual(DeterministicEnclosure(0,F(1,2),True).decide(c),'excluded')
        self.assertEqual(DeterministicEnclosure(None,None,evaluable=False).decide(c),'unevaluable')
        self.assertEqual(DeterministicEnclosure(1,0).decide(c),'incompatible')
        self.assertIn('feasibility',DeterministicEnclosure(F(3,4),1).decide(c))

    def test_population_dynamic_witnesses(self):
        f=CapacityFamily();b=TwoBandClass();self.assertEqual(b.bounds(f)['interval'],(F(20,41),1))
        repaired=ReadoutCalibration().interval(b.bounds(f)['interval']);self.assertEqual(repaired,(F(33,49),F(4,5)))
        for p in repaired:
            witness=b.witness(p);self.assertEqual(witness.mean,1);self.assertEqual(witness.recovery_enclosure(f)['lower'],p)
        self.assertEqual(F(33,49)-F(2,3),F(1,147))

    def test_dilution_source_and_native_masking(self):
        s=SandwichSource(BindingSite(1,1),BindingSite(1,1));c=paper_certificates()['main']
        self.assertTrue(c.check()['high_margin']);self.assertTrue(c.check()['low_sign'])
        self.assertAlmostEqual(float(s.signal(.08)),float(s.signal(50)),places=14)
        self.assertNotAlmostEqual(float(s.signal(.008)),float(s.signal(5)),places=4)
        self.assertEqual(s.paired(.1,1),s.paired(100,.001))
        a,b=ObservationBudget(F(1,100),F(1,100)).bounds(c.margin);self.assertEqual(a,b)

    def test_joint_issuance_is_not_conditional_error(self):
        g,z=specimen_bound(F(9,20),6,9);miss=1-(1-F(11,20)**6)*z
        self.assertLess(g,F(1,20));self.assertGreater(miss,F(1,20))
        self.assertEqual(z**9*miss,g)
        rule=IssuanceGuarantee(g,F(1,20),'complete independent reference/specimen experiment')
        self.assertTrue(rule.apply(True,True)['issued']);self.assertFalse(rule.apply(True,True,False)['issued'])

    def test_full_coverage_paths_and_prediction(self):
        for c in [F(0),F(1,2),F(1),F(3,2),F(2)]:
            r=path_floor(c,2);x,y,a,b=r['attaining_stages'];self.assertEqual((x*y+a*b)/2,r['floor'])
            self.assertTrue(all(0<=v<=1 for v in (x,y,a,b)))
        self.assertEqual(path_floor(F(3,2),2)['floor'],F(1,2))
        self.assertEqual(founder_cdf(6),F(245,256));self.assertEqual(founder_cdf(6,True),F(121,128))
        self.assertLess(founder_cdf(6,True),F(19,20));self.assertGreater(founder_cdf(7,True),F(19,20))
        self.assertEqual(thinned_cdf_two(F(1,2)),thinned_cdf_two(F(1,2),True))
        self.assertGreater((thinned_cdf_two(1)-thinned_cdf_two(1,True))*(thinned_cdf_two(F(3,4))-thinned_cdf_two(F(3,4),True)),0)
        self.assertLess((thinned_cdf_two(1)-thinned_cdf_two(1,True))*(thinned_cdf_two(F(1,4))-thinned_cdf_two(F(1,4),True)),0)

    def test_amplification_obstruction_and_repair(self):
        a=AmplificationSource();timing_dual_certificate()
        intercept=a.certify(5).miss[0]+5*a.certify(4).blank[0]
        self.assertGreater(intercept-F(5,100),F(555,10000))
        marker=IdentityChannel().guaranteed_errors(a.certify(7))
        self.assertLess(marker['blank_upper'],F(3,10000));self.assertLess(marker['miss_upper'],F(423,10000))

    def test_material_and_measurement_perturbation(self):
        c=MaterialCertificate(F(10),F(1,20),F(9,10),F(1,5),DirectReserve(F(2)))
        h=c.witness(F(29,5),F(19,5));self.assertEqual(h.fresh,F(169,100));h.ledger()
        r=CofactorReactor(LinearRate(1),LinearRate(1),Reporter(release=.2)).run(recovery=30)[2]
        self.assertAlmostEqual(r['independent_integral_ratio_numeric'],3,places=9)
        self.assertLess(r['finite_account_residual'],1e-10)


if __name__=='__main__':unittest.main()
