Cell role is fixed by position. Even row and even column is a
junction, even row and odd column is a pipe running left to right, odd row
and even column is a pipe running top to bottom, odd row and odd column is
filler. Direction is never drawn because it never varies.
Two graphs ship per role. _init.onnx maps the board to the
starting answer state. _step.onnx runs one supervision step and
returns the predicted board, the next state, and a halting probability. The
loop is not in the graph. This page drives it:
let {y0: y, z0: z} = await init.run({x});
for (let s = 0; s < sup_steps; s++) {
const out = await step.run({x, y, z});
render(out.pred);
y = out.y_out; z = out.z_out;
if (out.halt.data[0] > halt_threshold) break;
}
Every step is rendered, including the ones before the answer is right. The
model writes only the erased cells; its predictions on given cells are
discarded, which is what the training harness does.
The instance generator and the reference solver are reimplemented in
JavaScript on this page from the same construction the training data used:
pick a 2-core shape for the level, grow it to twelve erased pipes with leaf
edges, draw seventeen flows, then pin flows to a bound until the erased
subsystem has exactly one in-range solution. The reference solver
enumerates the cycle space of the erased subgraph, so it is exact.