← Home
petri-nets ode game-theory tic-tac-toe rate-constants incidence-reduction

The Incidence Reduction

Prerequisites: Tic-Tac-Toe Model for the game net and its scores, and Declarative Differential Models for how a net becomes an ODE.

In Tic-Tac-Toe Model, we ran ODE simulations with mass-action kinetics to evaluate board positions. The scores for the empty board came back as floats:

Center (1,1):  1.27
Corners:       0.95
Edges:         0.63

Nothing in the net is a hand-coded heuristic, a game tree search or training data, and the ranking (center > corners > edges) is the familiar one. Those three numbers come from an earlier version of the net than the one that post now describes — its score section has the history. The public, runnable net, go-pflow's examples/tictactoe, prints 0.487, 0.359 and 0.248 for the same three cells in its README.

Both sets are suspiciously proportional. Divide each by the smallest: 1.27 : 0.95 : 0.63 ≈ 2.02 : 1.51 : 1, and 0.487 : 0.359 : 0.248 ≈ 1.96 : 1.45 : 1. Both are close to 4 : 3 : 2.

The ODE is tracking three integers — not computing them exactly, the ratios are off by a few percent, but recovering the ranking and grouping the integers predict.

Uniform Rates as a Probe

Set every transition's rate constant to 1.0 and run the ODE. With uniform rates, mass-action dynamics carry no bias from tuning, so the only signal is topology, and whatever structure the net has shows up as flow toward terminal states.

For tic-tac-toe, the terminal states are win transitions — sinks in the net. Every move transition feeds tokens toward pattern collectors, and pattern collectors feed tokens into WinX or WinO. With all rates equal, the tokens accumulated in the win places by a fixed horizon reflect how many paths feed each position into a win.

The integers behind the ODE are the incidence degrees — the number of arcs from each position's history place to downstream win transitions:

 3  2  3
 2  4  2
 3  2  3

The center participates in 4 win patterns (row + column + 2 diagonals). Corners participate in 3 (row + column + 1 diagonal). Edges participate in 2 (row + column). These are exact — they're arc counts in the graph, not simulation results.

Larger Boards

The incidence degree formula generalizes to any N×N board. Each position at (i, j) gets:

So the only possible degrees are {4, 3, 2}, and degree 4 only occurs at the center of odd-sized boards. go-pflow's TestIntegerReduction (examples/tictactoe/cmd/nxn_bench_test.go) builds the N×N game net for N = 3 to 7 and checks each history place's arc count against that formula. Then it scores every opening move by running the uniform-rate ODE from t = 0 to 9 and reading win_x − win_o, and prints each degree's score as a ratio to the degree-2 score:

N=3:  degree 4 ratio 1.960 (expected 2.000, err  -2.0%)
      degree 3 ratio 1.445 (expected 1.500, err  -3.6%)

N=5:  degree 4 ratio 1.615 (expected 2.000, err -19.2%)
      degree 3 ratio 1.279 (expected 1.500, err -14.7%)

N=7:  degree 4 ratio 1.734 (expected 2.000, err -13.3%)
      degree 3 ratio 1.355 (expected 1.500, err  -9.7%)

Those ratios are printed, not asserted, and we did not re-run the test for this revision. The ODE stays close to the integer ratios at N = 3 and drifts above it. Our explanation is that more positions compete for flow through shared win transitions: in this net a win transition consumes every history place on its line at once. The test asserts the ordering, not the ratios. Positions with the same degree must score within 5% of each other, and a higher degree must always score higher. On the empty board that makes the ODE's opening move the arc-counting opening move at every size tested. Move selection needs the ranking, and on these five boards the ranking held.

Reverse-Engineering Rate Constants

For tic-tac-toe we already know the model — we built it. For models extracted from event logs via process mining, or for nets where the strategic structure isn't obvious, the uniform-rate probe should expose the weighting the topology already carries. The procedure:

  1. Set all rates to 1.0, removing any manual tuning
  2. Run the ODE to steady state, or to a fixed horizon
  3. Read the terminal accumulations — token flow into goal, win or completion places
  4. Normalize: divide by the smallest, then scale to the smallest whole-number ratio (×2 for tic-tac-toe; rounding 2.02 : 1.51 : 1 directly would give 2 : 2 : 1)
  5. Assign the results as rate constants

