Files
digital-drosophila/models/male-cns-lif/apl-timing-validation-v1/prepare.py
T
2026-09-30 13:18:18 +08:00

181 lines
12 KiB
Python

"""Lock both validation cohorts before outcomes; read no old novel-odor dynamics."""
from datetime import datetime, timezone
import ast
import json
import platform
import shutil
import subprocess
import sys
import numpy as np
import pandas as pd
import yaml
from context import (ROOT, MODEL, EXP, AJ, AJ_MODEL, AG, CFG, PINS, STATIC,
read, save, digest, sources, integrity, budget, bit_equal)
from encoder_inputs import frozen_pn_drive, make_requests, write_npz
def copy_exact(source, target):
target.parent.mkdir(parents=True, exist_ok=True)
with source.open('rb') as source_stream, target.open('xb') as target_stream:
shutil.copyfileobj(source_stream, target_stream)
assert digest(source) == digest(target)
def main():
assert not EXP.exists() or not any(EXP.iterdir()), 'Never reuse a populated experiment'
assert shutil.disk_usage(EXP.parent).free > CFG['output_budget_bytes'] + 10 * 1024**3
for relative, expected in PINS.items():
assert digest(ROOT / relative) == expected, relative
previous = read(AJ / 'audit/final-status.json')
assert previous['status'] == 'PASS-FIXED-CAL-APL-TIMING-HYPOTHESIS'
assert previous['delay18_representation_pass'] and previous['old_frozen_integrity_and_five_reference_pass']
assert CFG['apl'] == read(AJ_MODEL / 'config.json')['apl']
assert CFG['gates'] == read(AJ_MODEL / 'config.json')['gates']
assert CFG['apl_delay_steps'] == 18 and not CFG['training'] and not CFG['candidate_generation']
seed_audit = read(MODEL / 'seed-audit.json')
assert seed_audit['proposed_seeds'] == CFG['validation']['seeds'] and seed_audit['collision_found'] is False
seed_sources = []
for row in seed_audit['inspected_files']:
if row.get('remote_path'):
path = ROOT / row['remote_path']
assert path.is_relative_to(ROOT) and '..' not in path.parts
assert digest(path) == row['sha256'], row['remote_path']
seed_sources.append(dict(path=path.relative_to(ROOT).as_posix(), sha256=row['sha256']))
assert seed_sources, 'At least exact-mapped static seed sources must be checked on server'
for name in ('protocol', 'cases', 'gpu', 'oracle', 'component-audit', 'audit', 'validation', 'regression', 'logs', 'extension-build'):
(EXP / name).mkdir(parents=True, exist_ok=False)
command = [sys.executable, '-B', '-m', 'unittest', 'discover', '-v', '-s', str(MODEL), '-p', 'test_*.py']
test = subprocess.run(command, cwd=MODEL, text=True, capture_output=True)
with (EXP / 'regression/unit-tests.log').open('x', encoding='utf-8') as stream:
stream.write(test.stdout + test.stderr)
save(EXP / 'regression/unit-tests.json', dict(command=command, exit_code=test.returncode,
pass_all=test.returncode == 0, sha256=digest(EXP / 'regression/unit-tests.log')))
assert test.returncode == 0
inputs = {relative: expected for relative, expected in PINS.items()}
for row in seed_sources:
inputs[row['path']] = row['sha256']
for path in (AJ / 'audit/final-status.json', AJ / 'protocol/preregistered.json',
AG / 'protocol/calibration-cases.json', AG / 'protocol/encoder-audit.json'):
inputs[path.relative_to(ROOT).as_posix()] = digest(path)
save(EXP / 'protocol/preregistered.json', dict(timestamp_utc=datetime.now(timezone.utc).isoformat(),
sources=sources(), config=CFG, inputs=[dict(path=path, sha256=sha) for path, sha in sorted(inputs.items())],
parent_commit=subprocess.check_output(['git', '-C', str(ROOT), 'rev-parse', 'HEAD'], text=True).strip(),
prior_AJ_CAL_outcomes_known=True, before_new_requests_and_brain_trajectories=True,
training=False, candidate_generated=False, historical_never_simulated_odor_claim=False,
seed_collision_audit_scope='Only enumerated static sources and explicitly evaluated derivations; no universal independence claim',
shared_seed_across_conditions=True, new_dynamic_scope='seed_validation then conditionally novel_to_aj',
source_engine='Unmodified SHA-pinned AJ backend functions, using original __file__ and globals',
oracle_limit='Independent Brian LIF and delay FIFO, shared frozen Torch APL component',
python=sys.version, machine=platform.machine(), numpy=np.__version__))
save(EXP / 'regression/old-integrity-before.json', integrity())
from run_case import preflight
preflight()
import torch
cfg_path = ROOT / 'models/male-cns-lif/olfactory-grounding-v1/phase4l.yaml'
oc = yaml.safe_load(cfg_path.read_text())
assert oc['odor_encoder']['duration_ms'] == CFG['validation']['duration_ms']
assert oc['odor_encoder']['modes'] == CFG['validation']['modes']
panel = pd.read_parquet(STATIC / 'odor-encoder/frozen-odor-panel.parquet')
assert len(panel) == 12 and panel.odor_id.is_unique
assert panel.split.tolist() == ['calibration'] * 6 + ['heldout'] * 6
median = float(np.median(panel.mapped_response_sum))
assert median == CFG['validation']['median_mapped_response_sum']
selection = read(STATIC / 'odor-encoder/selection.json')
mapping = pd.read_parquet(STATIC / 'receptor-mapping/olfactory-mapping.parquet')
with np.load(STATIC / 'odor-encoder/mapped-glomerular-vectors.npz', allow_pickle=False) as source:
assert set(source.files) == set(panel.odor_id) | {'glomeruli'}
assert source['glomeruli'].tolist() == selection['glomeruli_order']
vectors = {oid: source[oid].copy() for oid in panel.odor_id}
encoder_source = ROOT / 'models/male-cns-lif/phase4l.py'
drive, ast_sha = frozen_pn_drive(encoder_source, PINS[str(encoder_source.relative_to(ROOT))])
cached = {}
static_rows = {}
for cohort, frame in (('seed_validation', panel.iloc[:6]), ('novel_to_aj', panel.iloc[6:])):
static_rows[cohort] = [dict(odor_id=str(odor.odor_id), odor_index=index,
source_panel_split=str(odor.split)) for index, (_, odor) in enumerate(frame.iterrows())]
for mode in CFG['validation']['modes']:
for index, (_, odor) in enumerate(frame.iterrows()):
targets, rates, ignored_frame = drive(str(odor.odor_id), vectors[odor.odor_id], mapping,
selection['glomeruli_order'], mode, median, oc)
assert targets.dtype == np.int32 and rates.dtype == np.float32 and len(targets) > 0
assert len(np.unique(targets)) == len(targets) and np.all((targets >= 0) & (targets < CFG['neurons']))
assert np.isfinite(rates).all() and np.all(rates > 0)
cached[(cohort, mode, index)] = (targets, rates)
# Reproduce all 60 known CAL input arrays, without any old heldout trajectory.
control_rows = []
old_inventory = read(AG / 'protocol/calibration-cases.json')
assert len(old_inventory) == 60
for row in old_inventory:
targets, rates = cached[('seed_validation', row['mode'], row['odor_index'])]
old_case = AG / 'cases' / row['name']
spec = read(old_case / 'spec.json')
assert spec['odor_id'] == static_rows['seed_validation'][row['odor_index']]['odor_id']
with np.load(old_case / 'pn-drive.npz', allow_pickle=False) as old:
assert bit_equal(targets, old['targets']) and bit_equal(rates, old['rates_hz'])
requests = make_requests(targets, rates, row['seed'])
with np.load(old_case / 'requests.npz', allow_pickle=False) as old:
assert bit_equal(requests[:, 0], old['tick']) and bit_equal(requests[:, 1], old['neuron_idx'])
control_rows.append(dict(case=row['name'], pass_all=True, seed=row['seed'],
old_requests_sha256=digest(old_case / 'requests.npz'), old_drive_sha256=digest(old_case / 'pn-drive.npz'),
target_rate_and_request_arrays_bitwise=True))
save(EXP / 'protocol/encoder-control.json', dict(pass_all=True, cases=control_rows,
old_heldout_dynamic_access=False, comparison='All original 60 CAL request/drive arrays; no trajectory or RNG-column reorder'))
template = read(AJ / 'cases/delay18' / CFG['control_cases'][0] / 'spec.json')
assert template['apl_delay_steps'] == 18 and template['steps'] == 1000 and template['record_history'] is False
control_cases = []
for name in CFG['control_cases']:
source = AJ / 'cases/delay18' / name
target = EXP / 'cases/controls' / name
target.mkdir(parents=True, exist_ok=False)
spec = read(source / 'spec.json')
spec.update(budget_root=str(EXP), output_budget_bytes=CFG['output_budget_bytes'])
save(target / 'spec.json', spec)
for filename in ('requests.npz', 'pn-drive.npz'):
copy_exact(source / filename, target / filename)
control_cases.append(dict(name=name, source_case=str(source), source_output=str(AJ / 'gpu/delay18' / (name + '-r0'))))
save(EXP / 'protocol/control-cases.json', control_cases)
records = []
for cohort, frame in (('seed_validation', panel.iloc[:6]), ('novel_to_aj', panel.iloc[6:])):
for mode in CFG['validation']['modes']:
for index, (_, odor) in enumerate(frame.iterrows()):
targets, rates = cached[(cohort, mode, index)]
for seed in CFG['validation']['seeds']:
requests = make_requests(targets, rates, seed)
name = f'{cohort}-{mode}-{index:02d}-s{seed}'
target = EXP / 'cases' / cohort / name
target.mkdir(parents=True, exist_ok=False)
expected = float(rates.sum()) * 1000 * .1 / 1000.
spec = dict(template, name=name, kind='fullgraph', validation_cohort=cohort,
source_panel_split=str(odor.split), source_panel_row=int(odor.name),
odor_id=str(odor.odor_id), odor_name=str(odor.odor_name), mode=mode, seed=seed,
odor_index=index, expected_external_events=expected, target_count=len(targets),
rate_sum_hz=float(rates.sum()), budget_root=str(EXP), output_budget_bytes=CFG['output_budget_bytes'])
save(target / 'spec.json', spec)
write_npz(target / 'requests.npz', tick=requests[:, 0], neuron_idx=requests[:, 1])
write_npz(target / 'pn-drive.npz', targets=targets, rates_hz=rates)
records.append(dict(name=name, cohort=cohort, source_panel_split=str(odor.split),
source_panel_row=int(odor.name), mode=mode, odor_id=str(odor.odor_id), odor_index=index,
seed=seed, targets=len(targets), requests=len(requests), expected_external_events=expected,
rates_sum=float(rates.sum())))
assert len(records) == 120 and len({row['name'] for row in records}) == 120
save(EXP / 'protocol/validation-cases.json', records)
save(EXP / 'protocol/encoder-audit.json', dict(panel_count=12, cal_count=6, novel_to_aj_count=6,
median_mapped_response_sum=median, seeds=CFG['validation']['seeds'],
seeds_static_audit_sha256=digest(MODEL / 'seed-audit.json'), cohorts_static_panel_rows=static_rows,
requested_before_any_dynamics=True, historical_never_simulated_claim=False,
old_heldout_dynamic_access=False, seed_namespace_universally_independent_claim=False,
source_function='Unmodified AST node pn_drive from pinned phase4l.py; only np/pd/typing dependencies',
source_sha256=digest(encoder_source), function_ast_sha256=ast_sha, torch=torch.__version__, numpy=np.__version__,
control_60_original_CAL_arrays_exact=True, target_rng_column_order='Original function output, unchanged',
generation='Original float32 rates*.1/1000 GPU Bernoulli; same seed across conditions; sort only resulting sparse requests',
expected_not_realized_input_energy_matched=True, no_learning=True))
save(EXP / 'protocol/prepared-hashes.json', [dict(path=p.relative_to(EXP).as_posix(), sha256=digest(p), bytes=p.stat().st_size)
for directory in ('protocol', 'cases') for p in sorted((EXP / directory).rglob('*'))
if p.is_file() and p.name != 'prepared-hashes.json'])
budget()
print('REGISTERED 2 controls +120 fixed validation cases; 60 original input arrays exact; no brain trajectories', flush=True)
if __name__ == '__main__':
main()