-
-
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
Move size_zero() calls after other consistency checks (L-Z) #1761
Conversation
Awesome. I can review this tomorrow (Friday) after my wrist recovers from today's review :-) |
Jenkins Console Log Machine informationProductName: Mac OS X ProductVersion: 10.11.6 BuildVersion: 15G22010CPU: G++: Clang: |
This time the changes revealed a little bug in |
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.
This looks really great. I had some higher level comments on code organization, but this is good to merge as is. I'll leave it approved but won't merge it in case you want to act on some of the optional change requests. Otherwise, feel free to merge.
* @param name5 Variable name (for error messages) | ||
* @param x5 Variable to check for consistent size | ||
* @throw <code>invalid_argument</code> if sizes are inconsistent | ||
*/ |
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.
[comment]
Not a request for this PR, but this should all be rewritten for arbitrary sizes using parameter packs. It'd also greatly simplify the docs.
const size_t N = x.row(0).size(); | ||
const size_t M = x.col(0).size(); | ||
|
||
static const char *function = "bernoulli_logit_glm_rng"; |
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.
[optional]
Maybe we should sit down and scope out design for this. I'm happier with all the static constants being defined up top with the using statements. The reason is that they're both static and so don't execute anything at runtime. Putting them up front makes it easier to read the rest of the code that does get executed.
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.
Well I moved them closer to the consistency checks, which is the only place where they are used. The thing is that in this and the other glm functions, there are some constants to be computed before they can be used in the consistency checks...
const size_t N_instances = T_x_rows == 1 ? stan::math::size(y) : x.rows(); | ||
const size_t N_attributes = x.cols(); | ||
|
||
static const char *function = "normal_id_glm_lpdf"; |
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.
[optional]
Here's another that got moved too far down. In most instances, it's above the first executing statement.
if (!include_summand<propto, T_y, T_scale, T_shape>::value) { | ||
return 0; | ||
} | ||
|
||
T_partials_return logp(0); | ||
operands_and_partials<T_y, T_scale, T_shape> ops_partials(y, y_min, alpha); |
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.
[optional]
I would've moved the declaration for ops_partials
down, not up. The general principle is to declare local variables as close to where you use them as possible. The exception's all the static stuff, which is best to pull out of the way of what actually gets executed.
Not critical here, of course. I'm just trying to lay out the general principles of code organization with this PR as an example.
return 1.0; | ||
} | ||
|
||
T_partials_return P(1.0); |
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.
[optional]
This variable should be declared/defined just before the loop where it is used.
if (!include_summand<propto, T_log_rate>::value) { | ||
return 0.0; | ||
} | ||
|
||
T_partials_return logp(0.0); |
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.
[optional]
Same deal---move this to before where it gets used. The point is that you don't want to have to scan for where a variable is initialized when using it.
|
||
T_partials_return P(0.0); | ||
operands_and_partials<T_y, T_dof, T_scale> ops_partials(y, nu, s); | ||
|
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.
[optional]
I don't understand all the vertical space placement. I'd prefer to just get rid of almost all the blank vertical lines in this code. At the very least, we should get rid of spaces between contiguous blocks of variable declarations.
|
||
if (size_zero(y)) { | ||
return cdf; | ||
return 1.0; |
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.
This is much better than defining a variable and returning it. Plus, the partials return isn't even the right type---it'd just get promoted to the return type anyway.
[optional]
This can just be 1
---the compiler doesn't need the .0
unless there's a chance of ambiguity. It will promote appropriately at compile time.
if (size_zero(y)) { | ||
return lcdf; | ||
return 0; |
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.
like so!
I'll merge as I've spent enough time moving code up and down. I can see it's not perfect, but it's more consistent than ever. One day perhaps we'll revisit with a clear plan! :) |
've spent enough time moving code up and down. I can see it's not
perfect, but it's more consistent than ever.
That is why I marked the changes as optional :-). We decided not to hold
back solid improvements just because it'd be possible to make them better.
…On Fri, Mar 6, 2020 at 12:04 PM Marco Colombo ***@***.***> wrote:
Merged #1761 <#1761> into develop.
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
<#1761?email_source=notifications&email_token=AAZ2D73HS2VKDVHVLS3TFQDRGEUJBA5CNFSM4LCPDPKKYY3PNVWWK3TUL52HS4DFWZEXG43VMVCXMZLOORHG65DJMZUWGYLUNFXW5KTDN5WW2ZLOORPWSZGOXESANYQ#event-3106146018>,
or unsubscribe
<https://github.com/notifications/unsubscribe-auth/AAZ2D726JLSZ4GBLYGPLIODRGEUJBANCNFSM4LCPDPKA>
.
|
Summary
This is the second of two PRs that deals with moving the
size_zero
calls after the other consistency checks on function arguments. This covers all distributions with names starting L-Z. Closes #1757.This also improves the consistency of the placement of the using std:: statements and the declaration of the operands_and_partials variable. Following @bob-carpenter's suggestion in #1758 (comment), now all
using
statements are at the beginning of the function.I went back and reordered those also for the distributions done in #1758: given that these appear alphabetically first, the relevant changes concerning this PR appear after after some scrolling. If you want to isolate them from the rest, they are contained in the first commit.
Tests
No new tests.
Side Effects
None.
Checklist
Math issue Move size_zero checks after consistency checks on arguments #1757
Copyright holder: Marco Colombo
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