For the tic-tac-toe model, this recovers:

x_play_11 (center): rate = 4
x_play_00 (corner): rate = 3
x_play_01 (edge):   rate = 2

These are the values the rate auto-derivation of Chapter 13 computes by traversing the bipartite graph directly: for each play transition, count the win transitions that consume its unique output place. That implementation is deriveRatesFromTopology in the ZK ODE circuit generator, which is not public, and it does the graph traversal, not this ODE probe. We have no code that runs the probe end to end and writes the rates back; the three rates above are arithmetic on the scores at the top of this post. On tic-tac-toe the two routes land on the same integers, the ODE taking the scenic route. On larger nets we expect the probe to give a starting point for rate constants even when the ratios don't round cleanly, but we haven't tried it.

What the Integers Mean

The incidence degree has a precise interpretation: it counts the number of independent paths from a candidate action to a goal state. In game terms, it measures how many ways this move can contribute to winning.

For tic-tac-toe:

For a resource model with completion states, the same count would measure how many production paths a resource participates in. For a workflow with terminal states, it would measure how many routes to completion pass through a given activity.

Whether the probe recovers that count for any net with designated terminal transitions is the hope, not the result. It holds on the counting side of the boundary below, and the nets actually checked are tic-tac-toe here plus poker, Connect Four and Hex on the analysis net in the paper.

Absorbing the Search Tree

The Petri net has absorbed the search tree.

In classical game AI, you evaluate a position by searching. Build a tree of all possible move sequences. Propagate values from leaf nodes (wins, losses, draws) back up to the root. Minimax, alpha-beta, MCTS — they all walk the tree, one branch at a time, accumulating evidence about which moves lead to good outcomes.

The analysis net doesn't walk anything. It encodes all the constraint structure — every win line, every path to victory — as topology. The search tree's branching factor becomes arc multiplicity. The tree's depth becomes path length through the net. The tree's leaf evaluations become terminal transitions. The entire combinatorial structure that search would explore is baked into the graph before a single token moves.

Then mass-action kinetics does the rest. Tokens flow from sources through accumulators into drains, all in parallel. Every path is "explored" at once, as concurrent fluid flow rather than a sequential traversal — the ODE pressurizes every branch instead of choosing one, and the steady state reflects the aggregate.

On the analysis net, this is why the center scores highest: it has 4 drain transitions (4 win lines) pulling tokens out of its accumulator, while edges have only 2. More drains mean faster depletion, lower equilibrium concentration, and — after inversion — higher strategic value.

The decoupling lemma from the paper is what makes that exact. The analysis net is built for the purpose, and it is not the game net of the sections above. Each cell's play transition reads a source place catalytically and deposits into the cell's accumulator, and each win line through the cell is a separate drain on that accumulator. So each accumulator obeys ẋᵢ = 1 - nᵢxᵢ, and no information leaks between accumulators. pflow-rs's test_integer_reduction_tictactoe, with its _5x5 and _7x7 siblings in crates/pflow/src/lib.rs, builds that net, runs Tsit5 to equilibrium, and asserts center : corner-or-diagonal : edge = 2 : 1.5 : 1 to within 0.05 at every size. That is the ratio the game net drifts away from as N grows. In the game net a win transition consumes all its history places at once, so the accumulators are coupled. On the analysis net you can go from integers (arc counts) to reals (concentrations) and back to integers without losing anything. On the game net you get the ranking back, approximately.

Minimax compresses a search tree into a single value by exploring it. Incidence reduction encodes the tree's win lines as a bipartite graph and reads a value straight off the encoding, with the ODE as a check on the reading. What it encodes is less than the whole tree, though.

One boundary, learned the hard way (clarified 2026-08-24): what the graph absorbs is the tree's strategic structure — which positions feed how many live paths to victory. It does not absorb the tree's adversarial sequencing: a forced block is valuable because of what the opponent does next move, and no static count sees that. Tested against exact minimax over the same net, the incidence ranking (and the ODE that recovers it) will mis-rank a forced tactic — see the correction on the tic-tac-toe post. The reduction's right seat in gameplay is as a move-ordering prior inside the search: alpha-beta explores prior-ranked branches first, cutoffs fire early, and a mis-ranked tactic costs nodes rather than the game. The graph answers "what is strategically strong"; the search answers "what must happen now."

