“Know how to solve every problem that has been solved.” “What I cannot create, I do not understand.” — Richard Feynman

Project: A Neural Net That Finds the Symmetry

Projects

What you need to know first 13 concepts, 7 layers

The requisite-knowledge inventory for this page, bottom-up: the primitives at the base, combined upward until you reach what this page assumes. Skim the layers you already own; start wherever the ground gets unfamiliar.

  1. base
  2. L1
  3. L2
  4. L3
  5. L4
  6. L5
  7. L6
  8. you are here

3 of these are concepts without a dedicated page yet — the grey chips. Following the linked ones first makes the rest land.

The brute-force engine dies on a two-variable mystery whose formula costs eight tokens: its budget stops at six, and after two million candidates the best it can offer is 20% wrong. This page is the AI Feynman move that rescues it — train a neural network on the same samples, then interrogate the network for a symmetry the data never states out loud. The network is not the answer; it is a witness. Everything below — the failed search, the MLP and its backprop, the probes, the winning re-search — is one Knot program compiled to 49 KB of WebAssembly, running on your machine.

Knot sourcegenerated C49 KB WebAssemblybrute force fails · a neural net finds the reason · brute force wins
mystery: 225 samples of a hidden f(x, y)

Why a neural network, when it explains nothing?

The dataset is 225 fixed points. You cannot ask a dataset "what happens if I nudge both inputs by the same amount?" — the nudged point isn't in it. A network trained to rms 0.003 on those points can be asked: it interpolates, so counterfactual queries come for free. That is the entire role of the MLP here — a differentiable stand-in for that turns a frozen table into something you can poke.

# probe kinds: 1 shift both (+a,+a) · 2 shift x only · 3 scale both · 4 shift opposite
def probe(kind, n) {
    a = 0.35
    for t to n {
        x = (rand01() - 0.5) * 1.6          # points the dataset never contained
        y = (rand01() - 0.5) * 1.6
        g0 = nn_forward(x, y)
        g1 = 0.0
        if kind == 1.0 { g1 = nn_forward(x + a, y + a) }
        if kind == 2.0 { g1 = nn_forward(x + a, y) }
        if kind == 3.0 { g1 = nn_forward(1.3 * x, 1.3 * y) }
        if kind == 4.0 { g1 = nn_forward(x + a, y - a) }
        pv[t] = abs(g1 - g0)
    }
    return median_of(n)
}

Four pokes, each a hypothesis about structure. If , then can only depend on the difference ; if scaling both inputs changes nothing, it lives on the ratio; if the opposite shift is invisible, it lives on the sum. The trained network answers with a 300× gap between "shift both" and everything else. One substitution later, the mystery is a one-variable problem, the eight-token formula costs five, and the same enumeration budget that just failed now lands on with zero error.

The accounting is the lesson. The brute-force engine never improved — same alphabet, same budget, same scoring. What changed is the problem: each discovered symmetry deletes a variable, and deleting a variable shrinks the search space exponentially. That is the entire architecture of AI Feynman: dimensional analysis, separability, compositionality — every module is a differently-shaped probe whose only job is to hand the dumb enumerator a smaller problem.

Everything runs inside the one Knot source (tab ① above): the RPN enumerator shared with the symbolic-regression page, a 2→12→12→1 MLP with backprop written out by hand — the same flat-array style as the reverse-mode autodiff engine — a Park–Miller generator for the weights (chosen because 16807·s stays under 2⁵³, so the modular arithmetic is exact in a language whose only number is a double), and an insertion sort for the probe medians.

Try First

Each prompt asks a checkable question about the working code or math above — predict an output, derive a sign, state an invariant, find a bug. Commit to an answer before clicking "reveal." That commitment is the whole point: if your answer matched, you understand the piece you were looking at; if it didn't, that's the part worth re-reading.

predict
Phase 1 searches 11 symbols to length 6 and reports 1,948,717 sequences. Phase 4 searches 10 symbols (no ) at the same length cap. How many sequences is that, and how many would the two-variable search have needed to reach the 8-token formula directly?
why does this work
Why probe the network instead of probing the data directly — say, by finding sample pairs that happen to satisfy and comparing their values?
what if
Suppose the mystery had been — almost symmetric, not quite. What does the probe table look like, and what should the pipeline do?

Reproduce it

scripts/build_nns_wasm.sh rebuilds the pipeline. The native binary runs all four acts in 0.55 s. Together with the enumeration engine and the Meijer-G metamodeler this completes the trilogy: search, relax, and shrink — the three ways a machine gets a formula out of data.