Repository navigation
Conversation
Jenkins Console Log Machine informationDistributor ID: Ubuntu Description: Ubuntu 20.04.3 LTS Release: 20.04 Codename: focal CPU: Architecture: x86_64 CPU op-mode(s): 32-bit, 64-bit Byte Order: Little Endian Address sizes: 43 bits physical, 48 bits virtual CPU(s): 256 On-line CPU(s) list: 0-255 Thread(s) per core: 2 Core(s) per socket: 64 Socket(s): 2 NUMA node(s): 2 Vendor ID: AuthenticAMD CPU family: 23 Model: 49 Model name: AMD EPYC 7742 64-Core Processor Stepping: 0 Frequency boost: enabled CPU MHz: 1497.237 CPU max MHz: 3416.0681 CPU min MHz: 1500.0000 BogoMIPS: 4491.85 Virtualization: AMD-V L1d cache: 4 MiB L1i cache: 4 MiB L2 cache: 64 MiB L3 cache: 512 MiB NUMA node0 CPU(s): 0-63,128-191 NUMA node1 CPU(s): 64-127,192-255 Vulnerability Gather data sampling: Not affected Vulnerability Indirect target selection: Not affected Vulnerability Itlb multihit: Not affected Vulnerability L1tf: Not affected Vulnerability Mds: Not affected Vulnerability Meltdown: Not affected Vulnerability Mmio stale data: Not affected Vulnerability Old microcode: Not affected Vulnerability Reg file data sampling: Not affected Vulnerability Retbleed: Mitigation; untrained return thunk; SMT enabled with STIBP protection Vulnerability Spec rstack overflow: Mitigation; Safe RET Vulnerability Spec store bypass: Mitigation; Speculative Store Bypass disabled via prctl Vulnerability Spectre v1: Mitigation; usercopy/swapgs barriers and __user pointer sanitization Vulnerability Spectre v2: Mitigation; Retpolines; IBPB conditional; STIBP always-on; RSB filling; PBRSB-eIBRS Not affected; BHI Not affected Vulnerability Srbds: Not affected Vulnerability Tsa: Not affected Vulnerability Tsx async abort: Not affected Vulnerability Vmscape: Mitigation; IBPB before exit to userspace Flags: fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush mmx fxsr sse sse2 ht syscall nx mmxext fxsr_opt pdpe1gb rdtscp lm constant_tsc rep_good nopl xtopology nonstop_tsc cpuid extd_apicid aperfmperf rapl pni pclmulqdq monitor ssse3 fma cx16 sse4_1 sse4_2 x2apic movbe popcnt aes xsave avx f16c rdrand lahf_lm cmp_legacy svm extapic cr8_legacy abm sse4a misalignsse 3dnowprefetch osvw ibs skinit wdt tce topoext perfctr_core perfctr_nb bpext perfctr_llc mwaitx cpb cat_l3 cdp_l3 hw_pstate ssbd mba ibrs ibpb stibp vmmcall fsgsbase bmi1 avx2 smep bmi2 cqm rdt_a rdseed adx smap clflushopt clwb sha_ni xsaveopt xsavec xgetbv1 xsaves cqm_llc cqm_occup_llc cqm_mbm_total cqm_mbm_local clzero irperf xsaveerptr rdpru wbnoinvd amd_ppin arat npt lbrv svm_lock nrip_save tsc_scale vmcb_clean flushbyasid decodeassists pausefilter pfthreshold avic v_vmsave_vmload vgif v_spec_ctrl umip rdpid overflow_recov succor smca sev sev_es G++: g++ (Ubuntu 9.4.0-1ubuntu1~20.04) 9.4.0 Copyright (C) 2019 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. Clang: clang version 10.0.0-4ubuntu1 Target: x86_64-pc-linux-gnu Thread model: posix InstalledDir: /usr/bin |
|
@avehtari Hi! I was working on something related and took a similar, but a bit different approach. Here are some notes on how this can be further improved. I have this on a branch with Hessian tests (η from −800 to 720) and the Laplace test. I can fold it into this PR or rebase it as a follow-up once this is merged, or you can paste these to your agent. lmk what is a preferred option. :) CommentsChecked at 468ff26 with a probe (
Rows 1 and 6 are regressions of this branch (inf/inf; All of it goes away by never forming where log(1+e^u) is your |
|
@jachymb thanks for the review and suggestions. I'll check these |
…oose without rounding phi
|
@jachymb Rows 1 and 6 are regressions of this PR, and I could reproduce them. Your formulas are correct, and I used them. In the other PR checking your comments lead to additional findings, so I did ask Claude to check your comments, too, but I guess here the fix is the same as you had. Below there is one request for you
Row 7, the I also saw #3446 for the |
|
@avehtari could you resolve the conflicts in this PR to let jenkins run? |
|
conflict resolved (it was only in the include block) |
Jenkins Console Log Machine informationDistributor ID: Ubuntu Description: Ubuntu 20.04.3 LTS Release: 20.04 Codename: focal CPU: Architecture: x86_64 CPU op-mode(s): 32-bit, 64-bit Byte Order: Little Endian Address sizes: 52 bits physical, 57 bits virtual CPU(s): 192 On-line CPU(s) list: 0-191 Thread(s) per core: 2 Core(s) per socket: 48 Socket(s): 2 NUMA node(s): 2 Vendor ID: AuthenticAMD CPU family: 25 Model: 17 Model name: AMD EPYC 9474F 48-Core Processor Stepping: 1 Frequency boost: enabled CPU MHz: 1497.526 CPU max MHz: 4114.4229 CPU min MHz: 1500.0000 BogoMIPS: 7189.39 Virtualization: AMD-V L1d cache: 3 MiB L1i cache: 3 MiB L2 cache: 96 MiB L3 cache: 512 MiB NUMA node0 CPU(s): 0-47,96-143 NUMA node1 CPU(s): 48-95,144-191 Vulnerability Gather data sampling: Not affected Vulnerability Indirect target selection: Not affected Vulnerability Itlb multihit: Not affected Vulnerability L1tf: Not affected Vulnerability Mds: Not affected Vulnerability Meltdown: Not affected Vulnerability Mmio stale data: Not affected Vulnerability Old microcode: Not affected Vulnerability Reg file data sampling: Not affected Vulnerability Retbleed: Not affected Vulnerability Spec rstack overflow: Mitigation; Safe RET Vulnerability Spec store bypass: Mitigation; Speculative Store Bypass disabled via prctl Vulnerability Spectre v1: Mitigation; usercopy/swapgs barriers and __user pointer sanitization Vulnerability Spectre v2: Mitigation; Enhanced / Automatic IBRS; IBPB conditional; STIBP always-on; PBRSB-eIBRS Not affected; BHI Not affected Vulnerability Srbds: Not affected Vulnerability Tsa: Mitigation; Clear CPU buffers Vulnerability Tsx async abort: Not affected Vulnerability Vmscape: Mitigation; IBPB before exit to userspace Flags: fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush mmx fxsr sse sse2 ht syscall nx mmxext fxsr_opt pdpe1gb rdtscp lm constant_tsc rep_good amd_lbr_v2 nopl xtopology nonstop_tsc cpuid extd_apicid aperfmperf rapl pni pclmulqdq monitor ssse3 fma cx16 pcid sse4_1 sse4_2 x2apic movbe popcnt aes xsave avx f16c rdrand lahf_lm cmp_legacy svm extapic cr8_legacy abm sse4a misalignsse 3dnowprefetch osvw ibs skinit wdt tce topoext perfctr_core perfctr_nb bpext perfctr_llc mwaitx cpb cat_l3 cdp_l3 hw_pstate ssbd mba perfmon_v2 ibrs ibpb stibp ibrs_enhanced vmmcall fsgsbase bmi1 avx2 smep bmi2 erms invpcid cqm rdt_a avx512f avx512dq rdseed adx smap avx512ifma clflushopt clwb avx512cd sha_ni avx512bw avx512vl xsaveopt xsavec xgetbv1 xsaves cqm_llc cqm_occup_llc cqm_mbm_total cqm_mbm_local user_shstk avx512_bf16 clzero irperf xsaveerptr rdpru wbnoinvd amd_ppin cppc arat npt lbrv svm_lock nrip_save tsc_scale vmcb_clean flushbyasid decodeassists pausefilter pfthreshold avic v_vmsave_vmload vgif x2avic v_spec_ctrl vnmi avx512vbmi umip pku ospke avx512_vbmi2 gfni vaes vpclmulqdq avx512_vnni avx512_bitalg avx512_vpopcntdq la57 rdpid overflow_recov succor smca fsrm flush_l1d debug_swap G++: g++ (Ubuntu 9.4.0-1ubuntu1~20.04) 9.4.0 Copyright (C) 2019 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. Clang: clang version 10.0.0-4ubuntu1 Target: x86_64-pc-linux-gnu Thread model: posix InstalledDir: /usr/bin |
Fixes #3153. Fixes #1578. Addresses #2508 partially.
This PR improves
beta_binomial_lpmf,beta_binomial_cdf,beta_binomial_lcdf,beta_binomial_lccdf,beta_neg_binomial_lpmf,beta_neg_binomial_cdf,beta_neg_binomial_lcdf,beta_neg_binomial_lccdf,neg_binomial_lpmf,neg_binomial_2_lpmf,neg_binomial_2_log_lpmf,neg_binomial_2_log_glm_lpmf,dirichlet_multinomial_lpmf,lkj_corr_lpdf,lkj_corr_cholesky_lpdf,lkj_cov_lpdf,student_t_lpdf,multi_student_t_lpdf,multi_student_t_cholesky_lpdf,yule_simon_lpmf,yule_simon_cdf,yule_simon_lcdf,yule_simon_lccdf, and the derivatives oflbeta.Claude assisted with this PR.
Summary
Several distributions form a difference
f(x + k) - f(x). Herefislgamma,lbetaordigamma,xis a shape, concentration, dispersion or degrees-of-freedom parameter, andkis a count or an offset. Whenxis large, the two terms are large and almost equal, and the difference keeps no correct digits. In the values the terms have the size ofx, so the error is abouteps * x. In the gradients the terms are aboutlog(x), and a model with the parameter on the log scale multiplies the error byx.In the model of #3153,
beta_binomial_lpmf(57 | 117, s, s)withs = exp(lc) / 2, develop returns a log probability 81 too high fromlc = 42, and its gradient inlcis 0 or noise fromlc = 24. Warmup then finds a flat plateau and cannot leave it. With this PR the value is within2.3e-14of the exact value and the gradient within3.7e-14, forlcfrom 0 to 44.lcd/dlcFrom
lc = 34, the exact values are below the rounding error of any form (about2e-14), because57 log p + 60 log qis about -81 there.#2508 reports the same defect:
beta_binomial_lpmf(500 | 1000, s, s)fors = 0.5e10, 0.5e13, 0.5e19. Develop is wrong by5.3e-8,2.8e-4and693there, and returns+689.47at the largests. This PR fixes all three points, and they are rows of thebeta_binomial_lpmftest. This PR does not close #2508, because the comment there aboutbeta_binomial_lcdf(3 | 10, 298.3, 146.75)(NaN, exact-3.93335) has a different cause:hypergeometric_3F2does not stop at the zero term of the terminating series3F2({1, 302.3, -6}; {5, -151.75}; 1)(exact17.63), and a later0 * infgivesNaN. #3437 repairs that and closes #2508.#1578 reports wrong derivatives of
neg_binomial_lpmffor largealpha. Its example (n = 0,alpha = 1e10 + 1,beta = 0.8) is already correct on develop, because develop no longer uses the Poisson approximation that the issue describes. This PR repairs the loss that remains ind/dalpha = digamma(alpha + n) - digamma(alpha) + log(beta / (1 + beta)). The loss matters when the meanalpha / betastays fixed: the error ofalpha * d/dalphaon develop reaches 3.0 atalpha = 1e15, and with this PR it is1e-14(rows of the new large-shape test).The same root cause is in more functions. This PR repairs:
beta_binomial_lpmfbeta_neg_binomial_lpmfneg_binomial_lpmf,neg_binomial_2_lpmf,neg_binomial_2_log_lpmfneg_binomial_2_log_glm_lpmfdirichlet_multinomial_lpmflkj_corr_lpdf,lkj_corr_cholesky_lpdfyule_simon_lccdf(and_cdf,_lcdfin relative terms)beta_binomial_{cdf,lcdf,lccdf}inforNaNbeta_neg_binomial_{cdf,lccdf}student_t_lpdfnugradient 0.14multi_student_t_lpdf,multi_student_t_cholesky_lpdfnugradient 2e-7yule_simon_lpmflbeta(var,fvar), derivativeThe shape is
1e15for the first nine rows and at most1e15for the last four (nudecades forstudent_t_lpdf). "Log-shape gradient" isx * d/dx, the gradient that a sampler sees when the model parameter islog(x). All references are mpmath at 80 to 140 digits, and two independent routes agree:loggammafor the values, closed-formdigammadifferences andmp.difffor the gradients, and sums of the pmf for the cdfs.The four negative binomial functions also had two defects at other arguments: the value lost
phiat smallphi, and the GLM partials overflowed for a linear predictor above 709.8. This PR repairs both (items 5 and 6 of "Related defects fixed on the way").propto. In some of the new forms, a constant thatproptodrops cancels inside one expression against terms that depend on a parameter, so the code cannot skip it. For example,lbeta(n, alpha + 1)containslgamma(n). To keep theproptobehavior, the code adds such constants back with the opposite sign:lgamma(n)inyule_simon_lpmf, andlgamma(y + 1),phi log(phi)(dataphi) andy theta(datax,alphaandbeta) inneg_binomial_2_log_glm_lpmf, also in OpenCL. For the GLM with dataphi, this brings back a rounding error of abouteps * phi log(phi)in theproptovalue. A probe of all 14 changed densities, with every combination of data and parameter arguments, matches theproptoand full values of develop at all 456 points on the current head, and a new test checksfull - proptoagainst the dropped terms.Most of the added source lines are in six files:
prim/fun/log_rising_factorial_ratio.hpp(new helpers)prim/fun/digamma_diff.hpp(new)log_beta_ratio(new)digamma_diff(new)opencl/kernel_generator/elt_function_cl.hpp(registrations)student_t_lpdf(series), CPU and OpenCLEach of the other 26 distribution files (CPU, OpenCL and the GLM kernel) adds 3 to 61 lines.
What this PR adds
digamma_diff(x, d) = digamma(x + d) - digamma(x), a new function inprim/fun. It is public, but not exposed in the Stan language, because 19 distribution files and the derivatives oflbetause it.log_rising_factorialcan use it in a follow-up. It has three paths:dfrom 0 to 8 (a count):sum_{j < d} 1 / (x + j). All terms are positive, andd = 1gives exactly1 / x;x < 10andd >= 10: the plain difference, which loses only a few ulp there (the result is at least 0.72 anddigamma(x) <= 2.25);log1p(d / y)plus the asymptotic series, with the differencesy^-2i - (y + d)^-2iformed as(u - v) h_iso that nothing cancels.Over 7 281 points,
xfrom1e-3to1e18anddfrom1e-6to1e7, the error is at most 4.2 ulp; the plain difference reaches6.5e16ulp. The function is vectorized and works with all autodiff types through generic arithmetic, withexpect_adtests. The PR also adds an OpenCL device function with the same paths and a kernel-generator registration.internal::log_rising_factorial_ratio,internal::log_beta_ratioand their helpers inprim/fun/log_rising_factorial_ratio.hpp. They write eachlgammathroughlgamma_stirling_diff, so that the terms linear in the arguments cancel exactly, and they form the rest without cancellation: thex log1p(k / x) - kparts are split off fork < x, and the integer parts are added exactly.log_beta_ratio(alpha, beta, n, m) = lbeta(alpha + n, beta + m) - lbeta(alpha, beta)selects this form or the plainlbetaform by the size of their terms. The Stirling form has rounding errors of the size ofn + m, and thelbetaform of the size of the smaller shape. Without the selection, points withN = 1e6and one small shape lost up to 4e-11 where develop was correct.The
revandfwdderivatives oflbeta. The partial in an argument of at least 10 is now-digamma_diff(a, b). Below 10 it staysdigamma(a) - digamma(a + b), and the two partials sharedigamma(a + b)as before.lbetaitself is accurate at large arguments, but its derivative had the same cancellation. So every model that callslbetawith a large parameter had inaccurate gradients, and so didmulti_student_t_lpdf, which gets itsnugradient by autodiff throughlbeta. Below 10 the plain difference has an absolute error of a feweps, which stays at the rounding level on the log scale too.Changes per function
beta_binomial_lpmf: value bylog_beta_ratio, partials bydigamma_diff.beta_neg_binomial_lpmf: value as-log(n) - lbeta(n, beta) + log((r)_n / (r + alpha + beta)_n) + log((alpha)_r / (alpha + beta)_r), partials bydigamma_diff.neg_binomial_lpmf:alphapartial bydigamma_diff. Thebetapartial termalpha / beta - alpha / (1 + beta)is nowalpha / beta / (1 + beta). The value termlchoose(n + alpha - 1, n)is now-lbeta(alpha, n + 1) - log(n + alpha).neg_binomial_2_lpmf,neg_binomial_2_log_lpmf:phipartial bydigamma_diff. The value termlchoose(n + phi - 1, n)is now-lbeta(phi, n + 1) - log(n + phi). Whenphiis autodiff,neg_binomial_2_lpmfevaluateslog(mu + phi)once: the value and thephipartial both read it, and the lazy expression computed thelogtwice per element. The results are bitwise identical.neg_binomial_2_log_glm_lpmf: value per instance as-lbeta(phi, y + 1) - log(y + phi) - y log1p_exp(log(phi) - theta) - phi log1p_exp(theta - log(phi)), the form ofneg_binomial_2_log_lpmf, instead ofphi log(phi) - lgamma(phi) + lgamma(y + phi) - (y + phi) log(mu + phi) + y theta. The partials do not formexp(theta). Withu = theta - log(phi)ande = exp(-|u|),mu / (mu + phi)is1 / (1 + e)foru > 0ande / (1 + e)otherwise, andphi / (mu + phi)is the other of the two. Thethetapartial isy - (y + phi) mu / (mu + phi), and thephipartial ismu / (mu + phi) - (y / phi) phi / (mu + phi) - log1p_exp(u) + digamma_diff(phi, y)(formulas from @jachymb's review). The value and the partials shareeandlog1p(e):log1p_exp(±u) = max(±u, 0) + log1p(e). With a scalarphiand a vectory, the terms that depend onyonly (lchoose,lgamma(y + 1)underpropto,digamma_diff(phi, y)) are evaluated once per distinct count, throughinternal::per_count_values, if the largest count is at most4 N + 64. This is in the CPU version only.dirichlet_multinomial_lpmf: partials bydigamma_diff.lkj_corr_lpdf(andlkj_corr_cholesky_lpdf,lkj_cov_lpdfthroughdo_lkj_constant): the constant is a sum oflgamma(x + k/2) - lgamma(x). Each term is nowlgamma(k/2) - lbeta(k/2, x), and the code sets theetapartial explicitly withdigamma_diff.yule_simon_{cdf,lcdf,lccdf}:lgamma(alpha + 1) + lgamma(n + 1) - lgamma(n + alpha + 1)is nowlog(n) + lbeta(n, alpha + 1); partial bydigamma_diff.yule_simon_lpmf: valuelog(alpha) + lbeta(n, alpha + 1); partial1 / alpha - digamma_diff(alpha + 1, n).beta_binomial_{cdf,lcdf,lccdf}: the leadinglbeta(nu, mu) - lbeta(alpha, beta)bylog_beta_ratio, the digamma differences bydigamma_diff.beta_neg_binomial_{cdf,lcdf,lccdf}: the leading term is the log pmf atn + 1, now computed as inbeta_neg_binomial_lpmf; partials bydigamma_diff.student_t_lpdf: unchanged fornu < 40. Fornu >= 40, the termslgamma((nu + 1) / 2) - lgamma(nu / 2) - log(nu) / 2anddigamma((nu + 1) / 2) - digamma(nu / 2)come from the asymptotic series inh = nu / 2,-log(2) / 2 - 1/(8h) + 1/(192h^3) - 1/(640h^5) + 17/(14336h^7) - 31/(18432h^9), and its derivative. Against mpmath, fromh = 20to1e15, the errors are at most 0.9 and 2.4 eps. The series is also cheaper than twolgammaor twodigammacalls.multi_student_t_lpdf,multi_student_t_cholesky_lpdf: the constantlgamma((nu + p) / 2) - lgamma(nu / 2)is nowlgamma(p / 2) - lbeta(p / 2, nu / 2). The cholesky version sets thenupartial withdigamma_diff(nu / 2, p / 2); the other version gets it throughlbeta.beta_binomial_lpmf,neg_binomial_lpmf,neg_binomial_2_lpmf,neg_binomial_2_log_lpmf,neg_binomial_2_log_glm_lpmf(prim file and kernel) andstudent_t_lpdfcompute the same formulas.Related defects fixed on the way
lkj_corr_lpdfdroppedd constant / d etaateta == 1.0. The special case foreta == 1returned the constant as a number without a derivative. Ateta = 1withK = 3and the matrix in the new test, develop returnsd/deta = -0.165; the exact value is1.2214.eta = exp(0) = 1is the value of a positive parameter at the default initialization.beta_binomial_lcdfcomputedlog(1 - C), withCthe complementary series. Where the cdf is small, this keeps no digits, and with the accurateCit can becomelogof a value at or below 0. WhereC > 1/2, the function now uses the mirror relation:X <= nif and only ifN - X > N - n - 1, andN - Xhas the distributionbeta_binomial(N, beta, alpha). That is the same series with the shapes swapped, without the complement. On develop this function returnedNaNat 16 of 81 test points and was wrong by up to 61. Now it has the accuracy of the series everywhere. Foralpha = 1exactly, the mirrored series is0 / 0at one term, so that case keepslog(1 - C).beta_binomial_lpmfdid not check0 <= n <= N. The code built the check but never computed its result, so the function never returnedLOG_ZERO. Withoutproptothe value was-infby accident (throughbinomial_coefficient_log), but with a nonzero gradient. Underproptoit was finite:-8.216forn = 6,N = 5in the new test. The CPU version returnsLOG_ZEROwithout a gradient, and now the OpenCL version does too.neg_binomial_2_log_glm_lpmfwith a scalaralphaand a vectorphifailed. The kernel decided fromalphainstead ofphiwhether to sum thephiderivative. It returned work-group sums where per-instance derivatives were necessary, and the gradient assignment threw a size mismatch. The decision now depends onphionly, and the kernel does not compute thephiderivative whenphiis data. A new test covers both mixed cases: scalaralphawith vectorphi, and vectoralphawith scalarphi.neg_binomial_lpmf,neg_binomial_2_lpmfandneg_binomial_2_log_lpmflostphiat smallphi. They computedlchoose(n + phi - 1, n)asbinomial_coefficient_log(n + phi - 1, n), which roundsphiinton + phi - 1. The value then has an error of abouteps * n / phi. Atn = 1000,phi = 1e-8, the error is 7.9e-7 (5.0e-9 inneg_binomial_lpmf). Atn = 1,phi = 1e-17, the value is-inf; the exact value is-39.1439. These three functions and the GLM, CPU and OpenCL, now use-lbeta(phi, n + 1) - log(n + phi), and the errors at these points are at most 5.3e-13. The partials were already correct, because they use the exactphi.neg_binomial_2_log_glm_lpmfpartials overflowed forthetaabove 709.8. On develop thethetapartialy - exp(theta) (y + phi) / (exp(theta) + phi)isNaNattheta = 720(inf / inf) and-infattheta = 709; the exact value is-1.5at both points (y = 5and 3,phi = 1.5). Theeform in "Changes per function" has no overflow, and its second derivative does not cancel. Aty = 1,phi = 0.07, thefvar<var>Hessian entry inthetais now-4.7225e-17attheta = 35(develop: 0) and-1.40777e-13attheta = 27(develop:-1.40970e-13).Speed
For
nu < 40,student_t_lpdfexecutes the same operations as develop plus one comparison (+2.4 % instructions for value and gradient). Fromnu = 40it executes fewer: -52 % instructions for value and gradient atnu >= 100, and the scalar value takes 0.35 times as long.Time ratio to develop for the other changed functions, at ordinary arguments (shapes below 10 unless stated). Median of 5 interleaved rounds on one whole node (AMD EPYC 9965, g++ 11.5,
-O2); the spread between rounds is at most 2.9 %, except 4.3 % for one develop row.neg_binomial,neg_binomial_2,neg_binomial_2_loggradient, counts 0 to 8neg_binomial_2gradient,phifrom 10 to 1e4, counts 0 to 8neg_binomial_2gradient, counts 9 to 100neg_binomial_2, 1000 counts from 0 to 20, onephibeta_binomialgradient,N = 20lbetagradient, both arguments below 10lbetagradient, one argument from 10 to 1000neg_binomial_2_log_glm_lpmfvalue, N = 1000, K = 5, counts with mean 3alpha,betaalpha,beta, scalarphiproptopropto, all 1000 counts distinctpropto, counts from 5000 to 5999alpha,beta, vectorphixWith a scalar
phi, the GLM evaluateslchoose,lgamma(y + 1)and the digamma difference once per distinct count. Where the counts rarely repeat, the forms that repair the GLM (items 5 and 6) make it slower than develop.Limits that remain, by a different cause
beta_binomial_{cdf,lcdf,lccdf}stop their3F2series at a term below1e-6. This leaves errors up to about1e-5in the gradients, and the functions returnNaNor throw at many ordinary arguments, for example atbeta = 1, atalpha + beta = 1and at the point in beta_binomial_lpmf is unstable for large shape arguments #2508. Fix and speed up the terminating 3F2 series of the beta_binomial cdfs #3437 repairs these.beta_neg_binomial_{cdf,lcdf,lccdf}stop their series at a term below1e-8. They throw from shape1e4and can take seconds per call.beta_neg_binomial_cdfandbeta_neg_binomial_lcdfstill form the complement1 - ccdf, so they are wrong where the cdf is small. With the more accurate log pmf of this PR,1 - ccdfrounds to exactly 0 where the cdf is below about1e-15.beta_neg_binomial_cdfthen returns 0 withNaNgradients (15 of 2352 points of a wide grid), where develop returns a wrong finite value with finite gradients. Compute the beta_neg_binomial cdfs from sums of the pmf #3441 replaces the series and the complement and repairs all of these.d/dalphaandd/dbeta, and autodiff formsalpha d/dalpha + beta d/dbetaoutside it. For tied shapes in numerical instability in beta_binomial_lpmf at large shape parameters #3153, the two products are-1.5and+1.5, and their sum is27 / exp(lc). Each partial is accurate to a fewepsof its own terms, so the sum is accurate to a fewepsof 1.5, not of its own size.neg_binomial_2_log_lpmfHessian has the quotient-rule cancellation of item 6 at large|eta|(NaNentries ateta = 720and-400,n = 3,phi = 0.07). Develop has the same defect. A follow-up PR can use theeform of the GLM there too.log_rising_factorialis stilllgamma(x + n) - lgamma(x). No Stan Math function calls it. A follow-up can use the new helpers there.Tests
test/unit/math/prim/fun/digamma_diff_test.cpp,test/unit/math/mix/fun/digamma_diff_test.cpp: special cases, exact finite sums, 17 mpmath values, the count path and the plain path (digamma_diff(x, 1) == 1 / xexactly fromx = 1e-300to1e300);expect_adat 8 points.test/unit/math/prim/prob/beta_binomial_test.cpp: values at the points of numerical instability in beta_binomial_lpmf at large shape parameters #3153 and beta_binomial_lpmf is unstable for large shape arguments #2508 and at large unequal shapes; the difference to the binomial limit atlc = 42.test/unit/math/rev/prob/beta_binomial_lpmf_test.cpp(new): log-shape gradients at 8 points; thelcgradient of the model in numerical instability in beta_binomial_lpmf at large shape parameters #3153 forlc = 16 ... 32. Fromlc = 34, develop returns exactly 0, which is within1e-13of the exact gradient, so a test there cannot see the defect.test/unit/math/rev/prob/large_shapes_test.cpp(new): 92 rows over the other functions, includingstudent_t_lpdf, bothmulti_student_tfunctions,yule_simon_lpmfandlbeta. For each function, the rows are points where develop was wrong by more than 100 times the tolerance, plus one point at a small shape where develop was correct. The rows include the four negative binomial functions atphi = 1e-8and1e-17and the GLM attheta = 720and709. The file also tests thelkj_corrgradient ateta = 1, andfull - proptoagainst the dropped terms forstudent_t_lpdf,yule_simon_lpmf,beta_neg_binomial_lpmfand three cases of the GLM.test/unit/math/rev/prob/neg_binomial_2_log_glm_lpmf_test.cpp: a vector call against the sum of single-instance calls, value and partials, with and withoutpropto, once with repeated counts (per-count path) and once with a count above4 N + 64.test/unit/math/opencl/rev/(six files), because the existing differential tests compare OpenCL with the CPU and cannot see an error that both share. The four negative binomial reference tests include the small-phiand large-thetarows. Also: a device-function test fordigamma_diff; a test thatbeta_binomial_lpmfgivesLOG_ZEROwithout a gradient fornoutside0...N, also underpropto; a test ofneg_binomial_2_log_glm_lpmfwith a scalaralphaand a vectorphi, and the reverse.The tests find the defect. With the 23 develop headers swapped in (21
prim/probfiles and therev/fwdlbeta), all 4 newbeta_binomialcases and both large-shape cases fail. The 3 old cases and theproptocase pass (theproptocase states the develop rule). With the branch headers restored, all tests pass again. In OpenCL, with the develop OpenCL files every new absolute-reference test fails (6 files), and so do the two new tests of related defects 3 and 4. Every old differential test passes, including theproptocomparisons of the GLM andstudent_t_lpdf, exceptopencl_matches_cpu_bigof the GLM. That test runs after the exception of defect 4 in the same binary, and the exception leaves the autodiff stack dirty. For items 5 and 6, I swapped in the negative binomial headers of the PR version before the review fixes (468ff26dbb): exactly the 10 new rows oflarge_shapes_test.cppfail (13 expectations), and each of the four OpenCL negative binomial suites fails only its reference test, at the new rows.Full suites. At
468ff26dbb, all unit tests of the touched functions pass (51 files:prim,rev,fwd,mix, includinglbeta,digamma_diff,student_t,multi_student_tandlkj_cov), and so do the generatedtest/probtests ofbeta_binomial,beta_neg_binomial,neg_binomial,neg_binomial_2,yule_simonandstudent_t(271 306 cases). The OpenCL suites of the six distributions,digamma_diff,lbetaand the kernel generator pass on a V100 (126 cases). The review fixes changed only the four negative binomial functions. At the current head, after the merge of developd12f488749, these pass: the 25 unit test files of the negative binomial family (including the Laplace tests that useneg_binomial_2_logand the newglm_forward_mode_tape_testfrom develop), the generatedtest/prob/neg_binomialandtest/prob/neg_binomial_2tests (23 490 cases), and the four OpenCL negative binomial suites (V100). Doxygen 1.9.7 reports no warnings at01c1a90f87.Side effects
None
Release notes
Improved stability of
beta_binomial_lpmf,beta_binomial_cdf,beta_binomial_lcdf,beta_binomial_lccdf,beta_neg_binomial_lpmf,beta_neg_binomial_cdf,beta_neg_binomial_lcdf,beta_neg_binomial_lccdf,neg_binomial_lpmf,neg_binomial_2_lpmf,neg_binomial_2_log_lpmf,neg_binomial_2_log_glm_lpmf,dirichlet_multinomial_lpmf,lkj_corr_lpdf,lkj_corr_cholesky_lpdf,lkj_cov_lpdf,student_t_lpdf,multi_student_t_lpdf,multi_student_t_cholesky_lpdf,yule_simon_lpmf,yule_simon_cdf,yule_simon_lcdf,yule_simon_lccdf, and the derivatives oflbeta.Checklist
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