Files
2026-09-30 13:58:39 +08:00

178 lines
12 KiB
Python

"""All predeclared pairs and all trial outputs; never choose a winning odor."""
from itertools import combinations
import numpy as np
import pandas as pd
from context import EXP, AK, CFG, read, save as _save, digest, bit_equal, write_npz as _write_npz
from credit import pair_identity
def load_arrays(path):
with np.load(path, allow_pickle=False) as data:
return {key: data[key].copy() for key in data.files}
def metrics(values):
values = np.asarray(values, np.float64)
if not len(values):
return dict(min=None, mean=None, max=None, undefined_reason='No defined denominator observations')
return dict(min=float(values.min()), mean=float(values.mean()), max=float(values.max()))
def primary_rows(reg):
rows = [r for r in reg['planned'] if r['repeat'] == 0]
assert len(rows) == CFG['primary_trials'] and len({r['name'] for r in rows}) == len(rows)
return rows
def run(verify_only=False):
def save(path, value):
if verify_only:
assert read(path) == value, 'Summary JSON differs from recomputed evidence: ' + str(path)
else:
_save(path, value)
def write_npz(path, **value):
if verify_only:
old = load_arrays(path)
assert set(old) == set(value) and all(bit_equal(old[k], value[k]) for k in old)
else:
_write_npz(path, **value)
reg = read(EXP / 'protocol/preregistered.json')
assert read(EXP / 'audit/replays-complete.json')['pass_all']
data = load_arrays(EXP / 'protocol/incoming.npz')
for row in reg['planned']:
folder = EXP / 'trials' / (row['name'] + '-r' + str(row['repeat']))
hashes = read(folder / 'output-hashes.json')
assert {r['path'] for r in hashes} == {p.name for p in folder.iterdir() if p.name != 'output-hashes.json'}
for entry in hashes:
assert digest(folder / entry['path']) == entry['sha256']
original = load_arrays(AK / 'gpu' / row['cohort'] / (row['name'] + '-r' + str(row['repeat'])) / 'state.npz')
base = load_arrays(folder / 'baseline-replay.npz')
selected = np.isin(original['neuron_idx'], data['targets'])
assert all(bit_equal(base[k], original[k][data['targets']]) for k in ('v', 'g', 'ref', 'counts'))
assert all(bit_equal(base[k], original[k][selected]) for k in ('step', 'neuron_idx'))
candidate = pd.read_parquet(EXP / 'protocol/candidate-static.parquet')
target_meta = pd.read_parquet(EXP / 'protocol/mbon-metadata.parquet')
primary = primary_rows(reg)
repeats = []
for row in reg['planned']:
if row['repeat'] != 1:
continue
paths = [EXP / 'trials' / (row['name'] + '-r' + str(i)) for i in (0, 1)]
checks = {}
for filename in ('baseline-replay.npz', 'baseline-target-accounting.npz', 'baseline-edge-accounting.npz',
'conditional25-replay.npz', 'conditional25-target-accounting.npz', 'conditional25-edge-accounting.npz', 'credit.npz'):
a, b = (load_arrays(p / filename) for p in paths)
checks[filename] = set(a) == set(b) and all(bit_equal(a[k], b[k]) for k in a)
for filename in ('baseline-accounting.json', 'conditional25-accounting.json', 'credit.json', 'sensitivity.json'):
checks[filename] = read(paths[0] / filename) == read(paths[1] / filename)
assert all(checks.values()), 'Repeat accounting differs: ' + row['name']
repeats.append(dict(name=row['name'], checks=checks, pass_all=True))
assert len(repeats) == CFG['technical_repeats']
save(EXP / 'audit/repeat-checks.json', dict(pass_all=True, repeats=repeats))
summaries, target_rows, trial_metrics = [], [], []
for row in primary:
folder = EXP / 'trials' / (row['name'] + '-r0')
report = read(folder / 'summary.json')
assert report['pass_all'] and all(report['baseline_exact'].values())
summaries.append(report)
targets = load_arrays(folder / 'baseline-target-accounting.npz')
change = load_arrays(folder / 'conditional25-target-accounting.npz')
edges = load_arrays(folder / 'baseline-edge-accounting.npz')
exc = targets['accepted_positive_V'].sum(axis=1)
plastic_exc = targets['accepted_positive_V'][:, 0]
area_exc = targets['g_sign_integral_V_ms'][:, :, 0].sum(axis=1)
area_plastic = targets['g_sign_integral_V_ms'][:, 0, 0]
for i, meta in enumerate(target_meta.itertuples()):
entry = dict(name=row['name'], cohort=row['cohort'], mode=row['mode'], odor_id=row['odor_id'], seed=row['seed'],
neuron_idx=int(meta.neuron_idx), body_id=int(meta.body_id), annotation_type=meta.annotation_type,
compartment_verbatim=meta.mb_compartment_verbatim,
candidate_target=bool(np.any(candidate.target_neuron_idx.to_numpy() == meta.neuron_idx)),
accepted_total_positive_V=float(exc[i]), accepted_plastic_positive_V=float(plastic_exc[i]),
plastic_accepted_positive_fraction=None if exc[i] == 0 else float(plastic_exc[i] / exc[i]),
positive_source_g_area_V_ms=float(area_exc[i]), plastic_positive_g_area_V_ms=float(area_plastic[i]),
plastic_positive_g_area_fraction=None if area_exc[i] == 0 else float(area_plastic[i] / area_exc[i]),
baseline_spikes=int(targets['spike_count'][i]), conditional25_spikes=int(change['spike_count'][i]),
baseline_first_tick=int(targets['first_spike_tick'][i]), conditional25_first_tick=int(change['first_spike_tick'][i]),
max_abs_V_delta_SI=float(np.max(np.abs(targets['history_v'][:, i] - change['history_v'][:, i]))),
max_abs_g_delta_SI=float(np.max(np.abs(targets['history_g'][:, i] - change['history_g'][:, i]))))
target_rows.append(entry)
pick = data['is_candidate']
summary = dict(name=row['name'], cohort=row['cohort'], mode=row['mode'], odor_id=row['odor_id'], seed=row['seed'],
plastic_due_events=int(edges['due_count'][pick].sum()), plastic_accepted_events=int(edges['accepted_count'][pick].sum()),
plastic_rejected_events=int(edges['rejected_count'][pick].sum()),
plastic_pending_events=int(edges['pending_after_window_count'][pick].sum()),
plastic_edges_with_accepted_events=int(np.count_nonzero(edges['accepted_count'][pick])),
accepted_positive_V=float(exc.sum()), plastic_accepted_positive_V=float(plastic_exc.sum()),
plastic_accepted_positive_fraction=None if exc.sum() == 0 else float(plastic_exc.sum() / exc.sum()),
plastic_positive_g_area_fraction=None if area_exc.sum() == 0 else float(area_plastic.sum() / area_exc.sum()),
**report['sensitivity'])
trial_metrics.append(summary)
target_table = pd.DataFrame(target_rows)
if verify_only:
assert target_table.equals(pd.read_parquet(EXP / 'audit/per-MBON-primary.parquet'))
else:
target_table.to_parquet(EXP / 'audit/per-MBON-primary.parquet', index=False)
save(EXP / 'audit/primary-trial-metrics.json', trial_metrics)
pair_reports = []
for cohort in sorted({r['cohort'] for r in primary}):
for mode in sorted({r['mode'] for r in primary}):
rows = [r for r in primary if r['cohort'] == cohort and r['mode'] == mode]
odors = sorted({r['odor_index'] for r in rows})
assert len(rows) == 30 and len(odors) == 6
traces = {}; whole = {}; ids = {}
for odor in odors:
series = sorted((r for r in rows if r['odor_index'] == odor), key=lambda r: r['seed'])
assert len(series) == 5
ids[odor] = series[0]['odor_id']
credit = [load_arrays(EXP / 'trials' / (r['name'] + '-r0') / 'credit.npz') for r in series]
traces[odor] = np.stack([c['trace_gate'] for c in credit])
whole[odor] = np.stack([(c['spike_count_total'] > 0).astype(np.float32) for c in credit])
for a, b in combinations(odors, 2):
name = f'{cohort}-{mode}-{a:02d}-vs-{b:02d}'
result = dict(cohort=cohort, mode=mode, odor_a=ids[a], odor_b=ids[b], odor_index_a=a, odor_index_b=b)
for definition, series in (('virtual_gate900', traces), ('whole_window_auxiliary', whole)):
identities = pair_identity(series[a], series[b], data['edge_source_local'])
save_arrays = {k: v for k, v in identities.items() if isinstance(v, np.ndarray)}
write_npz(EXP / 'pairs' / (name + '-' + definition + '.npz'), **save_arrays)
summary = identities['summary']
# Historic local existence criterion only, no new overall pass rate.
summary['local_specific_KC_and_edges_exist_both_sides'] = all(
summary[unit]['category_counts'][side] >= 1 for unit in ('KC', 'edges') for side in ('A_specific', 'B_specific'))
summary['compartments'] = {}
for comp, group in candidate.groupby('target_compartment_verbatim', sort=True):
sub = pair_identity(series[a], series[b], data['edge_source_local'][group.index.to_numpy()])
summary['compartments'][str(comp)] = sub['summary']['edges']
result[definition] = summary
pair_reports.append(result)
assert len(pair_reports) == 60
save(EXP / 'audit/pair-identities.json', pair_reports)
blocks = {}
for cohort in sorted({r['cohort'] for r in primary}):
for mode in sorted({r['mode'] for r in primary}):
trials = [r for r in trial_metrics if r['cohort'] == cohort and r['mode'] == mode]
pairs = [p for p in pair_reports if p['cohort'] == cohort and p['mode'] == mode]
blocks[cohort + '/' + mode] = dict(trials=len(trials), pairs=len(pairs),
pairs_with_both_specific_KC_and_edge_sets=sum(p['virtual_gate900']['local_specific_KC_and_edges_exist_both_sides'] for p in pairs),
KC_empty_union_pairs=sum(p['virtual_gate900']['KC']['empty_union'] for p in pairs),
edge_empty_union_pairs=sum(p['virtual_gate900']['edges']['empty_union'] for p in pairs),
KC_active_set_Jaccard=metrics([p['virtual_gate900']['KC']['active_set_jaccard'] for p in pairs if not p['virtual_gate900']['KC']['empty_union']]),
candidate_edge_active_set_Jaccard=metrics([p['virtual_gate900']['edges']['active_set_jaccard'] for p in pairs if not p['virtual_gate900']['edges']['empty_union']]),
plastic_accepted_events=metrics([r['plastic_accepted_events'] for r in trials]),
plastic_fraction_of_all_MBON_accepted_positive=metrics([r['plastic_accepted_positive_fraction'] for r in trials if r['plastic_accepted_positive_fraction'] is not None]),
conditional25_event_changed_trials=sum(r['event_sequence_changed'] for r in trials),
conditional25_count_or_first_latency_changed_trials=sum(r['functional_count_or_first_latency_change'] for r in trials),
max_abs_V_difference_SI=max(r['max_abs_V_difference_SI'] for r in trials),
max_abs_g_difference_SI=max(r['max_abs_g_difference_SI'] for r in trials))
outcome = dict(arithmetic_and_coverage_pass=True, primary_trials=120, exact_repeats=24, pairs=60, blocks=blocks,
candidate_generated=False, learning_achieved=False, conditioning_executed=False, scientific_overall_PASS_threshold_defined=False,
maximum_observed_g_lane_roundoff_residual_SI=max(read(EXP / 'trials' / (r['name'] + '-r0') / 'baseline-accounting.json')['max_g_lane_residual_V'] for r in primary),
interpretation='Read-only credit delivery and fixed conditional sensitivity; not closed-loop memory or dopamine measurement')
save(EXP / 'audit/scientific-summary.json', outcome)
return outcome
if __name__ == '__main__':
print(run(), flush=True)