Repository navigation
Conversation
Would you mind marking these as drafts when this is the case? It's difficult to tell from the PR listing what is ready to review at the moment... |
Sure. I had not thought some of these PRs as drafts although they are based on other PRs, but I can do that. I don't know will happen now that @SteveBronder stacked them. Claude did warn that using github stacking can cause difficulties. |
|
Actually now that @SteveBronder stacked this PRs, you can easily see in the PR listing a small stack symbol and 1/2 or 2/2, so all with 2/2 require that some other PR is merged first. @WardBrian, do you still want that I change all 2/2:s in stacks to drafts? |
This PR is based on #3437 and must be merged after it.
This PR improves the speed of
beta_binomial_cdf,beta_binomial_lcdfandbeta_binomial_lccdf. The speed-up is from 1.3x to 176x.This was assisted by Claude
Summary
Motivation to speed-up comes from comments outside of gtihub issues. For example, in the forum thread Beta binomial truncated takes 1000x more time than the non truncated version (2021), a truncated model with
beta_binomial_lcdftook 193 s, and the same model without truncation took 1.5 s.With #3437,
beta_binomial_lcdfandbeta_binomial_lccdfevaluate a terminating 3F2 series withN - nterms (for thelcdfwhere the cdf is below 1/2, also the mirrored series withn + 1terms), and its two shape derivatives withgrad_F32;beta_binomial_cdfisexp(beta_binomial_lcdf(...)). These loops work in log scale withexpandlogcalls in every term, and most calls sum nearly the whole polynomial. A call withvarshapes takes about 0.1 ms atN = 1000and 0.9 ms atN = 10000. A series that needs more than1e5terms throws (the step limit ofhypergeometric_3F2).Most likely users use these cdfs this via brms. For the
beta_binomial()family, brms generatesbeta_binomial_lccdfandbeta_binomial_lcdfforcens()(R/stan-likelihood.R) and fortrunc()(same file); the brms tests check these calls (tests.stancode.R). Thezero_inflated_beta_binomialfamily builds itslcdfandlccdfonbeta_binomial_lccdf(fun_zero_inflated_beta_binomial.stan).This PR computes the cdfs as sums of the pmf,
pmf(k) = choose(N, k) B(k + alpha, N - k + beta) / B(alpha, beta):k = ndown to 0 and the upper tail fromk = n + 1up toN, in log scale with rescaling, by the term ratiopmf(k + 1) / pmf(k) = (N - k)(k + alpha) / ((k + 1)(N - k - 1 + beta)); the first term is the log pmf by Avoid the cancellation of lgamma, lbeta and digamma differences at large shape parameters #3434'sinternal::log_beta_ratio, which does not cancel at large shapes;pmf(k) d log pmf(k), withdigamma_diffat the first term and the recurrences1 / (k + alpha)and1 / (N - k - 1 + beta)after it;pmf(k + 1) / pmf(k) - 1has the sign ofA + B kwithA = N alpha - N + 1 - betaandB = 2 - alpha - beta, so the signs at the two ends of the remaining range show this. The sum then stops when a bound of the remaining terms is below1e-17of the partial sum. The pmf is unimodal foralpha + beta > 2and U-shaped foralpha + beta < 2; a U-shaped pmf can need all terms of a tail;n + 1below,N - nabove) is summed first. If it is at most 1/2, the other tail is its complement (log1m_exp), which then loses no digits. Else the other tail is summed too, and if that one is at most 1/2, the first tail is replaced by its complement: a sum near 1 that starts at a tiny term keeps the rounding error of the log of that term (about1e-13for a log of -500).No 3F2 function,
grad_F32or step limit is used. Most of the code changes are inprim/prob/beta_binomial_log_cdfs.hpp(new)prim/prob/beta_binomial_lcdf.hppprim/prob/beta_binomial_lccdf.hppIn addition
prim/prob.hppgets one include line, andbeta_binomial_cdfis unchanged. Tests add 157 lines.Accuracy on the grid of #3437 (3801 points per function:
Nfrom 1 to 117, allnup toN = 10and 10 values ofnabove, shapes from 0.1 to 1e4, and the point of #2508), against mpmath (sums of the pmf at 50 digits); before is #3437. Each cell: worst absolute error of the value /d/dalpha/d/dbeta:beta_binomial_cdfbeta_binomial_lcdfbeta_binomial_lccdfNeither version throws or returns
NaNon the grid. The largest value errors of thelcdfandlccdf(2.4e-13) are at log values near -620, a relative error of 4e-16, in both versions. Per point and function (the largest error over the value and both gradients, counted where it is above 1e-13), this PR is more than 2 times more accurate at 276 of the 11 403 cases and more than 2 times less accurate at 6.Beyond the grid:
beta_binomial_lccdf(1000 | 10000, 100, 30): the ccdf is practically 1; the value is-1.8e-71and the derivative with respect toalphais3.5e-71. Before, it returned-2.6e-12and-4.0e-12; this PR returns both with a relative error of 6e-13 (the absolute error of itslcdfat -163).N - nabove1e5: before, the functions threw where the series does not stop early, for example at(n, N, alpha, beta) = (50000, 200000, 0.5, 0.5)for all three functions (thelcdfevaluates theN - nseries before it chooses the mirror). This PR returns the values and gradients there (50 001 terms).Time per call with
varshapes (value and both gradients), Xeon E5-2680 v3, on the 60 points per function of the timing of #3437 (Nin {10, 100, 1000, 10000},nin {0.1, 0.5, 0.9}N, and the shape pairs (0.5, 2), (2, 3), (10, 10), (100, 30), (1000, 3000)), median of 5 repetitions per point, two interleaved rounds. Medians over the 45 calls perN(15 points, three functions); the last column is the geometric mean [min, max]:The smallest speed-up is 1.3x (
beta_binomial_lccdf(5 | 10, 100, 30): 1.56 us to 1.19 us). The time of this PR grows with the number of summed terms, about 30 ns per term; at these points that is mostly the shorter tail,0.1 Nterms.One smaller change:
beta_binomial_lccdfreturned 0 for the whole vector when one element hadn < 0; now that element contributes a term of 0 (log(1)), as an element withn >= Ndoes inbeta_binomial_lcdf.Limits that remain
nnear its middle, needs most of the shorter tail: 50 000 terms take about 1 to 1.5 ms.lcdfandlccdfvalues have the absolute error of the log pmf, about1e-16 |log pmf|(2.4e-13 at -620), as before.Nthe log pmf of the first term is a sum of terms of size up to1e5(for examplebinomial_coefficient_log(200000, 50000)), and every summed term inherits its rounding error. At(50000, 200000, 0.5, 0.5)that log pmf has an absolute error of 3.9e-12, and so has thelcdfvalue;beta_binomial_lpmfreturns the same log pmf. The gradients agree with mpmath to 6e-15.Tests
test/unit/math/rev/prob/beta_binomial_log_cdfs_test.cpp: values and log-scale gradients of the three functions at 15 points that cover every route (each tail first, each complement, both tails summed, and the complement of the second tail in both directions), the unimodal and the U-shaped pmf, an early stop at shapes (1000, 3000), the point of beta_binomial_lpmf is unstable for large shape arguments #2508, tails of2e-276,N = 1, anlccdfgradient of3.5e-71atN = 10000, andN = 200000. References: mpmath at 50 digits, sums of the pmf. Tolerances:1e-11relative for the values,1e-10relative tomax(1, |reference|)for the gradients. A second test checks vectors and the edge casesn < 0andn >= N.lcdforlccdfis between-7.8e-9and-2e-276(absolute errors from 1e-18 to 2.6e-12, above the relative tolerance), thelccdfgradient atN = 10000, the throw atN = 200000, and then < 0vector case.beta_binomialfamily andlarge_shapes_testpass, and so do the generated tests oftest/prob/beta_binomial(31 600 cases).Side Effects
None.
Release notes
Improved the speed of
beta_binomial_cdf,beta_binomial_lcdfandbeta_binomial_lccdfChecklist
Copyright holder: Aalto University
The copyright holder is typically you or your assignee, such as a university or company. By submitting this pull request, the copyright holder is agreeing to the license the submitted work under the following licenses:
- Code: BSD 3-clause (https://opensource.org/licenses/BSD-3-Clause)
- Documentation: CC-BY 4.0 (https://creativecommons.org/licenses/by/4.0/)
the basic tests are passing
./runTests.py test/unit)make test-headers)make test-math-dependencies)make doxygen)make cpplint)the code is written in idiomatic C++ and changes are documented in the doxygen
the new changes are tested