Audit conditional PN recruitment and graded APL source timing
This commit is contained in:
@@ -0,0 +1,258 @@
|
||||
"""Independently re-read evidence, aggregate descriptive outcomes, and seal."""
|
||||
from collections import Counter
|
||||
import numpy as np
|
||||
import pandas as pd
|
||||
import pyarrow.parquet as pq
|
||||
from context import (ROOT, MODEL, EXP, AG, AG_MODEL, GROUPS, read, save, digest, check,
|
||||
integrity, seal, bit_equal)
|
||||
from run_audit import graph_view, first_ticks, temporal_relation
|
||||
from structure_metrics import aggregate_structure
|
||||
from validate_events import validate_batch
|
||||
|
||||
|
||||
def expected_inventory():
|
||||
result = [(n, 0, 'fixture') for n in read(AG_MODEL / 'config.json')['fixtures']]
|
||||
for row in read(AG / 'protocol/calibration-cases.json'):
|
||||
result.append((row['name'], 0, 'calibration'))
|
||||
if row['seed'] == 51101:
|
||||
result.append((row['name'], 1, 'calibration'))
|
||||
return result
|
||||
|
||||
|
||||
def verify_trial(item):
|
||||
out = EXP / 'trials' / (item['case'] + '-r' + str(item['repeat']))
|
||||
source = ROOT / item['source']
|
||||
result = read(out / 'summary.json')
|
||||
hashes = read(out / 'output-hashes.json')
|
||||
assert len({r['path'] for r in hashes}) == len(hashes)
|
||||
assert {r['path'] for r in hashes} == {p.name for p in out.iterdir() if p.is_file() and p.name != 'output-hashes.json'}
|
||||
for row in hashes:
|
||||
assert digest(out / row['path']) == row['sha256'] and (out / row['path']).stat().st_size == row['bytes']
|
||||
assert (result['case'], result['repeat'], result['kind']) == (item['case'], item['repeat'], item['kind'])
|
||||
assert result['pass_all'] and all(result['exact'].values()) and result['APL_source_bound_pass']
|
||||
for name, sha in result['input_sha256'].items():
|
||||
assert digest(source / name) == sha
|
||||
spec = read(AG / 'cases' / item['case'] / 'spec.json')
|
||||
assert result['steps'] == spec['steps'] and result['duration_ms'] == spec['duration_ms']
|
||||
for key in ('mode', 'seed', 'odor_id'):
|
||||
assert result[key] == spec.get(key)
|
||||
graph = 'fixtures' if item['kind'] == 'fixture' else 'full'
|
||||
_, incoming, _, codes, targets, positions, _ = graph_view(graph)
|
||||
pn_table = pd.read_parquet(out / 'per-pn.parquet')
|
||||
kc_table = pd.read_parquet(out / 'per-kc-apl-sources.parquet')
|
||||
apl = read(out / 'apl-source-summary.json')
|
||||
assert apl['pass_all'] and apl['theoretical_bound']['applicable']
|
||||
assert all(v['bound_violations'] == 0 for v in apl['comparison'].values())
|
||||
assert not apl['source_majority_robustness_proven']
|
||||
with np.load(source / 'state.npz') as expected, np.load(out / 'replay-final.npz') as actual:
|
||||
assert bit_equal(actual['target_globals'], targets)
|
||||
for key in ('v', 'g', 'ref', 'counts'):
|
||||
assert bit_equal(actual[key], expected[key][positions])
|
||||
selected = np.isin(expected['neuron_idx'], targets)
|
||||
for key in ('step', 'neuron_idx'):
|
||||
assert bit_equal(actual[key], expected[key][selected])
|
||||
assert bit_equal(pn_table.neuron_idx.to_numpy(), targets)
|
||||
assert bit_equal(pn_table.spike_count.to_numpy(), actual['counts'])
|
||||
assert bit_equal(pn_table.first_spike_tick.to_numpy(), actual['first_spike'])
|
||||
assert bit_equal(actual['first_spike'], first_ticks(expected['step'], expected['neuron_idx'], targets))
|
||||
kc = np.load(AG / 'apl-bundle/kc_globals.npy')
|
||||
assert bit_equal(kc_table.neuron_idx.to_numpy(), kc)
|
||||
assert bit_equal(kc_table.first_spike_tick.to_numpy(), first_ticks(expected['step'], expected['neuron_idx'], kc))
|
||||
source_keys = expected['step'].astype(np.int64) * 166700 + expected['neuron_idx']
|
||||
assert np.all(source_keys[1:] > source_keys[:-1])
|
||||
source_time_keys = np.sort(expected['neuron_idx'].astype(np.int64) * spec['steps'] + expected['step'])
|
||||
final_first = actual['first_spike'].copy()
|
||||
assert np.array_equal(pn_table.first_spike_observed, pn_table.first_spike_tick >= 0)
|
||||
for name in pn_table.select_dtypes(include='number'):
|
||||
values = pn_table[name].to_numpy()
|
||||
assert not np.isinf(values).any()
|
||||
if np.isnan(values).any():
|
||||
assert name.startswith('first_') and np.array_equal(np.isnan(values), ~pn_table.first_spike_observed.to_numpy())
|
||||
assert np.isfinite(kc_table.select_dtypes(include='number').to_numpy()).all()
|
||||
design = pn_table.is_design_target.to_numpy()
|
||||
with np.load(AG / 'cases' / item['case'] / 'requests.npz') as req:
|
||||
table = pd.read_csv(source / 'requests.csv')
|
||||
assert np.array_equal(table.neuron_idx, req['neuron_idx']) and np.array_equal(table.tick, req['tick'])
|
||||
requested = np.bincount(req['neuron_idx'], minlength=166700)[targets]
|
||||
accepted = np.bincount(req['neuron_idx'][table.accepted.to_numpy().astype(bool)], minlength=166700)[targets]
|
||||
assert np.array_equal(pn_table.requested, requested) and np.array_equal(pn_table.accepted_requests, accepted)
|
||||
if item['kind'] == 'calibration':
|
||||
with np.load(AG / 'cases' / item['case'] / 'pn-drive.npz') as pdz:
|
||||
assert np.array_equal(design, np.isin(targets, pdz['targets']))
|
||||
totals = np.zeros(len(targets), np.int64)
|
||||
edge_totals = np.zeros(len(incoming.edge_id), np.int64)
|
||||
count = 0
|
||||
last_record_key = -1
|
||||
for batch in pq.ParquetFile(out / 'accepted-prefirst-edge-events.parquet').iter_batches(batch_size=65536):
|
||||
columns = {name: batch.column(name).to_numpy(zero_copy_only=False) for name in batch.schema.names}
|
||||
checked = validate_batch(columns, edge_ids=incoming.edge_id, srcglobals=incoming.src_global,
|
||||
dstglobals=targets[incoming.dst_local], weights=incoming.weights, target_globals=targets,
|
||||
target_first=final_first, source_event_keys=source_keys)
|
||||
totals += checked['per_target_count']
|
||||
count += checked['count']
|
||||
pos = np.searchsorted(incoming.edge_id, columns['edge_id'])
|
||||
keys = columns['arrival_tick'].astype(np.int64) * 25582938 + columns['edge_id']
|
||||
assert np.all(keys[1:] > keys[:-1]) and (not len(keys) or int(keys[0]) > last_record_key)
|
||||
if len(keys):
|
||||
last_record_key = int(keys[-1])
|
||||
np.add.at(edge_totals, pos, 1)
|
||||
assert np.array_equal(columns['incoming_edge_row'], pos)
|
||||
assert np.array_equal(columns['source_group'], np.asarray(GROUPS)[codes[pos]])
|
||||
assert np.array_equal(columns['target_is_design'], design[incoming.dst_local[pos]])
|
||||
assert count == result['observer']['first_arrival_record_count']
|
||||
expected_totals = sum((pn_table[g + '_accepted_nonzero_before_first_edges'].to_numpy() for g in GROUPS), start=np.zeros(len(targets), np.int64))
|
||||
assert np.array_equal(totals, expected_totals)
|
||||
edge_summary = pd.read_parquet(out / 'prefirst-edge-summary.parquet')
|
||||
assert int(edge_summary.accepted_event_count.sum()) == count
|
||||
assert len(edge_summary) == result['observer']['edge_summary_count']
|
||||
selected_edges = np.flatnonzero(edge_totals)
|
||||
assert np.array_equal(edge_summary.edge_id.to_numpy(), incoming.edge_id[selected_edges])
|
||||
assert np.array_equal(edge_summary.accepted_event_count.to_numpy(), edge_totals[selected_edges])
|
||||
# Independent completeness: initially ref=0 and no reset before the first spike.
|
||||
# Every nonzero source event arriving strictly before that boundary must be present.
|
||||
end = np.where(final_first[incoming.dst_local] >= 0, final_first[incoming.dst_local], spec['steps'])
|
||||
source_start = incoming.src_global.astype(np.int64) * spec['steps']
|
||||
source_end = source_start + np.maximum(end - 18, 0)
|
||||
independent_counts = np.searchsorted(source_time_keys, source_end) - np.searchsorted(source_time_keys, source_start)
|
||||
independent_counts[incoming.weights == 0] = 0
|
||||
assert np.array_equal(edge_totals, independent_counts), 'Independent timed antecedent coverage mismatch'
|
||||
# Validate aggregation receipts against per-neuron evidence instead of trusting JSON alone.
|
||||
for stratum, mask in (('all_PN', np.ones(len(targets), bool)), ('design_PN', design),
|
||||
('non_design_PN', ~design), ('never_active_PN', final_first < 0)):
|
||||
agg = result['observer']['aggregates'][stratum]
|
||||
assert agg['neurons'] == int(mask.sum()) and agg['spikes'] == int(pn_table.spike_count.to_numpy()[mask].sum())
|
||||
for group, metrics in agg['source_groups'].items():
|
||||
for metric, value in metrics.items():
|
||||
summed = pn_table[group + '_' + metric].to_numpy()[mask].sum(dtype=np.longdouble)
|
||||
if isinstance(value, int):
|
||||
assert int(summed) == value
|
||||
else:
|
||||
# Serialization to per-neuron f64 and regrouping changes only final reporting arithmetic.
|
||||
assert abs(float(summed) - value) <= 64 * np.finfo(np.float64).eps * max(1., abs(value))
|
||||
tick_table = pd.read_parquet(out / 'apl-per-tick.parquet')
|
||||
assert len(tick_table) == spec['steps'] * 6
|
||||
assert not tick_table[['tick', 'group', 'apl_index']].duplicated().any()
|
||||
assert set(tick_table.group.unique()) == {'design_ALPN', 'non_design_ALPN', 'KC'}
|
||||
for group in ('design_ALPN', 'non_design_ALPN', 'KC'):
|
||||
metric = group + '_h_sum_mV'
|
||||
observed = float(kc_table[metric].sum())
|
||||
expected_sum = apl['groups'][group]['h_sum_mV']
|
||||
assert abs(observed - expected_sum) <= 128 * spec['steps'] * np.finfo(np.float64).eps * max(1., abs(expected_sum))
|
||||
return result, pn_table, kc_table, apl
|
||||
|
||||
|
||||
def main():
|
||||
check()
|
||||
assert not (EXP / 'audit/failure.json').exists(), 'Cannot promote a preserved failure'
|
||||
inventory = read(EXP / 'protocol/inventory.json')
|
||||
identities = [(r['case'], r['repeat'], r['kind']) for r in inventory]
|
||||
assert identities == expected_inventory() and len(set(identities)) == 80
|
||||
completed = read(EXP / 'audit/completed.json')
|
||||
assert completed['pass_all']
|
||||
ids = [(r['case'], r['repeat']) for r in completed['trials']]
|
||||
assert len(ids) == len(set(ids)) == 80 and set(ids) == {(r[0], r[1]) for r in identities}
|
||||
assert all(r['pass_all'] for r in completed['trials'])
|
||||
repeats = completed['repeat_checks']
|
||||
assert len(repeats) == len({r['case'] for r in repeats}) == 12
|
||||
assert {r['case'] for r in repeats} == {r['case'] for r in inventory if r['repeat'] == 1}
|
||||
assert all(r['pass_all'] and all(r['checks'].values()) for r in repeats)
|
||||
reports, metrics, by_mode = [], [], {}
|
||||
cal_rows = read(AG / 'protocol/calibration-cases.json')
|
||||
odors = list(dict.fromkeys(r['odor_id'] for r in cal_rows))
|
||||
assert len(odors) == 6
|
||||
for item in inventory:
|
||||
report, pn, kc, apl = verify_trial(item)
|
||||
reports.append(report)
|
||||
print('VERIFIED', item['case'], item['repeat'], flush=True)
|
||||
if item['kind'] != 'calibration' or item['repeat'] != 0:
|
||||
continue
|
||||
metrics.append(dict(mode=report['mode'], odor_index=odors.index(report['odor_id']), seed=report['seed'],
|
||||
counts=pn.spike_count.to_numpy(), design_mask=pn.is_design_target.to_numpy()))
|
||||
by_mode.setdefault(report['mode'], []).append((report, pn, kc, apl))
|
||||
# Independently repeat the stored repeat gate without executing a trajectory.
|
||||
for item in inventory:
|
||||
if item['repeat'] != 1:
|
||||
continue
|
||||
a = EXP / 'trials' / (item['case'] + '-r0')
|
||||
b = EXP / 'trials' / (item['case'] + '-r1')
|
||||
for name in ('per-pn.parquet', 'prefirst-edge-summary.parquet', 'apl-per-tick.parquet', 'per-kc-apl-sources.parquet'):
|
||||
assert pd.read_parquet(a / name).equals(pd.read_parquet(b / name))
|
||||
assert digest(a / 'accepted-prefirst-edge-events.parquet') == digest(b / 'accepted-prefirst-edge-events.parquet')
|
||||
assert read(a / 'apl-source-summary.json') == read(b / 'apl-source-summary.json')
|
||||
with np.load(a / 'replay-final.npz') as aa, np.load(b / 'replay-final.npz') as bb:
|
||||
assert set(aa.files) == set(bb.files) and all(bit_equal(aa[k], bb[k]) for k in aa.files)
|
||||
structure = aggregate_structure(metrics)
|
||||
structure['odor_index_to_id'] = odors
|
||||
structure['ALPN_column_neuron_idx'] = np.load(AG / 'apl-bundle/pn_globals.npy').tolist()
|
||||
save(EXP / 'audit/PN-odor-structure.json', structure)
|
||||
aggregate = {}
|
||||
for mode, trials in by_mode.items():
|
||||
assert len(trials) == 30
|
||||
sources = {}
|
||||
for group in ('design_ALPN', 'non_design_ALPN', 'KC'):
|
||||
sources[group] = {metric: sum(a['groups'][group][metric] for _, _, _, a in trials) for metric in (
|
||||
'h_sum_mV', 'h_before_first_KC_sum_mV', 'h_never_fired_KC_sum_mV', 'h_before_first_any_KC_sum_mV')}
|
||||
sources[group]['drive_sum'] = sum(sum(a['groups'][group]['cumulative_drive_by_apl']) for _, _, _, a in trials)
|
||||
for group in sources:
|
||||
for key in ('h_sum_mV', 'h_before_first_KC_sum_mV', 'h_before_first_any_KC_sum_mV', 'drive_sum'):
|
||||
total = sum(s[key] for s in sources.values())
|
||||
sources[group][key + '_fraction'] = None if total == 0 else sources[group][key] / total
|
||||
source_inputs = {group: {metric: sum(r['observer']['aggregates']['non_design_PN']['source_groups'][group][metric]
|
||||
for r, _, _, _ in trials) for metric in trials[0][0]['observer']['aggregates']['non_design_PN']['source_groups'][group]}
|
||||
for group in GROUPS}
|
||||
allpn = pd.concat([p for _, p, _, _ in trials], ignore_index=True)
|
||||
allkc = pd.concat([k for _, _, k, _ in trials], ignore_index=True)
|
||||
activated = allkc[allkc.first_spike_tick >= 0]
|
||||
first_metrics = [r for r, _, _, _ in trials]
|
||||
aggregate[mode] = dict(trials=30,
|
||||
first_non_design_vs_first_KC=dict(Counter(r['first_non_design_vs_first_KC'] for r in first_metrics)),
|
||||
first_non_design_PN_tick_range=[min(r['first_non_design_PN_tick'] for r in first_metrics), max(r['first_non_design_PN_tick'] for r in first_metrics)],
|
||||
first_any_KC_tick_range=[min(r['first_any_KC_tick'] for r in first_metrics), max(r['first_any_KC_tick'] for r in first_metrics)],
|
||||
each_active_KC_relation=dict(activated.first_non_design_relation.value_counts()),
|
||||
each_active_KC_count=len(activated),
|
||||
each_active_KC_has_strict_pre_first_nondesign_PN_edge=int((activated.non_design_ALPN_strict_pre_first_edge_events > 0).sum()),
|
||||
PN_neuron_trials=len(allpn), PN_active_neuron_trials=int(allpn.first_spike_observed.sum()),
|
||||
PN_spikes=int(allpn.spike_count.sum()), design_PN_spikes=int(allpn.loc[allpn.is_design_target, 'spike_count'].sum()),
|
||||
nondesign_PN_spikes=int(allpn.loc[~allpn.is_design_target, 'spike_count'].sum()),
|
||||
non_design_PN_input_sources=source_inputs, APL_sources=sources,
|
||||
common_non_design_dimensions=structure['design']['common_non_design_count'],
|
||||
counts_are_neuron_trials_not_distinct_neurons=True)
|
||||
aggregate[mode]['each_active_KC_relation'] = {k: int(v) for k, v in aggregate[mode]['each_active_KC_relation'].items()}
|
||||
after = integrity()
|
||||
save(EXP / 'regression/old-integrity-after.json', after)
|
||||
assert read(AG / 'regression/frozen-five.json')['pass_all']
|
||||
result = dict(status='PASS-CONDITIONAL-PN-APL-SOURCE-AUDIT', pass_all=True,
|
||||
exact_PN_trials=80, fixture_dense_pre_post_trials=8, CAL_event_final_trials=72, repeat_accounting_pass=12,
|
||||
modes=aggregate, max_PN_voltage_ledger_residual_SI=max(r['observer']['voltage_decomposition']['maximum_reconstruction_residual_SI'] for r in reports),
|
||||
CPU_audit_wall_seconds=sum(r['CPU_audit_wall_seconds'] for r in reports),
|
||||
old_integrity_pass=all(r['pass'] for r in after.values()),
|
||||
prior_frozen_five_pass=True, frozen_five_reexecuted_this_audit=False,
|
||||
prior_frozen_five_sha256=digest(AG / 'regression/frozen-five.json'),
|
||||
new_brain_simulation=False, GPU_used=False, training=False, heldout_access=False,
|
||||
candidate_generated=False, learning_achieved=False, prior_CAL_failure_unchanged=True,
|
||||
source_fraction_robustness_proven=False, counterfactual_causality_tested=False,
|
||||
limitations=['Logged upstream spikes are conditioning inputs, not an independent whole-brain oracle',
|
||||
'Real timed edges are accepted antecedents, not unique causes or necessity proofs',
|
||||
'APL uses the unchanged nonnegative engineering input map, not signed PN-to-APL LIF drive',
|
||||
'APL summed traces pass prior per-tick error bounds; accumulated shares remain descriptive',
|
||||
'Shared PN activity does not imply absent odor information; no learning gate applied',
|
||||
'No independently saved per-tick PN states for CAL; fixtures have full histories',
|
||||
'Frozen five simulation executions were not repeated; previous sealed PASS checked by hash'])
|
||||
save(EXP / 'audit/final-status.json', result)
|
||||
with (EXP / 'REPORT.md').open('x') as f:
|
||||
f.write('# Phase 4AI — conditional PN recruitment and APL source audit\n\n'
|
||||
'Status: `PASS-CONDITIONAL-PN-APL-SOURCE-AUDIT`.\n\n'
|
||||
'80 existing records; PN events/counts/final states exact; eight fixture histories exact; twelve repeats exact. '
|
||||
'No new brain experiment, tuning, training, GPU, or learning candidate.\n\n'
|
||||
'See audit/final-status.json and audit/PN-odor-structure.json. Accepted edges are timed antecedents, '
|
||||
'not unique causes. Graded-APL cumulative source shares are descriptive, not causal or error-bounded majority claims. '
|
||||
'Prior CAL failure remains unchanged. Frozen integrity passed; five reference simulations were not rerun.\n')
|
||||
check()
|
||||
assert sum(p.stat().st_size for p in EXP.rglob('*') if p.is_file()) < 2 * 1024**3
|
||||
seal(MODEL)
|
||||
seal(EXP)
|
||||
print(result['status'], flush=True)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
Reference in New Issue
Block a user