Partial Training
By default, fit() fits all control points of the Bézier simplex simultaneously. The freeze argument lets you hold a subset of control points constant at their values in init, so that only the remaining (free) control points are fitted.
This is useful when:
Boundary constraints are known — If single-objective optimizations have already determined the vertex solutions, you can freeze those vertices and fit only the interior and edge control points.
Incremental refinement — Fit a low-degree model first, reuse its control points as the initialization for a higher-degree model, and freeze the already-accurate points to stabilize fitting.
Encoding prior knowledge — Pin control points whose values are theoretically or physically determined.
The example below demonstrates how to freeze the two vertices of a Bézier curve while fitting its interior control points.
The freeze argument takes a list of multi-indices (e.g., [[3, 0], [0, 3]]), and requires init, which gives the values of the frozen control points (see Initial Control Points).
The default "lstsq" solver solves the least-squares problem exactly for the free control points, and solver="trainer" (which needs the lightning extra; see Installation) starts from init and excludes the frozen control points from gradient updates.
import torch
import torch_bsf
ts = torch.tensor( # parameters on a simplex
[
[8/8, 0/8],
[7/8, 1/8],
[6/8, 2/8],
[5/8, 3/8],
[4/8, 4/8],
[3/8, 5/8],
[2/8, 6/8],
[1/8, 7/8],
[0/8, 8/8],
]
)
xs = 1 - ts * ts # values corresponding to the parameters
# Initialize 2D control points of a Bézier curve of degree 3
init = {
# index: value
(3, 0): [0.0, 0.1],
(2, 1): [1.0, 1.1],
(1, 2): [2.0, 2.1],
(0, 3): [3.0, 3.1],
}
# Or, generate random control points in [0, 1)
init = torch_bsf.BezierSimploid.rand((1,), 3, n_values=2)
# Or, load control points from a file saved by torch_bsf.simploidal.save
# init = torch_bsf.simploidal.load("control_points.yml")
# Fit the edge of a Bézier curve while its vertices are frozen
bs = torch_bsf.fit(
params=ts, # input observations (training data)
values=xs, # output observations (training data)
init=init, # values of the frozen control points; the degree is taken from it
freeze=[[3, 0], [0, 3]], # freeze vertices of the Bézier curve
)
# Predict with the trained model
t = [
[0.2, 0.8],
[0.7, 0.3],
]
x = bs(t)
print(x)
Bézier Simploids
freeze works in the same way for a Bézier simploid (see Simploidal Sets), whose indices have one multi-index per factor (e.g., ((2, 0, 0), (2, 0))).
import torch
from torch_bsf import BezierSimploid, fit
from torch_bsf.simploidal import sample_simploid
t = sample_simploid((2, 1), 100, seed=0) # parameters on a prism
x = t[:, :3] * t[:, 3:4]
init = BezierSimploid.zeros((2, 1), 2, n_values=3)
corner = ((2, 0, 0), (2, 0))
with torch.no_grad():
init[corner].copy_(torch.tensor([1.0, 0.0, 0.0]))
bs = fit(t, x, init=init, freeze=[corner]) # the type and degree are taken from init
print(bs[corner].tolist())
[1.0, 0.0, 0.0]
For fit_simploidal_set(), init is a simploidal Bézier space (or its proper control points), and each element of freeze is a pair (simploid, index) of any simploid of the set and a control point index of its Bézier simploid.
A control point on a shared face is the same whichever simploid names it.