#!/usr/bin/env python3
"""Write bound_frobenius/README_bound.md from the value files in this package and the run logs of the
two-path continuation (one summary line per point: relative two-path agreement and worst-entry relative
ball radius).  Digits printed are floors of -log10 of the logged quantities.
usage: build_bound_readme.py OUTDIR GRIDLOG [GRIDLOG ...]"""
import sys, re, math, os, glob
from common import sha256_file
outdir, logs = sys.argv[1], sys.argv[2:]
EXACT = {'g995':'199/200','g990':'99/100','g980':'49/50','g970':'97/100','gisco':'sqrt(8/9)','g920':'23/25',
         'g900':'9/10','g866':'sqrt(3)/2','g800':'4/5','g707':'sqrt(2)/2','g600':'3/5','g500':'1/2'}
ORDER = list(EXACT)
FAM = {'K30': ("K3 (Legendre)", 3, "values_K30_1_12.txt"), 'K3P': ("K3' (Apery)", 3, "values_K3P_1_12.txt"),
       'F43': ("CY3 (4F3)", 4, "values_F43_1_6.txt, values_F43_7_12.txt"), 'HAD': ("CY3' (Hadamard)", 4, "values_HAD_1_12.txt")}
summ = {}
pat = re.compile(r'^GATE (\S+) (\S+) gamma=\S+ z=(\S+) agreeAB=(\S+) \(\S+\) ballrad=(\S+) ')
logsha = []
for lg in logs:
    logsha.append((os.path.basename(lg), sha256_file(lg)[:16]))
    for line in open(lg):
        m = pat.match(line)
        if m:
            fam, tag, zs, agree, rad = m.groups()
            summ[(fam, tag)] = (zs, float(agree), float(rad))
# count entries in the shipped value files
nvals = 0; npts = 0
for vf in sorted(glob.glob(os.path.join(outdir, 'values_*.txt'))):
    for line in open(vf):
        if line.lstrip().startswith('W['): nvals += 2
        if line.startswith('POINT'): npts += 1
L = []
L.append("# Bound-arc Frobenius matrices of the four period geometries that occur through 5PM (the 4PM K3 and the three 5PM geometries; Table 6 of the paper)")
L.append("")
L.append("Files: values_K30_1_12.txt (K3, 3x3 at 12 points), values_K3P_1_12.txt (K3', 3x3 at 12 points),")
L.append("values_F43_1_6.txt and values_F43_7_12.txt (CY3, 4x4 at 6 + 6 points), values_HAD_1_12.txt (CY3', 4x4 at 12 points):")
L.append(f"{npts} point blocks, {nvals} real numbers (real and imaginary parts of {nvals//2} matrix entries).")
L.append("Operators, variables, the Frobenius normalization and the path classes are specified in ../operators.txt.")
L.append("")
L.append("## Format")
L.append("Each file starts with '#' comment lines.  A block")
L.append("")
L.append("    POINT <family> <tag> gamma=<exact value>")
L.append("      z_re=<Re z>")
L.append("      z_im=<Im z>")
L.append("      W[i,k] = <Re W_ik>  <Im W_ik>        (i, k = 1..r; r = 3 for K3, K3'; r = 4 for CY3, CY3')")
L.append("")
L.append("gives the Wronskian matrix W[i,k] = (d/dz)^(i-1) varpi_(k-1)(z) of the MUM Frobenius basis (varpi_0, ..., varpi_(r-1)),")
L.append("continued from z = 0 to the bound-arc point z(gamma) along the physical path.  Row 1 is the Frobenius basis itself;")
L.append("W[1,1] = varpi_0 is the entry printed (rounded to ten decimals) in Table 6.  The tags g995 ... g500 label the twelve")
L.append("energies gamma = 199/200, 99/100, 49/50, 97/100, sqrt(8/9), 23/25, 9/10, sqrt(3)/2, 4/5, sqrt(2)/2, 3/5, 1/2 (gisco = sqrt(8/9),")
L.append("the specific energy of the Schwarzschild innermost stable circular orbit).")
L.append("")
L.append("## Precision and enclosures")
L.append("All numbers are midpoints of complex balls computed in ball arithmetic at 600-bit working precision (about 180 decimal")
L.append("digits are printed).  Each matrix was transported along two homotopically equivalent paths (A and B, see ../operators.txt).")
L.append("The table lists, per point, the number of decimal digits to which the two transports agree (floor of -log10 of the")
L.append("largest entrywise difference divided by the largest entry) and the number of digits guaranteed by the rigorous ball radius of path A")
L.append("(floor of -log10 of the largest entrywise radius divided by the largest entry).  Every printed midpoint is therefore")
L.append("correct to at least the number of digits in the last column, relative to the largest entry of its matrix; digits beyond")
L.append("that are not significant.")
L.append("")
L.append("| geometry | tag | gamma | z (6 decimals) | two-path agreement (digits) | enclosure radius (digits) |")
L.append("|---|---|---|---|---|---|")
minrad = 999
for fam in ('K30', 'K3P', 'F43', 'HAD'):
    for tag in ORDER:
        zs, agree, rad = summ[(fam, tag)]
        da = math.floor(-math.log10(agree)); dr = math.floor(-math.log10(rad)); minrad = min(minrad, dr)
        L.append(f"| {FAM[fam][0]} | {tag} | {EXACT[tag]} | {zs.replace('im',' i')} | {da} | {dr} |")
L.append("")
L.append(f"Smallest enclosure-radius entry in the table: {minrad} digits.  The K3 column of Table 6 additionally agrees with")
L.append("(2/pi)^2 K(z)^2 on the principal arithmetic-geometric-mean branch, and the CY3' column with the direct series and with")
L.append("evaluation through the Hadamard factorization of the operator, as stated in the paper.")
L.append("")
L.append("Run logs read for this table (sha256, first 16 hex digits): " + ', '.join(f"{n} {h}" for n, h in logsha) + ".")
open(os.path.join(outdir, 'README_bound.md'), 'w').write('\n'.join(L) + '\n')
print(f'wrote README_bound.md: {npts} points, {nvals} numbers, min enclosure digits {minrad}')
