"""Morton Ghost (Case A.3) – persistent environmental impression with refractory period."""
import matplotlib.pyplot as plt
import numpy as np
from mercurial.core.pattern_completion import HopfieldPatternCompletion
from mercurial.simulation.engine import SimulationEngine
[docs]
def run_morton_ghost():
engine = SimulationEngine(dim=20)
engine.apply_empirical_parameters()
n_neurons = 200
ghost_pattern = np.zeros(n_neurons)
ghost_pattern[:20] = 1.0 # sparse pattern
completion = HopfieldPatternCompletion(
n_neurons=n_neurons,
stored_patterns=[ghost_pattern],
tau_a=0.020,
beta_sigmoid=10.0,
hebb_params=engine.hebbian_params,
)
dt = 0.01
t_span = (0.0, 10.0)
t = np.arange(t_span[0], t_span[1], dt)
overlaps = []
perception_events = []
refractory = 0
for step, ti in enumerate(t):
inp = np.random.normal(0, 0.005, size=n_neurons)
if ti < 0.5:
inp += 0.03 * ghost_pattern
_ = completion.step(dt, inp)
ov = abs(completion.get_overlap(ghost_pattern))
overlaps.append(ov)
if ov > 0.8 and refractory == 0:
perception_events.append(ti)
refractory = 50
if refractory > 0:
refractory -= 1
final_overlap = overlaps[-1]
print(
f"Perception events: {len(perception_events)} events, final overlap = {final_overlap:.3f}"
)
# Optional plot
plt.figure()
plt.plot(t, overlaps)
plt.xlabel("Time (s)")
plt.ylabel("Absolute overlap with ghost pattern")
plt.title("Morton Ghost – Stable pattern completion")
plt.ylim(0, 1)
plt.grid(True)
plt.show()
return final_overlap # <-- return scalar metric
if __name__ == "__main__":
run_morton_ghost()