Keyboard Indivisible Stochastic Process#
A pair of small Python programs for building and sampling stochastic models of typing, based on Jacob Barandes's theory of indivisible stochastic processes.
No mathematics required to use them. The math is explained below if you want it.
Requirements#
Python 3.8 or later. No third-party packages — only numpy, which is included with most Python installations. If you need to install it:
pip install numpy
Both programs require a Unix-like terminal (macOS or Linux). They will not work in IDLE, Jupyter, or Windows Command Prompt.
ispKeyboard.py — build a model#
Run it:
python3 ispKeyboard.py
A full-screen display appears. Type any keys. Every keypress is a division event: the model observes which key you pressed, updates its internal law, and immediately displays a new predicted distribution over what you might press next.
- Any printable key — registers as a division event and updates the model
- Backspace — undoes the last keypress
- Ctrl-S — saves the current model to a timestamped CSV file (e.g.
isp_model_20260620_143201.csv) - Escape — quits
What the display shows#
Configuration space C — the set of distinct keys seen so far. Grows the first time each new key appears.
Transition matrix Γ — the learned law of the process. Entry Γ(i, j) is the probability of pressing key i next, given that key j was just pressed. The column corresponding to the last key pressed is highlighted — this is the active prediction.
p(t) — the predicted distribution over the next keypress. This is exactly the highlighted column of Γ, sorted by probability. It updates after every keypress.
Key history — the full sequence of keys pressed so far.
Saving a model#
Press Ctrl-S at any time to save. The file is a plain CSV with one row per key and one column per key — rows are destinations, columns are sources. The first row and first column are labels. You can open it in any spreadsheet application.
isp_generate.py — sample from a model#
Load a saved model and generate a sequence stochastically characteristic of the typing that produced it:
python3 isp_generate.py my_model.csv
This opens an animated display showing the active column of Γ at each step, with the sampled key highlighted, and the growing output string below.
Options#
-n N, --length N number of keys to generate (default: 100)
-s KEY, --start KEY starting key (default: sampled from stationary distribution)
-t MS, --tempo MS milliseconds between keys in the animation (default: 120)
-o FILE, --output FILE write the generated string to a file
--no-display skip the animation, print the raw string to stdout
Examples#
# Generate 200 keys, slower animation
python3 isp_generate.py my_model.csv -n 200 -t 200
# Start from the letter 'e', save output to a file
python3 isp_generate.py my_model.csv -n 500 -s e -o generated.txt
# No animation, just the string — useful for piping
python3 isp_generate.py my_model.csv -n 1000 --no-display
# Pipe into a word counter
python3 isp_generate.py my_model.csv -n 10000 --no-display | tr ' ' '\n' | sort | uniq -c | sort -rn
Things worth trying#
Type structured text, then generate. Type a paragraph of prose, save the model, and generate from it. Recognizable patterns — "th", "er", "ing", spaces around short words — reappear in the output, garbled but statistically present.
Compare two models. Build one model by typing normally, another by keyboard-mashing. Generate from each and compare. The distributions in Γ will look very different.
Watch the matrix fill in. Start ispKeyboard and type slowly, one key at a time. Watch how each new keypress updates exactly one column of Γ (the column for the key you just pressed) and leaves all the others untouched. The column that updates is the one that was just used to make a prediction — the model is correcting itself in the light of new evidence.
Start the generator from different keys. The same model generates very different-feeling output depending on the starting key, because each starting key selects a different column of Γ as the first distribution.
What is an indivisible stochastic process?#
A stochastic process is a system that evolves probabilistically over time. The usual kind — a Markov process — has a simple compositional property: if you know the transition law from time A to time B, and from B to C, you can multiply them together to get the law from A to C directly. The future depends only on the present state, not on how you got there.
Indivisible stochastic processes, introduced by Jacob Barandes, relax this requirement. The dynamical law between any two moments is taken as primitive — it cannot necessarily be decomposed into a product of sub-step laws. The process is indivisible in the sense that you cannot split the interval between two events into smaller pieces and recover the same law by composing them.
This is not the same as a process with "memory effects" in the usual sense. The memory is not carried in the state of the system — it is encoded in the law itself.
The formal structure#
An indivisible stochastic process has three ingredients:
A configuration space C — the set of possible states the system can be in. Here, C is the set of keys on the keyboard.
A transition matrix Γ(t ← t₀) — a column-stochastic matrix whose entry Γ(i, j) gives the probability of being in configuration i at time t, given that the system was in configuration j at the conditioning time t₀. Every column sums to 1 and every entry is non-negative. This matrix encodes the nomological content of the model — the law.
Division events — the moments at which t₀ is defined. Between two division events, the law Γ is the only thing governing the process. At a division event, the conditioning time resets to now.
The law of total probability then gives:
p(t) = Γ(t ← t₀) · p(t₀)
where p(t₀) is the probability distribution at the last division event.
How the keyboard model fits#
Every keypress is a division event. At the moment you press key j, t₀ resets to now.
p(t₀) is a delta spike on j. We observed which key was pressed with certainty, so the distribution at t₀ is 1 on j and 0 everywhere else.
p(t) = column j of Γ. Multiplying Γ by a delta spike just selects one column. That column is the predicted distribution over the next keypress.
All memory lives in Γ. The spike p(t₀) carries no history — it is just the bare fact of the current keypress. But the column it selects was shaped by every previous keypress, through the accumulated bigram statistics that define Γ. Two typists who press the same key get the same spike, but very different predictions, because their Γ matrices reflect different histories.
The process is indivisible because Γ is updated globally from the full history at each division event. It is not a product of step matrices. There is no smaller law you can compose to recover it.
The stochastic-quantum correspondence#
Barandes shows that any indivisible stochastic process can be represented as a quantum system in a Hilbert space. The transition matrix Γ can always be written as:
Γ(i, j) = |Θ(i, j)|²
for some complex matrix Θ — the time-evolution operator. The squared moduli of Θ give the transition probabilities, exactly as the Born rule gives measurement probabilities from a quantum amplitude. The Hilbert space, wave functions, and density matrices emerge as convenient mathematical structure on top of the underlying stochastic process — not as fundamental ontology.
This correspondence runs in both directions. Any quantum system can be understood as an indivisible stochastic process in disguise. These programs are a small, tangible instance of that idea: a process whose law is irreducibly historical, whose state is a probability distribution, and whose evolution is governed by a matrix that is exactly the kind of object that appears in quantum mechanics.
References#
Barandes, J. A. (2025). "Quantum Systems as Indivisible Stochastic Processes." arXiv:2507.21192
Barandes, J. A. (2025). "The Stochastic-Quantum Correspondence." Philosophy of Physics, 3(1):8. arXiv:2302.10778
Barandes, J. A. (2023). "The Stochastic-Quantum Theorem." arXiv:2309.03085