Cost Functions

Base Classes

class ionworkspipeline.data_fits.objective_functions.costs.ObjectiveFunction(objective_weights: dict[str, float] | None = None, variable_weights: dict[str, float] | None = None)

Base class for all objective/cost functions.

Parameters

objective_weightsdict[str, float], optional

Per-objective weights. Keys are objective names, values are weights. Missing objectives default to weight 1.0.

variable_weightsdict[str, float], optional

Per-variable weights. Keys are variable names, values are weights. Missing variables default to weight 1.0.

Notes

Objective/variable scoping is configured after construction via set_calculation_structure() (the source of truth), or the convenience wrappers set_objective_names() and set_variable_names(). The structure maps each objective name to the variables to compute for it, or None for all; an empty list computes none. It round-trips through to_config() under the calculation_structure key.

Extends: ionworkspipeline.controllers.ConfigMixin

__call__(**kwargs)

Call self as a function.

property calculation_structure: dict[str, list[str] | None] | None

The configured calculation structure, or None to compute everything.

Maps each objective name to the explicit list of variable names to compute for it. A value of None for an objective computes all of that objective’s variables; an empty list computes none of them. A value of None for the whole structure computes every objective and every variable present in the outputs.

check_output_shapes(outputs: dict) None

Validate the model/data shapes this cost will score. No-op by default.

Element-wise costs override this to warn on length mismatches; it is called once at fit setup so the check stays out of the evaluation loop.

combine(accumulator: ScalarAccumulator | ResidualAccumulator, other: ScalarAccumulator | ResidualAccumulator | float | ndarray[Any, dtype[_ScalarType_co]]) ScalarAccumulator | ResidualAccumulator

Combine accumulator values.

Parameters

accumulator

The accumulator to add to.

other

Another accumulator, or a raw value to add with weight 1.0.

Returns

Accumulator

The updated accumulator (same object, mutated in place).

finalize_output(accumulator: ScalarAccumulator | ResidualAccumulator) float | ndarray[Any, dtype[_ScalarType_co]]

Finalize an accumulator to its output value.

get_objective_names(outputs: dict) list[str]

Get the names of objectives to evaluate over.

Returns the calculation structure’s keys when a structure is set, otherwise every objective name present in outputs.

get_variable_names(objective_name: str, outputs: dict, model: dict | None = None) list[str]

Get the variable names to compute for a single objective.

Resolves the calculation structure for objective_name: an explicit variable list is returned as-is (an empty list meaning “no variables”), while None — or an unset structure — returns every variable present in that objective’s model output.

Parameters

objective_namestr

Name of the objective whose variables to resolve.

outputsdict

Objective-name -> output container, as passed to __call__.

modeldict, optional

The already-unpacked model mapping for objective_name, passed by callers that have it to avoid re-unpacking outputs. Unpacked from outputs when omitted.

Returns

list[str]

The variable names to compute for objective_name.

property objective_names: list[str] | None

The configured objective names (structure keys), or None for all.

objective_weights(name: str, default: float = 1.0) float

Get the weight for an objective by name.

property residual_scale_factor: float

Scaling factor for regularizer residuals to match scalar semantics.

Regularizers contribute w * f(x)² in scalar mode. In residual mode they output sqrt(w) * f(x), which after scalarization becomes scalarize_factor * w * f(x)² where scalarize_factor is 1.0 for most costs but 0.5 for GaussianLogLikelihood. To preserve the scalar contribution, regularizer residuals are scaled by sqrt(residual_scale_factor) before accumulation, where residual_scale_factor = 1 / scalarize_factor.

scalarize(value: float | ndarray[Any, dtype[_ScalarType_co]], mode: Literal['scalar', 'residuals'] = 'scalar') float

Convert a cost value to a scalar.

For scalar mode, returns the value unchanged. For residual mode, computes the sum of squares.

set_calculation_structure(structure: dict[str, list[str] | None] | None) None

Set the exact objective/variable structure this cost computes over.

This is the single source of truth for both objective-level and variable-level scoping; set_objective_names() and set_variable_names() are thin wrappers over it.

Parameters

structuredict[str, list[str] | None] | None

