Files
digital-drosophila/models/male-cns-lif/late-kc-audit-v1/phase4w_describe.py
T

47 lines
3.8 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.
"""Descriptive summaries after preregistered diagnostics; no candidate selection."""
from pathlib import Path
import json
import pandas as pd
import numpy as np
import yaml
from phase4r import save
cfg=yaml.safe_load(Path(__file__).with_name('phase4w.yaml').read_text());exp=Path(cfg['experiment_root'])
assert not (exp/'checksums.sha256').exists(),'Refusing sealed output changes'
src=pd.read_parquet(exp/'audit/incoming-source-metadata.parquet')
meta=pd.read_parquet(exp/'audit/watched-metadata.parquet')
top=[];shadow=[]
for p in sorted((exp/'drive').glob('*-actual-edge-arrivals.parquet')):
trial=p.name.removesuffix('-actual-edge-arrivals.parquet');df=pd.read_parquet(p)
df=df[(df.arrival_step>=int(cfg['late_start_ms']/.1)) & (df.effective_weight>0)]
grouped=df.groupby(['target_neuron_idx','source_neuron_idx','source_category'],as_index=False).agg(
positive_drive=('effective_weight','sum'),events=('edge_id','size'),raw_synapse_count=('raw_synapse_count','first'))
grouped['positive_fraction']=grouped.positive_drive/grouped.groupby('target_neuron_idx').positive_drive.transform('sum')
grouped=grouped.merge(src,left_on='source_neuron_idx',right_on='neuron_idx',how='left').drop(columns='neuron_idx')
grouped['trial']=trial;top.append(grouped)
for p in sorted((exp/'drive').glob('*-shadow.parquet')):
df=pd.read_parquet(p);late=df[df.step>=int(cfg['late_start_ms']/.1)]
row={'file':p.name,'neuron_idx':int(df.neuron_idx.iloc[0]),'max_abs_rounding_residual':float(df.shadow_residual.abs().max()),
'mean_abs_rounding_residual':float(df.shadow_residual.abs().mean())}
row.update({col+'_late_mean':float(late[col].mean()) for col in df.columns if col.startswith('g_')})
shadow.append(row)
tops=pd.concat(top,ignore_index=True);tops.to_parquet(exp/'audit/late-positive-sources.parquet',index=False)
pd.DataFrame(shadow).to_parquet(exp/'audit/shadow-summary.parquet',index=False)
replay=pd.read_parquet(exp/'replay/results.parquet');drive=pd.read_parquet(exp/'drive/summary.parquet')
lines=['# Phase 4W mechanism summary','',
'Descriptive audit; no learning, model parameter change, or candidate selection. Six previously seen odors, one fixed seed each; not independent population generalization.','',
'| neuron_idx | body_id | actual annotation type |','|---:|---:|---|']
for _,r in meta.iterrows():lines.append(f'| {r.neuron_idx} | {r.body_id} | {r.annotation_type} |')
lines += ['', '| neuron_idx | source class | fraction of positive late arrivals |','|---:|---|---:|']
late=drive[drive.period=='late'].groupby(['neuron_idx','source_category']).positive_arrival_sum.sum()
for (node,cat),value in late.items():
den=late.loc[node].sum();lines.append(f'| {node} | {cat} | {100*value/den if den else 0:.4f}% |')
lines += ['', '| neuron_idx | isolated replay | late spike count range |','|---:|---|---:|']
for (node,mode),g in replay.groupby(['neuron_idx','mode']):lines.append(f'| {node} | {mode} | {g.late_spikes.min()}–{g.late_spikes.max()} |')
lines += ['', 'Replay holds all other recorded drive and the measured applied APL signal fixed. Removing a source class is a conditional single-cell test, not a closed-loop whole-brain intervention.',
'Drive fractions refer to delivered positive synaptic input, not fractions of biological causality or of net g. Inhibition and APL are separately accounted.',
'Ranked ancestry uses positive edges only; inhibitory influences are not claimed absent. Ranking is a heuristic; all path edges have real source events and arrival<=target-spike time.',
f"Float64 category shadow max absolute residual versus actual float32 g: {max(x['max_abs_rounding_residual'] for x in shadow):.9g}. This does not alter the exact CPU replay or actual queue checks."]
(exp/'audit/MECHANISM.md').write_text('\n'.join(lines)+'\n',encoding='utf-8')
print('\n'.join(lines))