Markov Chains#

markov(group, states, matrix) models stateful transitions - each call returns the next state based on the current one and a transition probability matrix. Each worker maintains its own chain state, starting at state 0.

The group key tracks state independently, so multiple groups can run separate chains concurrently within the same query.

See the Function Reference for the full signature and lifecycle details.

Example: order status progression#

up {
  create_orders `CREATE TABLE IF NOT EXISTS orders (
    id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    status STRING NOT NULL
  )`
}

run {
  insert_order(type: exec)
    `INSERT INTO orders (status) VALUES ($1)` (
    markov('order_status',
      ['pending', 'processing', 'shipped', 'delivered', 'returned'],
      [
        0.0, 1.0, 0.0, 0.0, 0.0,
        0.0, 0.3, 0.7, 0.0, 0.0,
        0.0, 0.0, 0.2, 0.8, 0.0,
        0.0, 0.0, 0.0, 0.9, 0.1,
        0.0, 0.0, 0.0, 0.0, 1.0
      ]
    )
  )
}

Transition matrix#

The matrix reads left-to-right per row. Each row must sum to 1.0.

From ↓ \ To →pendingprocessingshippeddeliveredreturned
pending0.01.0
picks up
0.00.00.0
processing0.00.30.7
ships
0.00.0
shipped0.00.00.20.8
arrives
0.0
delivered0.00.00.00.9
keeps
0.1
returns
returned0.00.00.00.01.0

Results#

After running, query the distribution:

SELECT status, count(*) AS total
FROM orders
GROUP BY 1
ORDER BY 2 DESC;

    status   | total
-------------+--------
  delivered  |  2953
  processing |   236
  returned   |   221
  shipped    |   214
  pending    |   195

Most rows end up in delivered because it has the highest stay probability (0.9). The chain cycles: returned orders flow back to pending, creating a realistic order lifecycle.