Maps each objective name to the variable names to compute for it, referring to the outputs[objective] model structure. None for an objective computes all of its variables; an empty list computes none of them. Passing None for the whole structure restores the default of computing every objective and variable.

set_objective_names(objective_names: list[str]) None

Restrict this cost to the given objectives (all variables of each).

Convenience wrapper over set_calculation_structure() that maps every name to None (compute all of that objective’s variables).

set_variable_names(objective_name: str, variable_names: list[str] | None) None

Set which variables to compute for a single objective.

Updates (or creates) the calculation structure entry for objective_name. None computes all of that objective’s variables; an empty list computes none. Other objectives already in the structure are left unchanged.

Notes

Inside a DataFit, scoping a subset of objectives is safe: binding fills in the other fit objectives with all variables. Evaluated directly, the structure is the full scope — only the objectives it names are computed.

to_config() dict

Convert the cost function to parser configuration format.

variable_weights(name: str, default: float = 1.0) float

Get the weight for a variable by name.

class ionworkspipeline.data_fits.objective_functions.costs.ErrorFunction(normalization: Normalization | str | float | None = None, nan_values=None, objective_weights: dict[str, float] | None = None, variable_weights: dict[str, float] | None = None, *, scale: str | float | None = None)

Base class for error-based cost functions.

Parameters

normalizationNormalization | str | float, optional

How to normalize weights across variables with different magnitudes. Options: “mean” (default), “identity”, “range”, “sum_squares”, “mean_squares”, “root_mean_squares”, or a float constant. Legacy names “sse”, “mse”, “rmse” are mapped to new names.

nan_valuesstr | float, optional

How to handle NaN values in model output. Defaults to 1e6. Options: float value, “mean”, “min”, or “raise”.

objective_weightsdict[str, float], optional

Per-objective weights.

variable_weightsdict[str, float], optional

Per-variable weights.

scalestr | float, optional

Deprecated. Use normalization instead.

Extends: ionworkspipeline.data_fits.objective_functions.costs.costs.ObjectiveFunction

check_output_shapes(outputs: dict) None

Warn on mismatched-length model/data variables this cost scores.

Element-wise costs (SSE/MSE/RMSE/MAE/Max) combine model and data point-by-point, so differing shapes silently produce a meaningless result — a common footgun when a single cost is applied to an objective exposing both a model-axis variable and a shorter data-axis one. This mirrors the objective/variable iteration of __call__() but only inspects shapes; it is run once at fit setup (not in the evaluation hot path) because a mismatch is a one-time configuration problem. Distribution metrics (Wasserstein) set requires_equal_length = False and are skipped, since unequal-length sample sets are expected there.

Parameters

outputsdict

Mapping of objective name to its (model, data) output container, as built by DataFit.evaluate_inputs_and_outputs.

nan_values(model_value: ndarray[Any, dtype[_ScalarType_co]], data_value: ndarray[Any, dtype[_ScalarType_co]]) float

Return the scalar fill value implied by the configured NaN policy.

Kept for backward compatibility.

to_config() dict

Convert the cost function to parser configuration format.

Error Functions

class ionworkspipeline.data_fits.objective_functions.costs.Max(normalization: Normalization | str | float | None = None, nan_values=None, objective_weights: dict[str, float] | None = None, variable_weights: dict[str, float] | None = None, *, scale: str | float | None = None)

Maximum error cost function.

Returns the maximum absolute difference between model and data: Max = max|model - data|

Extends: ionworkspipeline.data_fits.objective_functions.costs.costs.ErrorFunction

class ionworkspipeline.data_fits.objective_functions.costs.SSE(normalization: Normalization | str | float | None = None, nan_values=None, objective_weights: dict[str, float] | None = None, variable_weights: dict[str, float] | None = None, *, scale: str | float | None = None)

Sum-of-squared-errors cost function.

Calculates the sum of squared differences between model and data: SSE = Σ(model - data)²

Extends: ionworkspipeline.data_fits.objective_functions.costs.costs.ErrorFunction

