Loss-library test coverage map¶
This doc cross-references every public symbol exported from
torchregress.losses with the dedicated test class that locks its behavior
and the discriminator invariant the test guards.
When you change a loss internals formula, factory, or protocol, the table below
tells you which tests/losses/test_*.py file (and which Test* class inside
it) is the right entry point. The invariants listed are the mathematical
or structural promises the test enforces — failing any of them is the
canonical way a contract break shows up in CI.
Conventions¶
- DEDICATED — the symbol has a
Test<S>class (or top-leveltest_*function) that locks in its contract. - DIRECT-LIGHT — covered indirectly via the per-symbol regression suite
(
test_loss_fixes.py,test_sls_internals.py,test_eiv_internals.py,test_functional_wrappers.py,test_indirect_utilities.py), each one introduced to fill gaps in the per-class suites. - INDIRECT — exercised only by other tests' incidental usage. Marked so refactors catch them on the next review pass.
Master matrix¶
Note:
Test*class names are best-effort. If a refactor renames or splits a class, rungrep '^class Test' tests/losses/<file>.pyfor the current names rather than trusting this table verbatim. The test-file column is more stable -- use that as the canonical entry point.
| Symbol | Module | Test file | Test class / function | Discriminator invariant |
|---|---|---|---|---|
BaseLoss |
base.py |
tests/losses/test_base.py |
TestBaseLoss |
_reduce honours mean/sum/none/min/max; _reduce_with_mask filters & re-normalises only the masked entries |
RegressionLoss |
base.py |
tests/losses/test_base.py |
TestRegressionLoss |
forward raises NotImplementedError until subclassed; reduction flows through to subclasses |
DistributionLoss |
base.py |
tests/losses/test_base.py |
TestDistributionLoss |
Flags _extract_distribution_parameters and _calculate_nll as abstract; concrete subclass returns scalar |
WeightedLossWrapper |
base.py |
tests/losses/test_base.py |
TestWeightedLossWrapper + tests/losses/test_loss_fixes.py::TestWeightedLossWrapperPreservesReduction |
Honours the wrapped loss' pre-set reduction (sum/none); auto-mean fallback only when no prior reduction |
WeightedMSELoss |
base.py |
tests/losses/test_base.py |
TestWeightedLossWrapper |
MSE wrapping honours mask & weights |
WeightedL1Loss |
base.py |
tests/losses/test_base.py |
TestWeightedLossWrapper |
L1 wrapping honours reduction inheritance |
WeightedHuberLoss |
base.py |
tests/losses/test_base.py::TestWeightedClassificationLosses (slip) + test_functional_wrappers.py |
TestWeightedLossWrapper |
Huber's delta parameter passes through unchanged |
WeightedCrossEntropyLoss |
base.py |
tests/losses/test_base.py |
TestWeightedClassificationLosses |
Per-sample weights propagate to native CrossEntropyLoss |
WeightedNLLLoss |
base.py |
tests/losses/test_base.py |
TestWeightedClassificationLosses |
Mask-filtered per-sample NLL matches native NLLLoss mean |
BalancedMSELoss |
balanced_mse.py |
tests/losses/test_balanced_mse.py |
(per-class suite) | Effective MSE under target-density weights |
BinReweightedMSELoss |
balanced_mse.py |
tests/losses/test_balanced_mse.py |
(per-class suite) | Binned inverse-frequency weighted MSE with automatic edges |
BalancedMSEBMC |
balanced_mse_bmc.py |
tests/losses/test_balanced_mse_bmc.py |
(per-class suite) | Batch-coupled noise-adaptive Balanced MSE (BMC), label prior + sigma fitting, hand-formula parity |
RankSimLoss |
rank_sim.py |
tests/losses/test_rank_sim.py |
(per-class suite) | Ranking-similarity regularizer with blackbox rank gradient; hand-computable ranking checks |
BetaNLLLoss |
beta_nll.py |
tests/losses/test_beta_nll.py + tests/losses/test_functional_wrappers.py |
TestBetaNLLLossWrapper |
Detached var⁻ᵝ rescaling; reduces to vanilla Gaussian NLL at β=0 |
beta_nll_loss |
beta_nll.py |
tests/losses/test_functional_wrappers.py |
TestBetaNLLLossWrapper::test_parity_with_class |
Functional wrapper parity with BetaNLLLoss on tuple & concat inputs |
CensoredGaussianNLLLoss |
censored.py |
tests/losses/test_censored.py |
(per-class) | Censoring mask propagates to NLL |
CensoredQuantileLoss |
censored.py |
tests/losses/test_censored.py |
(per-class) | Pinball loss with left-/right-censoring adjustments |
AFTLoss |
censored.py |
tests/losses/test_censored.py |
(per-class suite) | Accelerated-failure-time log-location residual |
CQR |
conformal.py |
tests/losses/test_conformal.py |
TestCQR + tests/losses/test_loss_fixes.py::TestCQRCalibrationInvariants |
Finite-sample quantile thresholds; alpha restoration after calibrate; empty/all-masked calibration raises; calibrated interval is [q_lo - q_hat, q_hi + q_hat] |
CTI |
conformal.py |
tests/losses/test_conformal.py |
TestCTI |
Smallest density-level-set interval via grid search |
SLSConformal |
conformal.py |
tests/losses/test_sls_conformal.py |
(per-class) | Score = G(X,Y) / q_τ(X); interval from frontier level set |
ConformalLoss |
conformal.py |
tests/losses/test_conformal.py |
TestSplitConformal, TestCQR, etc. |
Method-routes to underlying predictor; pinball training loss for cqr/uacqr; rejects unknown kwargs |
ConformalPredictor |
conformal.py |
tests/losses/test_conformal.py |
(base for Test*Conformal) |
Virtual _compute_scores/_build_intervals; Mondrian + normalised + weighted composable features |
LevelSetConformalPredictor |
conformal.py |
tests/losses/test_conformal.py |
(via TestCTI, TestDistributionalConformal, TestSLSConformal) |
Shared _grid_search_level_set utility |
LocalConformal |
conformal.py |
tests/losses/test_conformal.py |
TestLocalConformal + tests/losses/test_loss_fixes.py::TestLocalConformalSentinelFallback |
Sentinel True column guards against underflow when cum-weights miss 1-α |
LocalConformalMAD |
conformal.py |
tests/losses/test_conformal.py |
TestLocalConformalMAD + tests/losses/test_loss_fixes.py::TestLocalConformalSentinelFallback |
Same sentinel behaviour under MAD scaling |
SplitConformal |
conformal.py |
tests/losses/test_conformal.py |
TestSplitConformal |
|residual| score; symmetric ŷ ± q_hat interval |
UACQR |
conformal.py |
tests/losses/test_conformal.py |
(per-class) | CQR with width-normalised scores |
DensityConformal |
conformal.py |
tests/losses/test_conformal.py |
TestDensityConformal |
KDE-adaptive score normalisation |
DistributionalConformal |
conformal.py |
tests/losses/test_conformal.py |
TestDistributionalConformal |
PIT-based score; ICDF interval construction |
MonteCarloConformal |
conformal.py |
tests/losses/test_conformal.py |
TestMonteCarloConformal |
MC sample mean/median + std normalisation |
MultiTargetConformal |
conformal.py |
tests/losses/test_conformal.py |
(per-class) | Per-dimension calibration independence |
PrevalenceAdjustedCP |
conformal.py |
tests/losses/test_conformal.py |
TestPrevalenceAdjustedCP |
Group-prevalence scales miscoverage rate |
R2CConformal |
conformal.py |
tests/losses/test_conformal.py |
TestR2CConformal |
APS-style sorted-bin inclusion |
BaseEIVLoss |
eiv.py |
tests/losses/test_eiv_internals.py |
TestBaseEIVLossInternals |
_prepare_covariance_from_sigma interpretation of scalar / 1d / 2d / 3d sigma; explicit() factory returns adapter |
EnsembleEIVLoss |
eiv.py |
tests/losses/test_eiv.py |
TestEIVLoss::test_ensemble_eiv_loss |
Gaussian-perturbation ensemble averaging |
FunctionalEIVLoss |
eiv.py |
tests/losses/test_eiv.py |
TestEIVLoss::test_functional_eiv_loss + TestEIVLossNumericalStability |
Jacobian-variance + NLL; analytical/mc/hybrid branches finite & monotonic in n_samples |
InputNoiseBinnedPDFLoss |
eiv.py |
(specialized class — INDIRECT, exercised via test_eiv.py) |
— | Binned-PDF marginalisation with Ordinal base |
LatentMarginalizationLoss |
eiv.py |
tests/losses/test_eiv_correctness.py |
TestEIVCorrectness::test_latent_marginalization_gaussian_prior + test_latent_marginalization_custom_sampler |
Analytical Gaussian-prior posterior and custom-sampler posterior paths; log-mean-exp marginalisation |
InputNoiseMDNLoss |
eiv.py |
(per-class — INDIRECT via test_mdn.py) |
— | MDN base loss + marginalisation |
NoisyInputPredictor |
eiv.py |
tests/losses/test_eiv_internals.py |
TestNoisyInputPredictor |
forward(x) returns mean over MC perturbations; antithetic yields distinct rows; non-tensor model is rejected |
OrthogonalDistanceRegressionLoss |
eiv.py |
tests/losses/test_eiv.py |
TestEIVLoss::test_odr_loss + TestEIVLossNumericalStability::test_odr_gradient_flow |
Latent-x optimisation step (approx) recovers Mahalanobis sum |
StructuralEIVLoss |
eiv.py |
tests/losses/test_eiv.py |
TestEIVLoss::test_structural_eiv_loss |
Cross-covariance σ_xy propagates through NLL |
EvidentialRegressionLoss |
evidential.py |
tests/losses/test_evidential.py |
TestEvidentialRegressionLoss |
NIG posterior + KL regularisation |
ExpectileLoss |
expectile.py |
tests/losses/test_expectile.py + tests/losses/test_functional_wrappers.py |
TestExpectileLoss + TestExpectileLossWrapper |
τ=0.5 collapses to MSE; asymmetric weights τ/1-τ |
expectile_loss |
expectile.py |
tests/losses/test_functional_wrappers.py |
TestExpectileLossWrapper |
Parity with ExpectileLoss class |
MultiExpectileLoss |
expectile.py |
tests/losses/test_non_gaussian_consistency.py |
TestExpectileContract |
Average across expectile levels per sample |
ExpectileCrossoverLoss |
expectile.py |
tests/losses/test_non_gaussian_consistency.py |
TestExpectileContract |
Crossover penalty on pairs of predictands |
FaithfulGaussianLoss |
faithful_gaussian.py |
tests/losses/test_faithful_gaussian.py |
(per-class) | Mean / variance decoupled layers |
GaussianCRPSLoss |
gaussian.py |
tests/losses/test_gaussian.py |
TestGaussianLosses::test_gaussian_crps_loss_matches_metric |
Analytic CRPS matches shared crps_gaussian metric |
GaussianNLLLoss |
gaussian.py |
tests/losses/test_gaussian.py |
TestGaussianLosses::test_gaussian_nll_loss + test_gaussian_consistency.py |
Accepts tuple / concat / mean-only formats; reduction modes |
LowRankGaussianLoss |
gaussian.py |
tests/losses/test_gaussian.py |
TestGaussianLosses::test_low_rank_gaussian_loss |
cov_factor @ cov_factor.T + diag(cov_diag) NLL |
MultivariateGaussianLoss |
gaussian.py |
tests/losses/test_gaussian.py + consistency suite |
TestGaussianLosses::test_multivariate_gaussian_loss |
Cholesky NLL with jitter; respects shape contracts |
create_gaussian_nll |
gaussian.py |
tests/losses/test_indirect_utilities.py |
TestCreateGaussianNll |
Factory routes by covariance_type; full ≈ multivariate route identity; use_mse_for_unit_variance → WeightedMSELoss |
GaussianWassersteinBoundLoss |
gaussian_wasserstein.py |
tests/losses/test_gaussian_wasserstein.py + consistency hybrid tests |
(per-class) | |μ-μ̂|² + |Σ½-Σ̂½|_F² in 4 covariance parameterisations |
gaussian_wasserstein_bound_loss |
gaussian_wasserstein.py |
tests/losses/test_functional_wrappers.py |
TestGaussianWassersteinBoundWrapper |
Functional parity across diag / covariance / sqrt / cholesky modes |
symmetric_spd_matrix_sqrt |
gaussian_wasserstein.py |
tests/losses/test_indirect_utilities.py |
TestSymmetricSpsMatrixSqrt |
eigh-based sqrt: symmetric, S·S = Σ, eps floors singletons |
DensityWeightedLoss |
imbalanced.py |
tests/losses/test_imbalanced.py |
(per-class) | Target-density reweighting |
FocalRLoss |
imbalanced.py |
tests/losses/test_imbalanced.py |
(per-class) | Focal-style per-sample modulation |
LDSLoss |
imbalanced.py |
tests/losses/test_imbalanced.py |
(per-class) | Label-distribution-shift reweighting |
PropensityWeightedLoss |
imbalanced.py |
tests/losses/test_imbalanced.py |
(per-class) | Inverse-propensity weighting |
get_regression_loss |
loss_registry.py |
tests/losses/test_loss_registry.py |
(per-class) | Lookup by registry key |
list_regression_losses |
loss_registry.py |
tests/losses/test_loss_registry.py |
(per-class) | Sorted list of registered names |
create_loss_from_config |
loss_registry.py |
tests/losses/test_loss_registry.py |
(per-class) | YAML-style config construction with aliases |
MixtureDensityLoss (re-exported as MixtureDensityLoss) |
mdn.py |
tests/losses/test_mdn.py |
(per-class) | Full-cov Cholesky backward finite & differentiable |
SLSLoss |
sls.py |
tests/losses/test_sls.py + consistency suite |
(top-level test_sls_loss_warmup_and_forward, etc.) |
Step-counter monotonic advance; warmup window; K>1 unfreeze gating |
VolumePreservingFlow |
sls.py |
tests/losses/test_sls.py (round-trip) + tests/losses/test_sls_internals.py |
TestVolumePreservingFlow |
Invertibility: flow.inverse(flow(y)) == y; alternating half-mask per layer |
MahalanobisFrontier |
sls.py |
tests/losses/test_sls_internals.py |
TestMahalanobisFrontierFull, TestMahalanobisFrontierLowRank |
Full-mode num_L_params = d(d+1)/2; low-rank default rank = ⌈√d⌉; G ≥ 0 invariant |
UnionFrontier |
sls.py |
tests/losses/test_sls_internals.py |
TestUnionFrontier |
K-component MahalanobisFrontier list; freeze/unfreeze gating; mixture weights sum to 1 |
NormalizingFlowLoss |
nflows.py |
tests/losses/test_nflows.py |
(per-class) | zuko-backed wrapper; loss wiring |
ContrastiveFlowLoss |
nflows.py |
tests/losses/test_contrastive_nflows.py |
(per-class) | Contrastive term |
create_flow_model |
nflows.py |
(INDIRECT inside test_nflows.py) |
— | Build flow from config |
create_flow_loss |
nflows.py |
(INDIRECT inside test_nflows.py) |
— | Build flow loss from config |
create_contrastive_flow_loss |
nflows.py |
(INDIRECT — special optional) | — | Build contrastive flow loss |
OrdinalCrossEntropyLoss |
ordinal.py |
tests/losses/test_ordinal.py |
(per-class) | Label-smoothed ordinal CE |
CumulativeLinkLoss |
ordinal.py |
tests/losses/test_ordinal.py |
(per-class) | Cumulative-link logistic loss |
NegativeBinomialNLLLoss |
poisson.py |
tests/losses/test_poisson.py |
(per-class) | NB NLL with dispersion parameter |
PoissonDevianceLoss |
poisson.py |
tests/losses/test_poisson.py |
(per-class) | Poisson deviance residual |
PoissonLikelihoodRatioLoss |
poisson.py |
tests/losses/test_poisson.py |
(per-class) | LR loss vs. Poisson mean |
ZeroInflatedPoissonNLLLoss |
poisson.py |
tests/losses/test_poisson.py |
(per-class) | ZIP NLL with mixing parameter |
PoissonGaussianLoss |
poisson_gaussian.py |
tests/losses/test_poisson_gaussian_convolution.py |
oracle + limits + gradcheck | Poisson-Gaussian convolution (detector) NLL |
PoissonGaussianContaminationMixtureLoss |
poisson_gaussian.py |
tests/losses/test_poisson_gaussian.py |
(per-class) + consistency | Poisson+Gaussian NLL mixture |
EnhancedPoissonGaussianContaminationMixtureLoss |
poisson_gaussian.py |
tests/losses/test_poisson_gaussian.py |
(per-class) + consistency | Gain-offset mixture w/ learnable params |
PoissonGaussianLikelihoodRatioLoss |
poisson_gaussian.py |
tests/losses/test_poisson_gaussian.py + consistency |
(per-class) | LR mixture NLL |
MultiQuantileLoss |
quantile.py |
tests/losses/test_quantile.py + tests/losses/test_non_gaussian_consistency.py |
TestMultiQuantileLoss |
Average across multiple quantiles per sample |
QuantileCrossoverLoss |
quantile.py |
tests/losses/test_quantile.py + consistency |
TestQuantileLoss::test_quantile_crossover_constraint |
Crossover penalty Σᵢ max(fᵢ - fᵢ₊₁, 0) |
QuantileLoss |
quantile.py |
tests/losses/test_quantile.py + tests/losses/test_functional_wrappers.py |
TestQuantileLoss, TestQuantileLossWrapper |
Asymmetric pinball; q=0.5 recovers MAE |
quantile_loss |
quantile.py |
tests/losses/test_functional_wrappers.py |
TestQuantileLossWrapper |
Parity with QuantileLoss class |
PseudoHuberLoss |
robust.py |
tests/losses/test_robust.py + consistency |
(per-class) | Smooth L1 alternative |
LogCoshLoss |
robust.py |
tests/losses/test_robust.py + consistency |
(per-class) | Log-cosh residual |
CharbonnierLoss |
robust.py |
tests/losses/test_robust.py + consistency |
(per-class) | √(r²+ε²) stem |
TukeyBiweightLoss |
robust.py |
tests/losses/test_robust.py + consistency |
(per-class) | Biweight ψ-function |
CauchyLoss |
robust.py |
tests/losses/test_robust.py + consistency |
(per-class) | log(1+(r/c)²) |
BarronLoss |
robust.py |
tests/losses/test_robust.py + consistency |
(per-class) | Continuously-interpolated L2/L1 shape via α |
AdaptiveRobustLoss |
robust.py |
tests/losses/test_robust.py + consistency |
(per-class) | Learnable α/β/scale |
CVaRLoss |
robust.py |
tests/losses/test_cvar.py |
(per-class) | Tail-risk expectation above α |
BoxCoxTransformLoss |
transforms.py |
tests/losses/test_transforms.py |
(per-class) | Box-Cox transform + base loss |
LogTransformLoss |
transforms.py |
tests/losses/test_transforms.py |
(per-class) | log + base loss |
SqrtTransformLoss |
transforms.py |
tests/losses/test_transforms.py |
(per-class) | √ + base loss |
TransformedTargetLoss |
transforms.py |
tests/losses/test_transforms.py |
(per-class) | Generic transform wrapper |
YeoJohnsonTransformLoss |
transforms.py |
tests/losses/test_transforms.py |
(per-class) | Yeo-Johnson (handles non-positive targets) |
CompoundPoissonLoss |
tweedie.py |
tests/losses/test_tweedie.py |
(per-class) | Compound Poisson-Gamma (1 < p < 2) |
GammaLoss |
tweedie.py |
tests/losses/test_tweedie.py |
(per-class) | Gamma loss (p=2) |
InverseGaussianLoss |
tweedie.py |
tests/losses/test_tweedie.py |
(per-class) | IG loss (p=3) |
TweedieLoss |
tweedie.py |
tests/losses/test_tweedie.py + tests/losses/test_functional_wrappers.py |
TestTweedieLoss, TestTweedieLossWrapper |
Routing by p: 0→normal, 1→Poisson, 2→gamma, 3→IG, 1<p<2→compound |
tweedie_loss |
tweedie.py |
tests/losses/test_functional_wrappers.py |
TestTweedieLossWrapper |
Wrapper parity |
ConsistencyRegLoss |
uncertain_gt.py |
tests/losses/test_uncertain_gt.py |
(per-class) | EMA-style consistency penalty |
NoisyTargetGaussianNLL |
uncertain_gt.py |
tests/losses/test_uncertain_gt.py |
(per-class) | Label-noise-aware Gaussian NLL |
PseudoLabelConsistencyLoss |
uncertain_gt.py |
tests/losses/test_uncertain_gt.py |
(per-class) | Pseudo-label agreement penalty |
PseudoLabelNLL |
uncertain_gt.py |
tests/losses/test_uncertain_gt.py |
(per-class) | NLL under pseudo-label distribution |
low_rank_output_dim |
utils/gaussian_output.py |
tests/losses/test_indirect_utilities.py |
TestLowRankOutputDim |
2F + F·R formula; monotonicity; ValueError on n_features<=0 or rank<=0 |
split_low_rank_gaussian_output |
utils/gaussian_output.py |
tests/losses/test_indirect_utilities.py |
TestSplitLowRankGaussianOutput |
Round-trip [mean \| factor \| diag]; unbatched shape; ValueError on wrong out_dim |
Supplementary symbol coverage¶
The matrix above covers the core loss surface; these additional public symbols are exercised by the tests listed here. Status follows the same conventions: DEDICATED when a Test* class targets the symbol, DIRECT-LIGHT when a focused test function exists in the per-symbol suites, and INDIRECT otherwise (a refactor should add a direct test).
| Symbol | Module | Test entry point | Coverage |
|---|---|---|---|
balanced_mse_bmc_loss |
balanced_mse_bmc.py |
tests/losses/test_balanced_mse_bmc.py::TestHandFormula |
DIRECT-LIGHT |
CVPlus |
conformal.py |
tests/losses/test_conformal.py::TestCVPlus |
DEDICATED |
ConformalizedDensity |
conformal.py |
tests/losses/test_conformalized_density.py::test_conformalized_density_scalar_coverage |
DEDICATED |
ContrastiveFlowConformal |
conformal.py |
tests/losses/test_conformalized_density.py::test_contrastive_flow_conformal_level_set |
DEDICATED |
EnsembleBatchCP |
conformal.py |
tests/losses/test_conformal.py::TestEnsembleBatchCP |
DEDICATED |
MultivariateScoreConformal |
conformal.py |
tests/test_multivariate_score_cp.py::test_covariance_shape_flexibility_and_errors |
DIRECT-LIGHT |
NonExchangeableConformalRegressor |
conformal.py |
tests/test_nexc_conformal.py::test_uniform_weights_recover_finite_sample_quantile |
DIRECT-LIGHT |
RankNContrastLoss |
contrastive.py |
tests/losses/test_rank_n_contrast.py::test_gradients_and_degenerate_batches |
DIRECT-LIGHT |
rank_n_contrast_loss |
contrastive.py |
tests/losses/test_rank_n_contrast.py::test_perfectly_ordered_features_score_lower_than_shuffled |
DIRECT-LIGHT |
InputNoiseAugmentationLoss |
eiv.py |
tests/losses/test_losses_regression_guards.py::test_a10_input_noise_augmentation_does_not_forward_weights |
DIRECT-LIGHT |
AsymmetricLaplaceNLLLoss |
families.py |
tests/losses/test_families.py::test_asymmetric_laplace_unconstrained_inputs_flag |
DIRECT-LIGHT |
BetaRegressionNLLLoss |
families.py |
tests/losses/test_families.py::test_beta_regression_registered |
DIRECT-LIGHT |
GEVNLLLoss |
families.py |
tests/losses/test_families.py::test_gev_unconstrained_inputs_flag |
DIRECT-LIGHT |
JohnsonSUNLLLoss |
families.py |
tests/losses/test_families.py::test_johnson_su_unconstrained_inputs_flag |
DIRECT-LIGHT |
SQRLoss |
families.py |
tests/losses/test_families.py::test_sqr_level_count_validated_and_registered |
DIRECT-LIGHT |
SinhArcsinhNLLLoss |
families.py |
tests/losses/test_families.py::test_sinh_arcsinh_registered |
DIRECT-LIGHT |
SkewNormalNLLLoss |
families.py |
tests/losses/test_families.py::test_skew_normal_class_functional_and_registry |
DIRECT-LIGHT |
SkewTLoss |
families.py |
tests/losses/test_families.py::test_skew_t_unconstrained_inputs_flag |
DIRECT-LIGHT |
asymmetric_laplace_nll |
families.py |
tests/losses/test_families.py::test_asymmetric_laplace_kappa_one_is_symmetric_laplace |
DIRECT-LIGHT |
beta_regression_nll |
families.py |
tests/losses/test_families.py::test_none_reduction_preserves_shape |
DIRECT-LIGHT |
gev_nll |
families.py |
tests/losses/test_families.py::test_gev_gumbel_limit_matches_general_formula_at_small_xi |
DIRECT-LIGHT |
johnson_su_nll |
families.py |
tests/losses/test_families.py::test_johnson_su_density_integrates_to_one |
DIRECT-LIGHT |
sinh_arcsinh_nll |
families.py |
tests/losses/test_families.py::test_none_reduction_preserves_shape |
DIRECT-LIGHT |
skew_normal_nll |
families.py |
tests/losses/test_families.py::test_skew_normal_class_functional_and_registry |
DIRECT-LIGHT |
skew_t_nll |
families.py |
tests/losses/test_families.py::test_none_reduction_preserves_shape |
DIRECT-LIGHT |
sqr_loss |
families.py |
tests/losses/test_families.py::test_sqr_constant_predictions_equal_mean_pinball |
DIRECT-LIGHT |
FeatureDistributionSmoother |
imbalanced.py |
tests/losses/test_imbalanced.py::TestFeatureDistributionSmoother |
DEDICATED |
recommended_tail_bound |
nflows.py |
tests/losses/test_nflows_tail_bound.py::test_recommended_tail_bound_is_data_range_with_margin_clipped |
DEDICATED |
BinnedDensityLoss |
noise_aware_density.py |
tests/losses/test_noise_density_contract_regressions.py::test_binned_uniform_sampling_density_and_cdf_agree |
DIRECT-LIGHT |
JointBinnedDensityLoss |
noise_aware_density.py |
tests/losses/test_binned_joint.py::test_joint_validation |
DIRECT-LIGHT |
NoiseAwareDensityLoss |
noise_aware_density.py |
tests/losses/test_noise_aware_density.py::test_noise_aware_flow_gradient_and_contamination |
DIRECT-LIGHT |
NeuralRatioLoss |
nre.py |
tests/losses/test_nre.py::_train_gaussian_ratio_estimator |
DIRECT-LIGHT |
build_ratio_classifier |
nre.py |
tests/losses/test_nre.py::test_build_ratio_classifier_validation_errors |
DEDICATED |
neural_ratio_logits |
nre.py |
tests/losses/test_nre.py::test_neural_ratio_logits_validation_errors |
DEDICATED |
neural_ratio_loss |
nre.py |
tests/losses/test_nre.py::test_functional_helper_matches_class |
DIRECT-LIGHT |
ConR |
prime.py |
tests/losses/test_prime_conr.py::test_conr_permutation_invariance |
DIRECT-LIGHT |
PrimeLoss |
prime.py |
tests/losses/test_prime_conr.py::test_label_range_pins_grid_and_allows_forward_without_fit |
DIRECT-LIGHT |
UncertaintyAwareConR |
prime.py |
tests/losses/test_noise_aware_density.py::test_uncertainty_aware_conr |
DIRECT-LIGHT |
conr_loss |
prime.py |
tests/losses/test_prime_conr.py::test_conr_mask_reduction_and_weights |
DIRECT-LIGHT |
uniform_proxy_targets |
prime.py |
tests/losses/test_prime_conr.py::test_uniform_proxy_targets_are_equal_width_and_exclude_endpoints |
DEDICATED |
rank_sim_regularizer |
rank_sim.py |
tests/losses/test_rank_sim.py::test_invalid_inputs_raise |
DIRECT-LIGHT |
CumulativeCDFLoss |
cdf.py |
tests/losses/test_cdf.py::test_cumulative_cdf_class |
DIRECT-LIGHT |
cumulative_cdf_loss |
cdf.py |
tests/losses/test_cdf.py::test_cumulative_cdf_loss_zero_for_perfect_step |
DEDICATED |
CorrectedScoreEIVLoss |
split_eiv.py |
tests/losses/test_split_eiv.py::test_corrected_score_decreases_on_small_mlp |
DIRECT-LIGHT |
SplitMeasurementLoss |
split_eiv.py |
tests/losses/test_split_eiv.py::test_split_loss_nonlinear_is_finite_and_differentiable_to_second_order |
DIRECT-LIGHT |
corrected_score_eiv_loss |
split_eiv.py |
tests/losses/test_split_eiv.py::test_helpers_match_classes_and_forward_sigma_override |
DIRECT-LIGHT |
split_measurement_loss |
split_eiv.py |
tests/losses/test_split_eiv.py::test_helpers_match_classes_and_forward_sigma_override |
DIRECT-LIGHT |
StudentTLoss |
student_t.py |
tests/losses/test_student_t.py::test_extreme_residuals |
DIRECT-LIGHT |
WaldoConformal |
waldo.py |
tests/losses/test_waldo.py::test_waldo_conformal_with_regressor_coverage |
DEDICATED |
WaldoCriticalValueRegressor |
waldo.py |
tests/losses/test_waldo.py::test_waldo_critical_value_regressor_fit_predict |
DEDICATED |
WaldoDensityConformal |
waldo.py |
tests/losses/test_waldo.py::test_waldo_density_conformal |
DEDICATED |
WaldoPosteriorCalibrator |
waldo.py |
tests/losses/test_waldo.py::test_waldo_posterior_calibrator |
DEDICATED |
waldo_statistic |
waldo.py |
tests/losses/test_waldo.py::test_waldo_statistic_shapes |
DEDICATED |
DiscreteWasserstein1Loss |
wasserstein1d.py |
tests/losses/test_wasserstein1d.py::test_default_unit_bins_and_validation |
DIRECT-LIGHT |
discrete_wasserstein1 |
wasserstein1d.py |
tests/losses/test_wasserstein1d.py::test_metric_properties |
DIRECT-LIGHT |
Internal helpers in utils/gaussian_output.py¶
The three helpers below are not in __all__ — they remain internal contract
helpers outside the public losses API. They are exercised indirectly by
their BetaNLLLoss/GaussianNLLLoss/FaithfulGaussianLoss callers but have
no dedicated test class. Treat any change as a cross-module refactor that
should land alongside a direct test in
tests/losses/test_indirect_utilities.py.
parse_heteroscedastic_output— tuple/dict/concat-2D routingsplit_mean_log_variance— tuple/dict/concat routing;ValueErroron odd dimsvariance_from_logvar— clamp + exp signing
Per-class test surface (consistency / cross-family)¶
| File | Purpose |
|---|---|
test_gaussian_consistency.py |
Cross-family Gaussian invariants (input formats, mask/weights contracts, gradient contracts, CRPS stability, Wasserstein relationships). Locks every variant of the Gaussian loss family to the same input contract. |
test_non_gaussian_consistency.py |
Cross-family contracts for Poisson-Gaussian, censored, Tweedie, quantile, ordinal, conformal, EIV, expectile, evidential, robust, balanced-MSE families. |
test_loss_fixes.py |
Regression tests for documented loss bugs — SLSLoss.step_counter, WeightedLossWrapper.reduction, MixtureDensityLoss.full-cov Cholesky backward, LocalConformal.predict_interval sentinel, plus CQR calibration invariants (alpha not mutated; empty/all-masked raises). Use this file first when investigating these invariants. |
test_sls_internals.py |
SLS internal modules — VolumePreservingFlow / MahalanobisFrontier (full + low-rank) / UnionFrontier / QuantileNetwork. |
test_eiv_internals.py |
EIV internal modules — NoisyInputPredictor / BaseEIVLoss._prepare_covariance_from_sigma. |
test_functional_wrappers.py |
Functional wrappers (quantile_loss, expectile_loss, beta_nll_loss, tweedie_loss, gaussian_wasserstein_bound_loss). |
test_indirect_utilities.py |
Public indirect utilities — low_rank_output_dim, split_low_rank_gaussian_output, symmetric_spd_matrix_sqrt, create_gaussian_nll. |
test_loss_registry.py |
get_regression_loss / list_regression_losses / create_loss_from_config. |
Discriminator invariants: where to look when refactoring¶
| Invariant category | Canonical test entrance | Module-level fallback |
|---|---|---|
| NLL formula and reduction | test_gaussian.py::TestGaussianLosses + test_gaussian_consistency.py::TestMaskContract |
test_beta_nll.py, test_poisson_gaussian.py |
| Pinball / quantile formulation | test_quantile.py::TestQuantileLoss + tests/losses/test_functional_wrappers.py::TestQuantileLossWrapper |
test_non_gaussian_consistency.py |
| CQR calibration invariants | test_loss_fixes.py::TestCQRCalibrationInvariants |
test_conformal.py::TestCQR |
| Determinism across dataloader calls (sentinel underflow) | test_loss_fixes.py::TestLocalConformalSentinelFallback |
test_conformal.py::TestLocalConformal |
| Volume-preserving flow invertibility | test_sls.py::test_volume_preserving_* + test_sls_internals.py::TestVolumePreservingFlow |
test_sls_internals.py |
| Mahalanobis frontier shape & rank default | test_sls_internals.py::TestMahalanobisFrontier{LowRank,Full} |
test_sls.py::test_mahalanobis_frontier_full_and_low_rank |
| K>1 union mixture weights | test_sls_internals.py::TestUnionFrontier::test_unfrozen_mixture_weights_sum_to_one_per_sample |
test_sls.py::test_union_frontier |
| MDN Cholesky backward (no leaf-tensor in-place write) | test_loss_fixes.py::TestMixtureDensityLossFullCovBackward |
test_mdn.py |
| Wrapper preserves caller-set reduction | test_loss_fixes.py::TestWeightedLossWrapperPreservesReduction |
test_base.py::TestWeightedLossWrapper |
| SLS curriculum monotonic advance | test_loss_fixes.py::TestSLSLossStepCounterAdvances |
test_sls.py::test_sls_loss_warmup_and_forward |
| Functional-wrapper parity (loss vs class) | All Test*Wrapper classes in test_functional_wrappers.py + test_indirect_utilities.py |
per-class suite |
| Gaussian Wasserstein bound 4-mode parity | test_functional_wrappers.py::TestGaussianWassersteinBoundWrapper::test_*_mode |
test_gaussian_wasserstein.py |
INDIRECT-only symbols (refactor risk)¶
The authoritative list is the Coverage column of the supplementary symbol coverage table: symbols marked DIRECT-LIGHT or INDIRECT have no dedicated Test* class. The zuko-dependent flow factories (create_flow_model, create_flow_loss, create_contrastive_flow_loss) remain the canonical example: optional dependency, covered indirectly.
Any non-trivial change to these symbols should land alongside a small
direct test in tests/losses/test_indirect_utilities.py (or specific
file) so their behaviour doesn't drift silently.
Per-class test surfaces¶
For matrix rows citing (per-class suite), the dedicated Test* classes live
in the file under Test file. Use grep '^class Test' <test_file> to list
the exact class names — the names change frequently and the matrix does not
attempt to enumerate them. Cross-consistency coverage is documented per file
in test_gaussian_consistency.py and test_non_gaussian_consistency.py.
Known silent regressions¶
The following invariants are documented. Pre-fix code raises the listed error under older PyTorch but is silently absorbed under modern PyTorch's version-counter autograd; the listed regression test now discriminates both states at runtime, so the original caveat no longer applies:
MixtureDensityLossH2 in-place scatter. Post-fix code composes the full-cov Cholesky factor functionally viatorch.where(diag_mask, L_diag, L_offdiag), yielding a brand-newL_matricestensor with_version == 0at forward-return time. Pre-fix code derivedL_matricesvia two in-place__setitem__writes ontoL_offdiag, bumping its version to>= 2by the time it was returned.The discriminatortests/losses/test_loss_fixes.py::TestMixtureDensityLossFullCovBackward::test_full_covariance_L_version_zerowraps_extract_distribution_parametersto captureL_matrices._versionimmediately after forward and asserts it equals 0, surviving PyTorch's silent absorption of the in-place pattern.
Coverage invariants: what test authors MUST pin¶
Future test authors must follow this discipline when introducing any
ad-hoc reference to a covariance, sigma, stddev, or Cholesky factor in a
test fixture. Ad-hoc torch.eye(...) / torch.diag(...) /
torch.diag_embed(...) literals MUST pin device and dtype so
the fixture does not silently rely on the loss module handling
dtype/device of input fixtures internally. Two accepted forms depending
on whether the literal is on the result side or the input side of
the comparison:
- Result comparison (the literal is the reference for a tensor returned by a loss module). Pin the literal to the result's metadata:
- Input builder (the literal is part of a fixture fed into a loss
module — e.g.
A @ A.T + torch.eye(dim) * jitter). Pin to the co-built anchor tensor that's already on the right device/dtype:
The legacy .to(cov.device, dtype=cov.dtype) cast on the literal is
accepted as a fallback when the torch.eye(...) / torch.diag(...)
form would change the literal's mathematical meaning (e.g. when the
literal is a hand-built third-party reference like torch.tensor([...])
the test materials outside an obvious anchor).
Why this discipline matters¶
torch.allclose and torch.testing.assert_close are
dtype/device-tied at the framework level. torch.eye(3) silently
defaults to float32/CPU; if a future loss module grows a
device-dispatching code path (e.g. CUDA NLL, autograd-double NLL, the
to("cuda") migration in test_gaussian.py's setUp) the test
would silently pass under old builds while passing against mismatched
metadata under new builds — a covered-by-follow-up symptom of implicit
fixture metadata rather than a single-step failure flagged by CI.
Concretely: under a dtype/device mismatch, torch.allclose raises
a RuntimeError rather than returning the comparison result. CI fails
with an unrelated-looking error message (e.g. Found dtype Float but
expected Double), masking the real loss-graph regression behind a
metadata mismatch — the developer fixes the missing dtype pin rather
than the actual loss bug the test was guarding.
Canonical examples for reference while authoring new tests¶
tests/losses/test_eiv_internals.py::TestBaseEIVLossInternals::test_prepare_covariance_*— the canonical result-comparison form. Pin the reference tocovafter_prepare_covariance_from_sigma:torch.eye(n_features, device=cov.device, dtype=cov.dtype) * 0.25.tests/losses/test_functional_wrappers.py::TestGaussianWassersteinBoundWrapper.setUp— the canonical input-builder form. Pin the SPD builder's eye to the co-builtA:A @ A.T + torch.eye(self.d, device=A.device, dtype=A.dtype).- All
_make_spd_cov-style helpers intests/losses/test_gaussian_consistency.pyand the_psd_matrixhelper intests/losses/test_indirect_utilities.pyreproduce the input-builder form on the helper's anchorA. tests/losses/test_gaussian.py::TestGaussianLosses.setUp— adds adtype=pin on top of an existingdevice=pin for the SPD jitter term.
Cross-cutting rule for code review¶
When reviewing or extending any test in tests/losses/, tests/,
notebooks/, or examples/, re-grep torch.eye and
torch.diag / torch.diag_embed. Any unpinned site that
- constructs an input fixture (an A @ A.T + eye(dim) * jitter
builder, an eye-in-a-list literal passed as a sigma parameter,
etc.), or
- compares against a result tensor in torch.allclose / torch.testing.assert_close,
is a coverage-invariance violation under this rule. Fix before merging, exactly per the patterns above.
Mechanical enforcement (TOR001 + TOR002 + TOR003)¶
Pin-rollout drift doctor¶
A second local hook, scripts/check_pin_rollout_drift.py, complements the
enforcer above by auditing every# noqa: TORxxxopt-out in thetests/,examples/,notebooks/, andsrc/ trees. Three severity
classes are reported:
[error]— the noqa is orphaned (notorch.eye / torch.diag / torch.diag_embedcall on that line). The opt-out is attached to nothing; remove it.[warning]— the noqa is redundant: the call on that line already pinsdevice=/dtype=(or chains.to(device=..., dtype=...)), so the noqa silences nothing. This typically follows a successful pin rollout -- remove the now-defunct opt-out to keep the source clean.[hint]-- advisory only (does NOT cause a non-zero exit): the cited rule ID does not match the file's path-resolved rule, or the rule ID is not in_RULE_PREFIXES(typo). The enforcer ignores cross-rule noqa already; the hint surfaces the stale scope assumption so a contributor can verify which rule the file actually lives in.
.pre-commit-config.yaml registers the doctor as a separate
repos: local hook entry (pin-rollout-drift-doctor) so its
diagnostics are distinct from the enforcer's TORxx output in
pre-commit logs.
Mechanical enforcement (TOR001 + TOR002 + TOR003)¶
A local pre-commit hook at scripts/check_test_fixture_pin_discipline.py
AST-scans every staged tests/**.py / examples/**.py /
notebooks/**.py / src/**.py file for un-pinned torch.eye(...) /
torch.diag(...) / torch.diag_embed(...) literals. The rule ID is
resolved per file path via POSIX path-component matching
(_rule_id_for_path in the script), so a file like
examples/tests/helper.py lands under TOR002 (the examples
directory component is the first match), not TOR001:
TOR001— files undertests/(the original tests-only scope).TOR002— files underexamples/ornotebooks/.TOR003— files undersrc/(production loss fixtures plus thealgorithms/,metrics/,ensemble/,utils/,losses/helpers that emit the same fixtures internally;.pre-commit-config.yamlregisters a third hook entry withfiles: '^src/.*\.py\$').
# noqa precedence contract: a # noqa: TOR00x comment on a line
silences only the matching rule ID — # noqa: TOR001 does NOT silence
a violation routed to TOR002 or TOR003. The order in
_RULE_PREFIXES matters: the script iterates path components in order
and returns the first component whose name matches (so a relative path
examples/tests/helper.py lands under TOR002, not via nested tests
substring). An absolute path with a pre-project-root src/ segment
(/home/user/src/torchregress/tests/foo.py) WILL route to TOR003
because src is matched first by the ABS path-component walk; callers
should normalize absolute paths to project-relative before relying on
the rule ID.
.pre-commit-config.yaml registers three repos: local: hook entries,
each with its own rule ID, so pre-commit output surfaces which scope
each violation belongs to. The script emits
filename:lineno: torch.<func>() missing device= or dtype= kwarg
violations to stderr and exits with status 1; the message body embeds
the resolved rule ID so # noqa opt-outs must match (# noqa: TOR001,
# noqa: TOR002, or # noqa: TOR003).
Recognised canonical pin patterns:
- Direct kwarg (works for torch.eye, which natively supports the
kwargs): torch.eye(N, device=A.device, dtype=A.dtype)
- Chained .to(...) cast (the documented fallback for torch.diag
and torch.diag_embed, which do NOT accept those kwargs natively):
torch.diag(matrix).to(device=matrix.device, dtype=matrix.dtype)
Inline opt-out: a trailing # noqa: TOR001 (under tests/) or
# noqa: TOR002 (under examples/ or notebooks/) comment on the
offending line. Signature scope is intentionally narrow — only direct
torch.<func>(...) attribute access is scanned. Aliases
(t.eye(...)), imports (from torch import eye; eye(...)), and
**kwargs splats are flagged as unverifiable; opt-out with the
appropriate # noqa: TORxxx for the splat case if it provably carries
the kwargs.
Why ast rather than a custom ruff plugin: ruff is a Rust CLI and
is not importable as a Python module for plugin code; AST-based
analysis covers the rule completely without spawning an extra Rust
tool. Unit-tested in
tests/utils/test_check_test_fixture_pin_discipline.py (24 cases
covering direct-kwarg pin, chained .to(), scope filters, walk depth,
and rule-ID stability).
TL;DR for code review¶
When reviewing a loss change, look for:
- The matrix row for the changed symbol — confirm the test class actually enforces the changed invariant (not just instantiates the loss).
- If you can't find a row, add a dedicated test before merging; the
INDIRECT-only section flags where the gap lives. - Re-running
torchregress/scripts/revert_verify.pyafter a change gives empirical evidence the test discriminates the bug class the change risks.