Symbolic regression searches the space of mathematical expressions themselves — not just their coefficients — for a formula that fits a dataset. This simulator runs it as genetic programming (GP): each candidate is a small expression tree built from x, constants, and the operators + − × ÷ √ sin (·)².
Fitness(tree) = RMSE( tree(xᵢ), yᵢ ) + 0.002·size(tree)
Selection: tournament of 3, elitism keeps the top 2 unchanged
Crossover: swap a random subtree between two parents (70% of children)
Mutation: replace a random subtree, or nudge a constant
Three linked panels track one shared population: the fit plot overlays the measured data with the current best-fit curve and a fading trail of recent generations' best curves (drag to pan, scroll/pinch to zoom); the fitness history chart plots best and median population RMSE per generation on a log scale, so early plateaus and later breakthroughs both stay visible; the population spread panel is every individual's fitness this generation sorted ascending, which is a direct readout of selection pressure and diversity — a tall, spiky bar chart means the population still has room to explore, a flat low chart means it has converged. This is exactly how tools like Eureqa or PySR discover closed-form physical laws — Kepler's third law itself, T² ∝ r³, was found this way from planetary data centuries before calculus existed to derive it analytically.
- Population size — more candidates explored per generation (widens the spread panel), at the cost of more evaluations per step.
- Mutation rate — probability a child is produced by mutation instead of crossover; too low stalls in a local optimum (fitness history flattens early), too high turns search into random guessing (spread panel stays noisy, history never converges).
- Data noise — measurement noise added to the synthetic dataset; realistic experimental data is never perfectly clean, and it sets a noise floor the best RMSE can never fall below.