101 lines
5.6 KiB
Python
101 lines
5.6 KiB
Python
"""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()
|