use num_traits::Float;
use strafe_type::{FloatConstraint, LogProbability64, Positive64, Probability64, Real64};
use super::{log_ppois, ppois};
use crate::{distribution::func::discrete_body, traits::DPQ};
pub fn qpois<PR: Into<Probability64>, PO: Into<Positive64>>(
p: PR,
lambda: PO,
lower_tail: bool,
) -> Real64 {
let p = p.into().unwrap();
qpois_inner(p, lambda, lower_tail, false)
}
pub fn log_qpois<LP: Into<LogProbability64>, P: Into<Positive64>>(
p: LP,
lambda: P,
lower_tail: bool,
) -> Real64 {
let p = p.into().unwrap();
qpois_inner(p, lambda, lower_tail, true)
}
fn qpois_inner<P: Into<Positive64>>(p: f64, lambda: P, lower_tail: bool, log: bool) -> Real64 {
let lambda = lambda.into().unwrap();
if !lambda.is_finite() {
return f64::nan().into();
}
if lambda == 0.0 {
return 0.0.into();
}
if p == f64::dt_0(lower_tail, log) {
return 0.0.into();
}
if p == f64::dt_1(lower_tail, log) {
return f64::infinity().into();
}
let mu = lambda;
let sigma = lambda.sqrt();
let gamma = 1.0 / sigma;
let ret = discrete_body(
mu,
sigma,
gamma,
p,
None,
lower_tail,
log,
&|p| ppois(p, lambda, lower_tail).into(),
&|p| log_ppois(p, lambda, lower_tail).into(),
);
ret.into()
}