Genetic programming breeds formulas until it rediscovers the law behind the data.
Six islands of 64 expression trees over x, constants and + - x / sin cos exp log sqrt and square evolve by tournament selection, subtree crossover and point, subtree, insertion and hoist mutations, trading their best trees around a ring. Every tree is scored on all points at once by a vectorized interpreter after linear scaling (its output is fitted as a + b f by least squares, so evolution only has to find the shape), the leaders get their constants polished by hill climbing, and an archive keeps the most accurate formula at each size: the Pareto front of simplicity against accuracy. The best tree is tidied algebraically (constant folding, like terms, powers, cancelled factors, checked numerically against the original) and drawn as a botanical specimen where operators are flowers, functions are buds, x is a leaf and constants are berries, with the formula typeset beneath it with real fractions, exponents and radicals (and absolute value bars wherever the protected square root or log needs them). Mystery curves include a damped spring, Planck's law, a resonance peak and the Maxwell-Boltzmann distribution.
Try it. Drag across the plot to draw your own curve and watch it find a formula. Pick a mystery curve with the numbered buttons or keys 1 to 7, click a red dot on the Pareto front to inspect that formula, and press R to rerun with a new seed.
Paste this into Claude Code, Codex or any coding agent to get a simple version running, then take it wherever you like.
Build a symbolic regression demo, where genetic programming evolves math formulas to fit a curve, using JavaScript and the HTML canvas element. Put everything in a single index.html file with no libraries or build step, so I can open it directly in a browser.
Start simple:
- Make a canvas that fills the window, stays sharp on high-DPI screens (scale by devicePixelRatio), and resizes with the window.
- Sample 40 points of a hidden target like exp(-x/4) cos(2x) for x from 0 to 10 and plot them as small circles.
- Represent formulas as expression trees: leaves are x or a constant, internal nodes are +, -, *, protected division, sin, cos and exp. Write a recursive evaluator, a random tree generator (ramped half and half) and a function that prints a tree as a string.
- Evolve a population of 300 trees: score each by mean squared error, keep the two best, and fill the rest by tournament selection plus subtree crossover and mutation, capping the tree size. Run a few generations per animation frame.
- Draw the best tree's curve over the points and print its formula and error.
Once that works, make it beautiful:
- Add linear scaling: fit y = a + b f(x) by least squares for each tree before scoring, so evolution only has to find the shape.
- Simplify the best formula before showing it (fold constants, drop times one and plus zero).
- Draw the best tree itself as a diagram that grows from a root, with operator nodes and leaves.
- Let me drag across the plot to draw my own curve as the new target.
Explain the key ideas in short code comments. When you're done, tell me how to open it and suggest three directions I could take it next, such as a Pareto front of simplicity against accuracy, island populations that swap their best trees, or typesetting the formula with real fractions and exponents.