#!/usr/bin/env python3
"""
Audit sanity checks for flagship artifacts.

This script performs mechanical checks that the flagship certificate numbers
match the host matrices in the shipped datasets for the built-in examples.

It is not a proof assistant. It is a deterministic sanity auditor.

Usage:
  python tools/audit_sanity_checks.py
"""

from __future__ import annotations
import os, json, math, itertools, argparse, sys

def load(p):
    with open(p,"r",encoding="utf-8") as f:
        return json.load(f)

def mm(X,Y):
    return [[sum(X[i][k]*Y[k][j] for k in range(len(Y))) for j in range(len(Y[0]))] for i in range(len(X))]

def min_entry(M):
    return min(min(r) for r in M)

def max_entry(M):
    return max(max(r) for r in M)

def tanh(x):
    return math.tanh(x)

def approx(a,b,eps=1e-9):
    return abs(float(a)-float(b)) <= eps

def check_fibonacci(root:str)->None:
    fib=load(os.path.join(root,"sources","host_data","fibonacci_fusion_data.json"))
    N=fib["fusion_matrices"]["N_tau"]["matrix_A_kj"]
    N2=mm(N,N)
    delta=min_entry(N2)
    U=max_entry(N2)
    Delta=2.0*math.log(U/delta)
    tau=tanh(Delta/4.0)

    cert=load(os.path.join(root,"sources","ru","robust_certificate_fibonacci_realhost_contraction.json"))
    assert approx(cert["doeblin"]["delta"], delta), "Fibonacci contraction: delta mismatch"
    assert approx(cert["doeblin"]["U_bound"], U), "Fibonacci contraction: U mismatch"
    assert approx(cert["rate_pack"]["tau_unperturbed"], tau), "Fibonacci contraction: tau mismatch"

    og4=load(os.path.join(root,"sources","ru","robust_certificate_fibonacci_realhost_og4_idle_avoidable.json"))
    assert approx(og4["doeblin"]["delta"], delta), "Fibonacci OG4: delta mismatch"
    assert og4["recurrence"]["details"]["og4_avoidance_cycle"] == ["eI"], "Fibonacci OG4: avoidance cycle mismatch"

    og1=load(os.path.join(root,"sources","ru","robust_certificate_fibonacci_realhost_og1_period2.json"))
    periods=og1["tight_core"]["tight_scc_summary"]["periods"]
    assert periods == [2], "Fibonacci OG1: period list mismatch"
    assert og1["tight_core"]["tight_scc_summary"]["aperiodic_scc_count"] == 0, "Fibonacci OG1: aperiodic_scc_count mismatch"

def is_strict_pos(M):
    return all(M[i][j] > 0 for i in range(len(M)) for j in range(len(M[0])))



def check_toric(root:str)->None:
    toric=load(os.path.join(root,"sources","host_data","toric_code_fusion_data.json"))
    Ne=toric["fusion_matrices"]["N_e"]["matrix_A_kj"]
    Nm=toric["fusion_matrices"]["N_m"]["matrix_A_kj"]
    Nx=toric["fusion_matrices"]["N_eps"]["matrix_A_kj"]

    # permutation property: each column has exactly one 1 and others 0
    def is_perm(A):
        n=len(A)
        for j in range(n):
            col=[A[i][j] for i in range(n)]
            if sum(col)!=1:
                return False
            if any(x not in (0,1) for x in col):
                return False
        return True
    assert is_perm(Ne) and is_perm(Nm) and is_perm(Nx), "Toric OG3 sanity: fusion matrices should be permutation matrices"

    cert=load(os.path.join(root,"sources","ru","robust_certificate_og3_toric_code_fusion.json"))
    assert cert["doeblin"]["delta"] == 0.0, "Toric OG3: delta should be 0"


def check_ising(root:str)->None:
    ising=load(os.path.join(root,"sources","host_data","ising_fusion_data.json"))
    S=ising["fusion_matrices"]["N_sigma"]["matrix_A_kj"]
    P=ising["fusion_matrices"]["N_psi"]["matrix_A_kj"]

    # Quick brute sanity: no strictly positive product up to length 10
    letters=[S,P]
    for L in range(1,11):
        for word in itertools.product([0,1], repeat=L):
            M=[[1,0,0],[0,1,0],[0,0,1]]
            for idx in word:
                M=mm(letters[idx], M)
            if is_strict_pos(M):
                raise AssertionError("Ising OG3 sanity: found strictly positive product at length "+str(L))

    cert=load(os.path.join(root,"sources","ru","robust_certificate_og3_ising_fusion.json"))
    assert cert["doeblin"]["delta"] == 0.0, "Ising OG3: delta should be 0"

    # OG2 projection sanity: P_even kills sigma and return map needs sigma
    m=load(os.path.join(root,"sources","ru_bridge","og2_ising_projection_inconsistency_model.json"))
    P_even=m["templates"]["P_even"]["matrix"]
    N_sigma=m["templates"]["N_sigma"]["matrix"]
    P_after=m["templates"]["P_after_sigma"]["matrix"]

    # Verify P_even kills sigma basis vector e_sigma = (0,0,1)
    e_sigma=[0,0,1]
    out=[sum(P_even[i][k]*e_sigma[k] for k in range(3)) for i in range(3)]
    assert out == [0,0,0], "Ising OG2 sanity: P_even does not kill sigma"

    # Verify P_after_sigma kills inputs 1 and psi but not sigma
    e1=[1,0,0]
    epsi=[0,1,0]
    osig=[0,0,1]
    def apply(A,v):
        return [sum(A[i][k]*v[k] for k in range(3)) for i in range(3)]
    assert apply(P_after, e1) == [0,0,0], "Ising OG2 sanity: P_after_sigma should kill 1"
    assert apply(P_after, epsi) == [0,0,0], "Ising OG2 sanity: P_after_sigma should kill psi"
    assert apply(P_after, osig) != [0,0,0], "Ising OG2 sanity: P_after_sigma should not kill sigma"

def main()->int:
    ap=argparse.ArgumentParser()
    ap.add_argument("--root", default=".", help="Project root")
    args=ap.parse_args()
    root=os.path.abspath(args.root)

    check_fibonacci(root)
    check_ising(root)
    check_toric(root)
    print("AUDIT SANITY CHECKS PASSED")
    return 0

if __name__=="__main__":
    raise SystemExit(main())
