"""Fresh paper-specific rational certificates, kept separate from edited numerical models."""
from fractions import Fraction as F
import sympy as sp
import two_site
import slope_certificate as slope
import deadline_validated as deadline


class TwoSiteCertificate:
    def calculate(self):
        data,lo,up,hl,hu,Q,D,pairs,d,H=two_site.calculate()
        # Independently reconcile every validated-integrator coefficient with the source.
        assert Q-sp.diag(*list(d))-sp.eye(6)/10 == sp.Matrix(deadline.L)/200
        assert d==sp.Matrix(deadline.C)/200
        for i,row in enumerate(pairs):
            actual={}
            for j,k,p in row:
                key=tuple(sorted((j,k)));actual[key]=actual.get(key,0)+p/10
            supplied={}
            for j,k,p in deadline.P[i]:
                key=tuple(sorted((j,k)));supplied[key]=supplied.get(key,0)+sp.Rational(p,200)
            assert actual==supplied
        self.lower={k:[F(x) for x in v] for k,v in lo.items()}
        self.upper={k:[F(x) for x in v] for k,v in up.items()}
        return dict(summary=data,states=two_site.ST if hasattr(two_site,'ST') else [(0,0),(0,1),(0,2),(1,0),(1,1),(2,0)],lower=self.lower,upper=self.upper,response_gap_lower=[F(x) for x in hl],response_gap_upper=[F(x) for x in hu],integrator_coefficients_verified=True)

    def regrowth(self,threshold=300):
        if type(threshold) is not int or threshold<2:raise ValueError('threshold must be an integer >=2')
        lower=1-self.upper['J'][5]
        upper=min(F(1),(1-self.lower['I'][5])/(1-max(self.upper['I'])**threshold))
        return dict(threshold=threshold,joint_eventual_lower=lower,independent_eventual_upper=upper,gap_lower=lower-upper)


class SmoothSlopeCertificate:
    def calculate(self,left=F(7),right=F(9),pieces=40):
        left,right=F(left),F(right)
        if not 0<=left<=right<=9 or type(pieces) is not int or pieces<1:
            raise ValueError('this source certificate supports 0 <= slope <= 9 and positive integer pieces')
        rows=[]
        for i in range(pieces):
            a=left+(right-left)*i/pieces;b=left+(right-left)*(i+1)/pieces
            states,ix,dl,du,result=slope.certificate(a,b)
            J,I=result['J'],result['I'];k=ix[9,7];active=ix[16,0]
            lower=I['lower'][k]-J['upper'][k]
            hitgap=(1-J['upper'][k])-(1-I['lower'][k])/(1-max(I['upper'])**2000)
            rows.append(dict(slope=[a,b],gap_lower=lower,gap_upper=I['upper'][k]-J['lower'][k],all_active_gap_upper=I['upper'][active]-J['lower'][active],regrowth_2000_gap_lower=hitgap,
                joint=[J['lower'][k],J['upper'][k]],independent=[I['lower'][k],I['upper'][k]],independent_max_upper=max(I['upper']),iterations=[J['iterations'],I['iterations']],min_residual=[J['minres'],I['minres']],
                states=states,death_lower=dl,death_upper=du,joint_lower=J['lower'],joint_upper=J['upper'],independent_lower=I['lower'],independent_upper=I['upper']))
        return dict(sites=16,rows=rows,gap_lower=min(r['gap_lower'] for r in rows),all_active_gap_upper=max(r['all_active_gap_upper'] for r in rows),regrowth_2000_gap_lower=min(r['regrowth_2000_gap_lower'] for r in rows),scope='Fresh exact supersolutions and downward iterations, with statewise rational hazard envelopes; all states saved for every cell.')


class DeadlineCertificate:
    def calculate(self):
        zero=deadline.integrate(F(0)); z=deadline.integrate(F(299,300))
        lower=1-F(zero['AA_lower'])-F(300,299)**299*(F(z['AA_upper'])-F(zero['AA_lower']))
        assert lower>F(765,1000)
        return dict(u0=zero,uz=z,deadline=300,threshold=300,joint_hit_by_deadline_lower=lower,scope='Fresh 15000-step outward integer Taylor integration, twice. The coefficient of u0 is positive: its LOWER enclosure is required. This is a first-passage lower bound from an endpoint event, not an equality.')
