Skip to content

SGA-PDE

A genetic search over expression trees; the coefficients come from the algorithm's own sparse regression.

algorithm
sga
score
AIC min
cost
medium
derivatives
finite_diff autograd
equation form
EVOLUTION
data layout
grid

Usage

import kd

dataset = kd.load_kdv()
model = kd.Model(algorithm="sga", generations=200, seed=42)
model.fit(dataset)
print(model.best_expr_)

Main parameters

Parameter Default Resume Description
num 20 resume-safe Population size.
p_cro 0.5 resume-safe Crossover probability per generation.
p_mute 0.3 resume-safe Per-node mutation probability.
p_var 0.5 resume-safe Probability that a node in a freshly generated term tree is a variable rather than an operator.
p_rep 1.0 resume-safe Replace-draw probability for non-elite members.
depth 4 init-only Maximum term-tree depth.
width 5 init-only Maximum terms per candidate equation.
aic_ratio 1.0 init-only AIC complexity-penalty ratio.
lam 0.0 init-only Internal STRidge ridge strength.
All fields of SGAConfig
Field Type Default
num int 20
p_var float 0.5
p_mute float 0.3
p_cro float 0.5
p_rep float 1.0
seed int 0
depth int 4
width int 5
aic_ratio float 1.0
lam float 0.0
d_tol float 1.0
maxit int 10
str_iters int 10
normalize int 2
dedup_mode DedupMode pre_prune
use_autograd bool False
field_model FieldModel \| None None
autograd_train_epochs int 1000
autograd_train_lr float 0.001
autograd_train_patience int \| None None
autograd_train_val_ratio float 0.0

Worked example

The run below uses the KdV dataset that ships with KD: a 256 × 201 grid whose cosine initial condition steepens under the nonlinear term and then breaks into a train of solitary waves that separate at different speeds, the tallest of them reaching an amplitude of 2.3.

Heatmap of the KdV field u(x, t)
The observed field u over x and t.

Running the snippet above, model.best_expr_ is:

SGA-PDE · kdv · seed 42 generation 200 / 200 · nmse 2.70e-06 · AIC -19.42
\(u_t =\)\(-u\,u_x\)\(-0.0025\,u_{xxx}\)
Equation
Discovered \(u_t = -u\,u_x -0.0025\,u_{xxx}\)
Reference \(u_t = -u\,u_x -0.0025\,u_{xxx}\)

Both terms and both coefficients match. The search was not narrowed to them: SGA-PDE was given no candidate library, so the two terms were assembled from operators during the run, and the two coefficients came from its own sparse regression rather than from a fit against the answer.

Measured u_t, predicted u_t, and the residual between them
The discovered equation evaluated against the data. The first two panels share a color scale and are indistinguishable by eye; the third is their difference, at most 9.4e-02, under 2% of the 5.97 peak of u_t, and confined to the two t boundaries and the steepest wave crest.

Result interpretation

model.best_score_ is an AIC: lower is better. It combines fit error and equation length, so nmse alone does not determine which of two equations is preferred.

The coefficients in model.best_expr_ are the algorithm's own, not a platform refit, and can be read directly.

The search is recorded as well. kd.VizEngine renders the per-generation record; alongside the universal convergence curve, SGA-PDE contributes diagnostic panels of its own, three of which this run drew (the full list is under Visualization):

Best AIC and population mean AIC per generation
The best AIC starts at −18.38 and drops to −19.42 at generation 9, with no further improvement over the remaining 190; the population mean falls from −0.38 and meets it at generation 16.
Offspring diversity, complexity evolution and fitness spread panels
Left: distinct candidate expressions per generation, up to 38 in the opening generations and then down to about 19, oscillating between 18 and 21 as the population converges. Middle: mean term count of this generation's candidates, climbing from 1.8 to around 4 and oscillating there (4.85 at its highest), so mutation is still doing work. Right: mean AIC of the surviving population.
viz = kd.VizEngine(output_dir="out/kdv")
viz.render_all(model.result_, algorithm=model.algorithm_, dataset=dataset)

Method

A candidate equation is a set of expression trees. Genetic operators (crossover, mutation, replacement) produce the next generation; every candidate is fitted by an internal sparse regression (STRidge) to get its coefficients, then ranked by AIC and truncated to the best of the population. One generation is one KD iteration, and generations sets how many are run.

References

Chen et al. (2022). "Symbolic genetic algorithm for discovering open-form partial differential equations (SGA-PDE)". Phys. Rev. Research 4, 023174. Paper · arXiv:2106.11927

Code: YuntianChen/SGA-PDE

Implementation note: KD reproduces the paper's three-tree structure and its STRidge column normalization (normalize=2). An empty-support candidate is scored as infinite AIC, so a returned equation always carries at least one term.