Migrating to the unified v0 API
This release makes breaking API changes before 1.0. There are no legacy aliases or alternate result types.
Previous API |
Replacement |
|---|---|
BezierSimploid / SimploidalBezierSpace |
BezierSpace + BezierModel |
fit(params, values, degree, …) |
fit(space, Samples(params, values), …).model |
fit_simploidal_set |
BezierSpace.on_set + Samples.from_cells + fit |
fit_sgd |
minimize(model, loss, method=PreconditionedSGD(…)) |
fit_kfold / automatic ensemble |
cross_validate / explicit Ensemble(result.models) |
solver=”trainer” and Trainer keyword arguments |
integrations.lightning.regression_module |
init / freeze for regression |
FixedControls with explicit global coefficient values |
ridge / smoothness_weight |
QuadraticPenalty(ridge=…, smoothness=…) |
implicit normalization |
explicit output transforms before fitting |
save/load chosen by extension |
io.save_model / io.load_model |
separate simplex and simploid samplers and plotters |
sampling.sample / sampling.grid / plotting.plot_model |
BezierSimploidRegressor |
sklearn.BezierRegressor |
Regression now solves in CPU float64 and returns a float64 model. Penalties
are defined relative to weighted mean squared output-vector error, not a
sample-count-dependent sum. data_mse additionally divides by output size.
Existing numerical penalty values may therefore need retuning.
The internal _kernels package retains tested geometry algorithms. It is
private and is not a compatibility API.
Separate geometry, observations and fitted state
Construct BezierSpace from your input domain, then pair parameter rows
and outputs in Samples. Regression returns a FitResult containing a
model, numerical status, metrics and diagnostics. Call the model to predict;
the result object itself is not callable.
import torch
from torch_bsf import BezierSpace, Samples, fit, QuadraticPenalty
x = torch.linspace(0, 1, 20, dtype=torch.float64)
parameters = torch.stack([1 - x, x], dim=1)
values = (x.square() + .2 * x)[:, None]
space = BezierSpace.simplex(1, degree=2)
result = fit(space, Samples(parameters, values)).require_success()
predictions = result.model(parameters)
assert predictions.shape == (20, 1)
assert result.metrics["data_mse"] < 1e-24
assert result.diagnostics.compute_dtype == "float64"
For simplex, the dimension is one less than the barycentric column
count: two columns describe a segment, three describe a triangle. For
simploid, pass factor dimensions and a matching degree tuple. For an
assembled domain, retain per-row cell IDs with Points or
Samples.from_cells. Equal local coordinates in different cells need
not describe the same location. See Single and assembled domains for the
geometric picture and coordinate conventions.
Translate penalties and constraints deliberately
Replace numeric penalty keywords with a QuadraticPenalty configuration:
regularized = fit(
space, Samples(parameters, values),
penalty=QuadraticPenalty(ridge=1e-5, smoothness=1e-4),
).require_success()
assert regularized.model(parameters).shape == values.shape
Retune these strengths under the new normalized objective rather than
assuming that the old numbers have the same effect. The regression data
term is weighted mean squared vector error; the reported data_mse is
also divided by output count. Compare predictions in original output units,
not just an old scalar loss value.
Use FixedControls for coefficient values known exactly. An old initial
guess is not an exact constraint and should not automatically become a
fixed row. Conversely, a boundary that must remain exact should not be
represented only by a large sample weight. Resolve rows with
space.control_index because coefficient ordering is a property of the
compiled space. See Fixed controls.
For an original differentiable cost, construct a BezierModel with
explicit coefficients and pass it to minimize with a typed method.
Regression fit has no iterative initial model. Lightning is an optional
adapter around the common model rather than a regression solver selector.
See Explicit initial models and Objective minimization.
Replace implicit preprocessing and model storage
Fit output transforms on training data, apply the same transform to exact fixed values, and invert predictions before reporting physical errors. Within cross-validation, learn preprocessing separately inside each fold. Generic feature standardization is inappropriate for barycentric inputs because it destroys their per-factor sum-to-one constraints.
Use the explicit archive interface for new models:
from pathlib import Path
from tempfile import TemporaryDirectory
from torch_bsf.io import save_model, load_model
with TemporaryDirectory() as directory:
path = Path(directory) / "curve.bsf"
save_model(path, result.model)
restored = load_model(path)
assert torch.equal(restored(parameters), predictions)
The archive stores compiled geometry and coefficients regardless of the filename extension. It does not imply conversion of a legacy artifact. For old models, reconstruct their space and coefficient correspondence explicitly, then compare predictions at reference points before saving in the new format. A control-point CSV alone does not reconstruct glued topology.
Validation and integration changes
cross_validate returns fold results, and an ensemble must be constructed
explicitly when that is the intended predictor. Selecting a degree does
not by itself refit on all observations; perform that final fit with the
selected configuration. The scikit-learn GridSearchCV adapter follows
its own default refit policy. See Cross-validation and degree search and
Scikit-learn integration.
Before replacing an existing workflow, compare a fixed batch of predictions,
boundary values, transformed outputs and save/load results. Inspect
success and solver diagnostics rather than treating a returned model
as sufficient evidence of convergence. Numerical differences may reflect
the new precision, objective normalization or deliberately changed penalties;
identify which configuration is being compared.