38template <
typename Scalar>
40regularizedGammaP(std::type_identity_t<Scalar>
const & a, std::type_identity_t<Scalar>
const & x)
47 if (!(x < Eigen::NumTraits<Scalar>::infinity()))
49 return isNaN(x) ? x : Scalar(1);
51 using Literal =
typename Eigen::NumTraits<Scalar>::Literal;
52 Scalar
const epsilon = Scalar(Eigen::NumTraits<Scalar>::epsilon());
56 Scalar
const maxIterations =
57 Scalar(1000) + Scalar(2) * Eigen::numext::sqrt(Scalar(Scalar(-2) * a * Eigen::numext::log(epsilon)));
58 Scalar
const logPrefactor = Scalar(-x + a * Eigen::numext::log(x)) -
logGamma<Scalar>(a);
59 if (x < a + Scalar(1))
61 Scalar term = Scalar(1) / a;
64 scalarFromCount<Scalar>(n) < maxIterations && Eigen::numext::abs(term) > Eigen::numext::abs(sum) * epsilon;
67 term *= x / (a + Scalar(n));
70 Scalar
const p = sum * Eigen::numext::exp(logPrefactor);
71 return p < Scalar(1) ? p : Scalar(1);
74 Scalar
const tiny = Scalar((std::numeric_limits<Literal>::min)()) / epsilon;
75 Scalar b = x + Scalar(1) - a;
76 Scalar c = Scalar(1) / tiny;
77 Scalar d = Scalar(1) / b;
79 for (
int i = 1; scalarFromCount<Scalar>(i) < maxIterations; ++i)
81 Scalar
const an = -Scalar(i) * (Scalar(i) - a);
84 if (Eigen::numext::abs(d) < tiny)
89 if (Eigen::numext::abs(c) < tiny)
94 Scalar
const delta = d * c;
96 if (Eigen::numext::abs(Scalar(delta - Scalar(1))) <= epsilon)
101 Scalar
const p = Scalar(1) - Eigen::numext::exp(logPrefactor) * h;
102 return Scalar(0) < p ? p : Scalar(0);
121template <
typename Scalar>
123chiSquaredCdf(std::type_identity_t<Scalar>
const & x, std::type_identity_t<Scalar>
const & dof)
125 EMRYS_FILTER_ASSERT(dof > Scalar(0) &&
"the degrees of freedom must be positive");
126 return internal::regularizedGammaP<Scalar>(dof / Scalar(2), x / Scalar(2));
146template <
typename Scalar>
148chiSquaredQuantile(std::type_identity_t<Scalar>
const & probability, std::type_identity_t<Scalar>
const & dof)
150 EMRYS_FILTER_ASSERT(probability > Scalar(0) && probability < Scalar(1) &&
"the probability must be in (0, 1)");
151 EMRYS_FILTER_ASSERT(dof > Scalar(0) &&
"the degrees of freedom must be positive");
152 if (!(dof > Scalar(0)) ||
isNaN(probability))
154 return Eigen::NumTraits<Scalar>::quiet_NaN();
156 if (probability <= Scalar(0))
160 if (probability >= Scalar(1))
162 return Eigen::NumTraits<Scalar>::infinity();
164 Scalar
const epsilon = Scalar(Eigen::NumTraits<Scalar>::epsilon());
165 Scalar
const a = dof / Scalar(2);
166 Scalar
const logNormalizer = Scalar(a * Eigen::numext::log(Scalar(2))) +
logGamma<Scalar>(a);
167 Scalar lower = Scalar(0);
168 Scalar upper = dof < Scalar(1) ? Scalar(1) : dof;
183 if (lower == Scalar(0))
185 Scalar ratio = Scalar(0.5);
186 Scalar next = upper * ratio;
191 next = upper * ratio;
195 auto const middle = [&] {
196 return Scalar(2) * lower < upper && Scalar(0) < lower
197 ? Scalar(Eigen::numext::sqrt(lower) * Eigen::numext::sqrt(upper))
198 : Scalar((lower + upper) / Scalar(2));
201 Scalar step = upper - lower;
202 Scalar stepBefore = step;
203 for (
int i = 0; i < 200; ++i)
206 if (error < Scalar(0))
214 Scalar
const exponent = (a - Scalar(1)) * Eigen::numext::log(x) - x / Scalar(2) - logNormalizer;
215 Scalar
const density = Eigen::numext::exp(exponent);
218 Scalar next = x - error / density;
219 if (!(next > lower && next < upper)
220 || Eigen::numext::abs(Scalar(Scalar(2) * error)) > Eigen::numext::abs(Scalar(stepBefore * density)))
226 bool const converged = Eigen::numext::abs(step) <= Scalar(4) * epsilon * x;
The macros every header includes first.
Mathematical constants and scalar functions that work in every scalar type the library accepts,...
Scalar chiSquaredQuantile(std::type_identity_t< Scalar > const &probability, std::type_identity_t< Scalar > const &dof)
Definition ChiSquared.h:148
Scalar chiSquaredCdf(std::type_identity_t< Scalar > const &x, std::type_identity_t< Scalar > const &dof)
Definition ChiSquared.h:123
Scalar logGamma(std::type_identity_t< Scalar > const &x)
Definition Math.h:216
bool isNaN(T const &x)
Definition Math.h:329
bool isFinite(T const &x)
Definition Math.h:305