PyBNF objective functions (pybnf.objective)

Classes defining various objective functions used for evaluating points in parameter space

class pybnf.objective.AveNormSumOfSquaresObjective(ind_var_rounding=0)[source]

Sum of squares where each point is normalized by the average value of that variable, ((y-y’)/ybar)^2

eval_point(sim_data, exp_data, sim_row, exp_row, col_name)[source]

Calculate the objective function for a single point in the data This evaluation is what differentiates the different objective functions. :param sim_data: The simulation Data object :param exp_data: The experimental Data object :param sim_row: The row number to look at in sim_data :param exp_row: The row number to look at in exp_data :param col_name: The column name to look at (same for the sim_data and the exp_data) :return:

evaluate(sim_data, exp_data, show_warnings=True)[source]
Parameters:
  • sim_data (Data) – A Data object containing simulated data

  • exp_data (Data) – A Data object containing experimental data

  • show_warnings (bool) – If True, print warnings about unused data

Returns:

float, value of the objective function, with a lower value indicating a better fit.

class pybnf.objective.ChiSquareObjective(ind_var_rounding=0, overrides=None, noise=None, sigma_source=None, sigma_sources=None)[source]

Gaussian observation noise with sigma read per point from the data’s _SD column. Being fixed, the Gaussian normalizer is parameter-independent and dropped, leaving the chi-square data fit (ADR-0011/0021).

noise = <pybnf.noise.gaussian.Gaussian object>

The default per-observable noise model (applied to every column without an override): a NoiseModel plus its source(s). Subclasses set noise / sigma_source (a single source) as class attributes; neg_bin sets sigma_source per instance (its constant is a config value). A multi-parameter default (a whole-fit student_t line) is passed as sigma_sources (the mapping) to the constructor; _default_sources() reconciles the two (ADR-0058).

class pybnf.objective.ChiSquareObjective_Dynamic(ind_var_rounding=0, overrides=None, noise=None, sigma_source=None, sigma_sources=None)[source]

Gaussian observation noise with sigma a free parameter (sigma__FREE). Being estimated, the Gaussian normalizer +log sigma is retained (ADR-0011).

noise = <pybnf.noise.gaussian.Gaussian object>

The default per-observable noise model (applied to every column without an override): a NoiseModel plus its source(s). Subclasses set noise / sigma_source (a single source) as class attributes; neg_bin sets sigma_source per instance (its constant is a config value). A multi-parameter default (a whole-fit student_t line) is passed as sigma_sources (the mapping) to the constructor; _default_sources() reconciles the two (ADR-0058).

class pybnf.objective.ColumnSummationObjective(ind_var_rounding=0)[source]

Represents a type of objective function in which we perform some kind of summation for one column at a time. The assumption is that the independent variable is the same for each row.

eval_column(sim_data, exp_data, col_name)[source]

Calculate the objective function for a single column in the data This evaluation is what differentiates the different column based objective functions. :param sim_data: The simulation Data object :param exp_data: The experimental Data object :param col_name: The column name to look at (same for the sim_data and the exp_data) :return:

evaluate(sim_data, exp_data, show_warnings=True)[source]
Parameters:
  • sim_data (Data) – A Data object containing simulated data

  • exp_data (Data) – A Data object containing experimental data

  • show_warnings (bool) – If True, print warnings about unused data

Returns:

float, value of the objective function, with a lower value indicating a better fit.

classmethod from_config(config)[source]

Build this objective from the config dict (ADR-0011). The base takes no constructor args (e.g. direct_pass); subclasses that read config keys override – the uniform construction entry point replacing the registry’s per-objfunc config_args recipe.

class pybnf.objective.ConstraintCounter[source]

An objective function that just counts the numbered of failed constraints Used only in model checking

evaluate(sim_data, exp_data, show_warnings=True)[source]
Parameters:
  • sim_data (Data) – A Data object containing simulated data

  • exp_data (Data) – A Data object containing experimental data

  • show_warnings (bool) – If True, print warnings about unused data

Returns:

float, value of the objective function, with a lower value indicating a better fit.

evaluate_multiple(sim_data_dict, exp_data_dict, constraints=(), show_warnings=True)[source]

Count the number constraints that are not satisfied by the simulation data. Experimental (quantitative) data is ignored

class pybnf.objective.DirectPassObjective[source]

Passes through the score value directly from the simulated data.

Expects the simulated data to contain a single column ‘score’ with a single row. The experimental data is ignored: the analytical / bring-your-own objective IS the score, so there is nothing to compare against (ADR-0031/0059).

evaluate(sim_data, exp_data, show_warnings=True)[source]
Parameters:
  • sim_data (Data) – A Data object containing simulated data

  • exp_data (Data) – A Data object containing experimental data

  • show_warnings (bool) – If True, print warnings about unused data

Returns:

float, value of the objective function, with a lower value indicating a better fit.

evaluate_multiple(sim_data_dict, exp_data_dict, pset, constraints=(), show_warnings=True)[source]

Score straight off the model’s ‘score’ column, with no experimental-data pairing (ADR-0031/0059).

The base ObjectiveFunction.evaluate_multiple() only scores a model-output suffix that has a matching experimental-data suffix – the right rule for a per-point objective, but for direct_pass there is no exp column to compare to, so that rule forced an empty placeholder .exp file to exist purely to make the suffix match (the #425 discoverability footgun). This override drops the exp requirement: it sums the score of every output suffix the model emits (each read by evaluate(), which still requires a score column), so a closed-form / analytical target scores with no data file at all. Constraint penalties still apply, unchanged.

class pybnf.objective.InformationCriteria(k, n, log_likelihood, aic, bic, aicc)

AIC/BIC/AICc for a fit, alongside the inputs (k free params, n data points, log_likelihood) so a report can show the derivation. aicc is None when the small-sample correction is undefined (n <= k + 1).

aic

Alias for field number 3

aicc

Alias for field number 5

bic

Alias for field number 4

k

Alias for field number 0

log_likelihood

Alias for field number 2

n

Alias for field number 1

class pybnf.objective.KLLikelihood(ind_var_rounding=0)[source]

The Kullback-Leibler likelihood. It should be more efficient in parameter fitting as numerical experiments suggest

eval_column(sim_data, exp_data, col_name)[source]

Calculate the objective function for a single column in the data This evaluation is what differentiates the different column based objective functions. :param sim_data: The simulation Data object :param exp_data: The experimental Data object :param col_name: The column name to look at (same for the sim_data and the exp_data) :return:

class pybnf.objective.LaplaceObjective(ind_var_rounding=0, overrides=None, noise=None, sigma_source=None, sigma_sources=None)[source]

Laplace observation noise with the scale b a free parameter (b__FREE) – the heavy-tailed, outlier-robust likelihood behind least-absolute-deviation fitting (ADR-0021). Being estimated, the log(2 b) normalizer is retained, which is what keeps the fit from driving b -> inf. PEtab v2’s noiseDistribution = laplace; a fixed-scale Laplace is reachable per observable via read_exp_file / fix_at.

noise = <pybnf.noise.laplace.Laplace object>

The default per-observable noise model (applied to every column without an override): a NoiseModel plus its source(s). Subclasses set noise / sigma_source (a single source) as class attributes; neg_bin sets sigma_source per instance (its constant is a config value). A multi-parameter default (a whole-fit student_t line) is passed as sigma_sources (the mapping) to the constructor; _default_sources() reconciles the two (ADR-0058).

class pybnf.objective.LikelihoodObjective(ind_var_rounding=0, overrides=None, noise=None, sigma_source=None, sigma_sources=None)[source]

A per-point likelihood: a distribution-family NoiseModel scored against the data with its noise parameter drawn from a SigmaSource, summed over points (ADR-0011, ADR-0021). The (family, sigma_source) pair is selected per observable – the class-level default applies to every column, overridden for named observables by self.overrides. The five legacy likelihood objfuncs are exactly this object with a fixed default pair (chi_sq = Gaussian x the _SD data column, chi_sq_dynamic = Gaussian x a free sigma, neg_bin = NegBinomial x a constant, …); per-observable selection is the new capability they all inherit.

The whole family/normalizer choice collapses to one per-point expression: the family’s data_fit always, plus each noise parameter’s param_normalizers entry iff that parameter’s source is estimated. That single rule reproduces every legacy objfunc – the data-fit-vs-nll split that used to be hard-coded per subclass now follows from whether each noise parameter is estimated (ADR-0011), and a two-parameter family (student_t’s sigma + df, ADR-0058) gates each independently.

data_fit_grad_point(sim_data, exp_data, sim_row, exp_row, col_name)[source]

d(data_fit)/d(prediction) for one scored point – the scalar-gradient seam an asymmetric family with no clean least-squares residual routes through (layer G, #454/#385): Laplace (its L1 data fit |z|/b is a cusp, sqrt(2 data_fit) ~ sqrt|z| has infinite slope at z=0, so it is inherently not least-squares, #459) and the count family (NegBinomial). A Gaussian or Student-t observable – whose data fit does reformulate as a smooth half-square – is routed through residual_point instead (has_least_squares_residual() decides).

The assembly accumulates sum_i w_i * data_fit_grad_point_i * d(prediction_i)/d theta directly into the scalar gradient and flags the result not least_squares_exact – the universal form a quasi-Newton (L-BFGS) step consumes. Reads the prediction through the same _prediction seam and the noise through the same _noise_values mapping eval_point uses, so it differentiates exactly the data fit PyBNF scores; the per-family slope is d_data_fit_d_prediction(). The per-point bootstrap weight is applied by the assembly, not here – mirroring residual_point.

eval_point(sim_data, exp_data, sim_row, exp_row, col_name)[source]

Calculate the objective function for a single point in the data This evaluation is what differentiates the different objective functions. :param sim_data: The simulation Data object :param exp_data: The experimental Data object :param sim_row: The row number to look at in sim_data :param exp_row: The row number to look at in exp_data :param col_name: The column name to look at (same for the sim_data and the exp_data) :return:

evaluate_pointwise(sim_data_dict, exp_data_dict, pset)[source]

The per-observation log-likelihoods this fit’s noise model assigns the data under pset – the pointwise decomposition LOO/WAIC consume (ADR-0056).

Returns (ids, values): ids a list of stable per-point labels (model/suffix/observable@indvar=value), values the matching np.ndarray of genuine, unweighted log-densities. Each value is the family’s complete normalized log_density (the constant Gaussian/Jacobian terms eval_point drops restored), NOT -eval_point: a predictive density needs the full normalization, and PyBNF’s per-point weights are a fitting device, not part of the generative model. So these do not sum to -score; they are the honest densities az.loo / az.waic need.

Mirrors evaluate_multiple’s per-evaluation setup – the {name: value} map a FreeParameterSigma reads, and the measurement-model observation layer – so the densities are scored against exactly the data evaluate saw. The emitted observation set is fixed by the experimental data (a point is skipped only on a NaN observation, never on anything draw-dependent), so every draw yields the same ids in the same order – the rectangular chain x draw x obs array the bridge needs.

classmethod from_config(config)[source]

Build this objective from the config dict (ADR-0011). The base takes no constructor args (e.g. direct_pass); subclasses that read config keys override – the uniform construction entry point replacing the registry’s per-objfunc config_args recipe.

has_least_squares_residual(col_name)[source]

Whether this observable contributes an exact least-squares residual/Jacobian (layer G, #454/#385; #459). True for a family whose data fit reformulates as a smooth half-square – the Gaussian (data_fit = 1/2 rho**2) and, #459, the Student-t (the exact square-root-loss residual sign(z) sqrt(2 data_fit), smooth through z=0) – on any scale and either location, so the assembly routes it through residual_point and a fixed-scale fit is least_squares_exact (#386’s LM/TRF consumes the residual form). False for an asymmetric family with no clean residual – Laplace (its L1 data fit |z|/b gives the cusp sqrt|z|, infinite slope at z=0) and the count family – whose gradient goes through the scalar data_fit_grad_point path, so the result is not least_squares_exact.

noise = None

The default per-observable noise model (applied to every column without an override): a NoiseModel plus its source(s). Subclasses set noise / sigma_source (a single source) as class attributes; neg_bin sets sigma_source per instance (its constant is a config value). A multi-parameter default (a whole-fit student_t line) is passed as sigma_sources (the mapping) to the constructor; _default_sources() reconciles the two (ADR-0058).

noise_grad_point(sim_data, exp_data, sim_row, exp_row, col_name)[source]

The per-point gradient of the loss w.r.t. each estimated free noise parameter at one scored point – {free_param_name: d loss/d param} (layer D/G, #451/#454/#385).

Empty for a fixed-noise point (chi_sq’s data column, a constant, a relative scale): no noise parameter is estimated, so the loss carries no normalizer and the noise scale adds no gradient column. Otherwise each estimated noise parameter contributes d(data_fit + its own normalizer)/d param, the column that keeps a free scale from running away. The per-parameter derivatives are the family’s own (d_nll_d_noise_params()):

  • Gaussian’s single sigma: (1 - rho**2)/sigma (the +log sigma normalizer, layer D) – rho the additive-space residual, so it composes with a log scale (#452); on the linear scale it is the historical closed form byte-for-byte.

  • Laplace’s scale b: -|residual|/b**2 + 1/b (the log(2 b) normalizer).

  • Student-t’s sigma and df – the first multi-parameter estimated-noise gradient (ADR-0058); each independently sourced and gated.

Read through the same _prediction / _noise_values seams eval_point and residual_point use, so the noise gradient differentiates exactly the loss PyBNF reports. Each free parameter is the noise parameter (factor 1), so the column maps straight to the source’s free-parameter name.

Lives on the scalar-gradient (L-BFGS) path only: a normalizer like +log sigma is not a sum of squares, so the trust-region residual form cannot represent it. The assembly adds this straight to the scalar gradient (and flags the residual form’s least-squares model inexact); the per-point bootstrap weight is applied there, not here – mirroring residual_point.

overrides

{col_name: (NoiseModel, {param: SigmaSource})} overriding the default per observable; empty -> every column uses the default, byte-identical to the pre-#410 single global objfunc.

required_free_noise_params()[source]

The free-parameter names this objective’s noise sources estimate (default spec + every override) – what _load_variables checks have matching FreeParameters (ADR-0021). Iterates each spec’s per-parameter source mapping (one source for the single-parameter families, two for student_t; ADR-0058).

residual_point(sim_data, exp_data, sim_row, exp_row, col_name)[source]

The least-squares residual r and its derivative d r/d pred for one scored point (#449/#385/#452/#459).

The residual a family whose data fit reformulates as a smooth half-square carries – the Gaussian (data_fit = 1/2 rho**2, so r is the standardized residual rho) and, layer-G follow-up #459, the Student-t (the exact square-root-loss residual r = sign(z) sqrt(2 data_fit), smooth through z=0). The assembly routes such a column here, an asymmetric family with no clean residual (Laplace, whose L1 data fit is a cusp; the count family) through data_fit_grad_point() instead (has_least_squares_residual() decides). The pure family math lives on the noise model (residual() / d_residual_d_prediction()); this seam sources the prediction and the noise parameters and delegates, so r is defined for the prediction as the MEDIAN or the MEAN (layer G, #454), additive on any scale (LINEAR, or a log scale: LOG10 / LN, #452). The residual lives in the additive (log) space, mu = forward(pred) - location offset, so its derivative picks up the scale’s chain factor forward'(pred) (1 on the linear scale, 1/(pred*ln10) for log10). The location offset is prediction-independent, so a MEDIAN (any scale) / a MEAN on the linear scale collapses to the historical Gaussian (pred-obs)/sigma / 1/sigma byte-for-byte; a MEAN on a log scale subtracts the family’s moment correction. Either way the family’s residual satisfies 1/2 r**2 == data_fit, so this returns the same data-fit loss eval_point does in residual form, and r * d_residual_d_prediction == d_data_fit_d_prediction, so the residual-Jacobian reproduces the objective gradient.

sigma (and Student-t’s df) may be fixed (chi_sq / lognormal / student_t) or an estimated free parameter (chi_sq_dynamic); the residual is identical either way – an estimated scale’s own gradient column (its retained +log sigma / df-block normalizer, which is not a square) is emitted separately by noise_grad_point() (layer D/G, #451/#454). Any other per-observable configuration raises GradientNotSupported (the capability gate); later layers extend it.

Out-of-support points (log scale): match ``evaluate``. On a log scale forward = log10 requires pred > 0 and obs > 0. PyBNF does not raise on a non-positive point here; it propagates a non-finite r (so the assembled gradient goes non-finite), exactly as evaluate returns a non-finite score for the same point rather than raising – the optimizer’s existing signal to reject the step. Raising would diverge the gradient from the scalar objective it differentiates (a point the objective merely scores inf/nan would instead abort assembly); propagating keeps the two paths consistent.

Reads the prediction through the same _prediction seam and the noise through the same _noise_values mapping eval_point uses, so the residual is the exact derivative of the loss PyBNF reports – same noise-weighting, same column selection. The per-point bootstrap weight is not applied here (the assembly folds sqrt(weight) into both r and the Jacobian, exactly as evaluate multiplies eval_point by the weight).

set_default_location(location)[source]

Apply a whole-fit default location interpretation (the global noise_location key, ADR-0024; the modern-edition median default, ADR-0031) to the class-default noise model – the one used for every observable without a per-observable noise_model override (those already carry their own location). Mirrors the per-observable location field via _apply_location; every family supports both mean and median (the neg_bin median is the per-point CDF inversion of issue #419).

supports_pointwise_log_likelihood = True

A per-point likelihood can be left-one-out, so it supports LOO/WAIC (ADR-0056).

class pybnf.objective.LogNormalObjective(ind_var_rounding=0, overrides=None, noise=None, sigma_source=None, sigma_sources=None)[source]

Lognormal observation noise: the Gaussian family additive on the log10 scale with the prediction interpreted as the median (ADR-0011, ADR-0022). sigma (the log10-scale standard deviation) comes from the data’s _SD column exactly as in chi_sq – being fixed, the Gaussian normalizer and the lognormal Jacobian are parameter-independent and dropped, leaving the log10-space squared residual (log10 sim - log10 exp)^2 / (2 sigma^2). log10 (not natural log) so sigma is a log10-scale standard deviation consistently with every other PyBNF log (ADR-0022); the natural-log lognormal density is Gaussian(LN, MEDIAN). Only the noise family differs from chi_sq – the seam proof that the scale and location axes compose. Observations and predictions must be positive (the lognormal support).

noise = <pybnf.noise.gaussian.Gaussian object>

The default per-observable noise model (applied to every column without an override): a NoiseModel plus its source(s). Subclasses set noise / sigma_source (a single source) as class attributes; neg_bin sets sigma_source per instance (its constant is a config value). A multi-parameter default (a whole-fit student_t line) is passed as sigma_sources (the mapping) to the constructor; _default_sources() reconciles the two (ADR-0058).

class pybnf.objective.NegBinLikelihood(r, ind_var_rounding=0, overrides=None)[source]

Negative-binomial likelihood with the dispersion r a fixed config constant (neg_bin_r). Fixed and self-normalizing, so the objective is the NegBinomial data fit (ADR-0011).

classmethod from_config(config)[source]

Build this objective from the config dict (ADR-0011). The base takes no constructor args (e.g. direct_pass); subclasses that read config keys override – the uniform construction entry point replacing the registry’s per-objfunc config_args recipe.

noise = <pybnf.noise.negative_binomial.NegBinomial object>

The default per-observable noise model (applied to every column without an override): a NoiseModel plus its source(s). Subclasses set noise / sigma_source (a single source) as class attributes; neg_bin sets sigma_source per instance (its constant is a config value). A multi-parameter default (a whole-fit student_t line) is passed as sigma_sources (the mapping) to the constructor; _default_sources() reconciles the two (ADR-0058).

class pybnf.objective.NegBinLikelihood_Dynamic(ind_var_rounding=0, overrides=None, noise=None, sigma_source=None, sigma_sources=None)[source]

Negative-binomial likelihood with the dispersion r a free parameter (r__FREE). NegBinomial’s PMF is self-normalizing, so nll == data_fit; the source is estimated but its normalizer is 0 (ADR-0011).

noise = <pybnf.noise.negative_binomial.NegBinomial object>

The default per-observable noise model (applied to every column without an override): a NoiseModel plus its source(s). Subclasses set noise / sigma_source (a single source) as class attributes; neg_bin sets sigma_source per instance (its constant is a config value). A multi-parameter default (a whole-fit student_t line) is passed as sigma_sources (the mapping) to the constructor; _default_sources() reconciles the two (ADR-0058).

class pybnf.objective.NormSumOfSquaresObjective(ind_var_rounding=0)[source]

Sum of squares where each point is normalized by the y value at that point, ((y-y’)/y)^2

eval_point(sim_data, exp_data, sim_row, exp_row, col_name)[source]

Calculate the objective function for a single point in the data This evaluation is what differentiates the different objective functions. :param sim_data: The simulation Data object :param exp_data: The experimental Data object :param sim_row: The row number to look at in sim_data :param exp_row: The row number to look at in exp_data :param col_name: The column name to look at (same for the sim_data and the exp_data) :return:

class pybnf.objective.ObjectiveCalculator(objective, exp_data_dict, constraints)[source]

Wrapper for all of the objects needed for the workers to calculate the objective function value. Contains the objective function, exp_data_dict, and constraint tuple

evaluate_objective(sim_data_dict, pset, show_warnings=True)[source]

Evaluate the objective using the input simulation data and the info contained in this object :param sim_data_dict: Dictionary of the form {modelname: {suffix1: Data1}} containing the simulated data objects :param show_warnings: If True, print warnings about unused data :type show_warnings: bool :return:

class pybnf.objective.ObjectiveFunction[source]

Abstract class representing an objective function Subclasses customize how the objective value is calculated from the quantitative exp data The base class includes all the support we need for constraints.

data_fit_grad_point(sim_data, exp_data, sim_row, exp_row, col_name)[source]

d(data_fit)/d(prediction) for one scored point – the scalar-gradient seam for an asymmetric family whose data fit is not a sum of squares (layer G, #454/#385). The base raises GradientNotSupported (it is reached only when has_least_squares_residual() is False, which the base never reports). Only LikelihoodObjective overrides it.

evaluate(sim_data, exp_data, show_warnings=True)[source]
Parameters:
  • sim_data (Data) – A Data object containing simulated data

  • exp_data (Data) – A Data object containing experimental data

  • show_warnings (bool) – If True, print warnings about unused data

Returns:

float, value of the objective function, with a lower value indicating a better fit.

evaluate_multiple(sim_data_dict, exp_data_dict, pset, constraints=(), show_warnings=True)[source]

Compute the value of the objective function on several data sets, and return the total. Optionally may pass an iterable of ConstraintSets whose penalties will be added to the total :param sim_data_dict: Dictionary of the form {modelname: {suffix1: Data1}} containing the simulated data objects :type sim_data_dict: dict :param exp_data_dict: Dictionary of the form {modelname: {suffix1: Data1}} containing experimental Data objects :type exp_data_dict: dict :param constraints: Iterable of ConstraintSet objects containing the constraints that we should evaluate using the simulated data :type constraints: Iterable of ConstraintSet :param show_warnings: If True, print warnings about unused data :type show_warnings: bool :return:

evaluate_pointwise(sim_data_dict, exp_data_dict, pset)[source]

Per-observation log-likelihoods for one parameter set – the pointwise decomposition LOO/WAIC consume, as opposed to evaluate_multiple’s scalar total (ADR-0056). Returns (ids, values)ids a list of stable per-point labels, values the matching np.ndarray of genuine, unweighted log-densities – or None for an objective that is not a per-point likelihood. The base is that no-op; LikelihoodObjective overrides it (and flips supports_pointwise_log_likelihood).

classmethod from_config(config)[source]

Build this objective from the config dict (ADR-0011). The base takes no constructor args (e.g. direct_pass); subclasses that read config keys override – the uniform construction entry point replacing the registry’s per-objfunc config_args recipe.

has_least_squares_residual(col_name)[source]

Whether one scored column contributes an exact least-squares residual/Jacobian (a Gaussian, whose data_fit is 1/2 rho**2) vs only the scalar data-fit gradient an asymmetric family carries (Laplace / Student-t, layer G of #385). The assembly routes a True column through residual_point() (the residual-Jacobian form) and a False one through data_fit_grad_point() (the scalar accumulator).

True on the base, where residual_point() itself refuses an unsupported objective – so a non-likelihood / unsupported objective still raises GradientNotSupported there rather than being silently routed elsewhere. Only LikelihoodObjective overrides this to distinguish its families.

measurement = None

The measurement-model observation layer (ADR-0036): a MeasurementLayer that materializes each expression observableFormula’s column into the simulated data (using the PSet) before the by-name objective match below. None (the default for every job without an expression measurement model) is an exact no-op, so the objective is byte-identical to its pre-#407 behavior. New-era PEtab/SBML (and the retrofitted new-era BNGL-expression) path attaches a populated layer in config.py.

noise_grad_point(sim_data, exp_data, sim_row, exp_row, col_name)[source]

The per-point gradient of the loss w.r.t. each estimated free noise parameter – {free_param: d loss/d param} (layer D, #451).

Empty on the base: a non-likelihood objective (least-squares, distance, pass-through) estimates no noise parameter, so its scale contributes no gradient column. Only LikelihoodObjective overrides it, and only for the cut-1 Gaussian case with a free-parameter scale – the noise twin of the per-point residual_point seam (whose base refuses, since the assembly reaches that first and gates the whole configuration there).

required_free_noise_params()[source]

The free-parameter names this objective requires the fit to declare for its estimated noise sources – empty unless it is a likelihood with a free-parameter noise source (ADR-0021). _load_variables checks these against the declared free parameters, generalizing the old per-objfunc sigma__FREE / r__FREE hard-coded checks.

residual_point(sim_data, exp_data, sim_row, exp_row, col_name)[source]

The standardized residual rho and its derivative d rho/d prediction for one scored point – the per-point seam the gradient path differentiates (#449/#385).

rho and d rho/d pred are defined so that this point’s contribution to the loss is 1/2 rho**2 and d(loss)/d pred = rho * d rho/d pred – the residual form scipy.least_squares minimizes, agreeing with the scalar gradient by construction. The assembly multiplies d rho/d pred by the forward sensitivity d pred/d theta (routed through #448’s chain-rule factor) to build the residual-Jacobian column.

The base raises GradientNotSupported: only a per-point likelihood (LikelihoodObjective) defines a residual, and only for the cut-1 Gaussian/MEDIAN configuration (the noise scale – linear or log – and a fixed-or-single-free sigma are admitted; #452/#451). Every other objective (least-squares, distance, pass-through) and every later layer raises until its support lands – so #386 can fall back to a gradient-free step.

supports_pointwise_log_likelihood = False

Whether this objective can decompose its value into genuine per-observation log-likelihoods (ADR-0056) – the precondition for LOO/WAIC. True only for a per-point likelihood (LikelihoodObjective); a least-squares / distance / pass-through objective has no normalized density to leave one out of, so it stays False and evaluate_pointwise returns None (the LOO/WAIC no-op gate).

class pybnf.objective.SumOfDiffsObjective(ind_var_rounding=0)[source]
eval_point(sim_data, exp_data, sim_row, exp_row, col_name)[source]

Calculate the objective function for a single point in the data This evaluation is what differentiates the different objective functions. :param sim_data: The simulation Data object :param exp_data: The experimental Data object :param sim_row: The row number to look at in sim_data :param exp_row: The row number to look at in exp_data :param col_name: The column name to look at (same for the sim_data and the exp_data) :return:

class pybnf.objective.SumOfSquaresObjective(ind_var_rounding=0)[source]
eval_point(sim_data, exp_data, sim_row, exp_row, col_name)[source]

Calculate the objective function for a single point in the data This evaluation is what differentiates the different objective functions. :param sim_data: The simulation Data object :param exp_data: The experimental Data object :param sim_row: The row number to look at in sim_data :param exp_row: The row number to look at in exp_data :param col_name: The column name to look at (same for the sim_data and the exp_data) :return:

class pybnf.objective.SummationObjective(ind_var_rounding=0)[source]

Represents a type of objective function in which we perform some kind of summation over all available experimental data points individually.

eval_point(sim_data, exp_data, sim_row, exp_row, col_name)[source]

Calculate the objective function for a single point in the data This evaluation is what differentiates the different objective functions. :param sim_data: The simulation Data object :param exp_data: The experimental Data object :param sim_row: The row number to look at in sim_data :param exp_row: The row number to look at in exp_data :param col_name: The column name to look at (same for the sim_data and the exp_data) :return:

evaluate(sim_data, exp_data, show_warnings=True)[source]
Parameters:
  • sim_data (Data) – A Data object containing simulated data

  • exp_data (Data) – A Data object containing experimental data

  • show_warnings (bool) – If True, print warnings about unused data

Returns:

float, value of the objective function, with a lower value indicating a better fit.

classmethod from_config(config)[source]

Build this objective from the config dict (ADR-0011). The base takes no constructor args (e.g. direct_pass); subclasses that read config keys override – the uniform construction entry point replacing the registry’s per-objfunc config_args recipe.

prediction_sensitivity(sim_data, sim_row, col_name, exp_data, exp_row, raw_sens, index)[source]

∂pred/∂θ (a native-space (n_param,) vector) for one matched point – the gradient seam mirroring _prediction() (#453/#385), branch for branch.

_prediction forms the scored value from the simulation through up to one trajectory transform; this returns that value’s parameter sensitivity, so the assembly differentiates exactly what it scores. raw_sens(column_name, row) is the sensitivity of a sim column as ``_prediction`` reads it – the #447 tensor with any Data-level normalization (ADR-0053) already folded in (so a normalized fit threads the normalizer’s own derivative, and the transforms below compose on top of it exactly as scoring applies normalize -> _prediction). index maps a free-parameter name to its column.

  • Plain (the default, byte-identical to the raw observable): raw_sens(col, row).

  • Cumulative -> incident (ADR-0051): the prediction is raw_i - raw_{i-1} (row 0 keeps its raw value), so ∂pred_i/∂θ = raw_sens(col, i) - raw_sens(col, i-1) – a difference of sensitivity rows (row 0 keeps the plain value).

  • Per-measurement scale/offset (ADR-0045): a general PEtab formula, so its sensitivity is the formula’s symbolic gradient chained through each referenced column’s raw_sens plus any estimated placeholder/parameter it names (prediction_sensitivity()).

A per-measurement model takes priority and the two are mutually exclusive, exactly as in _prediction(); both default off, so a plain job returns the raw observable’s sensitivity unchanged.

class pybnf.objective.WassersteinObjective(ind_var_rounding=0)[source]

The 1-Wasserstein (earth-mover) distance between the simulated and experimental profiles, summed over observables (ADR-0031). Like kl it is a column-joint objective – it compares the shape of a whole column at once, not point by point – but where kl is the multinomial cross-entropy (a likelihood), this is a geometric distance: the minimal total mass-displacement to morph one normalized profile into the other. The two span the profile_objective family’s ends (statistical vs geometric), which is why the family is an objective, not a model (ADR-0031).

Each column is normalized to a probability distribution over its row index, and the 1-Wasserstein distance on the (unit-spaced) index line is sum_i |CDF_sim_i - CDF_exp_i| – the integral of the absolute CDF gap, which is the closed form of the 1-D earth-mover distance. The configurable support and spacing (placing the profile on real coordinates rather than the index) are the deferred profile_objective value grammar (ADR-0031); the default here is unit index spacing. A non-positive or negative simulated column cannot be normalized, so it scores inf (the worst fit), mirroring kl’s degenerate-profile guard. Oracle: scipy.stats.wasserstein_distance over the index with the normalized columns as weights.

eval_column(sim_data, exp_data, col_name)[source]

Calculate the objective function for a single column in the data This evaluation is what differentiates the different column based objective functions. :param sim_data: The simulation Data object :param exp_data: The experimental Data object :param col_name: The column name to look at (same for the sim_data and the exp_data) :return:

pybnf.objective.build_named_objective(config, token)[source]

Build the objective for a modern objective = <token> key (ADR-0031): the bare score passthrough, or a legacy token desugared to the per-point engine. A profile-objective token (kl / wasserstein) is redirected to its own key rather than silently desugared, keeping one home per objective.

pybnf.objective.build_profile_objective(config, token)[source]

Build the objective for a modern profile_objective = <token> key – a column-joint (shape-comparison) objective (ADR-0031). A per-point token is redirected to objective / noise_model.

pybnf.objective.build_whole_fit_noise_objective(config)[source]

Build the objective for a whole-fit noise_model = <family>, ... line – the no-observable ('noise_model', None) key (ADR-0031). The named per-point noise model becomes the fit-wide default, with per-observable noise_model lines overriding it.

pybnf.objective.information_criteria(log_likelihood, k, n)[source]

AIC / BIC / AICc from a fit’s maximized log-likelihood (pure arithmetic).

Parameters:
  • log_likelihood – the maximized log-likelihood lnL at the best fit – the sum of the noise model’s complete per-point log_density, NOT the (constant-dropped) -score the optimizer minimizes.

  • k – number of free (fitted) parameters, INCLUDING any estimated noise parameter – a fitted sigma / b / r is itself a free parameter (ADR-0021), so counting the declared free parameters already includes it.

  • n – number of scored data points.

Returns:

an InformationCriteria. aicc is None when n <= k + 1 (the correction 2k(k+1)/(n-k-1) has a non-positive denominator there and is conventionally reported as undefined).

AIC = 2k - 2 lnL; BIC = k ln(n) - 2 lnL; AICc = AIC + 2k(k+1)/(n-k-1).

pybnf.objective.likelihood_information_criteria(objective, sim_data_dict, exp_data_dict, pset, k)[source]

Information criteria for objective scored at pset, or None.

Returns None – rather than a misleading number – when the objective is not a per-point likelihood (sos / sod / norm_sos / kl / wasserstein / direct_pass: no normalized density, so no AIC; the same gate LOO/WAIC use), when no point is scored, or when the log-likelihood is not finite. Otherwise the log-likelihood is the sum of the objective’s complete per-point log_density over the scored data (evaluate_pointwise, ADR-0056), n is that point count, and k the free-parameter count.