class ionworkspipeline.data_fits.objective_functions.costs.MSE(normalization: Normalization | str | float | None = None, nan_values=None, objective_weights: dict[str, float] | None = None, variable_weights: dict[str, float] | None = None, *, scale: str | float | None = None)

Mean-squared-error cost function.

Calculates the mean of squared differences: MSE = Σ(model - data)² / n

Extends: ionworkspipeline.data_fits.objective_functions.costs.costs.ErrorFunction

class ionworkspipeline.data_fits.objective_functions.costs.RMSE(normalization: Normalization | str | float | None = None, nan_values=None, objective_weights: dict[str, float] | None = None, variable_weights: dict[str, float] | None = None, *, scale: str | float | None = None)

Root-mean-squared-error cost function.

Calculates the square root of MSE: RMSE = √(Σ(model - data)² / n)

This cost function only supports scalar output.

Extends: ionworkspipeline.data_fits.objective_functions.costs.costs.ErrorFunction

class ionworkspipeline.data_fits.objective_functions.costs.MAE(normalization: Normalization | str | float | None = None, nan_values=None, objective_weights: dict[str, float] | None = None, variable_weights: dict[str, float] | None = None, *, scale: str | float | None = None)

Mean-absolute-error cost function.

Calculates the mean of absolute differences: MAE = Σ|model - data| / n

Extends: ionworkspipeline.data_fits.objective_functions.costs.costs.ErrorFunction

class ionworkspipeline.data_fits.objective_functions.costs.ChiSquare(variable_standard_deviations: dict[str, float], nan_values=None)

Chi-square cost function with per-variable standard deviations.

Calculates chi² = Σ((model - data) / σ)² where σ is the standard deviation for each variable.

Parameters

variable_standard_deviationsdict[str, float]

Dictionary mapping variable names to their standard deviations.

nan_valuesstr | float, optional

How to handle NaN values.

Extends: ionworkspipeline.data_fits.objective_functions.costs.costs.ErrorFunction

to_config() dict

Convert the cost function to parser configuration format.

Multi-Cost Functions

class ionworkspipeline.data_fits.objective_functions.costs.MultiCost(costs: dict, normalization: Normalization | str | float | None = None, nan_values=None, objective_weights: dict[str, float] | None = None, variable_weights: dict[str, float] | None = None, *, scale: str | float | None = None)

Cost function combining multiple costs with weights.

Parameters

costsdict[ObjectiveFunction, float]

Dictionary mapping cost functions to their weights.

normalization, nan_values, objective_weights, variable_weights

Passed to ErrorFunction base class.

scalestr | float, optional

Deprecated. Use normalization instead.

Extends: ionworkspipeline.data_fits.objective_functions.costs.costs.ErrorFunction

check_output_shapes(outputs: dict) None

Delegate to each sub-cost (each has its own metric and scoping).

scalarize(value: float | ndarray[Any, dtype[_ScalarType_co]], mode: Literal['scalar', 'residuals'] = 'scalar') float

Convert the finalized cost value to a scalar.

Uses the passed-in value directly, which includes any regularization terms added after MultiCost.__call__ returns. This ensures Evaluation.value_scalarized reflects the true total cost.

property supports_residuals: bool

bool(x) -> bool

Returns True when the argument x is true, False otherwise. The builtins True and False are the only two instances of the class bool. The class bool is a subclass of the class int, and cannot be subclassed.

property supports_scalar: bool

bool(x) -> bool

Returns True when the argument x is true, False otherwise. The builtins True and False are the only two instances of the class bool. The class bool is a subclass of the class int, and cannot be subclassed.

Design Functions

class ionworkspipeline.data_fits.objective_functions.costs.DesignFunction(objective_weights: dict[str, float] | None = None)

Cost function for design optimization problems.

Used for optimization objectives where the goal is to maximize or minimize design metrics (energy density, power density, etc.) rather than fit to data.

Parameters

objective_weightsdict[str, float], optional

Per-objective weights.

Extends: ionworkspipeline.data_fits.objective_functions.costs.costs.ObjectiveFunction

parse_variable_value(value: float | list | tuple | ndarray[Any, dtype[_ScalarType_co]], variable_name: str) float

Parse a variable value from model output.