(Sequel, 2026-08-25: the boundary is real but it belongs to the unmodified net, not to the method. Adversarial sequencing can enter the flow — by declaring the opponent's policy as structure (extra play transitions catalyzed by the threats they answer) in a derived evaluation net, after which the continuous evaluator is exhaustively minimax-equivalent with no search at all. And the incidence prior specifically must not be re-applied on top: the topology computes it exactly once, and writing it into weights or rates again measurably degrades play. See the resolution on the tic-tac-toe post.)

The Net as a Lens

In category theory, a lens is a bidirectional map between a complex structure and a simpler view of it. The analysis net with strategic values in place reads like one, sitting between the game's full state space and a vector of strategic values. We haven't checked the lens laws for it, so take this as the shape of the idea, not a theorem.

The get: given a marking (board state), read strategic values from the net's topology, with no search. The drain arc counts are the view. The put would be: make a move, recount drains against the win lines still live (the dynamic evaluation below), and the view updates without a search tree being rebuilt. The analysis net as built doesn't do that recount itself; something outside it has to drop the blocked lines.

The decoupling property would give this lens a product structure. Each position's equation ẋᵢ = 1 - nᵢxᵢ is independent — a lens per place, composed in parallel — so updating one position's view doesn't touch the others, and each position resolves its new value from its remaining drain connections.

The net types can be read as different lens configurations over the same Petri net substrate. A GameNet lens views state through turn structure and win conditions. A ResourceNet lens views state through conservation laws and capacity. The mathematical object is the same — places, transitions, arcs — but the lens determines what you see through it.

Complexity

What does "absorbing the search tree" buy in computational terms?

The evaluation has two phases: build the analysis net, then read the strategic values from it.

Reading values: O(p). The decoupled ODE ẋᵢ = 1 - nᵢxᵢ has an analytical solution — the equilibrium is just xᵢ = 1/nᵢ. We don't need a numerical solver. Scan the incidence matrix, count drain arcs per accumulator, invert. One pass over the places.

Building the net: O(k · m) where k is the number of winning patterns (constraints) and m is the pattern length. For tic-tac-toe: 8 win lines × 3 cells = 24 arc insertions. For Connect Four: 69 win lines × 4 cells = 276, the drain count in the paper's Connect Four net. For poker hand ranking: 9 hand categories, each with its own number of drains.

Compare this to search:

Method Complexity Tic-tac-toe
Minimax O(b^d) at most 9! = 362,880 move orders (fewer, since games end at a win)
Alpha-beta O(b^(d/2)) fewer; not measured here
Incidence reduction O(k·m) build + O(p) eval 8×3 + 9 = 33 ops

The gap is large for tic-tac-toe. The question is what determines k.

For grid games with line win conditions — tic-tac-toe, Connect Four — k grows polynomially in the board dimension. An n×n board with n-in-a-row wins has k = O(n) lines per direction × O(1) directions. The analysis net stays manageable.

For poker hand ranking, k is fixed at the 9 hand categories of the ZK Hold'em analysis net, regardless of the number of players or betting rounds. The drain count per category is chosen by hand, though, so there the ordering is an input, not something the net derives (paper).

For games with emergent constraints — chess tactics, Go territory, complex strategy games — k becomes the problem. You can't enumerate checkmate patterns without effectively searching for them, because the constraint structure emerges from interaction instead of being declared in the rules. We haven't built an analysis net for a game like that; our expectation is that k approaches the game tree size there and the technique loses its advantage.

The boundary is structural: incidence reduction is efficient when the win conditions are declared (lines on a grid, hand rankings, resource thresholds) rather than emergent (tactical combinations, positional advantage). Declared constraints give you a polynomial-sized analysis net. Emergent constraints push k back toward exponential, and you're better off searching.

This matches the boundary between counting and simulation from a different angle. Independent sinks with declared constraints → counting in O(k·m + p). Interacting resources with emergent structure → simulation, or search, at higher cost.

Dynamic Evaluation

The empty board is the base case. The real utility comes from injecting a live state and recomputing.

When a position is occupied, its token has been consumed — it drops out of the flow calculation. The incidence degree is now computed only against still-reachable win transitions. A corner that participates in 3 win patterns on an empty board might connect to only 1 if the opponent has blocked the other two.

Given any board state:

  1. Identify which win transitions are still reachable (not blocked by opponent pieces)
  2. For each empty position, count the number of reachable win transitions it connects to
  3. The highest count is the strategically strongest move — which, per the boundary above, is not always the right move when a forced tactic is on the board

We describe the counting version as a procedure; we don't know of code that packages it. The ODE version is what go-pflow's examples/tictactoe runs, re-scoring every legal move on each turn. For simple nets, this is integer counting. For complex nets where resource competition and multi-hop connectivity create non-trivial dynamics, the ODE simulation resolves what counting cannot. But the mechanism is the same — evaluate positions by their connectivity to terminals, weighted by the current state.

The Boundary Between Counting and Simulation

Tic-tac-toe reduces to {4, 3, 2} because the win transitions are independent sinks. No position competes with another for shared resources on the path to winning. The incidence structure has no dynamics — just a direct count.

The coffee shop is different. Multiple drink recipes compete for shared ingredients (beans, water, milk). The espresso and latte transitions both consume beans, and three drinks draw on milk, so the question the ODE answers is which stock runs out first and when — milk, at about 22 minutes by that post's linear estimate. No arc count gives you that. The ODE earns its keep.

Texas Hold'em is different again. Multi-phase betting, role-based access, and conditional guards create a net where the connectivity to terminal states depends on dynamic state that can't be read off the static graph. The ODE must simulate the actual flow.

The boundary, as far as we have tested it: when terminal transitions are independent sinks with no shared upstream resources, incidence degree counting produces the same move recommendations as ODE simulation. The tested case is the opening move on N×N tic-tac-toe, N = 3 to 7. When paths interact — shared resources, mutual exclusion, conditional guards — the dynamics matter and the ODE is doing real work.

Which side of this boundary a model falls on tells you whether you need a solver or a graph traversal, and the uniform-rate probe is the diagnostic we'd use: run it and check whether positions with the same arc count get the same score.

Using the probe

That same check works as validation. If you build a game model and the uniform-rate ODE groups positions by incidence degree — same degree, same score; higher degree, higher score — the terminal transitions are behaving as independent sinks, and if the grouping breaks, the first place we'd look is resource coupling nobody intended. For models extracted from data, by process mining or by hand, the probe should give a starting point for rate constants that you then adjust against observed data instead of guessing from scratch; as said above, that procedure isn't built yet. And where the ODE ranking matches the incidence ranking you may not need the ODE for move selection at all — a graph query is faster, exact and easier to verify — which leaves the solver for the parts of the model where the dynamics matter.

What Changed

(2026-11-10.) Checked against go-pflow's TestIntegerReduction, pflow-rs's integer-reduction tests, Chapter 13 and the tic-tac-toe post as revised in October. Nothing was re-run.

  1. Two nets. The post ran the game net's approximate ratios and the analysis net's exact decoupling lemma together as one result. They are different nets, and each is now named and linked to its test.
  2. What the N×N test asserts. The ratio table is printed by the test, not asserted. It asserts same-degree grouping within 5% and degree ordering. The old third property, "move selection works", now says what follows from those two: the same opening move.
  3. Rate auto-derivation. It was attributed to go-pflow. It lives in the private ZK ODE generator, and it is a graph traversal; no code runs the ODE probe to recover rates. The normalize step also said "round", which turns 2.02 : 1.51 : 1 into 2 : 2 : 1.
  4. The 1.27 / 0.95 / 0.63 scores come from an earlier tic-tac-toe net; the public example's scores are given beside them.
  5. Smaller fixes. Poker has 9 hand categories, not 10, with hand-chosen drain counts. The minimax figure is 9! move orders, an upper bound. "The highest count is the best move" now carries the forced-tactic boundary. The coffee-shop example says what the ODE computes there, a depletion order, rather than "rational steady states". The lens section is marked as an unchecked reading.

Further Reading


Related: Paper: Incidence Reduction via Petri Net ODE Equilibrium · Tic-Tac-Toe Model · Earned Compression · Symmetric Monoidal Categories

×

Follow on Mastodon