Turbo is the K-coupling language. Four primitives (K, R, E, T) and a real programming language around them: variables, functions, control flow, recursion, lists, higher-order operations. This page walks from your first evaluate through to a working oscillator simulation. Every block runs in your browser. Click RUN on any block to try it.
The four primitives compute the coupling math. K(x) = x/(1+x) is the coupling function. R(x) = 1/(1+1/x) is the synchronization function. They are duals — K(R(x)) = R(K(x)) = x/(2+x).
K(1.868)
That's evaluating an expression. K of the coupling ceiling (K_c = 1.868, which is 256α). Try changing the argument.
Two ways to bind values: top-level assignment with =, or scoped let … in. Let-bindings stay local to their body. Top-level assigns persist.
x = 0.618 K(x) + R(x)
let x = 0.618 in let k = K(x) in let r = R(x) in k + r
The two programs compute the same value. Pick whichever reads cleaner for the problem.
if … then … else … is an expression, not a statement. It evaluates to one branch or the other. The result can be assigned, returned, passed as an argument.
x = 1.868 if K(x) > INV_PHI then "above coherence threshold" else "below threshold"
The classic threshold check. INV_PHI = 0.618 = 1/φ — the natural operating point of life-like systems (heart, brain, flock).
Named functions are defined with fn name(args) = body. Functions are values; once defined they can be passed, stored, called.
fn coupling_score(x) = K(x) * 100 coupling_score(0.618)
Functions close over their environment. They can use any variable that's in scope at the point of definition.
scale = 100 fn pct(x) = K(x) * scale pct(1.868)
For short, inline use — fn(x) = expr is an anonymous function. Useful when you don't want to name the helper.
map(fn(x) = K(x) * 100, [0.5, 1.0, 1.618, 1.868])
Lists are written with brackets. map, filter, reduce work as you'd expect — they take a function and a list.
oscillators = [0.3, 0.618, 1.0, 1.618, 1.868] # Apply K to each ks = map(K, oscillators) # Keep only the ones above 1/phi locked = filter(fn(x) = x > INV_PHI, ks) # Average them mean(locked)
Programs are sequences of statements; only the last expression's value is the result. Use print if you want to see intermediate values.
Functions can call themselves. Use it for iteration over structure (factorial, fibonacci, repeated application).
fn fact(n) = if n < 2 then 1 else n * fact(n - 1) fact(10)
A general iteration combinator — apply f to x, n times:
fn iterate(f, x, n) = if n == 0 then x else iterate(f, f(x), n - 1) # Apply K five times to 1.0 iterate(K, 1.0, 5)
Result: 1/6. Apply K repeatedly and it stairsteps down toward zero — coupling decays unless something feeds it.
Kuramoto's R is the canonical sync measure. Given a set of phases, R measures how aligned they are. R = 1 means all phases identical. R = 0 means uniformly scattered.
# Synced phases sync = kuramoto_R([0, 0.1, -0.05, 0.08, -0.03]) # Uniformly scattered scatter = kuramoto_R([0, pi/2, pi, 3*pi/2]) [sync, scatter]
A small classifier: take a list of oscillators, label each as locked or free based on its coupling, return the locked fraction.
fn is_locked(x) = K(x) > INV_PHI fn locked_fraction(xs) = let n = length(xs) in let locked = filter(is_locked, xs) in length(locked) / n oscillators = [0.2, 0.5, 0.8, 1.0, 1.3, 1.618, 1.868, 2.0] locked_fraction(oscillators)
You've covered the language. The remaining shape is just — combine these moves on bigger problems.
pip install begump then from gump.turbo import evaluate