181 lines
12 KiB
Python
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()
|