Validate isolated author LIF semantics without changing frozen models

This commit is contained in:
Digital Drosophila Archive
2026-09-30 07:23:09 +08:00
parent 5008cd85ca
commit 92241aea02
460 changed files with 46900 additions and 47 deletions
@@ -0,0 +1,71 @@
# Phase 4AD — independently authorized author-semantics laboratory
Human authorization: "允许独立新模型分支测试动力学假设".
Goal remains usable stimulus-specific learning, not reducing spike count or passing an isolated fixture.
All Phase 1–4AC scientific artifacts, canonical CSR/raw counts, transmitter signs,
W_syn=0.275, APL calibration, eligibility-v2 and the 14,232-edge plastic mask are
read-only. No training, threshold/gain/eta search, decoder, game or visual work in
this prerequisite laboratory. Existing candidate names are not replaced.
## Fixed comparison before results
Use the exact five preselected 4AC motifs and the same initial single seed event,
not newly selected cells. Record all five outcomes, including persistent firing.
Preserve true edge IDs, counts and original global neuron_idx/body_id.
1. Reproduce frozen explicit float32 Euler/operator semantics exactly, using 4AC
archived event/state arrays as an independent oracle.
2. Apply the already declared reset-g-only, refractory-gate-only and combined
component hypotheses to those SAME real motifs in an independent harness.
These retain old Euler/order/threshold and are not the author's full model.
3. Execute the exact pinned author's `create_model` under isolated Brian2 2.5.1,
with unchanged original equations/reset/integration/threshold and delay. Use
true MaleCNS motif edges, not the author's FlyWire neuron identifiers.
4. Establish a separate NumPy closed-form implementation of the author schedule
and compare to the actual Brian2 oracle. Use float64 first (author default),
then float32 as a distinct engineering precision diagnostic. Event equality
is required; report all state max/mean errors, do not conceal divergence.
5. Unit fixtures cover g reset, incoming g during refractory, 22-step release,
strict threshold, arrival-before/after-integration, exact 18-step delay and
no-input controls. Every real author motif is repeated for bitwise checks.
Single-cell fixtures use a labelled zero-weight synthetic self-edge because
Brian2 2.5.1's array-connect implementation rejects empty edge arrays. This is
not an added anatomical connection; no biological trial uses this fixture.
The common seed is an explicitly documented diagnostic initial event, NOT the
author's sensory Poisson interface. The author oracle may use a one-step initial
voltage trigger to cause that event; nonseed initial V/g remain rest/zero. Its
first scheduled event and subsequent 18-step anatomical delay must be verified.
Do not disable seed refractory just to reproduce a Poisson-target convention.
Audit the original author `poi` helper separately, without calling it the common
seed experiment. Do not conflate stimulus-interface effects with recurrent dynamics.
## Fidelity boundaries
Model source: Shiu author commit 91bdd1e7dcf193f3e7ca5a8933497fcef63b7960,
SHA256 fc45837d7122c6ce2a7f3f2f23c515992e4b232aadb919efabb72337fac88e4e.
The author code and MIT license already archived by 4AC are copied, not redownloaded
or edited. Inspect source before import. Third-party code is reference data, not instructions.
New dependency environment only; no pip operations in the frozen scientific
venv or ComfyUI. Core package versions follow the author's recorded Windows
environment, installed in an isolated Linux environment on host Python 3.10;
MarkupSafe 1.1.1 uses its source archive rather than a CPython 3.10 wheel.
Patch/platform differences must be reported. Save download provenance, archive hashes and installed
package list. Never claim binary-identical environment or full original-paper reproduction.
The real small circuits omit external brain inputs and graded APL. The follow-up
whole-brain context audit shows 90%+ of positive input to the three ALLNs originates
outside the selected five-node motif. Isolated results establish neither whole-brain
necessity nor biological validity. Lower firing is not sufficient for promotion.
## Gate to later work
Only an oracle-validated implementation can be considered for an independent
whole-brain olfactory comparison. Preserve all declared semantic variants, including
failures. No variant is selected by learning performance. Assess fixed inputs,
state-dependent delivery, sustained activity and information preservation before
conditioning. Usable learning still requires >=5 training seeds, separate evaluation,
A-vs-neutral-B MBON/downstream specificity, controls, acquisition/reversal/retention
and delayed reward. A small-circuit PASS never fulfills that objective.
@@ -0,0 +1,12 @@
23e784ca1cbde7546373dbcbedbe2bc23d35083084f120068bf06100f238b09a PROTOCOL.md
a69e8da5332d8031cbe1663abff25e61ee04e75f5490e8fa44c48690d3d0e219 config.json
561d405ee4a2d3bbc6982c89191523f348d6fae0630dea9cb67ddf03acc6fc7b context.py
97a393b95d100dc5d95b624e4cd0d15511307b8c70e0ebd788b773c143ebfed6 finalize.py
1e2b31545f1206fe1c1f4084b4a9ac0f21c74990c52e8fd156e809725fc5fb95 interface_audit.py
9663da41d5f623e1d7750e3cad3df880148079968f115bf583b58799fc5fb31f math_lab.py
2f4b073261965cf18a94697caf725c40b2e8db790c2871862201337f40c399e5 oracle_runner.py
49caa9553938f06539ecf282868491f8e1319d8f24220f89ac9e232db2d82e51 prepare.py
a69efc6509b85a5cc00a652caa4820c9c9e1406f6b97c6cc741322728c4d51c3 requirements-oracle.txt
8746e1971c5a40a738e10f8f574a243c29cefa5a8b9f61a2846557ceffd1289a run_lab.py
fe37a48ce804e6c50f93404bfd3c23a7e54cd49061bbdfb4860315879648c73b verify_frozen.py
07a22bade4892adca3a4585656aa3ecce5219790b0dc8a851a12bfd7248d3769 manifest.json
@@ -0,0 +1,36 @@
{
"name": "author-semantics-lab-v1",
"phase": "4AD",
"root": "/data/digital-drosophila",
"experiment": "experiments/phase4ad-author-semantics",
"model_directory": "models/male-cns-lif/author-semantics-lab-v1",
"prior_experiment": "experiments/phase4ac-lif-semantics",
"prior_model": "models/male-cns-lif/lif-semantics-audit-v1",
"human_authorization": "允许独立新模型分支测试动力学假设",
"dt_ms": 0.1,
"duration_ms": 1000.0,
"seed_margin_mv": 1.0,
"late_start_ms": 500.0,
"model": {
"dt_ms": 0.1,
"membrane_tau_ms": 20.0,
"synaptic_tau_ms": 5.0,
"refractory_ms": 2.2,
"resting_potential_mv": -52.0,
"reset_potential_mv": -52.0,
"threshold_mv": -45.0,
"synaptic_delay_ms": 1.8,
"w_syn_mv_per_anatomical_synapse": 0.275
},
"seed_node": 1381,
"motifs": ["pair", "trio", "five", "feedforward", "no_input"],
"component_policies": ["frozen", "reset_g_only", "refractory_gate_only", "reset_and_refractory"],
"author_precisions": ["float64", "float32"],
"comparison": {
"float64_state_max_abs_tolerance_mv": 0.00000001,
"float32_state_max_abs_tolerance_mv": 0.001,
"exact_spike_events_required_for_oracle_validation": true,
"precision_cross_comparison_may_diverge_but_must_be_reported": true
},
"no_training_or_candidate": true
}
@@ -0,0 +1,27 @@
import hashlib
import json
from pathlib import Path
MODEL=Path(__file__).resolve().parent
CFG=json.loads((MODEL/'config.json').read_text(encoding='utf-8'))
ROOT=Path(CFG['root']);EXP=ROOT/CFG['experiment'];AC=ROOT/CFG['prior_experiment']
def digest(path):
h=hashlib.sha256()
with Path(path).open('rb') as f:
for b in iter(lambda:f.read(8<<20),b''):h.update(b)
return h.hexdigest()
def save(path,value):
path=Path(path);path.parent.mkdir(parents=True,exist_ok=True)
with path.open('x',encoding='utf-8') as f:json.dump(value,f,indent=2,ensure_ascii=False,allow_nan=False);f.write('\n')
def source_hashes():
return {p.name:digest(p) for p in sorted(MODEL.iterdir()) if p.is_file() and p.name not in ('manifest.json','checksums.sha256')}
def check_prereg():
pre=json.loads((EXP/'protocol/preregistered.json').read_text())
assert pre['source_hashes']==source_hashes(),'Source changed after preregistration'
for r in pre['input_hashes']:
assert digest(ROOT/r['path'])==r['sha256'],r['path']
return pre
@@ -0,0 +1,411 @@
"""Seal a descriptive laboratory audit, including incomplete and failed runs.
Run this with the frozen scientific environment, not the isolated Brian2 venv.
No simulation, parameter selection, candidate promotion or old-artifact write occurs.
"""
from datetime import datetime, timezone
import json
import math
from pathlib import Path
import sys
import traceback
import numpy as np
import pandas as pd
from context import CFG, EXP, MODEL, ROOT, check_prereg, digest, save, source_hashes
from prepare import frozen_integrity
UNIT_NAMES = ("zero", "weak_excitation", "inhibition", "refractory_boundary",
"equal_threshold", "above_threshold", "nonzero_g_reset", "delay_18")
EXCLUDED_PARTS = {".venv", "__pycache__"}
SEAL_NAMES = {"manifest.json", "checksums.sha256"}
def read_json(path):
with Path(path).open(encoding="utf-8") as stream:
return json.load(stream, parse_constant=lambda value: (_ for _ in ()).throw(
ValueError("Nonfinite JSON number: " + value)))
def exception_record(error):
return {"type": type(error).__name__, "message": str(error),
"traceback": traceback.format_exc()}
def attempt(records, name, function):
"""Never let an earlier failed arm hide subsequent available evidence."""
try:
detail = function()
if not isinstance(detail, dict) or type(detail.get("pass")) is not bool:
raise ValueError("Check must provide an explicit Boolean pass")
item = {"name": name, **detail}
except Exception as error:
item = {"name": name, "pass": False, "error": exception_record(error)}
records.append(item)
return item
def require(condition, message):
if not condition:
raise ValueError(message)
def load_trace(directory, expected_nodes, steps, cfg, seed_node, natural_events=False):
events = pd.read_csv(directory / "events.csv", dtype={"step": "int64", "neuron_idx": "int64"})
require(list(events.columns) == ["step", "neuron_idx"], "Unexpected event columns")
for key in ("step", "neuron_idx"):
values = events[key].to_numpy()
require(np.isfinite(values).all() and np.equal(values, np.floor(values)).all(),
"Nonfinite or nonintegral event field: " + key)
ticks = events.step.to_numpy(np.int64)
nodes = events.neuron_idx.to_numpy(np.int64)
require(bool(np.all((ticks >= 0) & (ticks < steps))), "Event outside trial")
require(bool(np.all(np.diff(ticks) >= 0)), "Events not time ordered")
require(not events.duplicated().any(), "Duplicate event at one neuron/timestep")
require(bool(np.isin(nodes, expected_nodes).all()), "Event identity outside motif")
with np.load(directory / "state.npz", allow_pickle=False) as stored:
state = {key: stored[key].copy() for key in stored.files}
require(np.array_equal(state["nodes"], expected_nodes), "State neuron order differs")
history = state["history"]
require(history.shape == (steps, 3, len(expected_nodes)), "Incomplete state history")
require(all(np.isfinite(value).all() for value in state.values()), "Nonfinite state")
actual_counts = np.array([np.count_nonzero(nodes == node) for node in expected_nodes])
require(np.array_equal(state["counts"], actual_counts), "Counts disagree with raw events")
for index, key in enumerate(("v", "g", "ref")):
require(np.array_equal(state[key], history[-1, index]),
"Final state disagrees with history: " + key)
if seed_node is None and not natural_events:
require(len(ticks) == 0, "No-input control emitted a spike")
elif seed_node is not None:
require(np.array_equal(nodes[ticks == 0], [seed_node]),
"Declared initial seed event missing or duplicated")
late = ticks >= round(cfg["late_start_ms"] / cfg["dt_ms"])
per_node = [{"neuron_idx": int(node), "spikes": int(actual_counts[index]),
"late_spikes": int(np.count_nonzero(late & (nodes == node))),
"last_ms": float(ticks[nodes == node][-1] * cfg["dt_ms"])
if actual_counts[index] else None}
for index, node in enumerate(expected_nodes)]
return {"step": ticks, "neuron_idx": nodes, **state}, per_node
def compare_raw(actual, expected, tolerance):
require(math.isfinite(tolerance) and tolerance >= 0, "Invalid preregistered tolerance")
a = np.asarray(actual["history"], np.float64)
b = np.asarray(expected["history"], np.float64)
require(a.shape == b.shape and a.size > 0, "Incomplete comparison trajectories")
require(np.isfinite(a).all() and np.isfinite(b).all(), "Nonfinite comparison trajectory")
error = np.abs(a[:, :2] - b[:, :2])
exact_events = bool(np.array_equal(actual["step"], expected["step"]) and
np.array_equal(actual["neuron_idx"], expected["neuron_idx"]))
first = None
if not exact_events:
for step in range(len(a)):
aa = actual["neuron_idx"][actual["step"] == step]
bb = expected["neuron_idx"][expected["step"] == step]
if not np.array_equal(aa, bb):
first = step
break
prefix = error if first is None else error[:first]
reference_exact = bool(np.array_equal(a[:, 2], b[:, 2]))
count_exact = bool(np.array_equal(actual["counts"], expected["counts"]))
maximum = float(error.max())
return {"exact_events": exact_events, "exact_counts": count_exact,
"ref_exact": reference_exact, "max_abs_mv": maximum,
"mean_abs_mv": float(error.mean()),
"same_event_prefix_max_abs_mv": float(prefix.max()) if prefix.size else None,
"first_event_divergence_step": first, "tolerance_mv": tolerance,
"pass_oracle": exact_events and count_exact and reference_exact and maximum <= tolerance}
def comparison_record_matches(raw, stored):
"""Only descriptive mean reduction may differ between scientific NumPy builds."""
if set(raw) != set(stored):
return False
return all(math.isclose(raw[key], stored[key], rel_tol=0, abs_tol=1e-12)
if key == "mean_abs_mv" else raw[key] == stored[key] for key in raw)
def motif_nodes(cfg, motif):
with np.load(ROOT / cfg["prior_experiment"] / "motifs" / (motif + "-state.npz"),
allow_pickle=False) as prior:
return prior["nodes"].copy()
def check_summary_rows(table, motif, policy, precision, per_node):
part = table[(table.motif == motif) & (table.policy == policy) &
(table.precision == precision)]
require(len(part) == len(per_node) and not part.neuron_idx.duplicated().any(),
"Missing/duplicate per-neuron summary rows")
require(set(part.neuron_idx) == {row["neuron_idx"] for row in per_node},
"Summary neuron identities differ")
indexed = part.set_index("neuron_idx")
for row in per_node:
current = indexed.loc[row["neuron_idx"]]
require(current.spikes == row["spikes"] and current.late_spikes == row["late_spikes"],
"Summary spike counts disagree with raw events")
last = current.last_ms
require(pd.isna(last) if row["last_ms"] is None else last == row["last_ms"],
"Summary last-spike time disagrees with raw events")
def seal(root):
require(not any((root / name).exists() for name in SEAL_NAMES),
"Refusing to overwrite an existing seal: " + str(root))
files = []
for path in sorted(root.rglob("*")):
relative = path.relative_to(root)
if EXCLUDED_PARTS.intersection(relative.parts):
continue
require(not path.is_symlink(), "Unsealed symlink not permitted: " + str(path))
if not path.is_file() or (len(relative.parts) == 1 and path.name in SEAL_NAMES):
continue
files.append({"path": relative.as_posix(), "bytes": path.stat().st_size,
"sha256": digest(path)})
require(bool(files), "Refusing empty artifact manifest")
manifest = {"schema": "sha256-artifact-manifest-v1", "root": str(root),
"created_utc": datetime.now(timezone.utc).isoformat(),
"excluded_directory_names": sorted(EXCLUDED_PARTS),
"self_hash_policy": "Manifest lists payload files; checksums also hashes manifest; neither hashes checksums.",
"files": files}
save(root / "manifest.json", manifest)
checksum_rows = files + [{"path": "manifest.json", "sha256": digest(root / "manifest.json")}]
with (root / "checksums.sha256").open("x", encoding="utf-8", newline="\n") as stream:
for row in checksum_rows:
stream.write(row["sha256"] + " " + row["path"] + "\n")
for row in checksum_rows:
require(digest(root / row["path"]) == row["sha256"],
"Artifact changed while sealing: " + row["path"])
def main():
outputs = [EXP / "audit/finalize-start.json", EXP / "audit/final-summary.json",
EXP / "regression/old-integrity-after.json", EXP / "regression/preregistration-after.json",
EXP / "REPORT.md"] + [root / name for root in (MODEL, EXP) for name in SEAL_NAMES]
require(not any(path.exists() for path in outputs), "Refusing reused finalization outputs")
save(EXP / "audit/finalize-start.json", {"timestamp_utc": datetime.now(timezone.utc).isoformat(),
"python": sys.version, "executable": sys.executable, "learning": False,
"whole_brain_alternative_run": False})
checks = []
prereg = attempt(checks, "preregistration", lambda: {"pass": True, "record": check_prereg()})
if prereg["pass"]:
cfg = prereg["record"]["config"]
else:
# Read the sealed declaration for descriptive recovery, never bless source drift.
try:
cfg = read_json(EXP / "protocol/preregistered.json")["config"]
except Exception:
cfg = CFG
integrity = attempt(checks, "old_frozen_integrity_after", lambda: {
"pass": True, "results": frozen_integrity()})
save(EXP / "regression/old-integrity-after.json", integrity)
def completed():
record = read_json(EXP / "audit/run-complete.json")
require(record.get("learning_achieved") is False and
record.get("whole_brain_alternative_run") is False, "Run scope inconsistent")
require(record.get("author_original_source_sha256") == digest(EXP / "external-resources/model.py"),
"Author source hash disagrees with run-complete record")
return {"pass": record.get("all_author_oracle_comparisons_pass") is True and
record.get("all_frozen_components_match_archive") is True, "record": record}
run_complete = attempt(checks, "run_complete", completed)
def frozen_five_check():
record = read_json(EXP / "regression/frozen-five.json")
trials = record.get("trials", [])
require(len(trials) == 5 and len({row["trial"] for row in trials}) == 5,
"Exactly five distinct frozen reference trials are required")
required = {"step", "neuron_idx", "counts", "v", "g"}
exact = all(set(row.get("exact", {})) == required and
all(value is True for value in row["exact"].values()) for row in trials)
return {"pass": record.get("pass_all") is True and exact, "record": record,
"scope": "Old frozen runtime regression only, not a new-model dynamics gate."}
frozen_five = attempt(checks, "frozen_five_gpu_references", frozen_five_check)
def interface_check():
record = read_json(EXP / "oracle/poi-interface/audit.json")
flags = record.get("checks", {})
require(isinstance(flags, dict) and bool(flags), "Empty Poisson interface audit")
require(record.get("author_sha256") == digest(EXP / "external-resources/model.py"),
"Poisson audit source hash differs")
require(record.get("simulation_duration_ms") == 0 and
record.get("stochastic_time_steps") == 0 and
record.get("random_realization_tested") is False and
record.get("common_seed_experiment") is False, "Poisson audit scope differs")
for name, expected in record.get("input_hashes", {}).items():
require(digest(EXP / "oracle/poi-interface" / name) == expected,
"Poisson fixture input changed: " + name)
return {"pass": record.get("gate") is True and all(value is True for value in flags.values()),
"record": record, "scope": "Compile-time interface audit; no Poisson realization."}
interface = attempt(checks, "author_poi_compile_only", interface_check)
outcomes = []
components = []
steps = round(cfg["duration_ms"] / cfg["dt_ms"])
for motif in cfg["motifs"]:
for policy in cfg["component_policies"]:
def component_check(motif=motif, policy=policy):
nodes = motif_nodes(cfg, motif)
raw, per_node = load_trace(EXP / "components" / (motif + "-" + policy), nodes,
steps, cfg, None if motif == "no_input" else cfg["seed_node"])
outcomes.append({"motif": motif, "policy": policy, "precision": "float32",
"neurons": per_node, "activity_is_not_a_validation_gate": True})
table = pd.read_csv(EXP / "components/summary.csv", float_precision="round_trip")
check_summary_rows(table, motif, policy, "float32", per_node)
if policy == "frozen":
prior_dir = ROOT / cfg["prior_experiment"] / "motifs"
old_events = pd.read_parquet(prior_dir / (motif + "-events.parquet"))
require(np.array_equal(raw["step"], old_events.step) and
np.array_equal(raw["neuron_idx"], old_events.neuron_idx),
"Frozen events disagree with 4AC")
with np.load(prior_dir / (motif + "-state.npz"), allow_pickle=False) as old:
require(all(np.array_equal(old[key], raw[key]) for key in old.files),
"Frozen states disagree with 4AC")
return {"pass": True, "raw_and_summary_consistent": True,
"interpretation": "Artifact/finite/seed checks only; activity is descriptive."}
components.append(attempt(checks, "component:" + motif + ":" + policy, component_check))
unit_results = []
for precision in cfg["author_precisions"]:
for fixture in UNIT_NAMES:
def unit_check(precision=precision, fixture=fixture):
stem = fixture
record = read_json(EXP / "regression" / ("unit-" + stem + "-" + precision + ".json"))
require(record.get("fixture") == fixture and record.get("precision") == precision,
"Unit identity mismatch")
unit_cfg = dict(cfg, duration_ms=20.0)
seeded = fixture in ("refractory_boundary", "above_threshold")
directory = EXP / "oracle" / ("unit-" + stem + "-" + precision)
nodes = np.array([-2, -1]) if fixture == "delay_18" else np.array([-1])
seed = -2 if fixture == "delay_18" else (-1 if seeded else None)
actual, _ = load_trace(directory / "brian-output", nodes, 200, unit_cfg, seed,
natural_events=fixture == "nonzero_g_reset")
independent, _ = load_trace(directory / "independent-output", nodes, 200, unit_cfg, seed,
natural_events=fixture == "nonzero_g_reset")
raw = compare_raw(actual, independent, float(cfg["comparison"][precision + "_state_max_abs_tolerance_mv"]))
stored = read_json(directory / "comparison.json")
require(comparison_record_matches(raw, stored) and
comparison_record_matches(raw, record["comparison"]),
"Unit comparison differs from raw trajectories")
flags = record.get("checks")
require(isinstance(flags, dict) and bool(flags), "Empty unit checks cannot pass")
return {"pass": raw["pass_oracle"] and all(value is True for value in flags.values()),
"checks": flags, "raw_comparison": raw}
unit_results.append(attempt(checks, "unit:" + fixture + ":" + precision, unit_check))
author_results = []
precision_cross = []
for motif in cfg["motifs"]:
by_precision = {}
for precision in cfg["author_precisions"]:
def author_check(motif=motif, precision=precision):
nodes = motif_nodes(cfg, motif)
directory = EXP / "oracle" / (motif + "-" + precision)
seed = None if motif == "no_input" else cfg["seed_node"]
actual, per_node = load_trace(directory / "brian-output", nodes, steps, cfg, seed)
independent, _ = load_trace(directory / "independent-output", nodes, steps, cfg, seed)
by_precision[precision] = actual
outcomes.append({"motif": motif, "policy": "author_complete", "precision": precision,
"neurons": per_node, "activity_is_not_a_validation_gate": True})
raw = compare_raw(actual, independent, float(cfg["comparison"][precision + "_state_max_abs_tolerance_mv"]))
stored = read_json(directory / "comparison.json")
require(comparison_record_matches(raw, stored), "Author comparison differs from raw trajectories")
repeated, _ = load_trace(EXP / "oracle" / (motif + "-" + precision + "-repeat") /
"brian-output", nodes, steps, cfg, seed)
repeat_flags = read_json(EXP / "regression" / (motif + "-" + precision + "-repeat.json"))
require(set(repeat_flags) == set(actual) - {"nodes"}, "Incomplete repeat comparison fields")
repeat_raw = {key: bool(np.array_equal(actual[key], repeated[key])) for key in repeat_flags}
require(repeat_raw == repeat_flags, "Repeat flags disagree with raw arrays")
table = pd.read_csv(EXP / "audit/all-motif-results.csv", float_precision="round_trip")
check_summary_rows(table, motif, "author_complete", precision, per_node)
return {"pass": raw["pass_oracle"] and all(repeat_raw.values()),
"raw_comparison": raw, "repeat_exact": repeat_raw}
author_results.append(attempt(checks, "author:" + motif + ":" + precision, author_check))
def cross_check(motif=motif):
raw = compare_raw(by_precision["float32"], by_precision["float64"],
float(cfg["comparison"]["float32_state_max_abs_tolerance_mv"]))
stored = read_json(EXP / "regression" / (motif + "-precision-cross-comparison.json"))
require(comparison_record_matches(raw, stored), "Precision cross comparison differs from raw trajectories")
return {"pass": True, "comparison": raw,
"interpretation": "Reporting consistency only; cross-precision divergence is allowed and retained."}
precision_cross.append(attempt(checks, "precision_cross_record:" + motif, cross_check))
retained_errors = []
for path in sorted(EXP.rglob("error.json")):
if EXCLUDED_PARTS.intersection(path.relative_to(EXP).parts):
continue
try:
error = read_json(path)
except Exception as exception:
error = exception_record(exception)
retained_errors.append({"path": path.relative_to(EXP).as_posix(), "error": error})
checks.append({"name": "no_recorded_oracle_errors", "pass": not retained_errors,
"errors": retained_errors})
final_prereg = attempt(checks, "preregistration_at_seal", lambda: {"pass": True, "record": check_prereg()})
save(EXP / "regression/preregistration-after.json", {
"initial": prereg, "at_seal": final_prereg, "observed_source_hashes": source_hashes()})
passed = bool(checks) and all(item["pass"] for item in checks)
summary = {"phase": cfg.get("phase", "4AD"),
"status": "COMPLETE-ORACLE-VALIDATED-LAB-ONLY" if passed else "INCOMPLETE-OR-FAILED-LAB-VALIDATION",
"laboratory_validation_pass": passed, "checks": checks,
"component_checks": components, "unit_checks": unit_results,
"frozen_five_gpu_check": frozen_five, "author_poi_interface_check": interface,
"author_oracle_checks": author_results, "precision_cross_checks": precision_cross,
"motif_outcomes": outcomes, "run_complete_record": run_complete,
"whole_brain_alternative_run": False, "conditioning_run": False,
"learning_achieved": False, "candidate_generated": False, "selected_variant": None,
"goal_remains_unachieved": True,
"limits": ["No whole-brain or learning experiment in this protocol.",
"No activity-based variant selection; silence is not a success gate.",
"Isolated motifs omit external network input and graded APL.",
"Author equations on MaleCNS motifs do not reproduce the original paper's full brain or sensory interface.",
"Linux host and Python patch differences prevent a binary-identical author-environment claim."]}
save(EXP / "audit/final-summary.json", summary)
failures = [item for item in checks if not item["pass"]]
lines = ["# Phase 4AD 作者动力学语义实验室", "", "状态:`" + summary["status"] + "`。", "",
"本轮仅有预声明的小回路与算子实验;没有整脑替代动力学运行、conditioning、学习成功或新学习候选。",
"检查以原始事件、状态轨迹和预注册误差界限重算。缺失、失败、非有限值或初始事件丢失均不能通过;放电减少或静默本身不构成成功。", "",
f"核查通过 {sum(item['pass'] for item in checks)}/{len(checks)} 项;失败或不完整 {len(failures)} 项。",
"冻结历史完整性:" + ("通过。" if integrity["pass"] else "失败或未完成,详见保存的错误。"),
"源码与输入预注册一致性:" + ("通过。" if prereg["pass"] and final_prereg["pass"] else "失败或未完成;不得授予验证成功。"), "",
"| 回路 | 语义 | 精度 | 总spikes | late spikes |", "|---|---|---|---:|---:|"]
for row in outcomes:
lines.append("| {} | {} | {} | {} | {} |".format(row["motif"], row["policy"], row["precision"],
sum(item["spikes"] for item in row["neurons"]), sum(item["late_spikes"] for item in row["neurons"])))
if not outcomes:
lines.append("| 无完整可读取结果 | 未执行或缺失 | — | — | — |")
lines.extend(["", "作者Brian2与独立NumPy比较:", "",
"| 实验 | 结果 | 事件一致 | 最大V/g误差 mV | 首次事件分歧step |", "|---|---|---|---:|---:|"])
for item in author_results:
raw = item.get("raw_comparison", {})
lines.append("| {} | {} | {} | {} | {} |".format(item["name"], "通过" if item["pass"] else "失败/缺失",
raw.get("exact_events", "未知"), raw.get("max_abs_mv", "未知"),
raw.get("first_event_divergence_step", "无或未取得")))
lines.extend(["", "float32与float64交叉比较仅记录精度影响,允许保留分歧,不能用于掩盖各自与独立oracle的失败。"])
for item in precision_cross:
raw = item.get("comparison")
if raw:
lines.append(f"- {item['name']}:事件一致={raw['exact_events']},最大误差={raw['max_abs_mv']} mV,首次事件分歧step={raw['first_event_divergence_step']}。")
if failures:
lines.extend(["", "失败与未完成项:", ""])
for item in failures:
detail = item.get("error", {}).get("message") or "原始条件未全部满足;完整字段见 final-summary.json。"
lines.append("- `" + item["name"] + "`:" + str(detail).replace("\n", " "))
lines.extend(["", "所有失败轨迹和错误文件原样保留;本简报没有选择获胜变体。",
"小回路缺少外部整脑输入与graded APL,不能证明整脑因果必要性、生物真实性或信息保持。初始诊断seed也不是作者的感官Poisson接口。",
"环境为Linux宿主,作者记录为Windows;Python补丁版本与环境差异见environment记录,不能称为二进制相同或原论文整脑复现。",
"后续整脑嗅觉比较仍须核查固定输入、实际送达事件、持续活动和信息保持;可用学习仍需至少5个训练seed、独立评估、MBON/downstream的A对中性B特异性及acquisition/reversal/retention/delayed-reward对照。",
"封存排除 .venv 与 __pycache__,保留环境安装报告;manifest列出payload哈希,checksums另含manifest,不存在自哈希循环。", ""])
with (EXP / "REPORT.md").open("x", encoding="utf-8") as stream:
stream.write("\n".join(lines))
seal(MODEL)
seal(EXP)
print(json.dumps({"status": summary["status"], "laboratory_validation_pass": passed,
"failed_checks": len(failures), "learning_achieved": False,
"whole_brain_alternative_run": False, "sealed": [str(MODEL), str(EXP)]},
ensure_ascii=False), flush=True)
return 0 if passed else 1
if __name__ == "__main__":
raise SystemExit(main())
@@ -0,0 +1,149 @@
"""Compile-only audit of the pinned author's sensory Poisson interface.
This is separate from the common single-seed diagnostic. Zero simulation time
is advanced, so this audit does not draw or validate any Poisson realization.
"""
from __future__ import annotations
import hashlib
import types
import numpy as np
import pandas as pd
from context import CFG, EXP, digest, save
from oracle_runner import AUTHOR_COMMIT, AUTHOR_SHA256, _code_records, _environment
def audit_author_poi() -> dict:
"""Create the original model and poi helper, compile at t=0, and save evidence."""
author_path = EXP / "external-resources" / "model.py"
author_bytes = author_path.read_bytes()
source_hash = hashlib.sha256(author_bytes).hexdigest()
if source_hash != AUTHOR_SHA256:
raise ValueError("The Poisson audit requires the exact pinned author source")
output = EXP / "oracle" / "poi-interface"
output.mkdir(parents=True, exist_ok=False)
environment = _environment()
save(output / "environment.json", environment)
if environment["packages"]["brian2"]["actual"] != "2.5.1":
raise RuntimeError("The Poisson interface audit requires Brian2 2.5.1")
import brian2 as b2
preferences = {name: b2.prefs[name] for name in (
"codegen.target", "core.default_float_dtype", "legacy.refractory_timing")}
old_dt = b2.defaultclock.dt
try:
b2.start_scope()
b2.prefs["codegen.target"] = "numpy"
b2.prefs["core.default_float_dtype"] = np.float64
b2.prefs["legacy.refractory_timing"] = False
b2.defaultclock.dt = float(CFG["dt_ms"]) * b2.ms
author = types.ModuleType("phase4ad_poi_author_" + source_hash[:12])
author.__file__ = str(author_path)
# Execute exactly the reviewed bytes; create no bytecode beside the source.
exec(compile(author_bytes, str(author_path), "exec"), author.__dict__)
parameters = dict(author.default_params)
nodes = np.array([-2, -1], dtype=np.int32)
completeness = pd.DataFrame(
{"local_index": np.array([0, 1], dtype=np.int32)},
index=pd.Index(nodes, name="synthetic_global_neuron_idx"))
connections = pd.DataFrame({
"Presynaptic_Index": np.array([0], dtype=np.int32),
"Postsynaptic_Index": np.array([1], dtype=np.int32),
"Excitatory x Connectivity": np.array([1], dtype=np.int64),
"raw_count": np.array([1], dtype=np.int64),
"edge_id": np.array([-1], dtype=np.int64),
"source_neuron_idx": nodes[:1], "target_neuron_idx": nodes[1:],
})
comp_path = output / "completeness.csv"
con_path = output / "connectivity.parquet"
completeness.to_csv(comp_path)
connections.to_parquet(con_path, index=False, engine="pyarrow")
neu, syn, spikes = author.create_model(comp_path, con_path, parameters)
rfc_before = np.asarray(neu.rfc[:] / b2.ms, dtype=np.float64).copy()
# One excited target plus one untouched cell makes the helper's scope
# observable. The optional second-rate class is not exercised here.
inputs, same_neu = author.poi(neu, [0], [], parameters)
if same_neu is not neu:
raise AssertionError("The author poi helper returned a different neuron group")
rfc_after = np.asarray(neu.rfc[:] / b2.ms, dtype=np.float64).copy()
before_v = np.asarray(neu.v_[:], dtype=np.float64).copy()
before_g = np.asarray(neu.g_[:], dtype=np.float64).copy()
before_w = np.asarray(syn.w_[:], dtype=np.float64).copy()
network = b2.Network(neu, syn, spikes, *inputs)
save(output / "schedule.json", {
"schedule": list(network.schedule),
"summary": str(network.scheduling_summary()),
})
network.run(0 * b2.ms, namespace={})
save(output / "generated-code.json", _code_records(network))
input_records = []
for item in inputs:
# PoissonInput 2.5.1 retains its on-the-fly subgroup as _group;
# N/rate/weight/target_var are its public read-only properties.
target = item._group
input_records.append({
"name": item.name, "type": type(item).__name__,
"target_group": target.name,
"target_local_start": int(target.start),
"target_local_stop": int(target.stop),
"target_global_nodes": nodes[int(target.start):int(target.stop)].tolist(),
"target_var": item.target_var, "N": int(item.N),
"rate_hz": float(item.rate / b2.Hz),
"weight_mv": float(item.weight / b2.mV),
"weight_volt": float(item.weight / b2.volt),
"when": item.when, "order": int(item.order),
"dt_ms": float(item.clock.dt / b2.ms),
"abstract_code": str(item.abstract_code),
"generated_code": [str(code.code) for code in item.code_objects],
})
expected_rfc = float(parameters["t_rfc"] / b2.ms)
expected_weight = float(parameters["w_syn"] * parameters["f_poi"] / b2.mV)
expected_rate = float(parameters["r_poi"] / b2.Hz)
checks = {
"exact_author_source": digest(author_path) == source_hash,
"one_poisson_input": len(input_records) == 1,
"initial_refractory_is_original": bool(np.array_equal(rfc_before, [expected_rfc, expected_rfc])),
"only_excited_target_loses_refractory": bool(np.array_equal(rfc_after, [0., expected_rfc])),
"actual_voltage_interface": all(r["target_var"] == "v" for r in input_records),
"actual_N_one": all(r["N"] == 1 for r in input_records),
"actual_rate_150_hz": bool(expected_rate == 150. and all(r["rate_hz"] == expected_rate for r in input_records)),
"actual_weight_68_75_mv": bool(np.isclose(expected_weight, 68.75, rtol=0, atol=1e-12)
and all(np.isclose(r["weight_mv"], expected_weight, rtol=0, atol=1e-12) for r in input_records)),
"actual_synapses_slot_order_zero": all(r["when"] == "synapses" and r["order"] == 0 for r in input_records),
"zero_elapsed_time": float(network.t / b2.ms) == 0.,
"no_recorded_spikes": len(spikes.i[:]) == 0,
"compile_preserves_voltage": bool(np.array_equal(before_v, np.asarray(neu.v_[:]))),
"compile_preserves_g": bool(np.array_equal(before_g, np.asarray(neu.g_[:]))),
"compile_preserves_weights": bool(np.array_equal(before_w, np.asarray(syn.w_[:]))),
"compile_preserves_refractory_configuration": bool(np.array_equal(rfc_after, np.asarray(neu.rfc[:] / b2.ms))),
}
result = {
"gate": bool(all(checks.values())), "checks": checks,
"author_commit": AUTHOR_COMMIT, "author_sha256": source_hash,
"fixture": "two synthetic nodes, one raw_count=1 connection",
"nodes": nodes.tolist(), "exc_local_indices": [0], "exc2_local_indices": [],
"rfc_before_ms": rfc_before.tolist(), "rfc_after_ms": rfc_after.tolist(),
"poisson_inputs": input_records,
"synaptic_weight_mv": np.asarray(syn.w[:] / b2.mV, dtype=np.float64).tolist(),
"input_hashes": {"completeness.csv": digest(comp_path), "connectivity.parquet": digest(con_path)},
"simulation_duration_ms": 0., "stochastic_time_steps": 0,
"random_realization_tested": False, "common_seed_experiment": False,
"interpretation": "Original poi adds 68.75 mV to voltage at 150 Hz with N=1 in the synapses slot and sets its target rfc to zero. This interface is not the common initial seed experiment.",
"scope": "Compile-time interface audit only; no stochastic trial, learning, or whole-brain simulation. The optional exc2 helper branch is not exercised.",
}
save(output / "audit.json", result)
if not result["gate"]:
raise AssertionError("Author Poisson interface gate failed: " + str(checks))
return result
except Exception as error:
save(output / "error.json", {"type": type(error).__name__, "message": str(error)})
raise
finally:
for name, value in preferences.items():
b2.prefs[name] = value
b2.defaultclock.dt = old_dt
@@ -0,0 +1,67 @@
{
"schema": "sha256-artifact-manifest-v1",
"root": "/data/digital-drosophila/models/male-cns-lif/author-semantics-lab-v1",
"created_utc": "2026-09-29T23:19:04.144370+00:00",
"excluded_directory_names": [
".venv",
"__pycache__"
],
"self_hash_policy": "Manifest lists payload files; checksums also hashes manifest; neither hashes checksums.",
"files": [
{
"path": "PROTOCOL.md",
"bytes": 4577,
"sha256": "23e784ca1cbde7546373dbcbedbe2bc23d35083084f120068bf06100f238b09a"
},
{
"path": "config.json",
"bytes": 1332,
"sha256": "a69e8da5332d8031cbe1663abff25e61ee04e75f5490e8fa44c48690d3d0e219"
},
{
"path": "context.py",
"bytes": 1057,
"sha256": "561d405ee4a2d3bbc6982c89191523f348d6fae0630dea9cb67ddf03acc6fc7b"
},
{
"path": "finalize.py",
"bytes": 25910,
"sha256": "97a393b95d100dc5d95b624e4cd0d15511307b8c70e0ebd788b773c143ebfed6"
},
{
"path": "interface_audit.py",
"bytes": 8415,
"sha256": "1e2b31545f1206fe1c1f4084b4a9ac0f21c74990c52e8fd156e809725fc5fb95"
},
{
"path": "math_lab.py",
"bytes": 4533,
"sha256": "9663da41d5f623e1d7750e3cad3df880148079968f115bf583b58799fc5fb31f"
},
{
"path": "oracle_runner.py",
"bytes": 18548,
"sha256": "2f4b073261965cf18a94697caf725c40b2e8db790c2871862201337f40c399e5"
},
{
"path": "prepare.py",
"bytes": 3453,
"sha256": "49caa9553938f06539ecf282868491f8e1319d8f24220f89ac9e232db2d82e51"
},
{
"path": "requirements-oracle.txt",
"bytes": 453,
"sha256": "a69efc6509b85a5cc00a652caa4820c9c9e1406f6b97c6cc741322728c4d51c3"
},
{
"path": "run_lab.py",
"bytes": 10795,
"sha256": "8746e1971c5a40a738e10f8f574a243c29cefa5a8b9f61a2846557ceffd1289a"
},
{
"path": "verify_frozen.py",
"bytes": 2613,
"sha256": "fe37a48ce804e6c50f93404bfd3c23a7e54cd49061bbdfb4860315879648c73b"
}
]
}
@@ -0,0 +1,70 @@
"""Independent event-scheduled author equation and preserved frozen component arms."""
import sys
from pathlib import Path
import numpy as np
sys.path.insert(0,'/data/digital-drosophila/models/male-cns-lif/lif-semantics-audit-v1')
from math_reference import params, state
def component(nodes,edges,weights,config,policy,seed_node):
p=params(config['model']);n=len(nodes);steps=round(config['duration_ms']/config['dt_ms'])
ix={int(x):i for i,x in enumerate(nodes)}
src=np.array([ix[int(x)] for x in edges.source_neuron_idx],np.int32)
dst=np.array([ix[int(x)] for x in edges.target_neuron_idx],np.int32)
v=np.full(n,p['rest'],np.float32);g=np.zeros(n,np.float32);ref=np.zeros(n,np.int32)
qlen=p['delay_steps']+1;q=np.zeros((qlen,n),np.float32)
history=np.empty((steps,3,n),np.float32);counts=np.zeros(n,np.int32);ts=[];ns=[]
for t in range(steps):
v,g,ref,fire=state(v,g,ref,q[t%qlen],p,policy);q[t%qlen]=0
if t==0 and seed_node is not None:
k=ix[seed_node];assert not fire[k] and ref[k]==0
fire[k]=True;v[k]=p['reset'];ref[k]=p['ref_steps']
if policy in ('reset_g_only','reset_and_refractory'):g[k]=np.float32(0)
counts+=fire;active=np.flatnonzero(fire);ts.extend([t]*len(active));ns.extend(nodes[active].tolist())
selected=np.flatnonzero(fire[src]);selected=selected[np.argsort(dst[selected],kind='stable')]
for target in np.unique(dst[selected]):
acc=np.float32(0)
for e in selected[dst[selected]==target]:acc=np.float32(acc+weights[e])
slot=(t+p['delay_steps'])%qlen;q[slot,target]=np.float32(q[slot,target]+acc)
history[t]=v,g,ref
return dict(step=np.array(ts,np.int32),neuron_idx=np.array(ns,np.int32),counts=counts,v=v,g=g,ref=ref,history=history,queue=q)
def author_numpy(nodes,edges,config,precision,seed_node,external_arrivals=None):
"""Analytic integration in SI volts; sequential arrival writes follow spike detection."""
f=np.dtype(precision).type;m=config['model'];n=len(nodes);dt=config['dt_ms']
steps=round(config['duration_ms']/dt);rs=round(m['refractory_ms']/dt);ds=round(m['synaptic_delay_ms']/dt)
ix={int(x):i for i,x in enumerate(nodes)}
src=np.array([ix[int(x)] for x in edges.source_neuron_idx],np.int32)
dst=np.array([ix[int(x)] for x in edges.target_neuron_idx],np.int32)
weights=np.asarray(edges.raw_count.to_numpy(np.float64)*(m['w_syn_mv_per_anatomical_synapse']*.001),dtype=precision)
rest=m['resting_potential_mv']*.001;reset=m['reset_potential_mv']*.001;threshold=m['threshold_mv']*.001
v=np.full(n,rest,dtype=precision);g=np.zeros(n,dtype=precision)
last=np.full(n,-1000000,np.int64);counts=np.zeros(n,np.int32)
em=np.exp(-dt/m['membrane_tau_ms']);es=np.exp(-dt/m['synaptic_tau_ms'])
drive=m['synaptic_tau_ms']/(m['membrane_tau_ms']-m['synaptic_tau_ms'])*(em-es)
history=np.empty((steps,3,n),np.float64);queue=[[] for _ in range(ds+1)];ts=[];ns=[]
external=np.zeros((steps,n),dtype=precision) if external_arrivals is None else np.asarray(np.asarray(external_arrivals,np.float64)*.001,dtype=precision)
assert external.shape==(steps,n)
for t in range(steps):
available=(t-last)>=rs
# Use previous g for the coupled exact differential update, then cast to variable dtype.
oldg=g.copy()
v[available]=np.asarray(rest+em*(v[available]-rest)+drive*oldg[available],dtype=precision)
g[available]=np.asarray(es*oldg[available],dtype=precision)
if t==0 and seed_node is not None:v[ix[seed_node]]=f(threshold+config['seed_margin_mv']*.001)
fire=available&(v>threshold);last[fire]=t;counts+=fire
active=np.flatnonzero(fire);ts.extend([t]*len(active));ns.extend(nodes[active].tolist())
accept=available&~fire
due=queue[t%(ds+1)];queue[t%(ds+1)]=[]
for e in due:
if accept[dst[e]]:g[dst[e]]=f(g[dst[e]]+weights[e])
for j in np.flatnonzero(external[t]):
if accept[j]:g[j]=f(g[j]+external[t,j])
queue[(t+ds)%(ds+1)].extend(np.flatnonzero(fire[src]).tolist())
v[fire]=f(reset);g[fire]=f(0)
ref=np.maximum(rs-(t-last),0).astype(np.int32)
history[t]=np.asarray(v,np.float64)*1000,np.asarray(g,np.float64)*1000,ref
return dict(step=np.array(ts,np.int32),neuron_idx=np.array(ns,np.int32),counts=counts,
v=np.asarray(v,np.float64)*1000,g=np.asarray(g,np.float64)*1000,ref=ref,history=history,weights=np.asarray(weights,np.float64)*1000)
@@ -0,0 +1,346 @@
"""Run the pinned author's create_model in a dedicated, serial Brian2 process.
This module never edits the author source or its parameters. The caller supplies
an exclusive output directory and the already validated, signed connectivity
multipliers in ``raw_count``. Global IDs are not FlyWire IDs and are mapped only
for this small-circuit diagnostic. Brian stores voltages in SI volts internally;
the returned state and weights are converted to mV in the selected dtype.
"""
from __future__ import annotations
import hashlib
import importlib.metadata
import json
import platform
import sys
import types
from pathlib import Path
import numpy as np
import pandas as pd
AUTHOR_SHA256 = "fc45837d7122c6ce2a7f3f2f23c515992e4b232aadb919efabb72337fac88e4e"
AUTHOR_COMMIT = "91bdd1e7dcf193f3e7ca5a8933497fcef63b7960"
PACKAGE_PINS = {
"brian2": "2.5.1", "numpy": "1.22.3", "pandas": "1.4.3",
"scipy": "1.8.1", "pyarrow": "11.0.0", "joblib": "1.2.0",
"cython": "0.29.33", "jinja2": "2.11.3", "markupsafe": "1.1.1",
"sympy": "1.12", "mpmath": "1.3.0", "pyparsing": "3.0.9",
"packaging": "23.1", "setuptools": "67.8.0",
"python-dateutil": "2.8.2", "pytz": "2023.3", "six": "1.16.0",
"wheel": "0.38.4",
}
def _json(path: Path, value) -> None:
with path.open("x", encoding="utf-8") as output:
json.dump(value, output, indent=2, sort_keys=True, allow_nan=False)
output.write("\n")
def _steps(value: float, dt: float, label: str, *, positive=False) -> int:
ratio = float(value) / dt
if not np.isfinite(ratio) or ratio < 0:
raise ValueError(f"{label} must be finite and nonnegative")
result = int(round(ratio))
if not np.isclose(ratio, result, rtol=0, atol=1e-9):
raise ValueError(f"{label} must be an integer number of dt steps")
if result > np.iinfo(np.int32).max or (positive and result == 0):
raise ValueError(f"{label} is outside the supported step range")
return result
def _int_vector(values, label: str, dtype=np.int64) -> np.ndarray:
source = np.asarray(values)
if source.ndim != 1 or source.dtype.kind not in "iu":
raise ValueError(f"{label} must be a one-dimensional integer array")
limits = np.iinfo(dtype)
if np.any(source < limits.min) or np.any(source > limits.max):
raise ValueError(f"{label} is outside {np.dtype(dtype).name} range")
return source.astype(dtype, copy=True)
def _environment() -> dict:
packages = {}
for name, expected in PACKAGE_PINS.items():
try:
actual = importlib.metadata.version(name)
except importlib.metadata.PackageNotFoundError:
actual = None
packages[name] = {"expected": expected, "actual": actual,
"matches": actual == expected}
return {
"python": platform.python_version(), "author_python": "3.10.11",
"python_patch_matches": platform.python_version() == "3.10.11",
"python_executable": sys.executable, "platform": platform.platform(),
"author_platform": "Windows", "packages": packages,
"all_package_pins_match": all(p["matches"] for p in packages.values()),
"binary_identical_author_environment_claimed": False,
}
def _code_text(value):
if isinstance(value, dict):
return {str(key): _code_text(item) for key, item in value.items()}
return str(value)
def _code_records(network) -> list:
records = []
for obj in network.sorted_objects:
record = {"name": obj.name, "type": type(obj).__name__,
"when": obj.when, "order": int(obj.order),
"active": bool(obj.active)}
for key in ("abstract_code", "user_code"):
if hasattr(obj, key):
record[key] = _code_text(getattr(obj, key))
record["code_objects"] = [
{"name": code.name, "type": type(code).__name__,
"generated_code": _code_text(code.code)}
for code in getattr(obj, "code_objects", ())
]
records.append(record)
return records
def run_brian(author_path: Path, io_dir: Path, nodes: np.ndarray,
edges: pd.DataFrame, config: dict, precision: str,
seed_node: int | None, external_arrivals=None) -> dict:
"""Execute an unchanged author model and return canonical end-of-tick arrays.
``external_arrivals`` is either None or a (T, N) array in mV. Every nonzero
entry gets its own SpikeGeneratorGroup source and zero-delay conditional
synaptic write, ordered after the anatomical synapses. It is not direct
Python assignment to g. ``seed_margin_mv`` may be zero for a strict-threshold
fixture; positive margins must remain representably above the threshold.
This function controls process-global Brian preferences and is not thread
safe. Use only the isolated oracle environment, serially or in subprocesses.
A failed run keeps its exclusive inputs and an error record for diagnosis.
"""
if precision not in ("float64", "float32"):
raise ValueError("precision must be float64 or float32")
dtype = np.dtype(precision)
nodes = _int_vector(nodes, "nodes", np.int32)
if not len(nodes) or np.any(np.diff(nodes.astype(np.int64)) <= 0):
raise ValueError("nodes must be nonempty, sorted, and unique")
required = ["edge_id", "source_neuron_idx", "target_neuron_idx", "raw_count"]
if not set(required).issubset(edges.columns):
raise ValueError(f"edges require columns {required}")
edge_ids = _int_vector(edges.edge_id, "edge_id")
if np.any(np.diff(edge_ids) <= 0):
raise ValueError("edge_id order must be canonical, increasing, and unique")
sources = _int_vector(edges.source_neuron_idx, "source_neuron_idx", np.int32)
targets = _int_vector(edges.target_neuron_idx, "target_neuron_idx", np.int32)
multipliers = _int_vector(edges.raw_count, "raw_count")
if not np.isin(sources, nodes).all() or not np.isin(targets, nodes).all():
raise ValueError("all edge endpoints must occur in nodes")
lookup = {int(node): i for i, node in enumerate(nodes)}
if seed_node is not None and int(seed_node) not in lookup:
raise ValueError("seed_node must occur in nodes")
dt_ms = float(config["dt_ms"])
if not np.isfinite(dt_ms) or dt_ms <= 0:
raise ValueError("dt_ms must be finite and positive")
total_steps = _steps(config["duration_ms"], dt_ms, "duration_ms", positive=True)
model = config["model"]
refractory_steps = _steps(model["refractory_ms"], dt_ms, "refractory_ms")
delay_steps = _steps(model["synaptic_delay_ms"], dt_ms, "synaptic_delay_ms")
margin_mv = float(config["seed_margin_mv"])
if not np.isfinite(margin_mv) or margin_mv < 0:
raise ValueError("seed_margin_mv must be finite and nonnegative")
if "dt_ms" in model and float(model["dt_ms"]) != dt_ms:
raise ValueError("top-level and model dt_ms disagree")
arrivals = None
if external_arrivals is not None:
arrivals = np.asarray(external_arrivals, dtype=np.float64)
if arrivals.shape != (total_steps, len(nodes)) or not np.isfinite(arrivals).all():
raise ValueError("external_arrivals must be finite with shape (T, N)")
author_path = Path(author_path).resolve(strict=True)
author_bytes = author_path.read_bytes()
author_hash = hashlib.sha256(author_bytes).hexdigest()
if author_hash != AUTHOR_SHA256:
raise ValueError(f"Author source hash mismatch: {author_hash}")
io_dir = Path(io_dir).resolve()
io_dir.mkdir(parents=True, exist_ok=False)
environment = _environment()
_json(io_dir / "environment.json", environment)
if environment["packages"]["brian2"]["actual"] != "2.5.1":
raise RuntimeError("The author oracle requires exactly Brian2 2.5.1")
import brian2 as b2
saved_preferences = {
"codegen.target": b2.prefs["codegen.target"],
"core.default_float_dtype": b2.prefs["core.default_float_dtype"],
"legacy.refractory_timing": b2.prefs["legacy.refractory_timing"],
}
saved_dt = b2.defaultclock.dt
try:
b2.start_scope()
b2.prefs["codegen.target"] = "numpy"
b2.prefs["core.default_float_dtype"] = dtype.type
b2.prefs["legacy.refractory_timing"] = False
b2.defaultclock.dt = dt_ms * b2.ms
# Compile the checked bytes themselves: no source rewrite or __pycache__
# is possible, and a subsequent file change cannot alter imported code.
author = types.ModuleType("phase4ad_pinned_author_" + author_hash[:12])
author.__file__ = str(author_path)
exec(compile(author_bytes, str(author_path), "exec"), author.__dict__)
parameters = dict(author.default_params)
checks = {}
for config_key, author_key, unit in (
("membrane_tau_ms", "t_mbr", b2.ms),
("synaptic_tau_ms", "tau", b2.ms),
("refractory_ms", "t_rfc", b2.ms),
("synaptic_delay_ms", "t_dly", b2.ms),
("resting_potential_mv", "v_0", b2.mV),
("reset_potential_mv", "v_rst", b2.mV),
("threshold_mv", "v_th", b2.mV),
("w_syn_mv_per_anatomical_synapse", "w_syn", b2.mV),
):
expected = float(model[config_key])
actual = float(parameters[author_key] / unit)
if not np.isfinite(expected) or not np.isclose(actual, expected, rtol=0, atol=1e-12):
raise ValueError(f"config {config_key}={expected} differs from author {actual}")
checks[config_key] = {"config": expected, "author": actual}
completeness = pd.DataFrame({"local_index": np.arange(len(nodes), dtype=np.int32)},
index=pd.Index(nodes, name="global_neuron_idx"))
connections = pd.DataFrame({
"Presynaptic_Index": [lookup[int(x)] for x in sources],
"Postsynaptic_Index": [lookup[int(x)] for x in targets],
"Excitatory x Connectivity": multipliers,
"edge_id": edge_ids,
"source_neuron_idx": sources, "target_neuron_idx": targets,
}).astype({"Presynaptic_Index": "int32", "Postsynaptic_Index": "int32"})
comp_path = io_dir / "completeness.csv"
con_path = io_dir / "connectivity.parquet"
completeness.to_csv(comp_path)
connections.to_parquet(con_path, index=False, engine="pyarrow")
neu, syn, spikes = author.create_model(comp_path, con_path, parameters)
if np.dtype(neu.variables["v"].dtype) != dtype or np.dtype(syn.variables["w"].dtype) != dtype:
raise AssertionError("Brian did not allocate the requested floating-point dtype")
np.testing.assert_array_equal(np.asarray(syn.i[:]), connections.Presynaptic_Index)
np.testing.assert_array_equal(np.asarray(syn.j[:]), connections.Postsynaptic_Index)
objects = [neu, syn, spikes]
seed_state = {"requested_global_node": None if seed_node is None else int(seed_node),
"margin_mv": margin_mv, "injections": 0}
if seed_node is not None:
seed_local = lookup[int(seed_node)]
def inject_seed():
if seed_state["injections"] == 0:
if float(b2.defaultclock.t / b2.ms) != 0:
raise AssertionError("Seed injection must occur at tick zero")
neu.v[seed_local] = parameters["v_th"] + margin_mv * b2.mV
applied = float(neu.v[seed_local] / b2.mV)
if margin_mv > 0 and not applied > float(parameters["v_th"] / b2.mV):
raise ValueError("The positive seed margin rounded away in the selected dtype")
seed_state["applied_mv"] = applied
seed_state["injections"] = 1
objects.append(b2.NetworkOperation(inject_seed, clock=neu.clock,
when="before_thresholds", order=0,
name="oracle_seed_injection"))
external_metadata = {"events": 0, "ordering": "after default_synapses.pre"}
if arrivals is not None:
event_ticks, event_targets = np.nonzero(arrivals)
event_values = arrivals[event_ticks, event_targets]
external_metadata["events"] = int(len(event_ticks))
if len(event_ticks):
event_ids = np.arange(len(event_ticks), dtype=np.int32)
external_source = b2.SpikeGeneratorGroup(
len(event_ticks), indices=event_ids,
times=event_ticks.astype(np.float64) * dt_ms * b2.ms,
sorted=True, clock=neu.clock, name="zz_external_sources")
external_syn = b2.Synapses(
external_source, neu, model="w : volt", on_pre="g_post += w",
delay=0 * b2.ms, name="zz_external_arrivals")
external_syn.connect(i=event_ids, j=event_targets)
external_syn.w = event_values * b2.mV
external_syn.pre.order = int(syn.pre.order) + 1
if external_syn.pre.when != syn.pre.when:
raise AssertionError("External and anatomical pathways must share a schedule slot")
objects.extend([external_source, external_syn])
external_metadata["pathway_order"] = int(external_syn.pre.order)
external_metadata["actual_weights_mv"] = np.asarray(external_syn.w[:] / b2.mV, dtype=dtype).tolist()
pd.DataFrame({"tick": event_ticks, "neuron_idx": nodes[event_targets],
"requested_mv": event_values}).to_csv(io_dir / "external-arrivals.csv", index=False)
trace = b2.StateMonitor(neu, ["v", "g", "lastspike", "not_refractory"],
record=True, when="end", name="oracle_end_state")
objects.append(trace)
network = b2.Network(*objects)
_json(io_dir / "run-spec.json", {
"author_sha256": author_hash, "author_commit": AUTHOR_COMMIT,
"precision": precision, "config": config, "parameter_checks": checks,
"dt_ms": dt_ms, "steps": total_steps, "refractory_steps": refractory_steps,
"delay_steps": delay_steps, "nodes": nodes.tolist(), "edge_ids": edge_ids.tolist(),
"seed": seed_state.copy(), "external_arrivals": external_metadata,
"preferences": {"codegen.target": "numpy", "legacy.refractory_timing": False,
"core.default_float_dtype": precision},
"weight_rule": "raw_count multiplied by unchanged author w_syn; no sign inference",
"internal_voltage_unit": "volt", "returned_voltage_unit": "mV",
})
_json(io_dir / "schedule.json", {"schedule": list(network.schedule),
"summary": str(network.scheduling_summary())})
network.run(float(config["duration_ms"]) * b2.ms, namespace={})
_json(io_dir / "generated-code.json", _code_records(network))
ticks_float = np.asarray(spikes.t[:] / b2.ms, dtype=np.float64) / dt_ms
ticks = np.rint(ticks_float).astype(np.int32)
if not np.allclose(ticks_float, ticks, rtol=0, atol=1e-6):
raise AssertionError("Spike timestamps do not lie on the configured integer clock")
event_nodes = nodes[np.asarray(spikes.i[:], dtype=np.int32)]
order = np.lexsort((event_nodes, ticks))
ticks, event_nodes = ticks[order], event_nodes[order]
counts = np.asarray(spikes.count[:], dtype=np.int32).copy()
if int(counts.sum()) != len(ticks):
raise AssertionError("SpikeMonitor counts disagree with event records")
trace_ticks = np.asarray(trace.t[:] / b2.ms, dtype=np.float64) / dt_ms
if trace_ticks.shape != (total_steps,) or not np.allclose(
trace_ticks, np.arange(total_steps), rtol=0, atol=1e-6):
raise AssertionError("End-state trace has the wrong tick range")
voltage = np.asarray(trace.v / b2.mV, dtype=dtype).T.copy()
conductance = np.asarray(trace.g / b2.mV, dtype=dtype).T.copy()
last_spike_ms = np.asarray(trace.lastspike / b2.ms, dtype=np.float64).T
seen = np.isfinite(last_spike_ms) & (last_spike_ms >= 0)
# Brian's never-spiked sentinel can be far outside int32. Convert only
# real nonnegative timestamps, then compute an end-of-tick countdown.
last_ticks = np.zeros(last_spike_ms.shape, dtype=np.int64)
last_ticks[seen] = np.rint(last_spike_ms[seen] / dt_ms).astype(np.int64)
elapsed = np.arange(total_steps, dtype=np.int64)[:, None] - last_ticks
ref = np.where(seen, np.maximum(refractory_steps - elapsed, 0), 0).astype(np.int32)
available = np.asarray(trace.not_refractory, dtype=bool).T
if not np.array_equal(available, ref == 0):
raise AssertionError("Recorded refractory flag disagrees with the integer countdown")
history = np.stack([voltage, conductance, ref.astype(dtype)], axis=1)
if not np.isfinite(history).all():
raise AssertionError("Nonfinite author state")
if seed_node is not None:
seed_state["spiked_at_zero"] = bool(np.any((ticks == 0) & (event_nodes == seed_node)))
if seed_state["injections"] != 1 or (margin_mv > 0 and not seed_state["spiked_at_zero"]):
raise AssertionError("The common initial seed event was not produced exactly once")
_json(io_dir / "seed.json", seed_state)
weights = np.asarray(syn.w[:] / b2.mV, dtype=dtype).copy()
_json(io_dir / "actual-weights.json", {
"edge_id": edge_ids.tolist(), "weights_mv": weights.tolist(),
"weights_volt": np.asarray(syn.w_[:], dtype=np.float64).tolist(),
})
if hashlib.sha256(author_path.read_bytes()).hexdigest() != author_hash:
raise AssertionError("Author source changed during execution")
return {"step": ticks, "neuron_idx": event_nodes, "counts": counts,
"v": voltage[-1].copy(), "g": conductance[-1].copy(),
"ref": ref[-1].copy(), "history": history, "weights": weights}
except Exception as error:
_json(io_dir / "error.json", {"type": type(error).__name__, "message": str(error)})
raise
finally:
for name, value in saved_preferences.items():
b2.prefs[name] = value
b2.defaultclock.dt = saved_dt
@@ -0,0 +1,56 @@
"""Predeclare and verify old inputs before executing any alternative dynamics."""
import ast
from datetime import datetime, timezone
import importlib.metadata
import json
import platform
from pathlib import Path
import shutil
import subprocess
import sys
from context import CFG,ROOT,EXP,MODEL,AC,digest,save,source_hashes
def frozen_integrity():
sys.path.insert(0,str(ROOT/CFG['prior_model']))
import audit_semantics as old
result=old.integrity()
for p in (ROOT/CFG['prior_model'],AC,ROOT/'registry/feedback-context-review-20260930'):
result[str(p.relative_to(ROOT))]=old.manifest_check(p,digest)
assert all(x['pass'] for x in result.values())
return result
def main():
assert (MODEL/'oracle_runner.py').is_file()
assert not (EXP/'protocol').exists(),'Refusing reused experiment protocol'
for d in ('protocol','external-resources','inputs','components','oracle','regression','audit','performance'):(EXP/d).mkdir()
source=AC/'external-resources/model.py'
assert digest(source)=='fc45837d7122c6ce2a7f3f2f23c515992e4b232aadb919efabb72337fac88e4e'
tree=ast.parse(source.read_text())
assert all(isinstance(x,(ast.Import,ast.ImportFrom,ast.Assign,ast.FunctionDef,ast.Expr)) for x in tree.body)
inputs=[source,AC/'external-resources/LICENSE',AC/'external-resources/environment_full.yml',
AC/'audit/selected-real-edges.csv',AC/'audit/selected-metadata.parquet',ROOT/CFG['prior_model']/'math_reference.py']
for name in CFG['motifs']:
inputs.extend([AC/'motifs'/f'{name}-edges.csv',AC/'motifs'/f'{name}-events.parquet',AC/'motifs'/f'{name}-state.npz'])
save(EXP/'protocol/preregistered.json',dict(config=CFG,timestamp_utc=datetime.now(timezone.utc).isoformat(),
source_hashes=source_hashes(),input_hashes=[dict(path=str(p.relative_to(ROOT)),sha256=digest(p),bytes=p.stat().st_size) for p in inputs],
parent_commit=subprocess.check_output(['git','-C',str(ROOT),'rev-parse','HEAD'],text=True).strip(),
pre_model_execution=True))
save(EXP/'regression/old-integrity-before.json',frozen_integrity())
for name in ('model.py','LICENSE','environment_full.yml'):
dst=EXP/'external-resources'/name
with (AC/'external-resources'/name).open('rb') as src,dst.open('xb') as out:shutil.copyfileobj(src,out)
assert digest(dst)==digest(AC/'external-resources'/name)
versions={n:importlib.metadata.version(n) for n in ('numpy','pandas','pyarrow','torch','scipy')}
save(EXP/'environment/frozen-scientific-environment.json',dict(python=sys.version,executable=sys.executable,
platform=platform.platform(),package_versions=versions))
save(EXP/'environment/bootstrap-notes.json',dict(isolated_venv_only=True,existing_environments_modified=False,
initial_install_failure='New venv pip22.0.2 lacks --report; upgraded ONLY new venv pip to author-pinned23.0.1 before installing',
MarkupSafe='Author-pinned1.1.1 used PyPI source distribution and legacy setup.py because no CPython3.10 wheel; other requested core packages used wheels',
author_environment='Windows conda CPython3.10.11',actual_environment='Linux CPython3.10.12; not binary-identical',
package_download_provenance='install-report.json contains HTTPS PyPI archive URLs and SHA256 for packages'))
print('PREPARED: old integrity PASS; independent model hypotheses preregistered',flush=True)
if __name__=='__main__':main()
@@ -0,0 +1,20 @@
# Package versions in the pinned author's environment_full.yml, Linux wheels.
# The host Python patch is recorded separately; this is not the author's Windows binary environment.
brian2==2.5.1
numpy==1.22.3
pandas==1.4.3
scipy==1.8.1
pyarrow==11.0.0
joblib==1.2.0
cython==0.29.33
jinja2==2.11.3
markupsafe==1.1.1
sympy==1.12
mpmath==1.3.0
pyparsing==3.0.9
packaging==23.1
setuptools==67.8.0
python-dateutil==2.8.2
pytz==2023.3
six==1.16.0
wheel==0.38.4
@@ -0,0 +1,158 @@
"""Run fixed component arms and independent author oracle, preserving divergences."""
import importlib.metadata
import json
from pathlib import Path
import platform
import sys
import subprocess
import time
import numpy as np
import pandas as pd
from context import CFG,ROOT,EXP,MODEL,AC,digest,save,check_prereg
from math_lab import component,author_numpy
from oracle_runner import run_brian,PACKAGE_PINS
def save_result(where,result,nodes):
where.mkdir(parents=True,exist_ok=False)
pd.DataFrame(dict(step=result['step'],neuron_idx=result['neuron_idx'])).to_csv(where/'events.csv',index=False)
np.savez_compressed(where/'state.npz',nodes=nodes,**{k:v for k,v in result.items() if k not in ('step','neuron_idx')})
def compare(actual,expected,precision):
event=bool(np.array_equal(actual['step'],expected['step']) and np.array_equal(actual['neuron_idx'],expected['neuron_idx']))
a=np.asarray(actual['history'],np.float64);b=np.asarray(expected['history'],np.float64)
assert a.shape==b.shape
errs=np.abs(a[:,:2]-b[:,:2])
# Describe numerical prefix separately from post-event-divergence trajectories.
first=None
for t in range(len(a)):
aa=actual['neuron_idx'][actual['step']==t];bb=expected['neuron_idx'][expected['step']==t]
if not np.array_equal(aa,bb):first=t;break
prefix=errs[:first] if first is not None else errs
tol=CFG['comparison'][precision+'_state_max_abs_tolerance_mv']
return dict(exact_events=event,exact_counts=bool(np.array_equal(actual['counts'],expected['counts'])),
ref_exact=bool(np.array_equal(a[:,2],b[:,2])),max_abs_mv=float(errs.max()),mean_abs_mv=float(errs.mean()),
same_event_prefix_max_abs_mv=float(prefix.max()) if prefix.size else None,
first_event_divergence_step=first,tolerance_mv=tol,
pass_oracle=bool(event and errs.max()<=tol and np.array_equal(a[:,2],b[:,2])))
def oracle_trial(name,nodes,edges,cfg,precision,seed,external=None):
io=EXP/'oracle'/(name+'-'+precision)
result=run_brian(EXP/'external-resources/model.py',io,nodes,edges,cfg,precision,seed,external)
independent=author_numpy(nodes,edges,cfg,precision,seed,external)
comparison=compare(result,independent,precision)
save(io/'comparison.json',comparison)
save_result(io/'brian-output',result,nodes);save_result(io/'independent-output',independent,nodes)
assert np.isfinite(result['history']).all() and np.isfinite(independent['history']).all()
return result,comparison
def unit_fixtures():
rows=[];nodes=np.array([-1],np.int32)
# Brian2 2.5.1 calls max/min on connect arrays and rejects zero-length arrays.
# An explicitly synthetic zero-weight self-edge is inert, not an anatomical edge.
inert=pd.DataFrame(dict(edge_id=[-1],source_neuron_idx=[-1],target_neuron_idx=[-1],raw_count=[0]),dtype='int64')
for precision in CFG['author_precisions']:
# Synthetic fixture indices are negative and are not MaleCNS body IDs.
c=dict(CFG,duration_ms=20.0)
cases={}
a=np.zeros((200,1));cases['zero']=(a,None,1.0)
a=np.zeros((200,1));a[0,0]=1.;cases['weak_excitation']=(a,None,1.0)
a=np.zeros((200,1));a[0,0]=-1.;cases['inhibition']=(a,None,1.0)
a=np.zeros((200,1));a[[0,21,22,23],0]=.1;cases['refractory_boundary']=(a,-1,1.0)
a=np.zeros((200,1));cases['equal_threshold']=(a,-1,0.0)
a=np.zeros((200,1));cases['above_threshold']=(a,-1,1.0)
a=np.zeros((200,1));a[0,0]=2000.;cases['nonzero_g_reset']=(a,None,1.0)
for name,(arr,seed,margin) in cases.items():
cfg=dict(c,seed_margin_mv=margin)
r,cmp=oracle_trial('unit-'+name,nodes,inert,cfg,precision,seed,arr)
h=r['history'];events=r['step'];checks={}
if name=='zero':checks={'no_events':len(events)==0,'g_zero':bool(np.all(h[:,1]==0)),
'rest_stationary':bool(np.max(np.abs(h[:,0]-CFG['model']['resting_potential_mv']))<1e-3)}
elif name in ('weak_excitation','inhibition'):
checks={'no_events':len(events)==0,'arrival_at_zero':bool(h[0,1,0]>0 if name=='weak_excitation' else h[0,1,0]<0),
'integration_next_step':bool(h[1,0,0]>h[0,0,0] if name=='weak_excitation' else h[1,0,0]<h[0,0,0])}
elif name=='refractory_boundary':checks={'one_seed':np.array_equal(events,[0]),'reject_through_21':bool(np.all(h[:22,1]==0)),
'accept_at_22':bool(h[22,1,0]>0),'release_at_22':bool(h[21,2,0]==1 and h[22,2,0]==0),'reset_g_at_zero':h[0,1,0]==0}
elif name=='equal_threshold':checks={'strict_threshold_no_event':len(events)==0}
elif name=='nonzero_g_reset':checks={'natural_spike_at_1':np.array_equal(events,[1]),
'nonzero_g_before_spike':bool(h[0,1,0]>1999),'zero_g_after_spike':bool(np.all(h[1:,1,0]==0))}
else:checks={'single_seed':np.array_equal(events,[0]),'reset_g':bool(h[0,1,0]==0)}
row=dict(fixture=name,precision=precision,checks={k:bool(v) for k,v in checks.items()},comparison=cmp)
rows.append(row);save(EXP/'regression'/('unit-'+name+'-'+precision+'.json'),row)
print(json.dumps(dict(unit=name,precision=precision,checks=all(checks.values()),oracle=cmp)),flush=True)
delay_nodes=np.array([-2,-1],np.int32)
weak_edge=pd.DataFrame(dict(edge_id=[-1],source_neuron_idx=[-2],target_neuron_idx=[-1],raw_count=[1]),dtype='int64')
r,cmp=oracle_trial('unit-delay_18',delay_nodes,weak_edge,c,precision,-2)
h=r['history'];checks=dict(one_seed=np.array_equal(r['step'],[0]),
zero_before_arrival=bool(np.all(h[:18,1,1]==0)),arrival_at_18=bool(h[18,1,1]>0),
first_voltage_effect_at_19=bool(h[19,0,1]>h[18,0,1]))
row=dict(fixture='delay_18',precision=precision,checks=checks,comparison=cmp)
rows.append(row);save(EXP/'regression'/('unit-delay_18-'+precision+'.json'),row)
save(EXP/'regression/unit-fixtures.json',rows)
# Unit oracle failures prevent real author-motif execution; preserve all failed traces.
assert all(all(r['checks'].values()) and r['comparison']['pass_oracle'] for r in rows),'Author operator unit gate failed'
def main():
check_prereg();assert not (EXP/'audit/run-start.json').exists(),'Refusing overwritten run'
assert all(importlib.metadata.version(n)==v for n,v in PACKAGE_PINS.items()),'Dependency-pin mismatch'
save(EXP/'environment/installed-packages.json',json.loads(subprocess.check_output([sys.executable,'-m','pip','list','--format=json'],text=True)))
save(EXP/'audit/run-start.json',dict(python=sys.version,platform=platform.platform(),
packages={n:importlib.metadata.version(n) for n in ('brian2','numpy','pandas','scipy','pyarrow','sympy','cython')},
codegen='numpy',learning=False,user_authorized_new_model_hypotheses=True))
t0=time.perf_counter();rows=[];validations=[]
for name in CFG['motifs']:
edges=pd.read_csv(AC/'motifs'/f'{name}-edges.csv').sort_values('edge_id')
old=np.load(AC/'motifs'/f'{name}-state.npz');nodes=old['nodes'];seed=None if name=='no_input' else CFG['seed_node']
weights=edges.raw_count.to_numpy(np.float32)*np.float32(CFG['model']['w_syn_mv_per_anatomical_synapse'])
for policy in CFG['component_policies']:
r=component(nodes,edges,weights,CFG,policy,seed)
assert np.isfinite(r['history']).all()
if policy=='frozen':
ev=pd.read_parquet(AC/'motifs'/f'{name}-events.parquet')
eq={k:bool(np.array_equal(old[k],r[k])) for k in old.files if k!='nodes'}
eq['events']=bool(np.array_equal(ev.step,r['step']) and np.array_equal(ev.neuron_idx,r['neuron_idx']))
assert all(eq.values()),eq
validations.append(dict(motif=name,frozen_vs_4AC_exact=eq))
save_result(EXP/'components'/(name+'-'+policy),r,nodes)
late=r['step']>=round(CFG['late_start_ms']/CFG['dt_ms'])
for node in nodes:
select=r['neuron_idx']==node
rows.append(dict(motif=name,policy=policy,precision='float32',neuron_idx=int(node),spikes=int(select.sum()),
late_spikes=int((select&late).sum()),last_ms=float(r['step'][select][-1]*CFG['dt_ms']) if select.any() else None))
pd.DataFrame(rows).to_csv(EXP/'components/summary.csv',index=False)
save(EXP/'regression/frozen-components.json',validations)
unit_fixtures()
from interface_audit import audit_author_poi
audit_author_poi()
ors=[]
for name in CFG['motifs']:
edges=pd.read_csv(AC/'motifs'/f'{name}-edges.csv').sort_values('edge_id')
nodes=np.load(AC/'motifs'/f'{name}-state.npz')['nodes'];seed=None if name=='no_input' else CFG['seed_node'];by_precision={}
for precision in CFG['author_precisions']:
r,cmp=oracle_trial(name,nodes,edges,CFG,precision,seed);by_precision[precision]=r
repeat=run_brian(EXP/'external-resources/model.py',EXP/'oracle'/(name+'-'+precision+'-repeat'),nodes,edges,CFG,precision,seed)
exact_repeat={k:bool(np.array_equal(r[k],repeat[k])) for k in r}
save_result(EXP/'oracle'/(name+'-'+precision+'-repeat')/'brian-output',repeat,nodes)
save(EXP/'regression'/(name+'-'+precision+'-repeat.json'),exact_repeat)
assert all(exact_repeat.values()),exact_repeat
late=r['step']>=round(CFG['late_start_ms']/CFG['dt_ms'])
for node in nodes:
chosen=r['neuron_idx']==node
rows.append(dict(motif=name,policy='author_complete',precision=precision,neuron_idx=int(node),
spikes=int(chosen.sum()),late_spikes=int((chosen&late).sum()),last_ms=float(r['step'][chosen][-1]*CFG['dt_ms']) if chosen.any() else None))
ors.append(dict(motif=name,precision=precision,comparison=cmp))
print(json.dumps(dict(motif=name,precision=precision,events=len(r['step']),late=int(late.sum()),oracle=cmp)),flush=True)
save(EXP/'regression'/(name+'-precision-cross-comparison.json'),compare(by_precision['float32'],by_precision['float64'],'float32'))
pd.DataFrame(rows).to_csv(EXP/'audit/all-motif-results.csv',index=False)
save(EXP/'regression/author-motifs.json',ors)
save(EXP/'performance/summary.json',dict(wall_seconds=time.perf_counter()-t0,backend='CPU NumPy + Brian2',not_runtime_benchmark=True))
save(EXP/'audit/run-complete.json',dict(all_author_oracle_comparisons_pass=all(x['comparison']['pass_oracle'] for x in ors),
all_frozen_components_match_archive=True,learning_achieved=False,whole_brain_alternative_run=False,
author_original_source_sha256=digest(EXP/'external-resources/model.py')))
if __name__=='__main__':main()
@@ -0,0 +1,47 @@
"""Unchanged deterministic-v2 five-trial regression; old outputs are read only."""
import os
import sys
import time
import numpy as np
import pandas as pd
import yaml
from context import ROOT,EXP,CFG,save,check_prereg
def main():
check_prereg()
assert not (EXP/'regression/frozen-five.json').exists()
runtime=ROOT/'models/male-cns-lif/runtime-v2-deterministic-candidate'
# Discover the exact prior-audit runtime path from its immutable config.
prior=yaml.safe_load((ROOT/CFG['prior_model']/'config.yaml').read_text())
runtime=ROOT/prior['runtime'];pc=yaml.safe_load((runtime/'phase4p.yaml').read_text())
sys.path.insert(0,str(ROOT/'models/male-cns-lif/terminal-scope-diagnostic-v1'))
from diagnostic import queues
queues()
os.environ['CUDA_VISIBLE_DEVICES']=pc['device']['visible_gpu_uuid']
os.environ['CUDA_HOME']='/usr/local/cuda';os.environ['MAX_JOBS']='2';os.environ['TORCH_CUDA_ARCH_LIST']='8.9'
os.environ['PATH']=str(ROOT/'models/male-cns-lif/.venv/bin')+':/usr/local/cuda/bin:'+os.environ['PATH']
sys.path.insert(0,str(ROOT/'models/male-cns-lif'));sys.path.insert(0,str(runtime))
import torch,phase4p
free,total=torch.cuda.mem_get_info();assert free>2*1024**3
torch.cuda.reset_peak_memory_stats();t0=time.perf_counter()
rt=phase4p.CanonicalRuntime(pc,runtime,EXP)
rows=[]
for spec in pc['reference_trials']:
queues();base=ROOT/'experiments/phase4p-deterministic-runtime/phase4c-v2/reference'/spec['name']
ev=pd.read_parquet(base/'spike-events.parquet')
expected=dict(step=ev.step.to_numpy(),neuron_idx=ev.neuron_idx.to_numpy(),
counts=np.load(base/'per-neuron-spike-counts.int32.npy'),
v=np.load(base/'final-voltage.float32.npy'),g=np.load(base/'final-g.float32.npy'))
r=rt.run(np.flatnonzero(rt.pops[spec['population']]),spec['rate_hz'],spec['seed'],spec['duration_ms'])
eq={k:bool(np.array_equal(r[k],v)) for k,v in expected.items()}
row=dict(trial=spec['name'],exact=eq,wall_seconds=r['metrics']['wall_seconds'])
rows.append(row);save(EXP/'regression'/('frozen-'+spec['name']+'.json'),row)
print(row,flush=True)
save(EXP/'regression/frozen-five.json',dict(pass_all=all(all(x['exact'].values()) for x in rows),trials=rows,
oracle='frozen deterministic-v2, NOT author Brian2',wall_seconds=time.perf_counter()-t0,
peak_allocated_vram=int(torch.cuda.max_memory_allocated()),gpu=torch.cuda.get_device_name(),comfyui_modified=False))
assert all(all(x['exact'].values()) for x in rows)
if __name__=='__main__':main()