use kshana::raim::{
chi2_cdf, chi2_quantile, noncentral_chi2_cdf, normal_cdf, normal_quantile, pbias,
};
fn close(got: f64, want: f64, abstol: f64, reltol: f64, what: &str) {
let d = (got - want).abs();
assert!(
d <= abstol + reltol * want.abs(),
"{what}: kshana {got:.12e} vs SciPy {want:.12e} (|Δ|={d:.2e} > {abstol:.0e}+{reltol:.0e}·|want|)"
);
}
#[test]
fn chi2_cdf_matches_scipy() {
let cases: &[(f64, f64, f64)] = &[
(0.5, 1.0, 0.5204998778130466),
(1.0, 1.0, 0.6826894921370859),
(2.0, 1.0, 0.8427007929497151),
(3.841459, 1.0, 0.9500000053468042),
(5.0, 1.0, 0.9746526813225318),
(9.21034, 1.0, 0.9975934800522014),
(15.0, 1.0, 0.9998924888232705),
(30.0, 1.0, 0.9999999567953695),
(45.0, 1.0, 0.9999999999802965),
(0.5, 2.0, 0.22119921692859512),
(1.0, 2.0, 0.3934693402873665),
(2.0, 2.0, 0.6321205588285577),
(3.841459, 2.0, 0.8534999486480763),
(5.0, 2.0, 0.9179150013761012),
(9.21034, 2.0, 0.989999998140119),
(15.0, 2.0, 0.9994469156298522),
(30.0, 2.0, 0.9999996940976795),
(45.0, 2.0, 0.9999999998308102),
(0.5, 3.0, 0.08110858834532418),
(1.0, 3.0, 0.19874804309879915),
(2.0, 3.0, 0.42759329552912023),
(3.841459, 3.0, 0.7208995567559311),
(5.0, 3.0, 0.8282028557032668),
(9.21034, 3.0, 0.973378842463947),
(15.0, 3.0, 0.9981833510334277),
(30.0, 3.0, 0.9999986199429687),
(45.0, 3.0, 0.9999999990747298),
(0.5, 5.0, 0.007876706767370404),
(1.0, 5.0, 0.03743422675270362),
(2.0, 5.0, 0.15085496391539038),
(3.841459, 5.0, 0.42753956337478244),
(5.0, 5.0, 0.5841198130044919),
(9.21034, 5.0, 0.8990371607424125),
(15.0, 5.0, 0.9896376620842136),
(30.0, 5.0, 0.9999852514189616),
(45.0, 5.0, 0.9999999854912283),
(0.5, 8.0, 0.00013336965051406237),
(1.0, 8.0, 0.001751622556290824),
(2.0, 8.0, 0.01898815687615381),
(3.841459, 8.0, 0.1288632972898739),
(5.0, 8.0, 0.2424238668669339),
(9.21034, 8.0, 0.675136018272993),
(15.0, 8.0, 0.9408545401673161),
(30.0, 8.0, 0.9997886214965332),
(45.0, 8.0, 0.9999996320016274),
(0.5, 12.0, 2.7381356338284025e-07),
(1.0, 12.0, 1.4164937322342495e-05),
(2.0, 12.0, 0.000594184817581693),
(3.841459, 12.0, 0.013869813216517646),
(5.0, 12.0, 0.04202103819530614),
(9.21034, 12.0, 0.31513265527650813),
(15.0, 12.0, 0.7585635490297244),
(30.0, 12.0, 0.997207570667299),
(45.0, 12.0, 0.9999896949927592),
(0.5, 20.0, 2.0942485399973623e-13),
(1.0, 20.0, 1.709670029348906e-10),
(2.0, 20.0, 1.1142547833872071e-07),
(3.841459, 20.0, 3.330932704410381e-05),
(5.0, 20.0, 0.0002773520946208362),
(9.21034, 20.0, 0.019659538269975428),
(15.0, 20.0, 0.22359238698028533),
(30.0, 20.0, 0.9301463393005901),
(45.0, 20.0, 0.9988965307569716),
];
for &(x, k, want) in cases {
close(
chi2_cdf(x, k),
want,
1e-9,
1e-7,
&format!("chi2_cdf({x},{k})"),
);
}
}
#[test]
fn chi2_quantile_matches_scipy() {
let cases: &[(f64, f64, f64)] = &[
(0.9, 1.0, 2.705543454095418),
(0.95, 1.0, 3.8414588206941205),
(0.99, 1.0, 6.634896601021215),
(0.999, 1.0, 10.827566170662733),
(0.99999, 1.0, 19.511420964666268),
(0.9999999, 1.0, 28.373987362798125),
(0.9, 2.0, 4.605170185988092),
(0.95, 2.0, 5.99146454710798),
(0.99, 2.0, 9.21034037197618),
(0.999, 2.0, 13.815510557964274),
(0.99999, 2.0, 23.02585092994956),
(0.9999999, 2.0, 32.23619130296935),
(0.9, 3.0, 6.251388631170322),
(0.95, 3.0, 7.8147279032511765),
(0.99, 3.0, 11.34486673014437),
(0.999, 3.0, 16.26623619623813),
(0.99999, 3.0, 25.90174974567149),
(0.9999999, 3.0, 35.40575158101893),
(0.9, 5.0, 9.236356899781121),
(0.95, 5.0, 11.070497693516351),
(0.99, 5.0, 15.086272469388987),
(0.999, 5.0, 20.515005652432876),
(0.99999, 5.0, 30.85618994044592),
(0.9999999, 5.0, 40.86302108923746),
(0.9, 8.0, 13.361566136511728),
(0.95, 8.0, 15.507313055865453),
(0.99, 8.0, 20.090235029663233),
(0.999, 8.0, 26.12448155837614),
(0.99999, 8.0, 37.33159364443294),
(0.9999999, 8.0, 47.97246494259998),
(0.9, 12.0, 18.549347786703244),
(0.95, 12.0, 21.02606981748307),
(0.99, 12.0, 26.21696730553585),
(0.999, 12.0, 32.90949040736021),
(0.99999, 12.0, 45.076146524171676),
(0.9999999, 12.0, 56.43366123067437),
(0.9, 20.0, 28.411980584305635),
(0.95, 20.0, 31.410432844230925),
(0.99, 20.0, 37.56623478662506),
(0.999, 20.0, 45.31474661812586),
(0.99999, 20.0, 59.0445503868145),
(0.9999999, 20.0, 71.58930867948122),
];
for &(p, k, want) in cases {
close(
chi2_quantile(p, k),
want,
1e-6,
1e-6,
&format!("chi2_quantile({p},{k})"),
);
}
}
#[test]
fn normal_cdf_matches_scipy() {
let cases: &[(f64, f64)] = &[
(-3.0, 0.001349898031630093),
(-1.0, 0.15865525393145707),
(0.0, 0.5),
(1.0, 0.8413447460685429),
(1.959964, 0.9750000009035577),
(2.0, 0.9772498680518208),
(3.0, 0.9986501019683699),
(4.0, 0.9999683287581669),
(5.0, 0.9999997133484281),
(5.3267, 0.9999999499934271),
];
for &(z, want) in cases {
close(normal_cdf(z), want, 1e-9, 1e-7, &format!("normal_cdf({z})"));
}
}
#[test]
fn normal_quantile_matches_scipy() {
let cases: &[(f64, f64)] = &[
(0.5, 0.0),
(0.9, 1.2815515655446004),
(0.975, 1.959963984540054),
(0.99, 2.3263478740408408),
(0.999, 3.090232306167813),
(0.99999, 4.264890793923841),
(0.9999999, 5.199337582290661),
(0.99999995, 5.326723886278398),
(0.999999995, 5.73072886926708),
(0.9999999995, 6.109410191663287),
];
for &(p, want) in cases {
close(
normal_quantile(p),
want,
1e-4,
1e-6,
&format!("normal_quantile({p})"),
);
}
}
#[test]
fn noncentral_chi2_cdf_matches_scipy() {
let cases: &[(f64, f64, f64, f64)] = &[
(1.0, 1.0, 1.0, 0.4772498680518209),
(5.0, 1.0, 1.0, 0.8911774090184011),
(10.0, 1.0, 1.0, 0.9846858552504759),
(20.0, 1.0, 1.0, 0.9997418103789223),
(40.0, 1.0, 1.0, 0.99999994939973),
(1.0, 2.0, 4.0, 0.08189230363059402),
(5.0, 2.0, 4.0, 0.4958760288617339),
(10.0, 2.0, 4.0, 0.8314310864698685),
(20.0, 2.0, 4.0, 0.9894594878972105),
(40.0, 2.0, 4.0, 0.9999860484700465),
(1.0, 3.0, 9.0, 0.004766081943871699),
(5.0, 3.0, 9.0, 0.12312784130847292),
(10.0, 3.0, 9.0, 0.43321512043956073),
(20.0, 3.0, 9.0, 0.8845101735411985),
(40.0, 3.0, 9.0, 0.9990278644693452),
(1.0, 5.0, 16.0, 3.416191268071441e-05),
(5.0, 5.0, 16.0, 0.00737337689392745),
(10.0, 5.0, 16.0, 0.07974831517569392),
(20.0, 5.0, 16.0, 0.4981975393611857),
(40.0, 5.0, 16.0, 0.973100244008288),
(1.0, 3.0, 25.0, 4.9054252690677785e-06),
(5.0, 3.0, 25.0, 0.0011052916318189403),
(10.0, 3.0, 25.0, 0.018308683698619183),
(20.0, 3.0, 25.0, 0.22938493093002565),
(40.0, 3.0, 25.0, 0.8741537512138643),
(1.0, 8.0, 40.0, 2.0378777781848078e-11),
(5.0, 8.0, 40.0, 2.922341625994304e-07),
(10.0, 8.0, 40.0, 4.093966478244554e-05),
(20.0, 8.0, 40.0, 0.0060038094400554215),
(40.0, 8.0, 40.0, 0.28925765033413664),
];
for &(x, k, lam, want) in cases {
close(
noncentral_chi2_cdf(x, k, lam),
want,
1e-9,
1e-6,
&format!("ncx2_cdf({x},{k},{lam})"),
);
}
}
#[test]
fn pbias_matches_scipy_noncentrality() {
let cases: &[(f64, f64, f64, f64)] = &[
(6.634896601021215, 1.0, 0.001, 5.66606160971669),
(6.634896601021215, 1.0, 1e-07, 7.775166885741718),
(9.21034037197618, 2.0, 0.001, 6.009091854391071),
(9.21034037197618, 2.0, 1e-07, 8.136814116719645),
(11.34486673014437, 3.0, 0.001, 6.241795405377199),
(11.34486673014437, 3.0, 1e-07, 8.384444168227217),
(15.086272469388987, 5.0, 0.001, 6.580104500822473),
(15.086272469388987, 5.0, 1e-07, 8.747325265907646),
(19.511420964666268, 1.0, 0.001, 7.50740571963782),
(19.511420964666268, 1.0, 1e-07, 9.616510995662832),
(23.02585092994956, 2.0, 0.001, 7.807486418391467),
(23.02585092994956, 2.0, 1e-07, 9.926719718434315),
(25.90174974567149, 3.0, 0.001, 8.023757521044631),
(25.90174974567149, 3.0, 1e-07, 10.151806144388557),
(30.85618994044592, 5.0, 0.001, 8.352219555274482),
(30.85618994044592, 5.0, 1e-07, 10.495652642699305),
];
for &(t2, dof, p_md, want) in cases {
close(
pbias(t2, dof, p_md),
want,
1e-3,
1e-4,
&format!("pbias({t2},{dof},{p_md})"),
);
}
}