Data requirements
KD reads a set of observations and searches for the equation behind them. For field data that means
two things: a set of coordinate axes, and one or more fields sampled on those coordinates. Scalar
regression data is a plain X -> y table instead, and carries no axes at all. The derivatives, the
candidate terms and the coefficients are all produced by the algorithm.
Build a dataset from arrays
kd.PDEDataset.from_arrays wraps arrays you already have. The key order of coords fixes the axis
order, and each field array must have exactly the shape given by the axis lengths in that order.
import numpy as np
import kd
x = np.linspace(0.0, 2 * np.pi, 128, endpoint=False) # periodic axis, endpoint not repeated
t = np.linspace(0.0, 1.0, 64)
u = np.sin(x)[:, None] * np.exp(-t)[None, :] # shape (128, 64)
dataset = kd.PDEDataset.from_arrays(
coords={"x": x, "t": t},
fields={"u": u},
lhs="u_t",
periodic={"x"},
name="my-data",
)
kd.preview(dataset)
Dataset: my-data
Axes:
x | n=128 | range [0.000, 6.234] | step 0.04909 (uniform)
t | n=64 | range [0.000, 1.000] | step 0.01587 (uniform)
Fields:
u | dtype=float64 | shape=(128, 64) | min=-1.000 max=1.000 mean=0.000 (NaN=0)
LHS: u_t (field='u', axis='t')
Status: ready to fit
That dataset goes straight into kd.Model.fit(). kd.preview prints, per axis, the point count,
range and whether the step is uniform; per field, the dtype, shape, extrema and NaN count; plus the
left-hand side it parsed. kd.preview_report returns the same facts as an object you can read from
code.
Axis and field requirements
- Any number of axes is accepted. The
coordsmapping fixes both the count and the order, and each field array carries one dimension per axis. The example above has one spatial axis and time;kd.load_burgers_2d()is a bundled dataset with two spatial axes and time, andlap(u)sums the second derivative over whichever spatial axes the dataset has. Which layouts a given algorithm accepts is declared per algorithm and checked atfit()(see below). - Each axis is a 1-D increasing array: a decreasing coordinate is rejected by
from_arraysitself, at construction. - Axes are evenly spaced. Finite-difference stencils are written around a fixed step, so an unevenly spaced axis is rejected when the derivatives are taken (algorithms that differentiate a trained surrogate instead are not bound by this).
- Fields are floating-point arrays with no NaN and no Inf.
from_arrayscasts coordinates and fields tofloat64by default. - Axis names are free-form strings, but derivative symbols (
u_xx) are parsed against single-letter axis names, sox,y,tsave you trouble. periodicmarks the axes with periodic boundaries: they are differentiated with a wrap-around stencil, so boundary points keep the interior accuracy. Do not repeat the endpoint on a periodic axis (use[0, L), not[0, L]).
The left-hand side
lhs spells out the term on the left of the equation using KD's derivative naming convention; KD
parses the field, the axis and the order out of it.
lhs="u_t"(default): first-order in time, i.e.u_t = f(u, u_x, u_xx, ...). Most algorithms target this form.lhs="u_tt": second order. The bundledwaveandklein-gordondatasets are of this kind. DLGA-PDE is the algorithm that fits them:kd.DLGAConfig(target_lhs_order=2), or the ready-madekd.DLGAConfig.wave_preset()/kd.DLGAConfig.kg_preset(). Every other algorithm builds a first-order evaluator only, and raises atfit()on second-order data rather than quietly fitting a different target.- A steady problem has no time derivative and therefore no left-hand side: build it with
kd.PDEDataset.from_scatter(..., lhs="")and the equation reads as a sum of terms equal to zero. The three bundled Laplace / Poisson datasets are of this kind.
Scattered points
Data that does not sit on a regular grid goes through kd.PDEDataset.from_scatter: every coordinate
array and every field array is a 1-D array of length N, one entry per observed point, and the
coordinates need not be sorted. kd.PDEDataset.from_xlsx reads the same structure directly out of
an xlsx workbook by column header, which fits experimental data already stored as (x, y, u)
columns.
Scattered data is handled by EqGPT: its multi-case wave mode and its steady mode declare
scattered.
Tabular data
A scalar regression task is a plain X -> y table, and kd.TabularDataset carries one: X is an
array of shape (n_samples, n_features), y is a (n_samples,) array of the measured target,
var_names gives one name per column of X, and target_name names y. There are no coordinate
axes: a row is one observation, not a sample of a field. name, source and description record
where the table came from, and are required alongside the four above.
import numpy as np
import kd
pressure = np.linspace(1.0, 5.0, 40)
flow = np.linspace(0.2, 2.0, 40)
table = kd.TabularDataset(
X=np.column_stack([pressure, flow]),
y=2.0 * pressure + 3.0,
var_names=("pressure", "flow"),
target_name="yield",
name="my-table",
source="lab notebook",
description="reactor yield against pressure and flow rate",
)
fit() reads the table through one converter, and that is where the names and the values are
checked: every name is a Python identifier, distinct from the others, and neither a Python keyword
nor one of the names KD reserves for its own functions and derivatives; every value is finite; the
columns are read as float64.
That table goes straight into kd.Model.fit(). Each column becomes a field of its own and the
target column becomes the left-hand side. No derivatives are taken, so a column named x or t is
just another feature. The result is an expression in the feature names rather than a PDE.
result_.lhs_label is the target column, and best_expr_ carries the expression together with the
constants fitted for it. An algorithm whose tabular mode declares the REGRESSION form returns the
same answer on result_.equation as well, the target column on the left of it.
DISCOVER and PySR both read this layout: each declares a tabular mode, and KD selects that mode from
the dataset you hand to fit(). KD ships one table of its own, kd.load_tlc_cc(), which returns a
TabularDataset ready to fit.
Supported layouts per algorithm
Every mode of every algorithm declares the layouts it accepts (topologies: grid / scattered /
tabular) and the equation forms it searches (forms: EVOLUTION / HOMOGENEOUS / REGRESSION,
or empty for a mode that returns a bare expression) in
kd.instrument_schemas(); the spec strip at the top of each algorithm page
shows the same information. When the layout or the left-hand-side order of your data does not match
the algorithm, fit() raises and names what that algorithm does support.
To try an algorithm before pointing it at your own data, start from the bundled datasets. For how the derivatives are produced, see derivative sources.