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, data_key=None)[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
data_key – the (model, suffix) data key, used to resolve per-series analytic scaling (ADR-0066); None disables scaling.
- 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
_SDcolumn. 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 setssigma_sourceper instance (its constant is a config value). A multi-parameter default (a whole-fit student_t line) is passed assigma_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 sigmais 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 setssigma_sourceper instance (its constant is a config value). A multi-parameter default (a whole-fit student_t line) is passed assigma_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:
- 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, data_key=None)[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
data_key – the (model, suffix) data key of this experiment, used to resolve per-series analytic scaling (ADR-0066); None disables scaling (the default).
- Returns:
float, value of the objective function, with a lower value indicating a better fit.
- 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, data_key=None)[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
data_key – the (model, suffix) data key of this experiment, used to resolve per-series analytic scaling (ADR-0066); None disables scaling (the default).
- 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 fordirect_passthere is no exp column to compare to, so that rule forced an empty placeholder.expfile 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 byevaluate(), which still requires ascorecolumn), 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, replicates, log_likelihood_standard_error, replicates_requested)¶
- 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
- log_likelihood_standard_error¶
Alias for field number 7
- n¶
Alias for field number 1
- replicates¶
Alias for field number 6
- replicates_requested¶
Alias for field number 8
- 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
ba free parameter (b__FREE) – the heavy-tailed, outlier-robust likelihood behind least-absolute-deviation fitting (ADR-0021). Being estimated, thelog(2 b)normalizer is retained, which is what keeps the fit from drivingb -> inf. PEtab v2’snoiseDistribution = laplace; a fixed-scale Laplace is reachable per observable viaread_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 setssigma_sourceper instance (its constant is a config value). A multi-parameter default (a whole-fit student_t line) is passed assigma_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 byself.overrides. The five legacy likelihood objfuncs are exactly this object with a fixed default pair (chi_sq = Gaussian x the_SDdata 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_fitalways, plus each noise parameter’sparam_normalizersentry iff that parameter’s source isestimated. 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.- aligned_prediction_data(sim_data_dict, exp_data_dict, pset)[source]¶
Aligned
(prediction, observation, variance)for the Kalman proposal (ADR-0067 Stage 3; overridesObjectiveFunction.aligned_prediction_data()).Walks the same scored points as
evaluate_pointwise()in the same deterministic order (_pointwise_suffix’s model -> suffix -> row ->sorted(compare_cols)walk, with the same two data-only skips – a NaN observation and one outside its family’s observation domain), soprediction(the model outputf(theta)),observation(the datad), andvariance(the Gaussiansigma**2, theRdiagonal) are index-aligned and stable across draws. Returns threenp.ndarrays, orNoneunless every scored point is an ordinary additive-error Gaussian observable (linear scale): the Kalman gain’sR = diag(variance)is the Gaussian measurement covariance, so a log-scale (lognormal) or non-Gaussian (Laplace / Student-t / count) family has noRto form and the proposal is unsupported for that objective.
- 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|/bis a cusp,sqrt(2 data_fit) ~ sqrt|z|has infinite slope atz=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 throughresidual_pointinstead (has_least_squares_residual()decides).The assembly accumulates
sum_i w_i * data_fit_grad_point_i * d(prediction_i)/d thetadirectly into the scalar gradient and flags the result notleast_squares_exact– the universal form a quasi-Newton (L-BFGS) step consumes. Reads the prediction through the same_predictionseam and the noise through the same_noise_valuesmappingeval_pointuses, so it differentiates exactly the data fit PyBNF scores; the per-family slope isd_data_fit_d_prediction(). The per-point bootstrap weight is applied by the assembly, not here – mirroringresidual_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):idsa list of stable per-point labels (model/suffix/observable@indvar=value),valuesthe matchingnp.ndarrayof genuine, unweighted log-densities. Each value is the family’s complete normalizedlog_density(the constant Gaussian/Jacobian termseval_pointdrops restored), NOT-eval_point: a predictive density needs the full normalization, and PyBNF’s per-pointweightsare a fitting device, not part of the generative model. So these do not sum to-score; they are the honest densitiesaz.loo/az.waicneed.Mirrors
evaluate_multiple’s per-evaluation setup – the{name: value}map aFreeParameterSigmareads, and the measurement-model observation layer – so the densities are scored against exactly the dataevaluatesaw. The emitted observation set is fixed by the experimental data – a point is skipped on exactly two conditions, a NaN observation (missing data) and an observation outside its noise family’s observation domain (a negative count underneg_bin, #523), both properties of the data alone and never of the draw – so every draw yields the same ids in the same order, the rectangularchain x draw x obsarray 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-objfuncconfig_argsrecipe.
- has_least_squares_residual(col_name)[source]¶
Whether this observable contributes an exact least-squares residual/Jacobian (layer G, #454/#385; #459).
Truefor 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 residualsign(z) sqrt(2 data_fit), smooth throughz=0) – on any scale and either location, so the assembly routes it throughresidual_pointand a fixed-scale fit isleast_squares_exact(#386’s LM/TRF consumes the residual form).Falsefor an asymmetric family with no clean residual – Laplace (its L1 data fit|z|/bgives the cuspsqrt|z|, infinite slope atz=0) and the count family – whose gradient goes through the scalardata_fit_grad_pointpath, so the result is notleast_squares_exact.
- is_linear_gaussian()[source]¶
True iff the default family and every per-observable override are a linear-scale Gaussian (ADR-0067 Stage 3; overrides
ObjectiveFunction.is_linear_gaussian()).The config-time twin of
aligned_prediction_data()’s per-point gate (isinstance(family, Gaussian) and family.additive_on.ln_base == 0.0), checked against the declared families rather than a walked point set soproposal = kalmancan reject a non-Gaussian objfunc before the run starts. Bothchi_sq(fixed_SDsigma) andchi_sq_dynamic(an estimated free sigma) pass – the family is Gaussian either way, and the KalmanR = diag(sigma**2)is formed per accept from the current state’s sourced sigma. A log-scale (lognormal) or non-Gaussian (laplace/student_t/neg_bin) default or override makes itFalse.
- linear_profiling_plan(free_names, model_names, exp_data_dict, profiled_noise=())[source]¶
What
linear_profiling = 1would solve for in this fit, and why it would refuse (ADR-0132, #671) – the config-time gate, answered from the declared observable formulas, noise specs and binding tables rather than a walked point set, so a fit is refused before it starts.Returns
(groups, refusals).groupsis a sorted list of(names, columns)pairs: the sorted free-parameter names solved jointly and the frozenset of observable ids whose formulas read them. Coefficients that share an observable are solved together, transitively, because one observable’s residual couples every coefficient it reads.refusalsis a list of one-line reasons; a caller enables profiling only when it is empty, since profiling some of a fit’s linear coefficients while searching others changes what the searched ones mean.A declared free parameter is a candidate when an observable formula reads it, named directly or through a row-varying placeholder whose binding table maps to it on some row. It is refused, by name, when any of these holds:
it is also a model entity, so it moves the simulation, which a linear solve would ignore;
a noise source reads it – a free sigma, a sigma formula, a prediction-dependent sigma’s coefficient, or a per-row noise token – so moving it moves sigma and it is not a free linear coefficient (ADR-0123 finding 2: the Fiedler / Raia double binding, tested on resolved names);
it enters some observable’s formula nonlinearly;
an observable reading it is not a Gaussian, whose sum of squares in its own residual space is what the closed form minimizes (ADR-0130 finding 4);
an observable reading it is a log-scale Gaussian and it is not the single scale that multiplies the whole formula: on a log scale only a homogeneous scale is affine in the residual (as its logarithm), the ADR-0066 geometric-mean form (ADR-0134); an offset there, or two scales whose product is one degree of freedom, has no closed form;
observables reading it live in different residual spaces (one linear, one log), so its group has no single space to solve in;
an observable reading it is affine in each of its coefficients separately but not in all of them jointly (
scale*(x + offset)), whose solve is over a different parametrization than the declared one;an observable reading it is scored as a cumulative count (an offset cancels in the per-interval difference), already carries an ADR-0066 analytic per-series scale, or has a prediction-dependent sigma (the solve’s weights would depend on its own answer);
with noise profiling also on, its group’s observables do not all share one profiled sigma: the weights then depend on scales that depend on the coefficients, which needs an alternating solve (ADR-0130 finding 5).
- location_fisher_point(sim_data, exp_data, sim_row, exp_row, col_name)[source]¶
The expected per-point Fisher information of the location
kappa– the Gauss-Newton curvature the EFIM trust-region Hessian weightsd(prediction)/d(theta)by (job_type = gntr, #481). Read through the same_prediction/_noise_valuesseams asresidual_point/data_fit_grad_point, so it is the curvature of exactly the loss PyBNF scores.A residual-bearing family (Gaussian, Student-t) has
kappa == (d rho/d pred)**2identically – the assembly’s residual-Jacobian already carries it – so this returns that square directly (no new family math). This is the correct location Fisher for a prediction-dependent σ too (ADR-0080): the location block(1/σ²)outer(s_i, s_i)uses the partial∂ρ/∂pred = 1/σholding σ fixed, exactly as here – the scale’s own θ-dependence rides the noise block (noise_fisher_point()), not this one. A non-residual family (Laplace, count) delegates to the family’slocation_fisher(). Any configuration the family refuses (a MEDIAN-centered count, …) raisesGradientNotSupported, so the fit falls back to the scalar-gradient (L-BFGS-B) path (a MEAN-on-log estimated scale, whose location↔scale coupling this block does not model, is refused bynoise_fisher_point()– reached in the same assembly point loop – before the Hessian is returned).
- 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 setssigma_sourceper instance (its constant is a config value). A multi-parameter default (a whole-fit student_t line) is passed assigma_sources(the mapping) to the constructor;_default_sources()reconciles the two (ADR-0058).
- noise_fisher_point(sim_data, exp_data, sim_row, exp_row, col_name, raw_sens, index)[source]¶
The per-point expected Fisher noise block of the EFIM Hessian (#481; ADR-0080) – the full
(len(index), len(index))matrixΣ_p I_scale_p · outer(g_i^p, g_i^p)over the estimated noise parametersp, orNonefor a fixed-noise point. The curvature twin ofnoise_grad_point()(which returns the noise gradient vector the same way): each estimated parameter’s expected FisherI_scale_p(noise_param_fisher()) weights the outer product of its scale sensitivityg_i^p = ∂p/∂θ(sigma_sensitivity()) – the same∂σ/∂θvectornoise_grad_point()chains∂L/∂pthrough.For a
FreeParameterSigma(a bare free scale)g_i^pis the unit vectore_p(the free parameter is the noise parameter, model-unbound), soI_scale_p · outer(e_p, e_p)placesI_scale_pon that parameter’s own coordinate – byte- identical to the historical diagonal noise block (#481). For aPredictionFormulaSigma(sigma = sigma_abs + sigma_rel*y, ADR-0075)g_i^palso carries entries on the model-parameter columns (its∂σ/∂predictionchains the same forward sensitivity the residual rides), soouter(g_i^p, g_i^p)produces the genuine location↔scale coupling off the diagonal – the block ADR-0079 deferred and ADR-0080 assembles. Both terms are PSD (I_scale >= 0), so the block is PSD by construction.Empty (
None) for a fixed-noise point (no estimated parameter, no normalizer, no scale column). A coupled corner the family refuses – a MEAN-on-log estimated scale (a nonzero location↔scale cross-Fisher the moment offset introduces), the count family’s free dispersion, the Student-t 2-parameter block – raisesGradientNotSupportedfromnoise_param_fisher(), so the fit falls back to the scalar-gradient (L-BFGS-B) path.raw_sens/indexare the assembly’s forward- sensitivity accessor and free-parameter column map, andexp_data/exp_rowlocate the scored experimental point (read only by a per-measurement composite σ, #505) – all threaded tosigma_sensitivityexactly asnoise_grad_point()threads them (unused by a bare free scale).
- noise_grad_point(sim_data, exp_data, sim_row, exp_row, col_name, raw_sens, index)[source]¶
The estimated noise scale’s contribution to
∂(loss)/∂θat one scored point – the full(len(index),)native-space vectorΣ_p (∂L/∂p)·(∂p/∂θ)over the estimated noise parametersp, orNonefor a fixed-noise point (layer D/G, #451/#454/#385; ADR-0079).Nonefor 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∂(data_fit + its own normalizer)/∂θ, the column that keeps a free scale from running away. The per-parameter loss derivative∂L/∂pis the family’s own (d_nll_d_noise_params()):Gaussian’s single sigma:
(1 - rho**2)/sigma(the+log sigmanormalizer, layer D) –rhothe 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(thelog(2 b)normalizer).Student-t’s
sigmaanddf– the first multi-parameter estimated-noise gradient (ADR-0058); each independently sourced and gated.
Each
∂p/∂θcomes from the source’ssigma_sensitivity(): aFreeParameterSigmais the unit vectore_p(the scale is the free parameter, factor 1, model-unbound), so its column reduces to the historical scalar derivative on that parameter’s coordinate – byte-identical to the pre-ADR-0079 dict form. APredictionFormulaSigma(sigma = sigma_abs + sigma_rel*y, ADR-0075) instead returns the σ formula’s chain rule:∂σ/∂coeffon each coefficient’s column plus∂σ/∂predictionchained through the sameraw_sensforward sensitivity the residual rides – so a prediction-dependent scale perturbs the model-parameter columns too (and the fit is notleast_squares_exact). A PSet-only composite scale (FormulaSigma/PerMeasurementFormulaSigma, #505) returns the coefficient-only chain rule (no prediction term), the per-measurement variant also binding a row-varying token fromexp_data/exp_row(a numeric token contributes nothing, a parameter id lands∂σ/∂tokenon that parameter’s column).Read through the same
_prediction/_noise_valuesseamseval_pointandresidual_pointuse, so the noise gradient differentiates exactly the loss PyBNF reports. Lives on the scalar-gradient (L-BFGS) path only: a normalizer like+log sigmais 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 – mirroringresidual_point.raw_sens/indexare the assembly’s forward-sensitivity accessor and free-parameter column map, andexp_data/exp_rowlocate the scored point on the experimental data – all threaded tosigma_sensitivity(a free-parameter scale reads none of them; a prediction σ readsraw_sens; a per-measurement composite σ readsexp_data/exp_row).
- noise_profiling_plan()[source]¶
What
noise_profiling = 1would profile out of this objective, and why it would refuse (ADR-0108, #562) – the config-time gate, answered from the declared noise specs rather than a walked point set, so a fit is refused before it starts.Returns
(names, refusals):namesthe sorted estimated free-parameter names whose scale has a closed-form profile MLE,refusalsa list of one-line reasons a declared estimated scale is not profilable. A caller enables profiling only whenrefusalsis empty andnamesis not – profiling some of a fit’s estimated scales while searching others would silently change what the remaining ones mean.An estimated scale is profilable when all four hold:
its source is a plain
FreeParameterSigma– σ is a free parameter. A composite estimated σ (aformula/prediction_formula/ per-measurement source) has no closed form: its coefficients enter nonlinearly and are not what the profile solves for;it is the family’s primary noise parameter (
noise_params[0]) – Student-t’sdfis a second estimated parameter the σ profile cannot hold optimal;the family supplies the closed form (
supports_profiled_scale(): Gaussian / Laplace off the log-scale MEAN corner);every observable sharing the name uses the same family. The group’s MLE is one expression over its points – the Gaussian’s residual RMS is not the Laplace’s mean absolute residual – so a name that is a Gaussian sigma here and a Laplace scale there has no single closed form.
A fixed source (a data column, a constant, a relative scale) is silently skipped: it is not searched, so there is nothing to profile and nothing to refuse.
- 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_variableschecks 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
rand its derivatived r/d predfor 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, soris the standardized residualrho) and, layer-G follow-up #459, the Student-t (the exact square-root-loss residualr = sign(z) sqrt(2 data_fit), smooth throughz=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) throughdata_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, soris 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 factorforward'(pred)(1on 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/sigmabyte-for-byte; a MEAN on a log scale subtracts the family’s moment correction. Either way the family’sresidualsatisfies1/2 r**2 == data_fit, so this returns the same data-fit losseval_pointdoes in residual form, andr * d_residual_d_prediction == d_data_fit_d_prediction, so the residual-Jacobian reproduces the objective gradient.sigma(and Student-t’sdf) 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 bynoise_grad_point()(layer D/G, #451/#454). Any other per-observable configuration raisesGradientNotSupported(the capability gate); later layers extend it.Out-of-support points (log scale): match ``evaluate``. On a log scale
forward = log10requirespred > 0andobs > 0. PyBNF does not raise on a non-positive point here; it propagates a non-finiter(so the assembled gradient goes non-finite), exactly asevaluatereturns 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 scoresinf/nanwould instead abort assembly); propagating keeps the two paths consistent.Reads the prediction through the same
_predictionseam and the noise through the same_noise_valuesmappingeval_pointuses, 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 foldssqrt(weight)into bothrand the Jacobian, exactly asevaluatemultiplieseval_pointby the weight).
- set_default_location(location)[source]¶
Apply a whole-fit default location interpretation (the global
noise_locationkey, ADR-0024; the modern-edition median default, ADR-0031) to the class-default noise model – the one used for every observable without a per-observablenoise_modeloverride (those already carry their own location). Mirrors the per-observablelocationfield 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
_SDcolumn 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 PyBNFlog(ADR-0022); the natural-log lognormal density isGaussian(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 setssigma_sourceper instance (its constant is a config value). A multi-parameter default (a whole-fit student_t line) is passed assigma_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
ra 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-objfuncconfig_argsrecipe.
- 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 setssigma_sourceper instance (its constant is a config value). A multi-parameter default (a whole-fit student_t line) is passed assigma_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
ra free parameter (r__FREE). NegBinomial’s PMF is self-normalizing, sonll == 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 setssigma_sourceper instance (its constant is a config value). A multi-parameter default (a whole-fit student_t line) is passed assigma_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.
- aligned_prediction_data(sim_data_dict, exp_data_dict, pset)[source]¶
The aligned
(prediction, observation, variance)vectors for one parameter set – the raw per-point model outputf(theta), the matching observed datad, and the Gaussian measurement variancesigma**2– orNonewhen the objective is not a per-point Gaussian likelihood (ADR-0067 Stage 3, DREAM(KZS)).This is the seam the Kalman-inspired proposal reads: it needs the model output vector (not the scalar score) to build the parameter/output cross-covariance, plus the observed data and the measurement covariance
R = diag(variance)for the Kalman gain. The base is a no-op (a least-squares / distance / pass-through objective has no residual/output vector, and a non-Gaussian likelihood has no varianceR);LikelihoodObjectiveoverrides it for the Gaussian family.
- 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 raisesGradientNotSupported(it is reached only whenhas_least_squares_residual()is False, which the base never reports). OnlyLikelihoodObjectiveoverrides it.
- evaluate(sim_data, exp_data, show_warnings=True, data_key=None)[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
data_key – the (model, suffix) data key of this experiment, used to resolve per-series analytic scaling (ADR-0066); None disables scaling (the default).
- 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)–idsa list of stable per-point labels,valuesthe matchingnp.ndarrayof genuine, unweighted log-densities – orNonefor an objective that is not a per-point likelihood. The base is that no-op;LikelihoodObjectiveoverrides it (and flipssupports_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-objfuncconfig_argsrecipe.
- has_least_squares_residual(col_name)[source]¶
Whether one scored column contributes an exact least-squares residual/Jacobian (a Gaussian, whose
data_fitis1/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 throughresidual_point()(the residual-Jacobian form) and a False one throughdata_fit_grad_point()(the scalar accumulator).Trueon the base, whereresidual_point()itself refuses an unsupported objective – so a non-likelihood / unsupported objective still raisesGradientNotSupportedthere rather than being silently routed elsewhere. OnlyLikelihoodObjectiveoverrides this to distinguish its families.
- is_linear_gaussian()[source]¶
Whether every observable this objective scores uses a linear-scale Gaussian noise family – the config-time precondition for the Kalman-inspired DREAM proposal (ADR-0067 Stage 3, DREAM(KZS)), which forms
R = diag(sigma**2)from a Gaussian measurement covariance and so has noRfor a least-squares / distance / pass-through objective or a non-Gaussian / log-scale likelihood. The base isFalse(only a linear-GaussianLikelihoodObjectiveoverrides it); it letsproposal = kalmanreject an unsupported objfunc before the run starts, rather than silently degenerating todebecausealigned_prediction_data()returnsNoneat every accept.
- location_fisher_point(sim_data, exp_data, sim_row, exp_row, col_name)[source]¶
The expected per-point Fisher information of the location
kappafor one scored point – the Gauss-Newton curvature the EFIM trust-region path (job_type = gntr, #481) weightsd(prediction)/d(theta)by (H = sum_i w_i * kappa_i * outer(s_i, s_i)). The twin ofresidual_point()on the curvature side; the base raisesGradientNotSupported, since only a per-point likelihood defines a location Fisher (a non-likelihood / unsupported objective already refuses atresidual_point). OnlyLikelihoodObjectiveoverrides it.
- measurement = None¶
The measurement-model observation layer (ADR-0036): a
MeasurementLayerthat materializes each expressionobservableFormula’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 inconfig.py.
- noise_fisher_point(sim_data, exp_data, sim_row, exp_row, col_name, raw_sens, index)[source]¶
The per-point expected Fisher noise block of the EFIM Hessian – the full
(len(index), len(index))matrixΣ_p I_scale_p · outer(∂p/∂θ, ∂p/∂θ)over the estimated noise parameters, orNonefor a fixed-noise point (#481; ADR-0080). The twin ofnoise_grad_point()on the curvature side.Noneon the base (a non-likelihood objective estimates no noise parameter); onlyLikelihoodObjectiveoverrides it.
- noise_grad_point(sim_data, exp_data, sim_row, exp_row, col_name, raw_sens, index)[source]¶
The estimated noise scale’s contribution to
∂(loss)/∂θat one scored point – a full(len(index),)native-space vector, orNonefor a fixed-noise point (layer D, #451; ADR-0079).Noneon the base: a non-likelihood objective (least-squares, distance, pass-through) estimates no noise parameter, so its scale contributes no gradient column. OnlyLikelihoodObjectiveoverrides it – the noise twin of the per-pointresidual_pointseam (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_variableschecks these against the declared free parameters, generalizing the old per-objfuncsigma__FREE/r__FREEhard-coded checks.
- residual_point(sim_data, exp_data, sim_row, exp_row, col_name)[source]¶
The standardized residual
rhoand its derivatived rho/d predictionfor one scored point – the per-point seam the gradient path differentiates (#449/#385).rhoandd rho/d predare defined so that this point’s contribution to the loss is1/2 rho**2andd(loss)/d pred = rho * d rho/d pred– the residual formscipy.least_squaresminimizes, agreeing with the scalar gradient by construction. The assembly multipliesd rho/d predby the forward sensitivityd 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 andevaluate_pointwisereturns 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.
- analytic_scale_sensitivity(sim_data, exp_data, indvar, compare_cols, data_key, raw_sens, index)[source]¶
{col: (c*, ∂c*/∂θ)}for every analytically scaled column of one experiment – the gradient twin of_analytic_scale_factors()(ADR-0066, #533).The profiled scale is a function of the whole series, so its derivative is a single series-wide vector shared by every point of that column. Differentiating the profiling condition in closed form (an implicit-function derivative that happens to be explicit, because
c*is written out rather than solved for) gives, withs_ithe unscaled prediction,g_i = ∂s_i/∂θ,d_ithe observation andw_ithe point’s weight, summed over exactly the points the profiling includes:log family (
c* = exp(Σ w (ln d − ln s)/Σ w), the geometric-mean ratio):∂c*/∂θ = −c* · Σ_i w_i g_i/s_i / Σ_i w_i
linear family (
c* = N/D,N = Σ w s d,D = Σ w s²):∂c*/∂θ = Σ_i w_i (d_i − 2 c* s_i) g_i / D
The profiling criterion is not in general the objective’s own minimizer over
c(it is unweighted by σ and family-agnostic beyond the log/linear split), so this term does not vanish by the envelope theorem – it is a real part of∂pred/∂θ.Returns
{}when this experiment scales nothing, so an unscaled fit never walks the series.raw_sens/indexare the assembly’s forward-sensitivity accessor and free-parameter column map.
- 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, data_key=None)[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
data_key – the (model, suffix) data key, used to resolve per-series analytic scaling (ADR-0066); None disables scaling.
- 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-objfuncconfig_argsrecipe.
- prediction_sensitivity(sim_data, sim_row, col_name, exp_data, exp_row, raw_sens, index, scale_terms=None)[source]¶
∂pred/∂θ(a native-space(n_param,)vector) for one matched point – the gradient seam mirroring_prediction()(#453/#385), branch for branch._predictionforms 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 anyData-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).indexmaps 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_sensplus 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.Analytic per-series scale (ADR-0066, #479/#533): the scored value is
c*(θ)·s_i(θ)withc*profiled from the whole series, so its sensitivity is the product rulec*·∂s_i/∂θ + s_i·∂c*/∂θ– the series-wide term fromanalytic_scale_sensitivity(), the per-point term from the branches above (which read the unscaled prediction, exactly as the profiling does).scale_termsis that experiment’s{col: (c*, ∂c*/∂θ)}map; a column absent from it is unscaled in this experiment and collapses to the plain branch.scale_terms=Nonemeans the caller did not resolve the series at all (it supplied nodata_key), which is a refusal rather than a silently unscaled derivative.
- 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
klit is a column-joint objective – it compares the shape of a whole column at once, not point by point – but whereklis 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 theprofile_objectivefamily’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 deferredprofile_objectivevalue grammar (ADR-0031); the default here is unit index spacing. A non-positive or negative simulated column cannot be normalized, so it scoresinf(the worst fit), mirroringkl’s degenerate-profile guard. Oracle:scipy.stats.wasserstein_distanceover 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 barescorepassthrough, 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 toobjective/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-observablenoise_modellines 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
lnLat the best fit – the sum of the noise model’s complete per-pointlog_density, NOT the (constant-dropped)-scorethe optimizer minimizes.k – number of free (fitted) parameters, INCLUDING any estimated noise parameter – a fitted
sigma/b/ris itself a free parameter (ADR-0021), so counting the declared free parameters already includes it.n – number of scored data points.
- Returns:
an
InformationCriteria.aiccisNonewhenn <= k + 1(the correction2k(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
objectivescored atpset, orNone.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-pointlog_densityover the scored data (evaluate_pointwise, ADR-0056),nis that point count, andkthe free-parameter count.
- pybnf.objective.replicated_information_criteria(log_likelihoods, k, n, requested=None)[source]¶
AIC / BIC / AICc from several log-likelihoods of ONE parameter set, each from its own simulation, with the standard error of their mean (#676, ADR-0131).
For a stochastic model a simulation of the best fit is a draw, so the log-likelihood it gives is a noisy measurement of the parameter set rather than a fixed number. The criteria here are computed from the MEAN of the per-simulation log-likelihoods. That is the same average
best_fit_confirmation.txtreports for the objective value, so the two files estimate the same quantity for the same parameter set. It is not the log of the mean likelihood: over a handful of draws that number is dominated by the luckiest of them, which reintroduces exactly the optimism the confirmation stage removed. The mean of the log-likelihoods is a lower bound on the log marginal likelihood (Jensen), and the gap grows with the spread the standard error reports, so a reader can see how much the two would differ.- Parameters:
log_likelihoods – one full normalized log-likelihood per simulation; at least one.
k – free-parameter count, as for
information_criteria().n – scored point count, the same for every simulation.
requested – how many simulations were run to produce those values. Larger than
len(log_likelihoods)when some of them failed, scored nothing, or scored a different number of points; the report says so rather than leaving the reader to notice that the count is below what the fit asked for (#741). Defaults to the number of values, which is the truth whenever nothing was lost.
- Returns:
an
InformationCriteriawhoselog_likelihoodis the mean,replicatesthe number of values,replicates_requestedthe number of simulations behind them, andlog_likelihood_standard_errorthe standard error of that mean, orNonewhen there is a single value. AIC, BIC and AICc each carry twice that standard error, since each is-2 lnLplus a constant.