Skip to content

Model and result

kd.Model runs a search and returns a kd.ExperimentResult.

import kd

model = kd.Model(algorithm="sga", generations=200, seed=42)
model.fit(kd.load_kdv())
print(model.result_.equation, model.best_score_)

algorithm takes the name of any of the seven algorithms; each one's scope and parameters are on its own page under Algorithms. Passing config= supplies that algorithm's settings and becomes the single source for them, so supplying the same settings as keywords alongside it raises. Which parameters may change on a resume is covered in Parameter tiers and resuming, and what best_score_ measures in Score conventions and comparability.

Model

High-level facade for PDE discovery (PySR-style API).

Parameters:

  • algorithm (str, default: 'sga' ) –

    Search algorithm name.

  • generations (int, default: 50 ) –

    Search-loop length (default 50).

  • population (int, default: 20 ) –

    SGA population size (number of PDE candidates). SGA-only.

  • depth (int, default: 4 ) –

    Maximum tree depth per term. SGA-only.

  • width (int, default: 5 ) –

    Maximum number of terms per PDE. SGA-only.

  • aic_ratio (float, default: 1.0 ) –

    AIC penalty ratio. SGA-only.

  • derivatives (str, default: 'finite_diff' ) –

    Derivative provider mode: "finite_diff" or "autograd" (forwards use_autograd=True to SGAConfig).

  • seed (int, default: 0 ) –

    Random seed for reproducibility. It threads into every algorithm's default config when config= is unset; otherwise the config's own seed wins. Passing the facade seed= together with config= is rejected by _validate_config_exclusivity.

  • verbose (bool, default: True ) –

    When True, print per-iteration progress to stdout.

  • config (SGAConfig | DLGAConfig | DiscoverConfig | PySRConfig | PySINDyConfig | EqGPTConfig | Llm4edConfig | None, default: None ) –

    Optional pre-built SGAConfig, DLGAConfig, DiscoverConfig, PySRConfig, EqGPTConfig, Llm4edConfig, or PySINDyConfig. When provided, it is the single source of plugin settings.

  • callbacks (list[RunnerCallback] | None, default: None ) –

    Optional list of additional RunnerCallback instances to attach to the runner. The verbose progress printer is appended automatically when verbose=True.

  • surrogate_model (Module | None, default: None ) –

    Optional pre-trained torch.nn.Module forwarded to DLGAPlugin(surrogate_model=...).

  • provider (LLMProvider | None, default: None ) –

    Optional pre-built kd.llm.LLMProvider forwarded to Llm4edPlugin(provider=...). llm4ed-only — passing it with any other algorithm raises TypeError (silent drop is a bug-attractor).

  • checkpoint_dir (str | Path | None, default: None ) –

    Optional directory for periodic checkpoints.

  • checkpoint_every (int, default: 10 ) –

    Save a per-iteration checkpoint every N iterations (0-indexed: saves at 0, N, 2N, ...; default 10).

  • checkpoint_keep_last (int | None, default: None ) –

    Retention bound on PERIODIC checkpoints. None (default) keeps every one, so that the evidence trail stays complete; an int >= 1 keeps only the N most recent periodic checkpoints, pruning older ones from both the manifest and disk.

  • phases_path (str | Path | None, default: None ) –

    Optional phases.jsonl sink (kd-runphase-v1).

  • savgol_window (int, default: 0 ) –

    Savitzky-Golay smoothing window length. 0 (default) disables smoothing. A positive value smooths every field along every grid axis with that window length and polynomial order 3 before the search.

  • small_term_rtol (float, default: 0.0 ) –

    Relative coefficient threshold for the final answer. 0.0 (default) keeps the algorithm's answer. A value r in (0, 1) drops every term whose finite coefficient magnitude is below r times the largest finite coefficient magnitude.

  • **kwargs (Any, default: {} ) –

    Forwarded to the selected algorithm's config dataclass when the field is not already owned by a facade parameter. Unknown, cross-algorithm, colliding, or JSON-type-invalid fields raise at construction.

best_expr_ property

best_expr_: str

Best discovered expression string (post-fit only).

best_score_ property

best_score_: float

Best score from the last fit (post-fit only).

result_ property

Full ExperimentResult from the last fit (post-fit only).

algorithm_ property

algorithm_: SearchAlgorithm

The fitted SearchAlgorithm plugin instance (post-fit only).

fit

fit(
    dataset: PDEDataset | TabularDataset,
    resume_from: str | Path | None = None,
    *,
    sketch: Sketch | None = None,
    reseed: bool = False,
    verify: VerifyPolicy | None = None,
) -> Model

Run the search and populate post-fit attributes.

