1#ifndef _BBM_INVGAMMA_H_
2#define _BBM_INVGAMMA_H_
22 namespace inverse_gamma {
26 template<
typename T,
typename Mask>
27 inline T eq21(
const T& a,
const T& p,
const T& q,
const T& gamma,
const T& b, Mask todo)
30 if(bbm::none(todo))
return 0;
34 Mask mask = todo && ((
b*q > 1e-8) && (q > 1e-5));
36 if(bbm::any(mask)) u =
bbm::select(mask, bbm::pow(p * gamma*a, 1/a),
u);
37 if(bbm::any(todo)) u =
bbm::select(todo, bbm::exp((-q / a) - std::numbers::egamma), u);
40 return (u / (1 - (u / (a+1))));
46 inline T eq22(
const T& ,
const T& b)
48 T t = bbm::exp(-std::numbers::egamma - b);
49 T
u = t * bbm::exp(t);
56 inline T eq23(
const T& a,
const T& y)
58 T
u =
y - ((1-a) * bbm::log(y));
59 return y - ((1-a) * bbm::log(u)) - bbm::log(1 + ((1-a)/(1+
u)));
65 inline T eq24(
const T& a,
const T& y)
67 T
u =
y - ((1-a) * bbm::log(y));
68 return y - ((1-a) * bbm::log(u)) - bbm::log(
bbm::poly(u, (2-a)*(3-a), 2*(3-a), 1) /
bbm::poly(u, 2, (5-a), 1));
73 inline T eq25(
const T& a,
const T& y)
78 T c1 = (a-1) * bbm::log(y);
79 T c2 = (a-1) * (1+c1);
80 T c3 = (a-1) *
bbm::poly(c1, 0.5*(3*a-5), (a-2), -0.5);
81 T c4 = (a-1) *
bbm::poly(c1, (11*a2 - 46*a + 47) / 6.0, (a2 - 6*a + 7), -0.5*(3*a-5), 1.0/3.0);
82 T c5 = (a-1) *
bbm::poly(c1, (25*a3 - 195*a2 + 477*a - 379) / 12.0, (2*a3 - 25*a2 + 72*a - 61) * 0.5, (-3*a2 + 13*a - 13), (11*a - 17) / 6.0, -0.25);
85 return y +
bbm::poly( bbm::rcp(y), c1, c2, c3, c4, c5);
90 inline T eq32(
const T& p,
const T& q)
92 T t =
bbm::select(p < 0.5, bbm::sqrt(-2*bbm::log(p)), bbm::sqrt(-2*bbm::log(q)));
93 T s = t -
bbm::poly(t, 3.31125922108741, 11.6616720288968, 4.28342155967104, 0.213623493715853) /
bbm::poly(t, 1, 6.61053765625462, 6.40691597760039, 1.27364489782223, 0.3611708101884203e-1);
99 inline T eq31(
const T& a,
const T& p,
const T& q)
102 T sqrta = bbm::sqrt(a);
105 a - 1.0/3.0 + 16/(810*a),
106 sqrta - 7/(36*sqrta) - 433/(38880*a*sqrta),
108 1/(36*sqrta) + 256/(38880*a*sqrta),
119 inline T eq33(
const T& a,
const T& y,
const T& w)
121 T
u =
y + ((a-1) * bbm::log(w)) - bbm::log(1 + (1-a)/(1+w));
122 return y + ((a-1) * bbm::log(u)) - bbm::log(1 + (1-a)/(1+
u));
128 template<
size_t N,
typename T>
129 inline T Sn(
const T& x,
const T& a,
const T& tolerance=0)
133 auto mask = (partial > tolerance);
136 for(
size_t i=1; i <= N && bbm::any(mask); ++i)
142 mask = (partial > tolerance);
151 template<
size_t N,
typename T>
152 inline T Fn(
const T& x,
const T& a,
const T& v,
const T& tolerance=0)
154 return bbm::exp((v + x - bbm::log(Sn<N>(x,a,tolerance)))/a);
160 inline T eq35(
const T& a,
const T& p,
const T& w)
162 T
v = bbm::log(p) + bbm::lgamma(a+1);
164 T u1 = Fn<0>(w, a, v);
165 T u2 = Fn<1>(u1, a, v);
166 T u3 = Fn<2>(u2, a, v);
167 T
z = Fn<3>(u3, a, v);
176 inline T eq36(
const T& a,
const T&p,
const T& z)
178 T lnSn = bbm::log( Sn<100>(z, a, T(1e-4)) );
179 T
v = bbm::log(p) + bbm::lgamma(a + 1);
180 T zbar = bbm::exp((v + z - lnSn) / a);
181 T result = zbar * (1 - (a * bbm::log(zbar) -
z -
v + lnSn) / (a - zbar));
191 inline T eq3(
const T& a,
const T& x,
const T& lg)
193 return bbm::exp(-x - lg + bbm::log(x)*a);
199 inline T eq4(
const T& a,
const T& x,
const T& lg)
202 T delta = lg - ((a - 0.5)*bbm::log(a)) + a - 0.5*bbm::log(2.0*std::numbers::pi);
203 T
phi = lambda - 1 - bbm::log(lambda);
204 return bbm::sqrt(0.5*a/std::numbers::pi) * bbm::exp(-a*phi - delta);
209 inline T R(
const T& a,
const T& x,
const T& lg)
211 return bbm::select(a < 20, eq3(a,x,lg), eq4(a,x,lg));
217 template<
typename T,
typename Mask>
218 inline T a_less_one(
const T& a,
const T& p,
const T& q, Mask todo, Mask& )
221 if(bbm::none(todo))
return 0;
228 Mask mask = todo && ((
b > 0.6) || (b >= 0.45 && a >= 0.3));
230 T result =
bbm::select(mask, eq21(a,p,q,gamma,b,mask), 0);
231 if(bbm::none(todo))
return result;
234 mask = todo && ((a < 0.3) && (b >= 0.35));
236 if(bbm::any(mask)) result =
bbm::select(mask, eq22(a,b), result);
237 if(bbm::none(todo))
return result;
241 mask = todo && ((
b >= 0.15) || (a >= 0.3));
243 if(bbm::any(mask)) result =
bbm::select(mask, eq23(a,y), result);
244 if(bbm::none(todo))
return result;
247 mask = todo && (
b > 0.1);
249 if(bbm::any(mask)) result =
bbm::select(mask, eq24(a,y), result);
250 if(bbm::none(todo))
return result;
260 template<
typename T,
typename Mask>
261 inline T p_greater_half(
const T& a,
const T& q,
const T& w, Mask todo, Mask& )
264 if(bbm::none(todo))
return 0;
267 Mask mask = todo && (w < 3*a);
270 if(bbm::none(todo))
return result;
273 T D = bbm::max(a*(a-1), 2);
274 T lg = bbm::lgamma(a);
275 T lb = bbm::log(q) + lg;
277 mask = todo && (lb <= -D*2.3);
279 if(bbm::any(mask)) result =
bbm::select(mask, eq25(a,-lb), result);
280 if(bbm::none(todo))
return result;
290 template<
typename T,
typename Mask>
291 inline T p_less_half(
const T& a,
const T& p,
const T& w, Mask todo, Mask& converged)
294 if(bbm::none(todo))
return 0;
297 Mask mask = todo && (w < 0.15*(a+1));
299 if(bbm::any(mask))
z =
bbm::select(mask, eq35(a,p,w), z);
302 mask = todo && (
z < 0.01*(a+1) || z > 0.7*(a+1));
304 converged |= (
z <= 0.002*(a+1));
306 if(bbm::none(todo))
return result;
317 template<
typename T,
typename Mask>
318 inline T a_greater_one(
const T& a,
const T& p,
const T& q, Mask todo, Mask& converged)
321 if(bbm::none(todo))
return 0;
327 Mask mask = todo && (a >= 500 && bbm::abs(1-w/a) < 1e-6);
331 if(bbm::none(todo))
return result;
334 mask = todo && (p > 0.5);
336 result =
bbm::select(mask, p_greater_half(a,q,w,mask,converged), result);
337 if(bbm::none(todo))
return result;
340 result =
bbm::select(todo, p_less_half(a,p,w,todo,converged), result);
358 template<
typename T,
typename Mask>
359 inline T estimate(
const T& a,
const T& p,
const T& q, Mask mask, Mask& converged)
364 auto mask1 = mask && (a == 1);
366 if(bbm::any(mask1)) result =
bbm::select(mask1, -bbm::log(q), result);
367 if(bbm::all(mask1))
return result;
370 auto mask2 = mask && (a < 1);
371 result =
bbm::select(mask2, a_less_one(a, p, q, mask2, converged), result);
372 if(bbm::all(mask1 || mask2))
return result;
375 auto mask3 = mask && (a > 1);
376 result =
bbm::select(mask3, a_greater_one(a, p, q, mask3, converged), result);
392 template<
typename T,
typename Mask,
size_t NUM_ITR=3>
393 inline T inverse(
const T& a,
const T& p,
const T& q, Mask mask)
396 if(bbm::none(mask))
return 0;
399 Mask converged =
false;
400 auto x = estimate(a, p, q, mask, converged);
401 T lg = bbm::lgamma(a);
404 for(
size_t itr=0; itr < NUM_ITR && !bbm::all(converged); ++itr)
408 T t =
bbm::select(p <= 0.5, (bbm::get<"p">(pq) - p), (q - bbm::get<"q">(pq))) /
r;
409 T w = 0.5 * (a - 1 -
x);
412 auto m = (bbm::abs(t) <= 0.1) && (bbm::abs(w*t) <= 0.1);
431 template<
typename TA,
typename TP>
434 using result_t =
decltype(a + p);
435 auto mask = (a > 0) && (p > 0);
436 return bbm::detail::inverse_gamma::inverse(result_t(a), result_t(p), result_t(1-p), mask);
446 template<
typename TA,
typename TQ>
449 using result_t =
decltype(a + q);
450 auto mask = (a > 0) && (q > 0);
451 return bbm::detail::inverse_gamma::inverse(result_t(a), result_t(1-q), result_t(q), mask);
Packet-type friendly implementation of:
constexpr decltype(auto) b(bbm::color< T > &c)
Definition: color.h:24
constexpr decltype(auto) r(bbm::color< T > &c)
Definition: color.h:18
T & phi(vec2d< T > &v)
Definition: spherical.h:39
constexpr decltype(auto) u(bbm::vec2d< T > &v)
Definition: vec.h:37
constexpr decltype(auto) y(bbm::vec3d< T > &v)
Definition: vec.h:23
constexpr decltype(auto) z(bbm::vec3d< T > &v)
Definition: vec.h:26
constexpr decltype(auto) v(bbm::vec2d< T > &v)
Definition: vec.h:40
constexpr decltype(auto) x(bbm::vec3d< T > &v)
Definition: vec.h:20
Definition: aggregatebsdf.h:29
auto gamma_p_inv(const TA &a, const TP &p)
the inverse of the normalized upper incomplete gamma function
Definition: invgamma.h:432
constexpr auto select(MASK &&mask, const A &a, const A &b)
Definition: backbone.h:255
auto gamma_q_inv(const TA &a, const TQ &q)
the inverse of the normalized lower incomplete gamma function
Definition: invgamma.h:447
auto tgamma(const TA &a, const TX &x)
Unnormalized incomplete upper gamma function.
Definition: gamma.h:532
constexpr auto poly(T &&x, T0 &&c0, Ts &&... c)
Compute a polynomial .
Definition: poly.h:35
auto gamma_pq(const TA &a, const TX &x)
Normalized incomplete upper and lower gamma function.
Definition: gamma.h:593
Compile time polynomial using Horner's method.