Files
digital-drosophila/models/male-cns-lif/pn-recruitment-audit-v1/prepare.py
T
2026-09-30 10:45:48 +08:00

94 lines
6.9 KiB
Python

"""Register fixed conditional audit before reading PN contribution results."""
from datetime import datetime, timezone
import platform
import subprocess
import sys
import numpy as np
import pandas as pd
from context import (ROOT, MODEL, EXP, AH, AH_MODEL, AG, AG_MODEL, META, COEFF,
GROUPS, read, save, digest, sources, integrity, load_module)
def main():
assert not EXP.exists() or not any(EXP.iterdir()), 'Populated audit directory must not be reused'
assert read(AH / 'audit/final-status.json')['status'] == 'PASS-CONDITIONAL-KC-DRIVE-AUDIT'
assert read(AG / 'audit/final-status.json')['numerical_gate_pass']
for sub in ('protocol', 'regression', 'trials', 'audit', 'logs'):
(EXP / sub).mkdir(parents=True, exist_ok=False)
test_command = [sys.executable, '-B', '-m', 'unittest', '-v',
'test_pn_observer', 'test_apl_sources', 'test_structure_metrics', 'test_harness',
'test_validate_events', 'test_publication']
tested = subprocess.run(test_command, cwd=MODEL, capture_output=True, text=True)
with (EXP / 'regression/unit-tests.log').open('x') as f:
f.write(tested.stdout + tested.stderr)
save(EXP / 'regression/unit-tests.json', dict(command=test_command, exit_code=tested.returncode,
pass_all=tested.returncode == 0, sha256=digest(EXP / 'regression/unit-tests.log')))
assert tested.returncode == 0
paths = [AH / 'manifest.json', AH / 'checksums.sha256', AH_MODEL / 'manifest.json',
AH_MODEL / 'checksums.sha256', AH_MODEL / 'replay_core.py', AH_MODEL / 'populations.py',
AG / 'manifest.json', AG / 'checksums.sha256', AG_MODEL / 'manifest.json',
AG_MODEL / 'checksums.sha256', META, COEFF,
ROOT / 'datasets/male-cns-v1.0/processed/neuron-only/gpu/csr-weights.int64.npy']
save(EXP / 'protocol/preregistered.json', dict(
timestamp_utc=datetime.now(timezone.utc).isoformat(), sources=sources(),
inputs=[dict(path=str(p.relative_to(ROOT)), sha256=digest(p)) for p in paths],
parent_commit=subprocess.check_output(['git', '-C', str(ROOT), 'rev-parse', 'HEAD'], text=True).strip(),
scope='Post-outcome conditional PN/APL source audit; no new whole-brain simulation or learning',
previous_KC_outcome_known=True, before_PN_contribution_accounting=True,
new_GPU_use=False, max_threads=4, output_budget_bytes=2 * 1024**3,
per_trial_first_arrival_row_limit=1000000, truncation_allowed=False,
exact_gate='All PN events/counts/final v,g,ref; fixture pre/post histories; 12 deterministic accounting repeats',
APL_gate='Source float64 mathematical accounting within prior standard-float32 analytic roundoff bounds; not CUDA bitwise replay',
hypotheses={
'temporal_precedence': 'For every trial and every KC first spike, non-design PN spike must be strictly earlier; equals/after/absent retained',
'direct_PN_KC_arrival': 'PN source tick+18 strictly less than KC first spike; same tick arrival is after threshold',
'APL_source_precedence': 'Group h write at tick s affects only KC threshold ticks greater than s',
'APL_share': 'Cumulative group shares are descriptive float64; no accumulated source-share error bound or robust-majority claim',
'odor_structure': 'Fixed 686-dimensional counts; secondary fixed outside-six-odor-design-union subset; no activity-fraction or learning gate'},
attribution_limits=['Accepted edge antecedents are not proof of single-neuron necessity or intervention causality',
'Non-design means not in static design targets; does not mean noise or biologically incorrect',
'Source-V lanes are non-feedback accounting with initial/constant/request/reset/roundoff lanes',
'APL input matrix is legacy nonnegative raw-contact-normalized engineering mapping, not signed LIF current',
'No CAL per-tick target state was independently saved; final states and events only',
'Fixtures generated h for 4064 KC but applied only to fixture KC'],
python=sys.version, numpy=np.__version__, pandas=pd.__version__, machine=platform.machine(),
longdouble_mantissa_bits=int(np.finfo(np.longdouble).nmant)))
save(EXP / 'regression/old-integrity-before.json', integrity())
population = load_module('frozen_population_ai', AH_MODEL / 'populations.py')
assert digest(META) == population.METADATA_SHA256
meta = pd.read_parquet(META).sort_values('neuron_idx').reset_index(drop=True)
labels, report = population.classify(meta)
assert report['pass_all']
for name, count in (('ALLN', 420), ('ALIN', 24), ('ALON', 14), ('olfactory', 2639)):
selected = (meta.annotation_class == name).fillna(False).to_numpy(dtype=bool)
assert int(selected.sum()) == count and np.all(labels[selected] == 'other')
labels[selected] = 'olfactory_sensory' if name == 'olfactory' else name
assert set(np.unique(labels)).issubset(GROUPS)
for label, fname, count in (('KC', 'kc_globals.npy', 4064), ('APL', 'apl_globals.npy', 2), ('ALPN', 'pn_globals.npy', 686)):
observed = np.flatnonzero(labels == label).astype(np.int32)
assert len(observed) == count and np.array_equal(observed, np.load(AG / 'apl-bundle' / fname))
report.update(refined_exact_class_counts={label: int((labels == label).sum()) for label in GROUPS},
refinement='AH anatomical classifier, then exact ALLN/ALIN/ALON/olfactory classes split only from other; no name-prefix guessing')
save(EXP / 'protocol/population-audit.json', report)
save(EXP / 'protocol/metadata-schema.json', {c: dict(dtype=str(meta[c].dtype), nulls=int(meta[c].isna().sum())) for c in meta})
meta[['neuron_idx', 'body_id', 'annotation_class', 'annotation_type', 'neurotransmitter']].assign(
audit_source_group=labels).to_parquet(EXP / 'protocol/neuron-source-groups.parquet', index=False)
inventory = [dict(case=name, repeat=0, kind='fixture') for name in read(AG_MODEL / 'config.json')['fixtures']]
for row in read(AG / 'protocol/calibration-cases.json'):
inventory.append(dict(case=row['name'], repeat=0, kind='calibration'))
if row['seed'] == 51101:
inventory.append(dict(case=row['name'], repeat=1, kind='calibration'))
assert len(inventory) == len({(r['case'], r['repeat']) for r in inventory}) == 80
for row in inventory:
source = AG / 'gpu' / (row['case'] + '-r' + str(row['repeat']))
assert read(source / 'summary.json')['complete']
row['source'] = str(source.relative_to(ROOT))
save(EXP / 'protocol/inventory.json', inventory)
save(EXP / 'protocol/prepared-hashes.json', [dict(path=str(p.relative_to(EXP)), sha256=digest(p))
for p in sorted((EXP / 'protocol').iterdir()) if p.is_file() and p.name != 'prepared-hashes.json'])
print('REGISTERED fixed 80 existing records; no new brain simulation', flush=True)
if __name__ == '__main__':
main()