Brain-5D-Space / src /research /stdp_pair_timing.py
github-actions[bot]
Sync: publish Space API fix
5e0b58b
Raw History Blame Contribute Delete
3 kB
"""Deterministic laboratory protocol for pair-based STDP timing curves."""
from __future__ import annotations
from statistics import fmean
from typing import Any
from src.learning.stdp_plugin import STDPParameters, STDPSynapse
PROTOCOL_ID = "stdp_pair_timing_v1"
DELTA_T_MS = (-50, -20, -10, -5, -1, 0, 1, 5, 10, 20, 50)
REPLICATIONS = 10
INITIAL_WEIGHT = 0.5
PARAMETERS = STDPParameters(
a_plus=0.1,
a_minus=0.12,
tau_plus=20.0,
tau_minus=20.0,
)
def run_pair_timing_protocol() -> dict[str, Any]:
"""Measure the STDP timing curve with fixed, isolated conditions.
The protocol does not access the Brain-5D runtime, filesystem, network,
or any language model. Each replication receives a new synapse and the
same pre/post timing, making the measurement deterministic and auditable.
"""
rows: list[dict[str, float | int]] = []
for delta_t in DELTA_T_MS:
changes = [_measure_delta_weight(delta_t) for _ in range(REPLICATIONS)]
rows.append(
{
"delta_t_ms": delta_t,
"repeated_evaluations": REPLICATIONS,
"independent_runs": 0,
"mean_delta_weight": fmean(changes),
"min_delta_weight": min(changes),
"max_delta_weight": max(changes),
}
)
positive = [row["mean_delta_weight"] for row in rows if row["delta_t_ms"] > 0]
negative = [row["mean_delta_weight"] for row in rows if row["delta_t_ms"] < 0]
zero = next(row["mean_delta_weight"] for row in rows if row["delta_t_ms"] == 0)
supported = (
all(change > 0 for change in positive)
and all(change < 0 for change in negative)
and zero == 0.0
)
return {
"protocol": PROTOCOL_ID,
"seed": 42,
"conditions": {
"initial_weight": INITIAL_WEIGHT,
"parameters": PARAMETERS.to_dict(),
"repeated_evaluations_per_condition": REPLICATIONS,
"independent_runs_per_condition": 0,
},
"measurements": rows,
"summary": {
"total_replications": len(DELTA_T_MS) * REPLICATIONS,
"conditions": len(DELTA_T_MS),
"repeated_evaluations": len(DELTA_T_MS) * REPLICATIONS,
"independent_runs": 0,
"mean_ltp": fmean(positive),
"mean_ltd": fmean(negative),
"zero_delta_weight": zero,
"hypothesis_supported": supported,
"deterministic_identity": all(
row["min_delta_weight"] == row["max_delta_weight"] for row in rows
),
},
}
def _measure_delta_weight(delta_t_ms: int) -> float:
synapse = STDPSynapse.from_parameters(INITIAL_WEIGHT, PARAMETERS)
reference_tick = 100
if delta_t_ms < 0:
synapse.post_spike(reference_tick + delta_t_ms)
return synapse.pre_spike(reference_tick)
synapse.pre_spike(reference_tick)
return synapse.post_spike(reference_tick + delta_t_ms)