Parameters:

  • dataset (PDEDataset | TabularDataset) –

    A PDE dataset or public X -> y regression table.

  • resume_from (str | Path | None, default: None ) –

    Optional path to a checkpoint file written by a previous run (checkpoint_*.pt). The checkpoint restores search state (population / controller weights / best).

  • sketch (Sketch | None, default: None ) –

    Optional semantic search-space contract for this fit (kd.Sketch): pinned terms are deducted from the regression target and restored with their exact coefficients, and the run's result carries a sound SketchOutcome (result_.sketch_outcome) whose solution is only filled when the discovered law satisfies every sketch clause AND fits the data within verify (see below).

  • reseed (bool, default: False ) –

    Turn the resume into a BRANCH (K4). A plain resume keeps the checkpoint's random streams and continues one trajectory.

  • verify (VerifyPolicy | None, default: None ) –

    Residual gate the sketch exit judges the lifted law with. None resolves to kd.SKETCH_EXIT_VERIFY (nmse_max=0.05), so a sketch fit certifies only a law that also fits the data on the platform's own footing.

Returns:

  • Model –

    self for sklearn-style chaining.

Raises:

  • NotImplementedError –

    If algorithm is not supported.

  • TypeError –

    If sketch is neither a Sketch nor None.

  • ValueError –

    If sketch uses a clause the algorithm's capability declaration does not support, targets a non-evolution dataset, or declares an LHS differing from the dataset's resolved LHS; or if the dataset is missing the required LHS field or axis.

  • FileNotFoundError –

    If resume_from does not exist.

  • IsADirectoryError –

    If resume_from points at a directory.

  • RuntimeError –

    If a LEGACY resume_from (no config snapshot) was written by a structurally different config (state_dict shape mismatch on restore); a snapshot-bearing checkpoint hits the ValueError tier gate first.

train_surrogate

train_surrogate(
    dataset: PDEDataset | TabularDataset,
) -> tuple[Module, TrainingResult]

Train this instrument's derivative surrogate without running a search.

Returns:

  • tuple[Module, TrainingResult] –

    (module, training_result); the module is not installed on this facade.

Raises:

  • NotImplementedError –

    The instrument accepts no injected surrogate (empty config_artifact_keys), so it trains none; or the dataset's (topology, lhs_order) is one the instrument cannot fit -- the same gate fit runs before its platform build, with the same message.

  • TypeError –

    A tabular dataset (scalar regression has no field surrogate).

  • ValueError –

    This facade already holds an injected model (field_model / surrogate_model); training here would retrain and silently discard it. Also sga under the default derivatives="finite_diff", which never consults a surrogate.

Result structure

One fit produces one ExperimentResult, and the trailing-underscore attributes above are shortcuts into it. Its contents fall into four groups, and the entry below lists every field:

  • The answer. best_expression and best_score, with score_kind and score_direction stating what that number is and which direction is better.
  • Fit quality. final_eval, an EvaluationResult carrying mse, nmse, r² and the coefficients, alongside the actual and predicted values behind them.
  • Search progress. iterations, early_stopped, and recorder, the per-iteration record that kd.VizEngine draws from.
  • Provenance. dataset_name, algorithm_name and config, plus the manifest and run_record that seal the run against its inputs.

ExperimentResult dataclass

Bases: RunResult

Serializable value object for a completed experiment.

has_pareto_front

has_pareto_front() -> bool

Return whether the recorder contains a Pareto expression series.

has_search_trajectory

has_search_trajectory() -> bool

Whether any trajectory column exists, including an incomplete family.

load classmethod

load(path: Path | str) -> ExperimentResult

Load a serialized result from disk.

pareto_front

pareto_front() -> list[ParetoEntry]

Return the last complete recorder-backed Pareto front.

save

save(path: Path | str) -> None

Persist the result to disk as RFC 8259 compliant JSON.

search_trajectory

search_trajectory() -> list[
    list[SearchTrajectoryCandidate]
]

Return distinct fitted-structure observations by recorded iteration.

to_dict

to_dict() -> dict[str, Any]

Return a JSON-safe (RFC 8259) representation of the result.

Interruption of a running fit

kd.SearchInterrupted is the exception an embedding process raises inside a running fit to stop it: a signal handler, or a watchdog that enforces a wall-clock budget. The search stack lets this exception through instead of recording it as one more invalid candidate, so fit exits with it and the caller decides what to keep. The signal is scoped to the one search it lands in; a batch driver treats the interrupted episode as a failed entry and continues with the next one.

import signal

import kd


def stop(signum, frame):
    raise kd.SearchInterrupted("wall-clock budget reached")


signal.signal(signal.SIGTERM, stop)
model = kd.Model(algorithm="sga", generations=200, seed=42)
try:
    model.fit(kd.load_kdv())
except kd.SearchInterrupted:
    pass  # the search stopped where the signal landed