Skip to content

Conversation

@seantalts
Copy link
Member

@seantalts seantalts commented Aug 27, 2018

For background discussion, see this thread

Checklist

  • Copyright holder: (fill in copyright holder information)

    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: Columbia University
    - 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

@bob-carpenter
Copy link
Member

Please don't just refer to a thread in a PR description unless it's for background or something. Here it looks like the reviewer needs to review that thread in order to find the intent of the PR. I think the title's fine, and this can say "for background discussions, see this thread" to make it clear it's not necessary to read that thread to understand the PR.

I don't think the class should be named stan::math::finite as it has a very specific purpose.

Also, shouldn't this just be rolled into our basic is_finite tests for the vector case so that we don't have to go and change all our code one-off?

@seantalts
Copy link
Member Author

Fixed the text of the comment to make it clear that the thread was optional reading.

Unfortunately the class is already named that; this is just a specialization of it.

It is rolled into those checks via the template struct finite

Copy link
Member

@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.

Lots of changes requested for such a small PR!

#define STAN_MATH_PRIM_MAT_ERR_CHECK_FINITE_HPP

#include <Eigen/Dense>
#include <stan/math/prim/scal/err/check_finite.hpp>
Copy link
Member

Choose a reason for hiding this comment

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

This is not being used.

namespace math {
namespace {
template <typename T, int R, int C>
struct finite<Eigen::Matrix<T, R, C>, true> {
Copy link
Member

Choose a reason for hiding this comment

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

I'd prefer the name stan::math::internal::is_finite to indicate the behavior of the class.

static void check(const char* function, const char* name,
const Eigen::Matrix<T, R, C>& y) {
if (!y.allFinite())
domain_error(function, name, y, "is ", ", but must be finite!");
Copy link
Member

Choose a reason for hiding this comment

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

This degrades the error reporting so that it doesn't say which element. What does the print look like given that y is a matrix? Does it dump out the whole matrix?

What would you think of having a loop inside the test that picks out which element isn't finite? We don't care so much how long things take when they fail.


namespace stan {
namespace math {
namespace {
Copy link
Member

Choose a reason for hiding this comment

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

We decided to use the internal namespace rather than anonymous namespaces because the anonymous namespaces didn't seem to do what they advertised (file private scope). Here, it looks like you're specializing another structure in another anonymous namespace!

@seantalts
Copy link
Member Author

@bob-carpenter Would you mind reading my comment above about how finite is a pre-existing template struct (in that include file that is actually being used) and taking another look at the code with that information? Thanks.

@bob-carpenter
Copy link
Member

bob-carpenter commented Aug 27, 2018 via email

@seantalts
Copy link
Member Author

I didn't choose the namespace, either - I believe it has to be in the same namespace as the template struct it's specializing, right?

I don't see why the refactoring you want is associated with this pull request - I'm forced into this code in order to provide this functionality by the existing code. I can't do any of your suggestions without a larger refactoring effort. If you want to change the existing structure of how is_finite and finite etc are implemented that sounds like a great thing to write an issue about but do you think it's worth holding up this performance fix for the sake of that refactor?

@seantalts
Copy link
Member Author

I think it's harmful to have a policy to suggest that PRs fix all of the code and files that they merely touch or reference (versus just that the new code going in is a strict improvement upon the old). There are two reasons I believe that asking each PR to change all of its related code is harmful:

  1. Obviously this increases the burden on contributors a lot, but more importantly
  2. PRs are now much larger and mix many different intentions, so they become much more difficult to review and selectively merge or revert.

@bbbales2
Copy link
Member

I did a 3rd party review of this. I think the namespace thing needs to be a separate issue ("clean up anonymous namespaces in Stan"). These are clearly used elsewhere a lot.

The other two comments are worth addressing (unused include, error degradation)

@seantalts
Copy link
Member Author

The unused include is used to refer to the original finite struct that it is specializing. It doesn't compile without that.

The error degradation I missed before. I can have a loop on failure that picks out which elements are not finite I suppose.

@bbbales2
Copy link
Member

Lol, overload vs. specialization, man it's easy to miss the difference

@seantalts
Copy link
Member Author

I made an issue (#1006) and made the error message the same as in the previous code (thus also fixing the failing test, which looked for a specific error message). I think this is ready to go again (though feel free to wait until the tests pass).

@bob-carpenter
Copy link
Member

bob-carpenter commented Aug 28, 2018 via email

Copy link
Member

@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.

Looks good. Thanks for creating the separate issue for namespaces.

if (!value_of(y).allFinite()) {
for (int n = 0; n < y.size(); ++n) {
if (!(boost::math::isfinite)(y(n)))
domain_error_vec(function, name, y, n, "is ",
Copy link
Member

Choose a reason for hiding this comment

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

Thanks for refining the error message.

Another refactor we need to do is remove all these Boost things with the std lib. There's now std::isfinite in C++11.

@seantalts seantalts changed the title Use Eigen's allFinite to cut execution time of normal_glm (and others?) by 38% Use Eigen's allFinite to cut execution time of normal_glm (and others?) by 27% Aug 28, 2018
@seantalts
Copy link
Member Author

This is just waiting on a fix to the windows Jenkins box that's holding up all the tests.

@bgoodri
Copy link
Contributor

bgoodri commented Aug 29, 2018 via email

@seantalts seantalts merged commit 1875575 into develop Aug 29, 2018
@seantalts seantalts deleted the perf/isfinite branch August 29, 2018 21:09
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants