Improve Numerical Stability of Bernoulli CDF functions
Summary
This PR updates the Bernoulli CDF functions (_cdf, _lcdf, and _lccdf) to operate on the log scale as much as possible, to avoid issues with underflow and resolution around 1
Tests
Additional mix/prob tests have been added to ensure that the gradients aren't impacted (prim behaviour covered by the distribution tests)
Side Effects
N/A
Release notes
Improved numerical stability of Bernoulli CDF functions
Checklist
-
[x] Math issue #2783
-
[x] Copyright holder: Andrew Johnson
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/)
-
[x] the basic tests are passing
- unit tests pass (to run, use:
./runTests.py test/unit) - header checks pass, (
make test-headers) - dependencies checks pass, (
make test-math-dependencies) - docs build, (
make doxygen) - code passes the built in C++ standards checks (
make cpplint)
- unit tests pass (to run, use:
-
[x] the code is written in idiomatic C++ and changes are documented in the doxygen
-
[x] the new changes are tested
@andrjohns: please let me know when this is ready to review and merge. Thanks!
Thanks @bob-carpenter! This is ready for another look. I've updated the vectorisation by adding a prim implementation of the select function that is currently used by the OpenCL code for the same purpose (ternary operations that can be agnostic between scalar and Eigen inputs)
@SteveBronder when you have a minute (no rush at all), can you have a look at this PR? It involves re-implementing the the OpenCL code's select function, so would be great to have eyes on from someone that knows how it should be behaving
@bob-carpenter are you able to re-review this?
@SteveBronder are you able to double check the opencl select code?
dismiss the closed/reopened, I hit the trackpad on my laptop by accident
Thanks for the heads up. I just dismissed my review so that someone else could review it. I still don't feel I understand our new C++ conventions well enough to review PRs.
Sorry didn't have time today but Tuesday I can look at this
@SteveBronder I'll add an any() function, since I agree that would be super handy. Should I open a separate PR for the select() and any() functions and tests, or are you happy for me to include them in this one?
I'll update this PR once the helper functions from #2852 have been added and merged
@SteveBronder would you mind having another look at this when you get a minute? No rush
develop tests have been failing in the distribution tests since this was merged (https://jenkins.flatironinstitute.org/blue/organizations/jenkins/Stan%2FMath/detail/develop/194/pipeline/500)
I'm guessing this is due to -DSTAN_TEST_ROW_VECTORS which we don't use in CI for PRs
In file included from test/prob/bernoulli/bernoulli_cdf_00000_generated_ffv_test.cpp:3:
In file included from ./test/prob/test_fixture_distr.hpp:4:
In file included from ./stan/math/mix.hpp:4:
In file included from ./stan/math/mix/meta.hpp:6:
In file included from ./stan/math/fwd/core.hpp:4:
In file included from ./stan/math/fwd/core/fvar.hpp:4:
In file included from ./stan/math/prim/meta.hpp:72:
In file included from ./stan/math/prim/meta/append_return_type.hpp:4:
In file included from ./stan/math/prim/fun/Eigen.hpp:22:
In file included from lib/eigen_3.4.0/Eigen/Dense:1:
In file included from lib/eigen_3.4.0/unsupported/Eigen/../../Eigen/Core:295:
lib/eigen_3.4.0/Eigen/src/Core/PlainObjectBase.h:970:7: error: static_assert failed "INVALID_MATRIX_TEMPLATE_PARAMETERS"
EIGEN_STATIC_ASSERT((EIGEN_IMPLIES(MaxRowsAtCompileTime==1 && MaxColsAtCompileTime!=1, (int(Options)&RowMajor)==RowMajor)
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
lib/eigen_3.4.0/Eigen/src/Core/util/StaticAssert.h:33:40: note: expanded from macro 'EIGEN_STATIC_ASSERT'
#define EIGEN_STATIC_ASSERT(X,MSG) static_assert(X,#MSG);
^ ~
lib/eigen_3.4.0/Eigen/src/Core/Map.h:159:30: note: in instantiation of member function 'Eigen::PlainObjectBase<Eigen::Array<stan::math::var_value<double, void>, 1, -1, 0, 1, -1> >::_check_template_params' requested here
PlainObjectType::Base::_check_template_params();
^
./stan/math/rev/core/arena_matrix.hpp:62:9: note: in instantiation of member function 'Eigen::Map<Eigen::Array<stan::math::var_value<double, void>, 1, -1, 0, 1, -1>, 0, Eigen::Stride<0, 0> >::Map' requested here
: Base::Map(
@andrjohns are you able to take a look at this soon? Otherwise I think we may need to revert this to unblock our CI
Ah damn, yeah I'll have a look now