Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature/issue 962 bivar norm #1009

Closed
wants to merge 41 commits into from
Closed

Conversation

rtrangucci
Copy link
Contributor

@rtrangucci rtrangucci commented Aug 27, 2018

Summary

Adds std_binormal_lcdf and std_binormal_integral to compute the log-CDF and the CDF of the bivariate standard normal density.

Tests

Added tests for prim, rev, fwd, mix for std_binormal_integral and tests for prim, rev, mix for std_binormal_lcdf. Gradient and higher-order tests are in rev and mix for both functions.

./runTests.py test/unit/math/prim/scal/fun/std_binormal_integral_test.cpp 
./runTests.py test/unit/math/rev/scal/fun/std_binormal_integral_test.cpp 
./runTests.py test/unit/math/fwd/scal/fun/std_binormal_integral_test.cpp 
./runTests.py test/unit/math/mix/mat/fun/std_binormal_integral_test.cpp 

./runTests.py test/unit/math/prim/mat/fun/std_binormal_lcdf_test.cpp 
./runTests.py test/unit/math/rev/mat/fun/std_binormal_lcdf_test.cpp 
./runTests.py test/unit/math/mix/mat/fun/std_binormal_lcdf_test.cpp 

Side Effects

None

Checklist

  • Math issue Bivariate normal distribution #962

  • Copyright holder: Rob Trangucci

    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

    • unit tests pass (to run, use: ./runTests.py test/unit)
    • header checks pass, (make test-headers)
    • docs build, (make doxygen)
    • code passes the built in C++ standards checks (make cpplint)
  • the code is written in idiomatic C++ and changes are documented in the doxygen

  • the new changes are tested

@rtrangucci
Copy link
Contributor Author

@bob-carpenter this is ready for a review when you've got some time

Copy link
Contributor

@bob-carpenter bob-carpenter left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks. This is basically OK. I'd be a lot happier if all of the cut-and-paste code in the tests could be cosolidated.

stan/math/prim/mat/prob/std_binormal_lcdf.hpp Show resolved Hide resolved
stan/math/prim/mat/prob/std_binormal_lcdf.hpp Show resolved Hide resolved
const T_partials_return sqrt_one_minus_rho_sq = sqrt(one_minus_rho_sq);
const T_partials_return rho_times_y2 = rho_dbl * y2_dbl;
const T_partials_return y1_minus_rho_times_y2 = y1_dbl - rho_times_y2;
const bool y1_isfinite = std::isfinite(value_of_rec(y1_dbl));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Stan's is_finite will work directly on y1, I think---I'm not sure why there's a recursive value_of here.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think that Stan has an is_finite implementation that works for arbitrary types. Here's an implementation for vars: https://github.com/stan-dev/math/blob/502487c511594ccb93eb979df5b8fe163becb417/stan/math/rev/scal/fun/boost_isfinite.hpp but as far as I can tell this is it. I have the value_of_rec to handle the nested AD types cases.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for looking. That's a separate shortcoming of the math lib you don't need to address here.

if (!is_constant_struct<T_rho>::value)
ops_partials.edge2_.partials_[n]
+= cdf_ > 0 && y1_y2_arefinite && rho_lt_one
? inv_cdf_ * 0.5 / (stan::math::pi() * sqrt_one_minus_rho_sq)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Arithmetic is left associative, so all the constants should be pushed together, here (0.5 / ...).

? inv_cdf_ * 0.5 / (stan::math::pi() * sqrt_one_minus_rho_sq)
* exp(-0.5 / one_minus_rho_sq * y1_minus_rho_times_y2
* y1_minus_rho_times_y2
- 0.5 * y2_dbl * y2_dbl)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The -0.5 should go on the outside to save a multiplication,

exp(-0.5 * (square(y1_minus_rho_times_y2) / one_minus_rho_sq
            + square(y2_dbl)));

Copy link
Contributor Author

@rtrangucci rtrangucci Oct 2, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is square better to use than direct multiplication? i.e. x * x vs. square(x)?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Only if the variable can be an autodiff variable.

}
};

// vector<Row Vector>, real
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These should also be templatable. No big deal if you don't combine, but it's easier to maintain with fewer cut-and-paste functions.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, I'm OK templating these tests more. I did so for the copula PR, so redoing these should be easier.

template <typename T>
inline T operator()(
const Eigen::Matrix<T, Eigen::Dynamic, 1>& inp_vec) const {
vector<Matrix<T, Dynamic, 1>> y;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These four lines of code are repeated other than for type, so they should be pullable into a function.

};

// Row Vector, double
struct RV_D_std_binorm_lcdf {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Consolidate vetor and row vector versions using templating.

}
};

// double vector<Row Vector>, real
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Basically, way too many of these. Figure out how to consolidate using templates if at all possible.

If not, document the scheme up top.

vector<Eigen::Matrix<T, Eigen::Dynamic, 1>>& y, T& rho) {
int cntr = 0;
for (int i = 0; i < N_y; ++i) {
Eigen::Matrix<T, Eigen::Dynamic, 1> el(2);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

At the very least, these repeated pieces need to be turned into functions.

Does the y need to be passed in here as an argument since it's just being constructed? How about returning it rather than passing it in?

@syclik
Copy link
Member

syclik commented Feb 3, 2019

Closing due to inactivity.

@syclik syclik closed this Feb 3, 2019
@syclik syclik deleted the feature/issue-962-bivar-norm branch September 15, 2022 14:10
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

6 participants