-
-
Notifications
You must be signed in to change notification settings - Fork 187
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
Check input conditions for log1m() before delegating to log1p(). #725
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for submitting a pull request! We really appreciate it, especially when it's actually fixing the doc too!!!
A couple changes:
- please use
check_less_or_equal()
for the check. It'll give a more consistent error message (and gives the ability to really refactor chunks at once). - Add a test in the
log1m_test.cpp
file that checks that the error message correctly sayslog1m
instead oflog1p
(since that's the purpose of this pull request). One (easier) way to do this is to use theEXPECT_THROW_MSG()
macro that's used in a test like this one: https://github.com/stan-dev/math/blob/develop/test/unit/math/rev/mat/err/check_nonzero_size_test.cpp#L34
stan/math/prim/scal/fun/log1m.hpp
Outdated
inline double log1m(double x) { return stan::math::log1p(-x); } | ||
inline double log1m(double x) { | ||
if (x > 1) | ||
domain_error("Error in function log1m(double)", "log1m(x)", x, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
rather than domain_error
, please use check_less_or_equal()
. See the source here: https://github.com/stan-dev/math/blob/develop/stan/math/prim/scal/err/check_less_or_equal.hpp
Also see tests for usage: https://github.com/stan-dev/math/blob/develop/test/unit/math/prim/scal/err/check_less_or_equal_test.cpp
Also, do you know if the code is has dual copyright ownership? |
Thanks for the very quick review! I've now used |
I've set the tests up very carefully to verify that the autodiff versions throw exceptions under the exact same conditions as the One option would be to change the |
@bob-carpenter, I think changing the
Agree? If so, I can help add a |
stan/math/prim/scal/fun/log1m.hpp
Outdated
*/ | ||
inline double log1m(double x) { return stan::math::log1p(-x); } | ||
inline double log1m(double x) { | ||
check_less_or_equal("log1m(x)", "x", x, 1); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
replace "log1m(x)"
with `"log1m". You'll need to update the test to match. (The rest of our error messages just have the function name followed by colon, no arguments in the function)
@sycklik Do you want to do this just here or for all the C++ built-in functions? We have the same behavior with Most of them have If you think it's worth doing just for this one function, then go ahead, but please leave an issue to fix the rest. This would also be a good time to add |
Here it is. I wish I could follow your discussion, but I'm finding it impenetrable at this stage. When you reach an agreement, if you think it's worth spending some time to guide me through, I'll be happy to give it a go. :) |
It's all about symbol resolution and it's pretty critical for the Stan math lib because we overload everything for autodiff types.
We use the namespace stan::math (in the sense of having a top-level using statement for it all), so all the symbols from that namespace are available.
std::log1p(double) is part of the standard template library. std::log1p(int) is not. It relies on automatic promotion of int to double. stan::math::log1p(stan::math::var) is part of Stan---it's what we use for automatic differentiation types.
Now the problem arises that if we see log1p(int), it's ambiguous. The int can be promoted to double to match std::log1p(double), or the int can be promoted to stan::math::var (because there's an implicit constructor stan::math::var(int)).
To disambiguate, we define stan::math::log1p(int), which is more specific than either std::log1p(double) or stan::math::log1p(stan::math::var).
Now the question is whether we want the exception behavior of log1p to match the standard library or match the rest of the Stan library.
If we want it to match the rest of the Stan library, we need to define `stan::math::log1p(double)` with the appropriate behavior. Then we need to make sure that `log1p(double)` calls stan::math::log1p rather than std::log1p.
That then introduces the headache that if we are in a scope that's using `std::log1p(double)`, we get an ambiguity with `stan::math::log1p(double)`.
So basically a huge headache.
It's further complicated by the existence of `::log1p(double)` in the top-level namespace in the old `.h` forms of the C headers for C++.
And further complicated still by the fact that C++ decided to leave the size (and hence ambiguity) of various declarations (like int and long) up to the compiler writer.
Hope that helps. If not, it's a bit of a roadmap for understanding symbol resolution in C++, which is super important with templating.
… On Jan 20, 2018, at 9:52 AM, Marco Colombo ***@***.***> wrote:
Here it is. I wish I could follow your discussion, but I'm finding it impenetrable at this stage. When you reach an agreement, if you think it's worth spending some time to guide me through, I'll be happy to give it a go. :)
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub, or mute the thread.
|
You should put this on the wiki if you have some spare time. Helpful read. |
@bob-carpenter: sorry about flip flopping. After giving it thought, I think we should hold off on changing behavior until our next major version (or some other major version). @mcol, I'm going to submit a pull request to help fix the behavior on the check. If we want to keep the current behavior the same, we want to only use that check function when the input is not |
remove POST_LDLIBS from multiple_translation_units and add OpenCL to the default compiler options Remove space before 'Darwin' in make file testing on travis remove everything but the OpenCL headers ...
I opened up a PR on @mcol's fork. When that gets merged, it should update this PR. |
Feature/mcol fix 681
That should be it, I believe. |
Thanks, @mcol. When it passes tests, we'll merge. |
On Jan 22, 2018, at 8:32 AM, Daniel Lee ***@***.***> wrote:
@bob-carpenter: sorry about flip flopping. After giving it thought, I think we should hold off on changing behavior until our next major version (or some other major version).
:-) We've been flip-flopping on this issue from the get go. In the past, it was largely driven by a desire to get things to compile with a bit less understanding of namespaces and includes and name resolution than we have now.
The new exception test framework makes sure the throws happen in the same place, which caught a lot of inconsistencies. So I've already changed behavior. But this time, I was aiming at matching the built-in behavior.
I don't think we need to wait for a major version to change this behavior. It is backward-compatibility breaking in cases where you really did want to propagate a NaN, but that's not a good practice because they can't be used with autodiff.
Long term, I now agree that we should just take over everything and throw exceptions.
@mcol, I'm going to submit a pull request to help fix the behavior on the check. If we want to keep the current behavior the same, we want to only use that check function when the input is not nan.
Thanks.
|
Having fixed the missing header issue, can this be merged now (the jenkins failure seems to be unrelated to this)? |
Sorry, but we want to fix tests before merging. Changing something like the boundary conditions on functions could affect the distribution tests. It looks like Jenkins hung up on something here. I no longer know offhand how to restart it and there's not an obvious button. I think @seantalts wrote some doc somewhere, but searching and the index on our top-level wiki leave me to this old page: https://github.com/stan-dev/stan/wiki/Jenkins |
http://discourse.mc-stan.org/t/new-jenkins-jobs-tutorial/2383 though most of this is using the old UI, which you can get to with the exit button I restarted the tests already. |
Interesting - the distribution tests failed again for this PR. I haven't seen this disconnect error yet on develop or other PRs. Can anyone run the distribution tests locally? I'm using my cores for another simulation, haha. I will also try running this again on Jenkins with lower N_TESTS and see if that helps. |
So it passed with N_TESTS=500 instead of 1000, but I don't have a good answer for why this PR increased the load on the C++ compiler. Curiously, the distribution test run for this PR didn't even seem to take any longer than a regular run with N_TESTS=1000. Should we merge? |
Submission Checklist
./runTests.py test/unit
make cpplint
Summary:
This attempts to fix issue #681. I went with using Stan's
domain_error()
function, but alternatively I could have used Boost'sraise_domain_error()
as inwhich would have produced a message closer to the current one. I decided against it because the message would still have to reference boost::math::log1p, which may be confusing.
Intended Effect:
Trying
stan::math::log1m(2.0f)
will print the following error:Copyright and Licensing
Please list the copyright holder for the work you are submitting (this will be you or your assignee, such as a university or company):
Marco Colombo, University of Edinburgh
By submitting this pull request, the copyright holder is agreeing to license the submitted work under the following licenses: