With this latest version you should be able to write:
v ~ normal(0,sqrt(sigmasq_u));
And get almost exactly the same performance without having to muck
about with the log probability directly.
Or, alternatively, if you really care about getting the most speed
possible leave the lp__ statements as they are and replace the loop
> sum_of_squares <- 0.0; // or sum(pow(v, 2)) may / should work
> for(i in 1:N) {
> sum_of_squares <- sum_of_squares + pow(v[i], 2);
>
> }
with
sum_of_squares <- dot_product(v,v);
which will be a fair bit faster than the loop, particularly for large N.
Cheers,
Marcus
On Tue, Sep 11, 2012 at 9:44 AM, Ben Goodrich <goodri...@gmail.com> wrote:
> If you want a little more juice, you can exploit the fact that
>
> u' * A_inv * u = u' * ( LA_inv * LA_inv' ) * u = (u' * LA_inv) * (LA_inv' *
> u) = v' v
>
> where LA_inv is the Cholesky factor of A_inv and v = LA_inv' * u . Thus, the
> lower triangle of LA_inv' is all zeros. Stan is smart enough to ignore
> multiplication and addition involving zeros and also knows not to carry
> through a bunch of constant autodiffs.
>
> So, the blocks of your .stan file would look like
>
> transformed data {
> matrix[N,N] A_inv; A_inv <- inverse(A);
> t_LA_inv <- transpose(cholesky(A_inv));
> }
>
> model {
> vector[N] v;
> real sum_of_squares;
> v <- t_LA_inv * u;
>
> sum_of_squares <- 0.0; // or sum(pow(v, 2)) may / should work
> for(i in 1:N) {
> sum_of_squares <- sum_of_squares + pow(v[i], 2);
>
> }
>
> lp__ <- lp__ - 0.5 * N * log(sigmasq_u); // non-constant part of
> log(det(sigmasq_u * A)^-0.5)
>
> lp__ <- lp__ - sum_of_squares / (2 * sigmasq_u); // log of kernel of
> multivariate normal
>
> // rest of your likelihood and priors
> }
>
>
> Ben
>
>
> On Tuesday, September 11, 2012 4:32:25 AM UTC-4, Frank wrote:
>>
>> The custom made multivariate normal sampler suggested by Ben really did
>> the trick! Thanks allot.
>>
>> Memory is not an issue anymore, even with N = 1000.
>>
>> I think that Stan is now at least not slower than Jags/MCMCglmm ... on a
>> per iteration base. Considering that Stan is supposed to need much less
>> total number of iterations for a given ESS, it may have quiet an edge.
>>
>> Best regards,
>>
>> Frank
>>
>>
>>
>>
>> Am Dienstag, 11. September 2012 02:30:41 UTC+2 schrieb Ben Goodrich:
>>>
>>> On Monday, September 10, 2012 12:46:53 PM UTC-4, Marcus wrote:
>>>>
>>>> One thing you can try is to use multi_normal_cholesky
>>>>
>>>> I.E., add
>>>>
>>>> transformed data {
>>>> matrix[N,N] A_chol;
>>>> A_chol <- cholesky_decompose(A);
>>>> }
>>>>
>>>> then in the model
>>>>
>>>> u ~ multi_normal_cholesky(0,sqrt(sigmasq_u)*A_chol);
>>>>
>>>> Also, you should be able to use the vectorized version of the normal
>>>> distribution. I.E., instead of the for loop over ys write
>>>>
>>>> y ~ normal(beta0 + u, sqrt(sig2_e));
>>>
>>> Another thing to try (especially if RAM is the binding constraint) is to
>>> do the multivariate normal part yourself in the .stan file with
>>>
>>> lp__ <- lp__ + whatever;
>>>
>>> statements. If A_chol is fixed but sigmasq_u is a parameter, then
>>> sqrt(sigmasq_u)*A_chol is a parameter and multi_normal_cholesky() is doing a
>>> giant triangular solve every time the function gets called which also spews
>>> out a lot of autodiff calculations. If you invert A once at the outset (to
>>> get A_inv) and be careful not to divide by sigmasq_u too soon, it will go
>>> faster. Something like
>>>
>>> lp__ <- lp__ - 0.5 * N * log(sigmasq_u); // non-constant part of
>>> log(det(sigmasq_u * A)^-0.5)
>>> lp__ <- lp__ - (u' * A_inv * u) / ( 2 * sigmasq_u); // log of kernel of
>>> multivariate normal
>>>
>>> Ben
>>>
>
But then we should just vectorize all of multi_normal.
Multivariate normals may be a problem, though, in that
we won't be able to easily compute the gradients (or maybe
they're easier than I suspect?).
> The gradient wrt mu is not bad. The gradient wrt the primitive parameters
> underlying Sigma is more difficult, especially considering that
> multi_normal() wouldn't know how Sigma was constructed.
We could vectorize multi_normal_cholesky first and write the
vectorized mult_normal in terms of that. The derivatives wrt L should
be more straight forward in the cholesky form. Both cases would need
to rely on the identities
d inv(A) = - inv(A) * dA * inv(A)
and
d log(det(A)) = Tr(inv(A) dA)
for matrix A. Given those both forms should be relatively straight forward.
~>g++ --versiong++ (Ubuntu/Linaro 4.6.3-1ubuntu5) 4.6.3Copyright (C) 2011 Free Software Foundation, Inc.This is free software; see the source for copying conditions. There is NOwarranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.On Wed, Sep 12, 2012 at 7:28 PM, Ben Goodrich <goodri...@gmail.com> wrote:
On Wednesday, September 12, 2012 5:32:25 PM UTC-4, Ben wrote:r<T, std::allocator<_CharT> >&) [with T = double]':
chains.cpp:150: instantiated from here
../inst/include/stansrc/stan/prob/autocovariance.hpp:63: error:
return-statement with a value, in function returning 'void'
make: *** [chains.o] Error 1
ERROR: compilation failed for package 'rstan'
* removing '/home/domingue/R/x86_64-redhat-linux-gnu-library/2.15/rstan'
Warning in install.packages("rstan", type = "source") :
installation of package 'rstan' had non-zero exit status
BTW, can you tell us the output ofg++ --version
?
Thanks,
Ben
--