Files
digital-drosophila/models/male-cns-lif/timing-audit-v1/phase4r_report.py
T

75 lines
5.7 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""Summarize measured Phase 4R results; does not run or alter the brain."""
from pathlib import Path
import json
import pandas as pd
import numpy as np
root=Path('/data/digital-drosophila/experiments/phase4r-timing-audit')
read=lambda p:json.loads((root/p).read_text())
r=read('audit/results.json')
f=pd.read_parquet(root/'fixed-event/ratios.parquet')
h=pd.read_parquet(root/'timing/KC-histograms.parquet')
e=pd.read_parquet(root/'network-effects/credit-decomposition.parquet')
ages=pd.read_parquet(root/'timing/edge-age-at-90ms.parquet')
timing=[]
for (split,label),g in h[h.condition=='no_external_US'].groupby(['split','label']):
hist=g.groupby('start_ms').compartment_source_spikes.mean()
a=ages[(ages.split==split)&(ages.label==label)&(ages.window_ms==5)]
valid=a.age_at_US_ms.dropna()
timing.append({'split':split,'label':label,'peak_bin_start_ms':float(hist.idxmax()),
'peak_spikes_per_5ms':float(hist.max()),'spikes_85_90ms':float(hist.get(85,0)),
'fraction_events_first30ms':float(hist[hist.index<30].sum()/hist.sum()),
'median_last_spike_age_at_US_ms_edge_weighted':float(valid.median()) if len(valid) else None,
'p10_last_spike_age_ms':float(valid.quantile(.1)) if len(valid) else None,
'fraction_edges_recent_20ms':float((a.age_at_US_ms<=20).mean())})
paired=[]
for (split,condition,w),g in e.groupby(['split','condition','window_ms']):
paired.append({'split':split,'condition':condition,'window_ms':int(w),
'changed_event_streams':int((~g.KC_event_stream_exact_vs_noUS).sum()),'trials':len(g),
'mean_absolute_feedback_credit':float(g.network_feedback_credit_difference.abs().mean()),
'max_absolute_feedback_credit':float(g.network_feedback_credit_difference.abs().max()),
'mean_KC_count_L1':float(g.KC_count_L1_vs_noUS.mean())})
q=read('regression/phase4q-reproduction.json');rr=read('regression/full-runtime-10-repeat.json');fr=read('regression/five-frozen-trials.json')
ratios=pd.DataFrame(r['same_event_ratios']);held=ratios[ratios.split=='heldout']
notes=[
'Phase 4Q failure reproduced only for its declared timing protocol; it is not evidence against all local credit rules.',
'Early target-KC activity and late 90ms reinforcement are measured associations. No APL ablation was authorized, so APL causation remains unresolved.',
'The exact uniform-time expectations remove random-US sampling noise on the same KC event stream.',
'US=0..120ms versus 30..110ms is a protocol difference, not an event-energy mismatch. Both use one forced spike per selected DAN.',
'The same 1.8ms delay on KC and DAN leaves relative timing unchanged. Counting only KC arrival is a different gate convention.',
'Pre-existing Phase 4Q controls were offline algebraic tests. This audit adds recorded events, disk checkpoint restoration, real full-runtime repeats and frozen reference comparisons.',
'No timing/eligibility candidate was selected. Independent heldout seeds replicate diagnosis; heldout odor generalization was not tested.'
]
out={'status':'COMPLETED-DIAGNOSTIC-NO-CANDIDATE','timing':timing,'fixed_event_ratios':r['same_event_ratios'],
'paired_network_effects':paired,'phase4q_reproduced_exact':q['all_event_and_credit_exact'],
'full_runtime_ten_repeats_exact':rr['all_exact'],'five_reference_trials_two_repeats_exact':fr['all_exact'],
'symmetric_delay_exact':r['symmetric_delay_exact'],'interpretation_limits':notes,
'heldout_all_windows_ratio_below_one_Q':bool((held.ratio_Q<1).all()),
'heldout_all_windows_ratio_below_one_N':bool((held.ratio_N<1).all()),
'candidate_generated':False,'training_run':False,'next_phase_started':False,
'performance':read('performance/summary.json')}
out['mechanism_labels']=['KC-US-TIMING-MISMATCH-SUPPORTED','RANDOM-TIMING-DISTRIBUTION-EFFECT-CONFIRMED',
'CURRENT-GATE-CREDIT-UNCHANGED-BY-DAN-FEEDBACK','FROZEN-RUNTIME-REGRESSION-PASS']
out['next_step']='Pre-register stimulus and reinforcement timing using independent calibration data; keep brain and learning magnitude frozen. Do not select an optimum from heldout results.'
out['important_qualification']='Heldout 5ms/10ms credit exceeds the narrower random-N expectation (2.649x/1.338x), but calibration does not replicate this and all ratios remain below the prior 3x gate.'
controls=read('regression/offline-controls.json')
out['offline_controls_all_pass']=all(all(v for k,v in row.items() if k!='window_ms') for row in controls['rows'])
(root/'audit/mechanism-summary.json').write_text(json.dumps(out,indent=2,sort_keys=True)+'\n')
lines=['# Phase 4R — KC–US timing audit','',
'Status: COMPLETED-DIAGNOSTIC-NO-CANDIDATE. No training, new timing selection, weight update or next phase.','',
'## Fixed-event matched/random ratio','',
'| Seed split | Window (ms) | Random [0,120) | Random [30,110] |',
'|---|---:|---:|---:|']
for x in r['same_event_ratios']:
lines.append(f"| {x['split']} | {x['window_ms']} | {x['ratio_Q']:.6f} | {x['ratio_N']:.6f} |")
lines+=['','## Actual target-compartment KC timing','']
for x in timing:lines.append('- '+json.dumps(x))
lines+=['','## Verification','',f"- Phase 4Q events and credit reproduced: {out['phase4q_reproduced_exact']}",
f"- Ten full-runtime repeat runs exact: {rr['all_exact']}",f"- Five frozen trials, two repeats each: {fr['all_exact']}",
f"- Equal delay on both pathways preserves relative timing: {r['symmetric_delay_exact']}",'',
'## Interpretation and limits','']+['- '+x for x in notes]+['- '+out['important_qualification']]
lines+=['','![Timing audit](../figures/timing-audit.png)','',
'Final integrity verification is recorded separately in audit/frozen-integrity.json and the root checksums.sha256.']
(root/'audit/REPORT.md').write_text('\n'.join(lines)+'\n')
print(json.dumps(out,indent=2))