SGA-PDE
A genetic search over expression trees; the coefficients come from the algorithm's own sparse regression.
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.
Running the snippet above, model.best_expr_ is:
| 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.
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):
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.