jaxsr.constraints#
Physical Constraints for JAXSR.
Provides functionality to incorporate domain knowledge through: - Output bounds - Monotonicity constraints - Convexity constraints - Sign constraints on coefficients - Linear constraints on coefficients
- class jaxsr.constraints.ConstraintType(value, names=None, *, module=None, qualname=None, type=None, start=1, boundary=None)#
Bases:
EnumTypes of constraints supported.
- BOUND = 'bound'#
- MONOTONIC = 'monotonic'#
- CONVEX = 'convex'#
- CONCAVE = 'concave'#
- SIGN = 'sign'#
- LINEAR = 'linear'#
- FIXED = 'fixed'#
- CUSTOM = 'custom'#
- class jaxsr.constraints.Constraint(constraint_type: ~jaxsr.constraints.ConstraintType, target: str, params: dict[str, ~typing.Any] = <factory>, weight: float = 1.0, hard: bool = False)#
Bases:
objectBase constraint specification.
- Parameters:
constraint_type (ConstraintType) – Type of constraint.
target (str) – Target of constraint (“y” for output, feature name for input).
params (dict) – Constraint-specific parameters.
weight (float) – Weight for soft constraint penalty.
hard (bool) – If True, enforce as hard constraint.
- constraint_type: ConstraintType#
- target: str#
- params: dict[str, Any]#
- weight: float = 1.0#
- hard: bool = False#
- to_dict() dict[str, Any]#
Serialize to dictionary.
- classmethod from_dict(data: dict[str, Any]) Constraint#
Deserialize from dictionary.
- class jaxsr.constraints.Constraints#
Bases:
objectBuilder for constraint specifications.
Supports method chaining for convenient constraint construction.
Examples
>>> constraints = (Constraints() ... .add_bounds("y", lower=0) ... .add_monotonic("T", direction="increasing") ... .add_sign_constraint("T", sign="positive") ... )
- add_bounds(target: str = 'y', lower: float | None = None, upper: float | None = None, weight: float = 1.0, hard: bool = False) Constraints#
Add bounds constraint.
- Parameters:
target (str) – “y” for output bounds, or feature name.
lower (float, optional) – Lower bound.
upper (float, optional) – Upper bound.
weight (float) – Penalty weight for soft constraint.
hard (bool) – If True, project to satisfy constraint.
- Returns:
self – For method chaining.
- Return type:
- add_monotonic(feature: str, direction: str = 'increasing', weight: float = 1.0, hard: bool = False) Constraints#
Add monotonicity constraint.
- Parameters:
feature (str) – Feature name for which output should be monotonic.
direction (str) – “increasing” or “decreasing”.
weight (float) – Penalty weight.
hard (bool) – If True, enforce strictly.
- Returns:
self
- Return type:
- add_convex(feature: str, weight: float = 1.0, hard: bool = False) Constraints#
Add convexity constraint (positive second derivative).
- Parameters:
feature (str) – Feature name.
weight (float) – Penalty weight.
hard (bool) – If True, enforce strictly.
- Returns:
self
- Return type:
- add_concave(feature: str, weight: float = 1.0, hard: bool = False) Constraints#
Add concavity constraint (negative second derivative).
- Parameters:
feature (str) – Feature name.
weight (float) – Penalty weight.
hard (bool) – If True, enforce strictly.
- Returns:
self
- Return type:
- add_sign_constraint(basis_name: str, sign: str = 'positive', weight: float = 1.0, hard: bool = True) Constraints#
Add sign constraint on coefficient.
- Parameters:
basis_name (str) – Name of basis function whose coefficient is constrained.
sign (str) – “positive” or “negative”.
weight (float) – Penalty weight.
hard (bool) – If True, project coefficient to satisfy constraint.
- Returns:
self
- Return type:
- add_linear_constraint(A: Array, b: Array, weight: float = 1.0, hard: bool = False) Constraints#
Add linear constraint: A @ coefficients <= b.
- Parameters:
A (jnp.ndarray) – Constraint matrix of shape (n_constraints, n_basis).
b (jnp.ndarray) – Constraint bounds of shape (n_constraints,).
weight (float) – Penalty weight.
hard (bool) – If True, project to satisfy constraint.
- Returns:
self
- Return type:
- add_known_coefficient(basis_name: str, value: float, fixed: bool = True) Constraints#
Fix a coefficient to a known value.
- Parameters:
basis_name (str) – Name of basis function.
value (float) – Value to fix coefficient to.
fixed (bool) – If True, coefficient is fixed during fitting.
- Returns:
self
- Return type:
- add_custom(name: str, constraint_fn: Callable[[Array, Array, Array], float], weight: float = 1.0) Constraints#
Add a custom nonlinear constraint.
The constraint function should return a penalty value (0 if satisfied, positive otherwise). It receives (coefficients, X, y_pred) as arguments.
- Parameters:
name (str) – Name for this constraint (for reporting).
constraint_fn (callable) – Function (coefficients, X, y_pred) -> float penalty. Should return 0 when satisfied, positive when violated.
weight (float) – Penalty weight.
- Returns:
self
- Return type:
Examples
>>> # Constraint: sum of coefficients must equal 1 >>> def sum_to_one(coeffs, X, y_pred): ... return (jnp.sum(coeffs) - 1.0) ** 2 >>> constraints = Constraints().add_custom("sum_to_one", sum_to_one)
>>> # Constraint: prediction at x=0 should be near 0 >>> def zero_at_origin(coeffs, X, y_pred): ... origin = jnp.zeros((1, X.shape[1])) ... # Evaluate at origin requires basis evaluation ... return 0.0 # Placeholder >>> constraints = Constraints().add_custom("zero_origin", zero_at_origin)
>>> # Constraint: ratio of coefficients >>> def coeff_ratio(coeffs, X, y_pred): ... # coeffs[0] / coeffs[1] should be approximately 2 ... if len(coeffs) < 2 or abs(coeffs[1]) < 1e-8: ... return 0.0 ... ratio = coeffs[0] / coeffs[1] ... return (ratio - 2.0) ** 2
- add_physics_constraint(name: str, constraint_type: str, params: dict[str, Any], weight: float = 1.0) Constraints#
Add a physics-based constraint using predefined templates.
- Parameters:
name (str) – Name for the constraint.
constraint_type (str) – Type of physics constraint: - “asymptotic”: y -> value as x -> inf - “periodic”: y(x) = y(x + period) - “symmetric”: y(x) = y(-x) or y(x) = -y(-x) - “scaling”: y(ax) = a^n * y(x) for some n - “passthrough”: y(x0) = y0 (passes through a specific point)
params (dict) – Parameters for the constraint type.
weight (float) – Penalty weight.
- Returns:
self
- Return type:
Examples
>>> # y -> 0 as x -> infinity >>> constraints = Constraints().add_physics_constraint( ... "asymptotic_zero", "asymptotic", ... {"feature": "x", "value": 0.0, "at": "infinity"} ... )
>>> # y passes through (0, 1) >>> constraints = Constraints().add_physics_constraint( ... "initial_condition", "passthrough", ... {"point": [0.0], "value": 1.0} ... )
- to_dict() dict[str, Any]#
Serialize to dictionary.
- classmethod from_dict(data: dict[str, Any]) Constraints#
Deserialize from dictionary.
- class jaxsr.constraints.ConstraintEvaluator(constraints: Constraints, basis_names: list[str], feature_names: list[str])#
Bases:
objectEvaluates constraints for a given model.
- Parameters:
constraints (Constraints) – Constraint specifications.
basis_names (list of str) – Names of basis functions.
feature_names (list of str) – Names of input features.
- compute_penalty(coefficients: Array, predict_fn: Callable[[Array], Array], X: Array, y: Array | None = None) float#
Compute total penalty for constraint violations.
- Parameters:
coefficients (jnp.ndarray) – Current coefficients.
predict_fn (callable) – Function that predicts y given X.
X (jnp.ndarray) – Input points to check constraints.
y (jnp.ndarray, optional) – Target values (for output bounds).
- Returns:
penalty – Total weighted penalty.
- Return type:
float
- apply_hard_constraints(coefficients: Array) Array#
Project coefficients to satisfy hard constraints.
- Parameters:
coefficients (jnp.ndarray) – Current coefficients.
- Returns:
coefficients – Projected coefficients.
- Return type:
jnp.ndarray
- get_fixed_indices() list[tuple[int, float]]#
Get indices and values of fixed coefficients.
- Returns:
fixed – Indices and fixed values.
- Return type:
list of (int, float)
- compute_hard_penalty(coefficients: Array, predict_fn: Callable[[Array], Array], X: Array) float#
Compute penalty for hard shape constraints (MONOTONIC, CONVEX, CONCAVE, BOUND, LINEAR).
These are constraints marked as hard=True that cannot be enforced via simple coefficient projection (unlike SIGN/FIXED). They are penalized heavily during optimization to approximate hard enforcement.
- Parameters:
coefficients (jnp.ndarray) – Current coefficients.
predict_fn (callable) – Function that predicts y given X.
X (jnp.ndarray) – Input points to check constraints.
- Returns:
penalty – Total weighted penalty for hard shape constraints.
- Return type:
float
- check_satisfaction(coefficients: Array, predict_fn: Callable[[Array], Array], X: Array, tolerance: float = 1e-06) dict[str, bool]#
Check which constraints are satisfied.
- Parameters:
coefficients (jnp.ndarray) – Current coefficients.
predict_fn (callable) – Prediction function.
X (jnp.ndarray) – Test points.
tolerance (float) – Tolerance for constraint satisfaction.
- Returns:
satisfied – Constraint names mapped to satisfaction status.
- Return type:
dict
- jaxsr.constraints.fit_constrained_ols(Phi: Array, y: Array, constraints: Constraints, basis_names: list[str], feature_names: list[str], X: Array, max_iter: int = 100, tol: float = 1e-06, penalty_weight: float = 1.0, basis_library: Any | None = None, selected_indices: Any | None = None, enforcement: str = 'penalty', sample_weight: Array | None = None) tuple[Array, float]#
Fit least squares with constraints.
For simple SIGN/FIXED constraints, uses OLS + projection (fast path). For shape constraints (monotonic, convex, bounds, etc.), the solver is chosen by the
enforcementparameter.- Parameters:
Phi (jnp.ndarray) – Design matrix.
y (jnp.ndarray) – Target vector.
constraints (Constraints) – Constraint specifications.
basis_names (list of str) – Names of basis functions.
feature_names (list of str) – Names of input features.
X (jnp.ndarray) – Input data (for evaluating constraints).
max_iter (int) – Maximum iterations for optimizer.
tol (float) – Convergence tolerance for optimizer.
penalty_weight (float) – Weight for soft constraint penalties.
basis_library (BasisLibrary, optional) – Basis library for evaluating predictions at arbitrary X points.
selected_indices (array-like, optional) – Indices of selected basis functions in the full library.
enforcement (str) –
Constraint enforcement level:
"penalty"(default) – L-BFGS-B with penalty terms. Approximate."constrained"– scipytrust-constrwithLinearConstraint. Solver-tolerance guarantee (~1e-8)."exact"– cvxpy QP. Mathematical guarantee. Requirescvxpy.
sample_weight (jnp.ndarray, optional) – Per-sample weights of shape
(n_samples,). Only the least-squares part of the objective is weighted; the constraints are properties of the fitted function over the design space and are evaluated on the rawX, so a down-weighted row still has to obey them. The returned MSE is the weighted MSEsum_i w_i r_i^2 / n.
- Returns:
coefficients (jnp.ndarray) – Fitted coefficients.
mse (float) – (Weighted) mean squared error.
- Raises:
ValueError – If enforcement is not one of the valid levels, if
enforcement='exact'is used withhard=TrueCUSTOM constraints, or ifsample_weightis invalid.ImportError – If
enforcement='exact'andcvxpyis not installed.RuntimeError – If
enforcement='exact'and the QP is infeasible.
- jaxsr.constraints.build_constraint_scorer(constraints: Constraints, X: Array, basis_library: Any, feature_names: list[str], penalty_weight: float = 1.0, hard_penalty_weight: float = 1000.0) Callable#
Build a callable that scores constraint violations for a candidate model.
The returned scorer can be passed to selection strategies via the
constraint_scorerkeyword argument. During model selection each candidate’s information criterion is augmented by the penalty returned by the scorer, biasing selection towards models that can better satisfy the constraints.- Parameters:
constraints (Constraints) – Physical constraints to evaluate.
X (jnp.ndarray) – Training data used for constraint evaluation (shape
(n, d)).basis_library (BasisLibrary) – Full basis library (needed for
evaluate_subset).feature_names (list of str) – Names of input features (e.g.
["x1", "x2"]).penalty_weight (float) – Weight applied to soft constraint penalties.
hard_penalty_weight (float) – Weight applied to hard constraint penalties.
- Returns:
scorer –
scorer(result, indices) -> floatwhere result is aSelectionResultand indices is the list of selected basis function indices. Returns 0.0 when there are no violations.- Return type:
callable