The Yokai
The Yokai is a mobile agent that lives on a Kuramoto
environment and works to keep it out of step. It occupies one node at a time,
estimates the local mean-field angle, kicks its phase to oppose the local
alignment, then hops to a neighbor and does it again. It is a Maxwell’s
demon[1] rebuilt for phase space — it must measure the
field before it acts — and since Kuramoto was Japanese, the demon that haunts
his model is a yokai.
Driving the agent
Yokai lives on a Kuramoto
environment and mutates it in place. At each node it visits it estimates the
local mean-field angle, compares it to the phase sitting there, and kicks that
phase by a fixed strength in whichever direction opposes the local
alignment — then hops to a random neighbor and does it again. One environment
step drives the agent through speed such kicks:
import numpy as np
import networkx as nx
from pyGD import Kuramoto, Yokai
rng = np.random.default_rng(4)
G = nx.erdos_renyi_graph(500, 0.02, seed=4)
omegas = rng.standard_normal(G.number_of_nodes())
env = Kuramoto(sigma=2.0, G=G, omegas=omegas, rng=rng)
yok = Yokai(strength=0.5, beta=0.16, env=env, rng=rng)
for _ in range(600):
yok.evolve(env) # the agent kicks and hops
env.evolve() # the oscillators relax back toward each other
env.update_order_parameter()
print(env.r)
The order of the two calls is the whole contest: the agent scatters phases, the
coupling gathers them, and r settles wherever the two forces balance.
Strength and speed enter together
The agent has two knobs — how hard it kicks (\(\alpha\), strength) and
how fast it hops (\(\beta\), beta, which sets speed as a fraction of
the network size). A remarkable degeneracy hides in them: a weak, fast agent and
a strong, slow one behave identically as long as the product
\(\alpha\beta\) matches. You can watch the two collapse onto each other:
def final_r(strength, beta, seed=0):
rng = np.random.default_rng(seed)
env = Kuramoto(2.0, G, omegas, rng=rng)
yok = Yokai(strength, beta, env, rng=rng)
for _ in range(600):
yok.evolve(env)
env.evolve()
env.update_order_parameter()
return env.r
# same product alpha*beta = 0.08, different factors
print(final_r(0.5, 0.16))
print(final_r(0.8, 0.10))
The two lines should land close together, and both should sit below the
agent-free order parameter. That single product is exactly the ab you hand
to KuramotoCG — the coarse-grained dynamics remembers
the agent only through it.
Blinding the sensor
Because the agent must measure before it acts, you can ask what its measurements
are worth by corrupting them. The noise parameter (\(\eta\), from 0 to
1) blurs the agent’s read of the local mean field; at \(\eta = 1\) it kicks
blind:
env = Kuramoto(2.0, G, omegas, rng=np.random.default_rng(5))
yok = Yokai(0.5, 0.16, env, noise=0.5, rng=np.random.default_rng(6))
Sweep noise from 0 to 1 and measure how much desynchronization survives.
Whether the agent’s information is worth anything — whether corrupting it costs
the agent its grip — turns out to depend on the graph, and that dependence is
the paper’s central result. The theory page states it; the paper proves
it[2].