Brain-5D-Space / scripts /trace_restore_divergence.py
github-actions[bot]
Sync: publish Space API fix
5e0b58b
Raw History Blame Contribute Delete
4.5 kB
"""Trace A/B divergence tick-by-tick between K and N."""
from __future__ import annotations
import json
import sys
from pathlib import Path
sys.path.insert(0, str(Path(__file__).resolve().parent.parent))
from src.config.loader import ConfigDict
from src.homeostasis.engine import HomeostasisEngine
from src.learning.learning_engine import LearningEngine
from src.storage.checkpoint import capture_runtime_checkpoint, write_runtime_checkpoint
from src.storage.core_restore import restore_full
from src.storage.runtime import StorageRuntimeConfig, StorageSession
from tests._restore_helpers import (
K,
N,
build_absolute_schedule,
create_network,
make_config,
run_absolute_schedule,
)
OUT_DIR = Path(__file__).resolve().parent.parent / "tmp" / "trace_diag"
OUT_DIR.mkdir(parents=True, exist_ok=True)
def _write_artifacts(network, homeo, learn, tmp_path, schedule, config):
rt = StorageRuntimeConfig(
snapshot_path=tmp_path / "base.b5d",
journal_path=tmp_path / "base.b5d.journal",
commit_interval_ticks=1,
)
with StorageSession(network, rt):
pass
from tests._restore_helpers import capture_learning_state
learn_state = capture_learning_state(learn)
checkpoint = capture_runtime_checkpoint(
network,
homeostasis_rates=homeo._rates_hz,
learning_states=learn_state["states"] if learn_state else None,
pending_rewards=learn_state["pending_rewards"] if learn_state else None,
)
cp_path = tmp_path / "runtime.json"
write_runtime_checkpoint(cp_path, checkpoint)
cfg_path = tmp_path / "config.json"
cfg_path.write_text(json.dumps(config, sort_keys=True), encoding="utf-8")
sched_path = tmp_path / "schedule.json"
sched_path.write_text(json.dumps(schedule, sort_keys=True), encoding="utf-8")
return {
"snapshot": rt.snapshot_path,
"journal": rt.journal_path,
"checkpoint": cp_path,
"config": cfg_path,
"schedule": sched_path,
}
def _neuron_0_state(network, homeo):
n = network.neurons[0]
return {
"tick": network.current_tick,
"v": n.v,
"u": n.u,
"threshold_adaptation": n.threshold_adaptation,
"last_spike_tick": n.last_spike_tick,
"homeo_rate": homeo._rates_hz.get(0, 0.0) if homeo else None,
}
def main():
config = make_config()
schedule = build_absolute_schedule(config, N)
# Path A: run to N, recording neuron 0 each tick after K
net_a = create_network(config)
homeo_a = HomeostasisEngine(net_a, config)
homeo_a.attach()
learn_a = LearningEngine(net_a, config)
learn_a.attach()
run_absolute_schedule(net_a, schedule, K)
trace_a = []
while net_a.current_tick < N:
net_a.step()
trace_a.append(_neuron_0_state(net_a, homeo_a))
# Path B: run to K, restore, then step-by-step to N
net_b = create_network(config)
homeo_b = HomeostasisEngine(net_b, config)
homeo_b.attach()
learn_b = LearningEngine(net_b, config)
learn_b.attach()
run_absolute_schedule(net_b, schedule, K)
tmp_path = OUT_DIR / "path_b"
tmp_path.mkdir(exist_ok=True)
artifacts = _write_artifacts(net_b, homeo_b, learn_b, tmp_path, schedule, config)
bundle = restore_full(
snapshot_path=artifacts["snapshot"],
journal_path=artifacts["journal"],
checkpoint_path=artifacts["checkpoint"],
config=ConfigDict(config),
recovered_path=tmp_path / "recovered.b5d",
create_homeostasis_engine=True,
create_learning_engine=True,
)
trace_b = []
while bundle.network.current_tick < N:
bundle.network.step()
trace_b.append(_neuron_0_state(bundle.network, bundle.homeostasis_engine))
# Compare tick-by-tick
diff_tick = None
for i, (sa, sb) in enumerate(zip(trace_a, trace_b)):
if sa != sb:
diff_tick = i
break
out = OUT_DIR / "trace_comparison.json"
out.write_text(
json.dumps(
{"diff_tick_index": diff_tick, "A": trace_a, "B": trace_b}, indent=2
),
encoding="utf-8",
)
print(f"Trace written to {out}")
if diff_tick is not None:
tick = trace_a[diff_tick]["tick"]
print(f"First divergence at tick {tick}")
print(f" A: {trace_a[diff_tick]}")
print(f" B: {trace_b[diff_tick]}")
else:
print("No divergence found between K and N")
if __name__ == "__main__":
main()