"""Exploratory repeated-key period test for LP2 pages 0-2.
Permutation test controls selection of the largest score over periods 2..64.
Assumes rune-position-preserving periodic substitution with no skipped symbols.
"""
from pathlib import Path
import json
import numpy as np
P=Path(__file__).resolve().parent
R='ᚠᚢᚦᚩᚱᚳᚷᚹᚻᚾᛁᛄᛇᛈᛉᛋᛏᛒᛖᛗᛚᛝᛟᛞᚪᚫᚣᛡᛠ'
s=(P/'liber-primus__transcription--master.txt').read_text()
pages=s[s.index('ᚱ-'):].split('%')[15:73]
c=np.array([R.index(x) for x in ''.join(pages[:3]) if x in R])
periods=np.arange(2,65)
def profile(a):
    out=[]
    for k in periods:
        ct=np.bincount((np.arange(len(a))%k)*29+a,minlength=int(k*29)).reshape(k,29)
        sizes=ct.sum(axis=1)
        out.append(float((ct*(ct-1)).sum()/(sizes*(sizes-1)).sum()))
    return np.array(out)
obs=profile(c);rng=np.random.default_rng(3301)
null=np.array([profile(rng.permutation(c)) for _ in range(1000)])
# Normalize each period by its permutation variance before maximizing.
mu=null.mean(axis=0);sd=null.std(axis=0,ddof=1)
z=(obs-mu)/sd;null_max=((null-mu)/sd).max(axis=1)
adjusted_p=float((1+(null_max>=z.max()).sum())/(len(null)+1))
out={'target':'LP2 pages 0-2, continuous stream, title included', 'runes':len(c),
     'periods_tested':[2,64],'permutations':1000,'seed':3301,
     'max_adjusted_empirical_p':adjusted_p,
     'top_periods':[{'period':int(periods[i]),'within_column_ic':float(obs[i]),'permutation_z':float(z[i])} for i in np.argsort(z)[-5:][::-1]],
     'caution':'Exploratory, approximate calibration. Failure to detect periodicity does not exclude Vigenere, changing keys, transposition, skipped symbols or nonlinear schemes.'}
(P/'period_results.json').write_text(json.dumps(out,indent=2));print(json.dumps(out,indent=2))
