Skip to main content

gam_models/
transformation_normal.rs

1//! Conditional transformation model: estimate h(y|x) such that h(Y|x) ~ N(0,1).
2//!
3//! Given a response variable y and covariates x with a pre-built covariate design
4//! operator, this family estimates a smooth monotone transformation h(y | x) mapping
5//! the conditional distribution of Y|x onto a standard normal.
6//!
7//! The response-direction basis is `[1, I_1(y), ..., I_K(y)]`, tensored with an
8//! arbitrary covariate design operator. Column 0 is an unconstrained location
9//! component `b(x)`. The I-spline columns are direct non-negative shape
10//! functions `α_k(x)`, giving the SCOP representation
11//! `h(y, x) = b(x) + ε·(y−median_y) + Σ_k I_k(y) α_k(x)` and
12//! `h'(y, x) = ε + Σ_k M_k(y) α_k(x)`. Monotonicity is exact:
13//! the fixed derivative floor `ε` keeps the change-of-variables log-density
14//! away from the `log(0)` singularity, while the non-negative M-spline basis
15//! and the factored Khatri-Rao cone `α_k(x_i) >= 0` supply the learned shape.
16//!
17//! The log-likelihood per observation is the finite-support normalized
18//! change-of-variables density for a standard normal target:
19//!
20//!   ℓ_i = -½ h_i² + log(h'_i) - log(Φ(h_U(x_i)) - Φ(h_L(x_i)))
21//!
22//! where `h_i = b(x_i) + ε·(y_i−median_y) + Σ_k I_k(y_i) α_k(x_i)`
23//! and `h'_i = ε + Σ_k M_k(y_i) α_k(x_i)`. The endpoint normalizer is
24//! required because the I-spline response basis saturates at finite support
25//! values rather than mapping onto the full real line.
26
27mod alo_replay;
28mod endpoint_normalizer;
29
30// Shared imports re-exported so every concern submodule pulls them through
31// `use super::*;` without re-listing. `pub(crate)` lets the child globs see them.
32pub use alo_replay::{
33    TransformationNormalAloRowGeometry, TransformationNormalAloRowInput,
34    transformation_normal_alo_row_geometry,
35};
36pub(crate) use endpoint_normalizer::{
37    LogNormalCdfDiffDerivatives, endpoint_chain_first, endpoint_chain_fourth,
38    endpoint_chain_second, endpoint_chain_third, log_normal_cdf_diff,
39    log_normal_cdf_diff_derivatives,
40};
41
42pub(crate) use crate::custom_family::{
43    BlockWorkingSet, BlockwiseFitOptions, CustomFamily, CustomFamilyBlockPsiDerivative,
44    CustomFamilyHyperLayout, CustomFamilyJointHyperModeSelection,
45    CustomFamilyPsiDerivativeOperator, CustomFamilyWarmStart, ExactNewtonJointGradientEvaluation,
46    ExactNewtonJointHessianWorkspace, FamilyEvaluation, JointHessianSourcePreference,
47    MaterializablePsiDerivativeOperator, MaterializationIntent, ParameterBlockSpec,
48    ParameterBlockState, PenaltyMatrix, SharedCustomFamilyHyperLayout,
49    evaluate_custom_family_joint_hyper_best_mode_shared, fit_custom_family,
50    fit_custom_family_fixed_log_lambdas_from_mode_selection,
51    fit_custom_family_user_fixed_log_lambdas_from_mode_selection,
52};
53pub(crate) use crate::fit_orchestration::drivers::{
54    ExactJointEfsEvaluation, ExactJointEvaluation, ExactJointHyperSetup, SpatialFitProvenance,
55    freeze_term_collection_from_design, optimize_spatial_length_scale_exact_joint,
56    spatial_length_scale_term_indices,
57};
58pub(crate) use crate::exact_mode_branch::ExactCoefficientModeBranch;
59pub(crate) use crate::inference::model::{
60    TRANSFORMATION_SCORE_PIT_CLIP_EPS, TransformationScoreCalibration,
61};
62pub(crate) use crate::model_types::UnifiedFitResult;
63pub(crate) use crate::penalized_projection::solve_penalizedweighted_projection;
64pub(crate) use crate::probability::standard_normal_quantile;
65pub(crate) use crate::spatial_psi_bridge::build_block_spatial_psi_derivatives;
66pub(crate) use gam_linalg::faer_ndarray::{fast_ab, fast_abt, fast_atb};
67pub(crate) use gam_linalg::matrix::{
68    DenseDesignMatrix, DenseDesignOperator, DesignMatrix, FiniteSignedWeightsView, LinearOperator,
69    PsdWeightsView, SymmetricMatrix, dense_rowwise_kronecker,
70};
71pub(crate) use gam_problem::{
72    ExactNewtonJointPsiSecondOrderTerms, ExactNewtonJointPsiTerms, ExactNewtonJointPsiWorkspace,
73};
74pub(crate) use gam_terms::basis::initializewiggle_knots_from_seed;
75pub(crate) use gam_terms::basis::{
76    BasisOptions, Dense, KnotSource, create_basis, create_ispline_derivative_dense,
77    ispline_function_penalties,
78};
79pub(crate) use gam_terms::smooth::{
80    SpatialLengthScaleOptimizationOptions, SpatialLogKappaCoords, TermCollectionDesign,
81    TermCollectionSpec,
82};
83// #1521: relocated DOWN into gam_terms::smooth (was drivers::build_term_collection_design).
84pub(crate) use gam_problem::{
85    DriftDerivResult, HyperOperator, ProjectedFactorCache, ProjectedFactorKey,
86};
87pub(crate) use gam_runtime::resource::{MatrixMaterializationError, ResourcePolicy};
88pub(crate) use gam_terms::smooth::build_term_collection_design;
89pub(crate) use ndarray::{Array1, Array2, ArrayView1, ArrayView2, ArrayViewMut2, s};
90pub(crate) use std::cell::RefCell;
91pub(crate) use std::sync::{Arc, Mutex, OnceLock};
92
93mod config;
94mod custom_family;
95mod error;
96mod family;
97mod fit;
98mod kronecker_design;
99mod operators;
100mod penalty_scaling;
101mod psi_operator;
102mod response_basis;
103mod scop_curvature;
104mod scop_density;
105mod scop_psi;
106mod warm_start;
107
108pub use config::*;
109pub use error::*;
110pub use family::*;
111pub use fit::*;
112pub(crate) use kronecker_design::*;
113pub(crate) use operators::*;
114pub(crate) use penalty_scaling::*;
115pub use psi_operator::*;
116pub use response_basis::effective_response_num_internal_knots;
117pub(crate) use response_basis::{
118    assert_rowwise_kronecker_dimensions, build_response_basis, response_endpoint_value_bases,
119    response_floor_offsets,
120};
121pub use scop_density::*;
122pub(crate) use warm_start::*;
123
124#[cfg(test)]
125mod tests;