Struct DoubleT
struct DoubleT {
factor: UnitStudentT,
idiosyncratic: UnitStudentT,
}Expand description
The double-t copula’s two unit-variance t distributions.
Fields§
§factor: UnitStudentT§idiosyncratic: UnitStudentTImplementations§
§impl DoubleT
impl DoubleT
fn new(factor_dof: f64, idiosyncratic_dof: f64) -> Self
fn breakpoints(
thresholds: &[f64],
sqrt_rho: f64,
denom: f64,
reach: f64,
) -> Vec<f64>
fn breakpoints( thresholds: &[f64], sqrt_rho: f64, denom: f64, reach: f64, ) -> Vec<f64>
The factor line’s breakpoints, passive and sorted: the factor’s bulk
and each threshold’s transition window, each cut at centre ± {1, 2, 4, 6}·scale, and a geometric ladder ±6·4ᵏ out to reach and
past every window.
A t factor’s tails are too heavy for the Gaussian’s truncation at ±8,
and a small correlation puts a name’s transition far out in them
(C/√ρ ≈ −40 for a 1bp default probability at 5%) — so the grid
follows the thresholds. The cuts are set by where the integrand stops
being analytic: the unit t density has poles at ±i·√(ν − 2), the
conditional probability at √(ν̄ − 2)·w off the real axis about its
centre C/√ρ, w = √(1−ρ)/√ρ. Gauss–Legendre on one panel across
[−6, 6] converges only as fast as that pole’s distance allows
(it lost 2e-8 of a t₃’s mass); on panels no wider than the distance it
is exact to rounding. Past the windows the integrand is a product of
power-law tails, resolved on panels whose ends are within a factor of
four.
fn grid(&self, points: &[f64]) -> Vec<(f64, f64)>
fn grid(&self, points: &[f64]) -> Vec<(f64, f64)>
The factor grid over the panels the breakpoints cut, (m, dm·f_M(m))
pairs: Σ wᵢ·g(mᵢ) ≈ E[g(M)].
fn lifts<R: Scalar>(&self, marks: Option<(R, R)>) -> Option<NuLifts>
fn lifts<R: Scalar>(&self, marks: Option<(R, R)>) -> Option<NuLifts>
The ν-lifts marks needs, if any.
fn conditional_marked<R: Scalar>(
&self,
threshold: R,
sqrt_rho: R,
denom: R,
m: R,
marks: Option<(R, R)>,
lifts: Option<NuLifts>,
) -> R
fn conditional_marked<R: Scalar>( &self, threshold: R, sqrt_rho: R, denom: R, m: R, marks: Option<(R, R)>, lifts: Option<NuLifts>, ) -> R
The name’s conditional default probability at factor m, the
idiosyncratic ν lifted by marks.
fn latent<R: Scalar>(
&self,
grid: &[(f64, f64)],
x: R,
sqrt_rho: R,
denom: R,
) -> (R, R)
fn latent<R: Scalar>( &self, grid: &[(f64, f64)], x: R, sqrt_rho: R, denom: R, ) -> (R, R)
The latent variable’s CDF H(x) and density h(x) over a grid.
fn latent_marked<R: Scalar>(
&self,
grid: &[(f64, f64)],
x: R,
sqrt_rho: R,
denom: R,
(df, di): (R, R),
lifts: NuLifts,
) -> (R, R)
fn latent_marked<R: Scalar>( &self, grid: &[(f64, f64)], x: R, sqrt_rho: R, denom: R, (df, di): (R, R), lifts: NuLifts, ) -> (R, R)
latent with both degrees of freedom lifted: the
idiosyncratic CDF and density in ν, and each factor weight w
corrected by w·(g_ν·Δν + ½(g_νν + g_ν²)·Δν²). The corrections are
summed apart and are zero-valued, so the value is the unmarked sum’s.
fn threshold<R: Scalar>(
&self,
pd: R,
sqrt_rho: R,
denom: R,
marks: Option<(R, R)>,
) -> (R, Vec<(f64, f64)>)
fn threshold<R: Scalar>( &self, pd: R, sqrt_rho: R, denom: R, marks: Option<(R, R)>, ) -> (R, Vec<(f64, f64)>)
The default threshold C = H⁻¹(pd) and the grid it was solved on.
Newton from Φ⁻¹(pd) (X has unit variance), safeguarded by a
bracket, passively to rounding, the grid following the iterate’s
transition window; then two Newton steps in the mode on the final
grid. The passive residual is at rounding level, so the value does not
move, and each step doubles the orders of the implicit derivatives
∂C/∂pd, ∂C/∂ρ it carries — two give three.
fn capped_loss<R: Scalar>(
&self,
pd: R,
lgd: R,
cap: f64,
rho: R,
marks: Option<(R, R)>,
) -> R
fn capped_loss<R: Scalar>( &self, pd: R, lgd: R, cap: f64, rho: R, marks: Option<(R, R)>, ) -> R
The double-t LHP expected capped loss E[min(L, K)], as the
Gaussian’s capped_loss: K below the kink
m* = (C − √(1−ρ)·F_Z⁻¹(K/lgd))/√ρ, in closed form K·F_M(m*), and
the smooth piece above it on the panels past the kink, the first
starting at the kink so its nodes move with it in the mode. A cap at
or above lgd is never reached: the loss is lgd·pd, exactly the
marginal the threshold was solved to.