Contextualize isolated feedback motifs with archived whole-brain input accounting

This commit is contained in:
Digital Drosophila Archive
2026-09-30 01:07:42 +08:00
parent 6fc326ccd1
commit 5008cd85ca
13 changed files with 32125 additions and 0 deletions
+151
View File
@@ -0,0 +1,151 @@
"""Read-only reanalysis of sealed event accounting; no simulation/model mutation."""
from datetime import datetime, timezone
import hashlib
import json
from pathlib import Path
import sys
import numpy as np
import pandas as pd
ROOT=Path('/data/digital-drosophila')
Z=ROOT/'experiments/phase4z-pn-feedback-audit'
AC=ROOT/'experiments/phase4ac-lif-semantics'
OUT=ROOT/'registry/feedback-context-review-20260930'
def sha(path):
h=hashlib.sha256()
with path.open('rb') as f:
for b in iter(lambda:f.read(8<<20),b''):h.update(b)
return h.hexdigest()
def save(path,value):
with path.open('x',encoding='utf-8') as f:json.dump(value,f,indent=2,ensure_ascii=False,allow_nan=False);f.write('\n')
def verify_inputs():
selection={Z:['drive/edge-accounting.parquet','replay/results.parquet','drive/late-ISI-and-g.parquet',
'audit/incoming-source-metadata.parquet','audit/watched-metadata.parquet','regression/trials.json'],
AC:['audit/selected-real-edges.csv','motifs/summary.csv','audit/final-status.json']}
rows=[]
for folder,names in selection.items():
manifest=json.loads((folder/'manifest.json').read_text())
indexed={r['path']:r for r in manifest['files']}
for name in names:
p=folder/name;r=indexed[name]
assert p.is_file() and p.stat().st_size==r['bytes'] and sha(p)==r['sha256'],str(p)
rows.append(dict(path=str(p.relative_to(ROOT)),bytes=r['bytes'],sha256=r['sha256'],
sealed_manifest_sha256=sha(folder/'manifest.json')))
return rows
def analyze():
before=verify_inputs()
if OUT.exists():raise RuntimeError('Refusing existing output')
OUT.mkdir()
save(OUT/'protocol.json',dict(timestamp_utc=datetime.now(timezone.utc).isoformat(),
source=str(Path(__file__).resolve().relative_to(ROOT)),source_sha256=sha(Path(__file__)),
analysis='Post-hoc contextualization of preselected motifs using existing sealed accounting; no new simulations.',
scope='All six archived calibration odors, seed 131101, frozen_reference only; not heldout or learning evidence.',
inputs=before,metric='sum of positive arrived synaptic weights, NOT g trajectory attribution or causal responsibility'))
d=pd.read_parquet(Z/'drive/edge-accounting.parquet')
required={'trial','period','edge_id','source_neuron_idx','target_neuron_idx','raw_synapse_count','effective_weight',
'edge_event_count','positive_arrival_sum','negative_arrival_sum','source_role'}
assert required<=set(d)
d=d[d.trial.str.endswith('-frozen_reference')].copy()
expected={f'{i}-131101-frozen_reference' for i in range(6)}
assert set(d.trial)==expected and not d.duplicated(['trial','period','edge_id']).any()
assert set(d.period)=={'input_on','post_input','late'}
assert np.allclose(d.positive_arrival_sum,d.edge_event_count*np.maximum(d.effective_weight,0),rtol=0,atol=0)
assert np.allclose(d.negative_arrival_sum,d.edge_event_count*np.minimum(d.effective_weight,0),rtol=0,atol=0)
edges=pd.read_csv(AC/'audit/selected-real-edges.csv')
for e in edges.itertuples():
records=d[d.edge_id==e.edge_id]
assert len(records)>0
assert records.source_neuron_idx.eq(e.source_neuron_idx).all()
assert records.target_neuron_idx.eq(e.target_neuron_idx).all()
assert records.raw_synapse_count.eq(e.raw_count).all()
metadata=pd.read_parquet(Z/'audit/incoming-source-metadata.parquet').set_index('neuron_idx')
watch=pd.read_parquet(Z/'audit/watched-metadata.parquet').set_index('neuron_idx')
assert metadata.index.is_unique and watch.index.is_unique
nodes=[1197,1381,1511,82312,133666]
scopes={'pair':{1381,1511},'trio':{1197,1381,1511},'five':set(nodes)}
summaries=[];types=[];sources=[]
for (trial,period,target),g in d[d.target_neuron_idx.isin(nodes)].groupby(['trial','period','target_neuron_idx']):
den=float(g.positive_arrival_sum.sum());neg=float(g.negative_arrival_sum.sum())
assert den>0
per=g.groupby('source_neuron_idx',sort=False).positive_arrival_sum.sum().sort_values(ascending=False,kind='stable')
pos=per[per>0];n80=int(np.searchsorted(pos.cumsum().to_numpy(),.8*den,side='left')+1)
alln=float(g.loc[g.source_role.eq('ALLN'),'positive_arrival_sum'].sum())
alpn=float(g.loc[g.source_role.eq('ALPN'),'positive_arrival_sum'].sum())
for scope,subset in scopes.items():
internal=g.source_neuron_idx.isin(subset)&g.target_neuron_idx.isin(subset)
num=float(g.loc[internal,'positive_arrival_sum'].sum())
summaries.append(dict(trial=trial,period=period,target_neuron_idx=int(target),body_id=int(watch.loc[target,'body_id']),
annotation_type=watch.loc[target,'annotation_type'],scope=scope,target_in_scope=bool(target in subset),
positive_arrival_sum=den,negative_arrival_sum=neg,internal_positive_sum=num,
internal_positive_fraction=num/den,outside_positive_fraction=(den-num)/den,
active_positive_source_neurons=int(len(pos)),sources_for_80_percent=n80,
ALLN_positive_fraction=alln/den,ALPN_positive_fraction=alpn/den))
for src,value in per.items():
m=metadata.loc[src]
sources.append(dict(trial=trial,period=period,target_neuron_idx=int(target),source_neuron_idx=int(src),
source_body_id=int(m.body_id),source_type=m.annotation_type,positive_arrival_sum=float(value),positive_fraction=float(value/den)))
gg=g.assign(source_type=g.source_neuron_idx.map(metadata.annotation_type).fillna('UNKNOWN_TYPE'))
for typ,z in gg.groupby('source_type'):
types.append(dict(trial=trial,period=period,target_neuron_idx=int(target),source_type=str(typ),
positive_arrival_sum=float(z.positive_arrival_sum.sum()),positive_fraction=float(z.positive_arrival_sum.sum()/den),
source_neurons=int(z.source_neuron_idx.nunique())))
summary=pd.DataFrame(summaries);summary.to_csv(OUT/'context-fractions.csv',index=False)
pd.DataFrame(types).to_csv(OUT/'source-type-fractions.csv',index=False)
pd.DataFrame(sources).to_csv(OUT/'source-neuron-fractions.csv',index=False)
rep=pd.read_parquet(Z/'replay/results.parquet')
rep=rep[rep.trial.isin(expected)&rep.neuron_idx.isin(nodes)&rep['mode'].isin(['base','omit_ALLN','omit_ALPN'])].copy()
assert len(rep)==6*5*3
rep.to_csv(OUT/'existing-conditional-replay.csv',index=False)
late=summary[(summary.period=='late')&(summary.scope=='five')]
iso=pd.read_csv(AC/'motifs/summary.csv')
isi=pd.read_parquet(Z/'drive/late-ISI-and-g.parquet')
isi=isi[isi.trial.isin(expected)&isi.neuron_idx.isin(nodes)]
comparison=[]
for node,g in late.groupby('target_neuron_idx'):
rr=rep[rep.neuron_idx==node];ii=isi[isi.neuron_idx==node]
row=dict(neuron_idx=int(node),body_id=int(watch.loc[node,'body_id']),type=str(watch.loc[node,'annotation_type']),
internal_positive_fraction_min=float(g.internal_positive_fraction.min()),
internal_positive_fraction_max=float(g.internal_positive_fraction.max()),
sources_for_80_percent_min=int(g.sources_for_80_percent.min()),sources_for_80_percent_max=int(g.sources_for_80_percent.max()),
positive_sources_min=int(g.active_positive_source_neurons.min()),positive_sources_max=int(g.active_positive_source_neurons.max()),
isolated_five_late_spikes=int(iso[(iso.motif=='five')&(iso.neuron_idx==node)].late_spikes.iloc[0]),
whole_brain_late_rate_min=float(ii.late_rate_hz.min()),whole_brain_late_rate_max=float(ii.late_rate_hz.max()))
for mode in ('base','omit_ALLN','omit_ALPN'):
vals=rr.loc[rr['mode']==mode,'late_spikes']
row[mode+'_late_min']=int(vals.min());row[mode+'_late_max']=int(vals.max())
comparison.append(row)
comp=pd.DataFrame(comparison);comp.to_csv(OUT/'summary.csv',index=False)
lines=['# Feedback motif contextualization — read-only review','',
'This is not a new learning stage, intervention or model. Source: six archived calibration odors, one seed 131101, frozen_reference; all cases retained.',
'Late interval 500–1,000 ms. Fractions measure positive arrived weights, not causal importance, g attribution or net excitation after inhibition/APL.', '',
'| Target idx / type | Five-node internal positive input | Positive sources | Sources needed for 80% | Base late spikes | omit ALLN | omit ALPN |',
'|---|---:|---:|---:|---:|---:|---:|']
for r in comp.itertuples():
lines.append(f'| {r.neuron_idx} / {r.type} | {100*r.internal_positive_fraction_min:.2f}–{100*r.internal_positive_fraction_max:.2f}% | {r.positive_sources_min}–{r.positive_sources_max} | {r.sources_for_80_percent_min}–{r.sources_for_80_percent_max} | {r.base_late_min}–{r.base_late_max} | {r.omit_ALLN_late_min}–{r.omit_ALLN_late_max} | {r.omit_ALPN_late_min}–{r.omit_ALPN_late_max} |')
lines+=['', '## Consequence for the next experiment', '',
'The two-cell loop can sustain activity in isolation, but the full-brain watched ALLNs receive most positive input from outside the five-cell motif. Do not target only this pair as the established unique cause.',
'Existing conditional omissions freeze other recorded events: removing ALLN arrivals still leaves PN/other recorded drive. This establishes conditional sufficiency of residual input, NOT that an ALLN knockout in the live brain would fail.',
'Likewise a large input fraction is not a causal fraction; small inputs can matter near threshold. The VA6->KC edge illustrates why fractions alone are not a deletion target ranking.',
'Future separately authorized model tests should first validate operator semantics, then assess distributed local feedback and preservation of stimulus information, before learning. No gain/threshold/eta/mask tuning is licensed by this table.',
'No new simulations, learning, weights or frozen-file changes. No heldout data used. Usable associative learning remains unachieved.','']
with (OUT/'REPORT.md').open('x',encoding='utf-8') as f:f.write('\n'.join(lines))
after=verify_inputs();assert before==after
save(OUT/'verification.json',dict(pass_all=True,inputs_before_after_identical=True,
inputs_checked=len(before),edge_identity_matches=13,frozen_source_CPU_replay_checks='Previously sealed Phase4Z regressions, not rerun here',
new_simulations=0,learning_achieved=False))
records=[dict(path=str(p.relative_to(OUT)),bytes=p.stat().st_size,sha256=sha(p)) for p in sorted(OUT.iterdir()) if p.is_file()]
save(OUT/'manifest.json',dict(files=records))
with (OUT/'checksums.sha256').open('x') as f:
for r in records:f.write(r['sha256']+' '+r['path']+'\n')
print(comp.to_string(index=False));print('REVIEW SEALED; no new model or simulation')
if __name__=='__main__':analyze()