Seal Phase 4AH conditional KC drive audit and source accounting
This commit is contained in:
@@ -0,0 +1,42 @@
|
||||
"""Publish only small sealed conditional-audit evidence, not bulk backup."""
|
||||
import json
|
||||
from pathlib import Path
|
||||
import shutil
|
||||
import sys
|
||||
|
||||
ROOT = Path('/data/digital-drosophila')
|
||||
MODEL = ROOT / 'models/male-cns-lif/kc-drive-audit-v1'
|
||||
EXP = ROOT / 'experiments/phase4ah-kc-drive-audit'
|
||||
sys.path.insert(0, str(MODEL))
|
||||
from context import check, digest, save
|
||||
sys.path.insert(0, str(ROOT / 'models/male-cns-lif/terminal-scope-diagnostic-v1'))
|
||||
from diagnostic import manifest_check
|
||||
|
||||
|
||||
def main():
|
||||
check()
|
||||
verification = {str(p.relative_to(ROOT)): manifest_check(p, digest) for p in (MODEL, EXP)}
|
||||
assert all(v['pass'] for v in verification.values())
|
||||
registry = ROOT / 'registry/phase4ah-kc-drive-audit'
|
||||
registry.mkdir(exist_ok=False)
|
||||
records = []
|
||||
manifest = json.loads((EXP / 'manifest.json').read_text())
|
||||
for p in [EXP / r['path'] for r in manifest['files']] + [EXP / 'manifest.json', EXP / 'checksums.sha256']:
|
||||
if p.stat().st_size > 4 * 1024**2 or p.suffix not in ('.json', '.csv', '.md', '.sha256'):
|
||||
continue
|
||||
target = registry / 'evidence' / p.relative_to(EXP)
|
||||
target.parent.mkdir(parents=True, exist_ok=True)
|
||||
with p.open('rb') as src, target.open('xb') as dst:
|
||||
shutil.copyfileobj(src, dst)
|
||||
assert digest(target) == digest(p)
|
||||
records.append(dict(source=str(p.relative_to(ROOT)), copy=str(target.relative_to(registry)),
|
||||
bytes=p.stat().st_size, sha256=digest(p)))
|
||||
save(registry / 'evidence-index.json', records)
|
||||
save(registry / 'seal-verification.json', verification)
|
||||
with (EXP / 'REPORT.md').open('rb') as src, (ROOT / 'docs/progress/phase4ah-kc-drive-audit.md').open('xb') as dst:
|
||||
shutil.copyfileobj(src, dst)
|
||||
print(json.dumps(dict(copied=len(records), verification=verification)), flush=True)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
@@ -0,0 +1,100 @@
|
||||
"""Descriptive post-audit metrics from sealed outputs, without new trajectories."""
|
||||
from pathlib import Path
|
||||
import json
|
||||
import sys
|
||||
import numpy as np
|
||||
import pandas as pd
|
||||
|
||||
ROOT = Path('/data/digital-drosophila')
|
||||
EXP = ROOT / 'experiments/phase4ah-kc-drive-audit'
|
||||
MODEL = ROOT / 'models/male-cns-lif/kc-drive-audit-v1'
|
||||
sys.path.insert(0, str(MODEL))
|
||||
from context import read, save, digest
|
||||
from populations import GROUPS
|
||||
|
||||
|
||||
def ratio(a, b):
|
||||
return None if b == 0 else float(a / b)
|
||||
|
||||
|
||||
def main():
|
||||
final = read(EXP / 'audit/final-status.json')
|
||||
assert final['status'] == 'PASS-CONDITIONAL-KC-DRIVE-AUDIT'
|
||||
manifest = {r['path']: r for r in read(EXP / 'manifest.json')['files']}
|
||||
grouped = {}
|
||||
inputs = []
|
||||
for item in read(EXP / 'protocol/inventory.json'):
|
||||
if item['kind'] != 'calibration' or item['repeat'] != 0:
|
||||
continue
|
||||
name = item['case'] + '-r0'
|
||||
folder = EXP / 'trials' / name
|
||||
for filename in ('summary.json', 'per-kc.parquet', 'per-pn.parquet'):
|
||||
p = folder / filename
|
||||
rel = str(p.relative_to(EXP))
|
||||
assert digest(p) == manifest[rel]['sha256']
|
||||
inputs.append(dict(path=rel, sha256=manifest[rel]['sha256']))
|
||||
summary = read(folder / 'summary.json')
|
||||
kc = pd.read_parquet(folder / 'per-kc.parquet')
|
||||
pn = pd.read_parquet(folder / 'per-pn.parquet')
|
||||
grouped.setdefault(summary['mode'], []).append((summary, kc, pn))
|
||||
output = {}
|
||||
for mode, rows in grouped.items():
|
||||
assert len(rows) == 30
|
||||
allkc = pd.concat([x[1] for x in rows], ignore_index=True)
|
||||
assert len(allkc) == 30 * 4064
|
||||
strata = {}
|
||||
for label, data in (('all', allkc), ('ever_active', allkc[allkc.spike_count > 0]),
|
||||
('never_active', allkc[allkc.spike_count == 0])):
|
||||
exc = data[[g + '_accepted_exc_SI' for g in GROUPS]].sum(axis=1)
|
||||
inh = data[[g + '_accepted_inh_abs_SI' for g in GROUPS]].sum(axis=1)
|
||||
pnexc = data.ALPN_accepted_exc_SI
|
||||
margin = data.best_threshold_margin_mV
|
||||
strata[label] = dict(neuron_trials=len(data),
|
||||
with_ALPN_exc_neuron_trials=int((pnexc > 0).sum()),
|
||||
with_any_exc_neuron_trials=int((exc > 0).sum()),
|
||||
with_ALPN_exc_fraction=ratio(int((pnexc > 0).sum()), len(data)),
|
||||
with_any_exc_fraction=ratio(int((exc > 0).sum()), len(data)),
|
||||
accepted_exc_increment_sum_V=float(exc.sum()),
|
||||
accepted_inh_increment_abs_sum_V=float(inh.sum()),
|
||||
ALPN_exc_increment_sum_V=float(pnexc.sum()),
|
||||
APL_write_increment_sum_V=float(data.APL_write_SI.sum()),
|
||||
APL_write_ref_sum_V=float(data.APL_write_ref_SI.sum()),
|
||||
APL_pre_first_spike_increment_sum_V=float(data.APL_pre_first_spike_SI.sum()),
|
||||
APL_write_to_exc_increment_ratio=ratio(data.APL_write_SI.sum(), exc.sum()),
|
||||
refractory_target_ticks=int(data.refractory_ticks.sum()),
|
||||
negative_g_target_tick_fraction=ratio(data.negative_g_ticks.sum(), len(data) * 1000),
|
||||
best_threshold_margin_mV_quantiles={str(q): float(margin.quantile(q)) for q in (0, .25, .5, .75, 1)},
|
||||
source_g_area_V_ms={g: float(data['source_g_area_' + g + '_V_ms'].sum())
|
||||
for g in [n + '_' + sign for n in GROUPS for sign in ('exc', 'inh')] + ['graded_APL']},
|
||||
source_area_max_abs_residual_V_ms=float(data.source_g_area_residual_V_ms.abs().max()))
|
||||
accepted = sum(x[0]['input']['accepted'] for x in rows)
|
||||
requested = sum(x[0]['input']['requests'] for x in rows)
|
||||
source = final['modes'][mode]['source_groups']
|
||||
source_exc = {g: source[g]['accepted_exc_SI'] for g in GROUPS}
|
||||
output[mode] = dict(trials=30, input_requests=requested, input_accepted=accepted,
|
||||
input_acceptance_fraction=ratio(accepted, requested),
|
||||
PN_actual_spikes=sum(x[0]['input']['actual_spikes_by_source_group']['ALPN'] for x in rows),
|
||||
PN_design_targets_distinct=sorted({int(i) for _, _, pn in rows for i in pn.loc[pn.design_target, 'neuron_idx']}),
|
||||
PN_ever_active_distinct=sorted({int(i) for _, _, pn in rows for i in pn.loc[pn.actual_spikes > 0, 'neuron_idx']}),
|
||||
source_accepted_exc_increment_sum_V=source_exc,
|
||||
ALPN_fraction_of_accepted_exc_increment=ratio(source_exc['ALPN'], sum(source_exc.values())),
|
||||
ALPN_due_edges=source['ALPN']['due_edges'], ALPN_accepted_edges=source['ALPN']['accepted_edges'],
|
||||
ALPN_rejected_edges=source['ALPN']['rejected_edges'],
|
||||
ALPN_rejection_fraction=ratio(source['ALPN']['rejected_edges'], source['ALPN']['due_edges']),
|
||||
strata=strata)
|
||||
result = dict(scope='Post-outcome descriptive conditional audit, no causal intervention, no learning', modes=output,
|
||||
target_tick_and_neuron_trial_counts_not_unique_cells=True,
|
||||
ratios_are_cumulative_increment_bookkeeping_not_spike_causality=True,
|
||||
inputs=inputs, source_script_sha256=digest(Path(__file__)),
|
||||
sealed_model_manifest_sha256=digest(MODEL / 'manifest.json'),
|
||||
sealed_experiment_manifest_sha256=digest(EXP / 'manifest.json'))
|
||||
destination = ROOT / 'registry/phase4ah-kc-drive-audit/interpretation-metrics.json'
|
||||
save(destination, result)
|
||||
with destination.with_suffix('.sha256').open('x') as f:
|
||||
f.write(digest(destination) + ' ' + destination.name + '\n')
|
||||
print(json.dumps({mode: {k: v for k, v in data.items() if k not in ('PN_design_targets_distinct', 'PN_ever_active_distinct')}
|
||||
for mode, data in output.items()}, indent=2), flush=True)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
Reference in New Issue
Block a user