Thoughts
This does not really respond to Peter's question, but I think the current distribution tests are overkill. They take forever and don't catch bugs very efficiently.
Currently, we are testing all combinations var and double (possibly in vectors) for all of the arguments, and I guess soon for the various fvar types. I think we could get away with just testing that each distribution works when all of its arguments are simultaneously of type T.
This would not catch bugs where, in the normal distribution example, y is a double vector, mu is a var vector, and sigma is a double, etc. But all those combinations are really just exercising the type promotion stuff, which is something that could be (and hopefully is) done more directly with unit tests. And I think after this release comes out, we should switch to C++11 and be using auto internally inside the distributions, so that the scope for such bugs is a lot narrower.
Maybe it is worthwhile to make sure the compiler is instantiating all the various combinations of arguments correctly, but that could be done much more quickly by putting those in the -fsyntax-only pile.
Ben
On Wed, Jun 11, 2014 at 11:47 AM, Ben Goodrich <goodri...@gmail.com> wrote:This does not really respond to Peter's question, but I think the current distribution tests are overkill. They take forever and don't catch bugs very efficiently.
Sorry, Ben, but I'm not going to budge on testing our distributions.
1. They're not overkill. They're actually underkill. There are ways bugs can still get through.
2. They take a long time, but it isn't forever. If you're talking about catching gradient bugs inefficiently, I've had to hunt down bugs in gradients of our distributions by creating a model, running it, comparing the model distribution to what we expect it to be, figuring out which distributions it calls, finding out the parameter values that get passed into each distribution, making sure those all work, just to identify which piece has a bug. To me, that's much more inefficient. By the way, to test a single distribution family, including all the compilation time, it takes under 2 mins. I tested the normal distribution.
3. It may be overkill to run it on each commit, although I don't think so. Unfortunately, testing traits and other templated code might have weird effects that we can't effectively "unit" test. Or fail to somehow. That really means we should be testing it somewhere else, but they're things that we're not even aware we should be testing.
I think that implies we're doing it wrong.
4. These tests have been really effective in stopping defective vectorized distributions. I don't think you, Ben, have written any, so I'm not sure you're aware of the complexity of the way we're writing the distributions now. When we used to use auto-diff directly, even over vector arguments, life was a lot easier and we really didn't need this type of testing. Now, with all the optimizations we've taken with the distributions, these test make it a lot easier and quicker to get out more correct code.
I'm not saying that this is the best way to do it. If you can come up with something better, please, implement it or let someone know.
Currently, we are testing all combinations var and double (possibly in vectors) for all of the arguments, and I guess soon for the various fvar types. I think we could get away with just testing that each distribution works when all of its arguments are simultaneously of type T.
Yes, we're testing every combination of var, double x scalar, vector, row_vector, array. We can't get away with just a single type of T. More below.
This would not catch bugs where, in the normal distribution example, y is a double vector, mu is a var vector, and sigma is a double, etc. But all those combinations are really just exercising the type promotion stuff, which is something that could be (and hopefully is) done more directly with unit tests. And I think after this release comes out, we should switch to C++11 and be using auto internally inside the distributions, so that the scope for such bugs is a lot narrower.
So, this is where you're missing the point of this testing. It isn't exercising the type promotion. We're actually doing things at the double level, for these distributions.
Suppose there's a 2 argument probability distribution. If the first is scalar and the second is scalar, that's easy. If they're both vectors, that's easy too. The gradients are as expected. If the first is scalar and the second is a vector, the expression graph is going to put the first on the expression graph multiple times and the derivative with respect to that first variable is going to have to be adjusted. Same with the second variable.
We've "caught" a lot of bugs using the framework. It's really easy, as a programmer, to get indexes mixed up and increment the wrong derivative. It's easy to forget to loop over both variables in the same way. It's easy to forget to compute a vector of things if you needed them. These things should be straight-forward, and were at one point before we started optimizing our distribution code. To do what we're doing, I'd argue we need something like our current framework or better.
Sorry, but I'm adamant about keeping this level of testing as a minimum for the distribution tests. If you know of a faster way to do it, please let us know. Just FYI, we test:
- all versions of the function are callable (this is the instantiation that you're talking about)
- values, specified by the test writer, are callable
- invalid values, specified by the test writer, throw exceptions
- make sure the proportionality constant is actually constant
- we test against finite diff, just in case we messed up our hand calculations- we test against a second implementation, usually pure auto-diff, specified in the test itself
- we test with each value repeated in a vector. We make sure the log prob value is a multiple of the first, we make sure the gradient value is a multiple when it's a scalar and the other arguments have been broadcast.
- we test with a 0 length vector
- Bob