1 #include "bayesm.h"
2
3 //Used in rmvpGibbs and rmnpGibbs---------------------------------------------------------------------------------
condmom(vec const & x,vec const & mu,mat const & sigmai,int p,int j)4 vec condmom(vec const& x, vec const& mu, mat const& sigmai, int p, int j){
5
6 // Wayne Taylor 9/24/2014
7
8 //function to compute moments of x[j] | x[-j]
9 //output is a vec: the first element is the conditional mean
10 // the second element is the conditional sd
11
12 vec out(2);
13 int jm1 = j-1;
14 int ind = p*jm1;
15
16 double csigsq = 1/sigmai(ind+jm1);
17 double m = 0.0;
18
19 for(int i = 0; i<p; i++) if (i!=jm1) m += - csigsq*sigmai(ind+i)*(x[i]-mu[i]);
20
21 out[0] = mu[jm1]+m;
22 out[1] = sqrt(csigsq);
23
24 return (out);
25 }
26
rtrun1(double mu,double sigma,double trunpt,int above)27 double rtrun1(double mu, double sigma, double trunpt, int above) {
28
29 // Wayne Taylor 9/8/2014
30
31 //function to draw truncated normal
32 //above=1 means from above b=trunpt, a=-inf
33 //above=0 means from below a=trunpt, b= +inf
34 //modified by rossi 6/05 to check arg to qnorm
35
36 double FA,FB,rnd,result,arg;
37 if (above) {
38 FA = 0.0; FB = R::pnorm(((trunpt-mu)/(sigma)),0.0,1.0,1,0);
39 } else {
40 FB = 1.0; FA = R::pnorm(((trunpt-mu)/(sigma)),0.0,1.0,1,0);
41 }
42
43 rnd = runif(1)[0]; //runif returns a NumericVector, so using [0] allows for conversion to double
44 arg = rnd*(FB-FA)+FA;
45 if(arg > .999999999) arg = .999999999;
46 if(arg < .0000000001) arg = .0000000001;
47 result = mu + sigma*R::qnorm(arg,0.0,1.0,1,0);
48
49 return (result);
50 }
51
52 //Used in rhierLinearModel, rhierLinearMixture and rhierMnlRWMixture------------------------------------------------------
drawDelta(mat const & x,mat const & y,vec const & z,List const & comps,vec const & deltabar,mat const & Ad)53 mat drawDelta(mat const& x,mat const& y,vec const& z,List const& comps,vec const& deltabar,mat const& Ad){
54
55 // Wayne Taylor 10/01/2014
56
57 // delta = vec(D)
58 // given z and comps (z[i] gives component indicator for the ith observation,
59 // comps is a list of mu and rooti)
60 // y is n x p
61 // x is n x k
62 // y = xD' + U , rows of U are indep with covs Sigma_i given by z and comps
63
64 int p = y.n_cols;
65 int k = x.n_cols;
66 int ncomp = comps.length();
67 mat xtx = zeros<mat>(k*p,k*p);
68 mat xty = zeros<mat>(p,k); //this is the unvecced version, reshaped after the sum
69
70 //Create the index vectors, the colAll vectors are equal to span::all but with uvecs (as required by .submat)
71 uvec colAlly(p), colAllx(k);
72 for(int i = 0; i<p; i++) colAlly(i) = i;
73 for(int i = 0; i<k; i++) colAllx(i) = i;
74
75 //Loop through the components
76 for(int compi = 0; compi<ncomp; compi++){
77
78 //Create an index vector ind, to be used like y[ind,]
79 uvec ind = find(z == (compi+1));
80
81 //If there are observations in this component
82 if(ind.size()>0){
83 mat yi = y.submat(ind,colAlly);
84 mat xi = x.submat(ind,colAllx);
85
86 List compsi = comps[compi];
87 rowvec mui = as<rowvec>(compsi[0]); //conversion from Rcpp to Armadillo requires explict declaration of variable type using as<>
88 mat rootii = trimatu(as<mat>(compsi[1])); //trimatu interprets the matrix as upper triangular
89 yi.each_row() -= mui; //subtracts mui from each row of yi
90 mat sigi = rootii*trans(rootii);
91 xtx = xtx + kron(trans(xi)*xi,sigi);
92 xty = xty + (sigi * (trans(yi)*xi));
93 }
94 }
95 xty.reshape(xty.n_rows*xty.n_cols,1);
96
97 //vec(t(D)) ~ N(V^{-1}(xty + Ad*deltabar),V^{-1}) where V = (xtx+Ad)
98 // compute the inverse of xtx+Ad
99 mat ucholinv = solve(trimatu(chol(xtx+Ad)), eye(k*p,k*p)); //trimatu interprets the matrix as upper triangular and makes solve more efficient
100 mat Vinv = ucholinv*trans(ucholinv);
101
102 return(Vinv*(xty+Ad*deltabar) + trans(chol(Vinv))*as<vec>(rnorm(deltabar.size())));
103 }
104
runiregG(vec const & y,mat const & X,mat const & XpX,vec const & Xpy,double sigmasq,mat const & A,vec const & Abetabar,double nu,double ssq)105 unireg runiregG(vec const& y, mat const& X, mat const& XpX, vec const& Xpy, double sigmasq, mat const& A,
106 vec const& Abetabar, double nu, double ssq) {
107
108 // Keunwoo Kim 09/16/2014
109
110 // Purpose:
111 // perform one Gibbs iteration for Univ Regression Model
112 // only does one iteration so can be used in rhierLinearModel
113
114 // Model:
115 // y = Xbeta + e e ~N(0,sigmasq)
116 // y is n x 1
117 // X is n x k
118 // beta is k x 1 vector of coefficients
119
120 // Prior:
121 // beta ~ N(betabar,A^-1)
122 // sigmasq ~ (nu*ssq)/chisq_nu
123
124 unireg out_struct;
125
126 int n = y.size();
127 int k = XpX.n_cols;
128
129 //first draw beta | sigmasq
130 mat IR = solve(trimatu(chol(XpX/sigmasq+A)), eye(k,k)); //trimatu interprets the matrix as upper triangular and makes solve more efficient
131 vec btilde = (IR*trans(IR)) * (Xpy/sigmasq + Abetabar);
132 vec beta = btilde + IR*vec(rnorm(k));
133
134 //now draw sigmasq | beta
135 double s = sum(square(y-X*beta));
136 sigmasq = (s + nu*ssq)/rchisq(1,nu+n)[0]; //rchisq returns a vectorized object, so using [0] allows for the conversion to double
137
138 out_struct.beta = beta;
139 out_struct.sigmasq = sigmasq;
140
141 return (out_struct);
142 }
143
144 //Used in rnegbinRW and rhierNegbinRw-------------------------------------------------------------------------------------
llnegbin(vec const & y,vec const & lambda,double alpha,bool constant)145 double llnegbin(vec const& y, vec const& lambda, double alpha, bool constant){
146
147 // Keunwoo Kim 11/02/2014
148
149 // Computes the log-likelihood
150
151 // Arguments
152 // y - a vector of observation
153 // lambda - a vector of mean parameter (=exp(X*beta))
154 // alpha - dispersion parameter
155 // constant - TRUE(FALSE) if it computes (un)normalized log-likeihood
156
157 // PMF
158 // pmf(y) = (y+alpha-1)Choose(y) * p^alpha * (1-p)^y
159 // (y+alpha-1)Choose(y) = (alpha)*(alpha+1)*...*(alpha+y-1) / y! when y>=1 (0 when y=0)
160
161 int i;
162 int nobs = y.size();
163 vec prob = alpha/(alpha+lambda);
164 vec logp(nobs);
165 if (constant){
166 // normalized log-likelihood
167 for (i=0; i<nobs; i++){
168 // the fourth argument "1" indicates log-density
169 logp[i] = R::dnbinom(y[i], alpha, prob[i], 1);
170 }
171 }else{
172 // unnormalized log-likelihood
173 logp = sum(alpha*log(prob) + y % log(1-prob)); //% does element-wise multiplication
174 }
175 return (sum(logp));
176 }
177
lpostbeta(double alpha,vec const & beta,mat const & X,vec const & y,vec const & betabar,mat const & rootA)178 double lpostbeta(double alpha, vec const& beta, mat const& X, vec const& y, vec const& betabar, mat const& rootA){
179
180 // Keunwoo Kim 11/02/2014
181
182 // Computes log posterior for beta | alpha
183
184 // Arguments
185 // alpha - dispersion parameter of negative-binomial
186 // beta - parameter of our interests
187 // X, y - observation from data
188 // betabar - mean of beta prior
189 // rootA - t(rootA)%*%rootA = A (A^-1 is var-cov matrix of beta prior)
190
191 // Prior
192 // beta ~ N(betabar, A^-1)
193
194 vec lambda = exp(X*beta);
195 double ll = llnegbin(y, lambda, alpha, FALSE);
196
197 // unormalized prior
198 vec z = rootA*(beta-betabar);
199 double lprior = - 0.5*sum(z%z);
200
201 return (ll+lprior);
202 }
203
lpostalpha(double alpha,vec const & beta,mat const & X,vec const & y,double a,double b)204 double lpostalpha(double alpha, vec const& beta, mat const& X, vec const& y, double a, double b){
205
206 // Keunwoo Kim 11/02/2014
207
208 // Computes log posterior for alpha | beta
209
210 // Arguments
211 // alpha - dispersion parameter of negative-binomial
212 // beta - parameter of our interests
213 // X, y - observation from data
214 // a,b - parameters for Gamma distribution, alpha prior
215
216 // Prior
217 // alpha ~ Gamma(a,b)
218 // pdf(alpha) = b^a / Gamma(a) * alpha^(a-1) * e^(b*alpha)
219
220 vec lambda = exp(X*beta);
221 double ll = llnegbin(y, lambda, alpha, TRUE);
222 // unormalized prior
223 double lprior = (a-1)*log(alpha) - b*alpha;
224
225 return (ll+lprior);
226 }
227
228 //Used in rbprobitGibbs and rordprobitGibbs-----------------------------------------------------------------------
breg1(mat const & root,mat const & X,vec const & y,vec const & Abetabar)229 vec breg1(mat const& root, mat const& X, vec const& y, vec const& Abetabar) {
230
231 // Keunwoo Kim 06/20/2014
232
233 // Purpose: draw from posterior for linear regression, sigmasq=1.0
234
235 // Arguments:
236 // root = chol((X'X+A)^-1)
237 // Abetabar = A*betabar
238
239 // Output: draw from posterior
240
241 // Model: y = Xbeta + e e ~ N(0,I)
242
243 // Prior: beta ~ N(betabar,A^-1)
244
245 mat cov = trans(root)*root;
246
247 return (cov*(trans(X)*y+Abetabar) + trans(root)*vec(rnorm(root.n_cols)));
248 }
249
rtrunVec(vec const & mu,vec const & sigma,vec const & a,vec const & b)250 vec rtrunVec(vec const& mu,vec const& sigma, vec const& a, vec const& b){
251
252 // Keunwoo Kim 06/20/2014
253
254 //function to draw from univariate truncated norm
255 //a is vector of lower bounds for truncation
256 //b is vector of upper bounds for truncation
257
258 int n = mu.size();
259 vec FA(n);
260 vec FB(n);
261 vec out(n);
262 for (int i=0; i<n; i++) {
263 FA[i] = R::pnorm((a[i]-mu[i])/sigma[i],0,1,1,0);
264 FB[i] = R::pnorm((b[i]-mu[i])/sigma[i],0,1,1,0);
265 out[i] = mu[i]+sigma[i]*R::qnorm(R::runif(0,1)*(FB[i]-FA[i])+FA[i],0,1,1,0);
266 }
267
268 return(out);
269 }
270
271 //Used in rhierMnlDP and rhierMnlRwMixture------------------------------------------------------------------------
mnlMetropOnce(vec const & y,mat const & X,vec const & oldbeta,double oldll,double s,mat const & incroot,vec const & betabar,mat const & rootpi)272 mnlMetropOnceOut mnlMetropOnce(vec const& y, mat const& X, vec const& oldbeta,
273 double oldll,double s, mat const& incroot,
274 vec const& betabar, mat const& rootpi){
275 // Wayne Taylor 10/01/2014
276
277 // function to execute rw metropolis for the MNL
278 // y is n vector with element = 1,...,j indicating which alt chosen
279 // X is nj x k matrix of xvalues for each of j alt on each of n occasions
280 // RW increments are N(0,s^2*t(inc.root)%*%inc.root)
281 // prior on beta is N(betabar,Sigma) Sigma^-1=rootpi*t(rootpi)
282 // inc.root, rootpi are upper triangular
283 // this means that we are using the UL decomp of Sigma^-1 for prior
284 // oldbeta is the current
285
286
287 mnlMetropOnceOut metropout_struct;
288
289 double unif;
290 vec betadraw, alphaminv;
291
292 int stay = 0;
293 vec betac = oldbeta + s*trans(incroot)*as<vec>(rnorm(X.n_cols));
294 double cll = llmnl(betac,y,X);
295 double clpost = cll+lndMvn(betac,betabar,rootpi);
296 double ldiff = clpost-oldll-lndMvn(oldbeta,betabar,rootpi);
297 alphaminv << 1 << exp(ldiff);
298 double alpha = min(alphaminv);
299
300 if(alpha < 1) {
301 unif = runif(1)[0]; //runif returns a NumericVector, so using [0] allows for conversion to double
302 } else {
303 unif=0;}
304 if (unif <= alpha) {
305 betadraw = betac;
306 oldll = cll;
307 } else {
308 betadraw = oldbeta;
309 stay = 1;
310 }
311
312 metropout_struct.betadraw = betadraw;
313 metropout_struct.stay = stay;
314 metropout_struct.oldll = oldll;
315
316 return (metropout_struct);
317 }
318
319 //Used in rDPGibbs, rhierMnlDP, rivDP-----------------------------------------------------------------------------
rmultinomF(vec const & p)320 int rmultinomF(vec const& p){
321
322 // Wayne Taylor 1/28/2015
323
324 vec csp = cumsum(p);
325 double rnd = runif(1)[0]; //runif returns a NumericVector, so using [0] allows for conversion to double
326 int res = 0;
327 int psize = p.size();
328
329 for(int i = 0; i < psize; i++){
330 if(rnd > csp[i]) res = res+1;
331 }
332
333 return(res+1);
334 }
335
yden(std::vector<murooti> const & thetaStar_vector,mat const & y)336 mat yden(std::vector<murooti> const& thetaStar_vector, mat const& y){
337
338 // Wayne Taylor 2/4/2015
339
340 // function to compute f(y | theta)
341 // computes f for all values of theta in theta list of lists
342
343 // arguments:
344 // thetaStar is a list of lists. thetaStar[[i]] is a list with components, mu, rooti
345 // y |theta[[i]] ~ N(mu,(rooti %*% t(rooti))^-1) rooti is inverse of Chol root of Sigma
346
347 // output:
348 // length(thetaStar) x n array of values of f(y[j,]|thetaStar[[i]]
349
350 int nunique = thetaStar_vector.size();
351 int n = y.n_rows;
352 int k = y.n_cols;
353 mat ydenmat = zeros<mat>(nunique,n);
354
355 vec mu;
356 mat rooti, transy, quads;
357
358 for(int i = 0; i < nunique; i++){
359 //now compute vectorized version of lndMvn
360 //compute y_i'RIRI'y_i for all i
361
362 mu = thetaStar_vector[i].mu;
363 rooti = thetaStar_vector[i].rooti;
364
365 transy = trans(y);
366 transy.each_col() -= mu; //column-wise subtraction
367
368 quads = sum(square(trans(rooti) * transy),0); //same as colSums
369 ydenmat(i,span::all) = exp(-(k/2.0)*log(2*M_PI) + sum(log(rooti.diag())) - .5*quads);
370 }
371
372 return(ydenmat);
373 }
374
numcomp(ivec const & indic,int k)375 ivec numcomp(ivec const& indic, int k){
376
377 // Wayne Taylor 1/28/2015
378
379 //find the number of times each of k integers is in the vector indic
380 ivec ncomp(k);
381
382 for(int comp = 0; comp < k; comp++){
383 ncomp[comp]=sum(indic == (comp+1));
384 }
385
386 return(ncomp);
387 }
388
thetaD(mat const & y,lambda const & lambda_struct)389 murooti thetaD(mat const& y, lambda const& lambda_struct){
390
391 // Wayne Taylor 2/4/2015
392
393 // function to draw from posterior of theta given data y and base prior G0(lambda)
394
395 // here y ~ N(mu,Sigma)
396 // theta = list(mu=mu,rooti=chol(Sigma)^-1)
397 // mu|Sigma ~ N(mubar,Sigma (x) Amu-1)
398 // Sigma ~ IW(nu,V)
399
400 // arguments:
401 // y is n x k matrix of obs
402 // lambda is list(mubar,Amu,nu,V)
403
404 // output:
405 // one draw of theta, list(mu,rooti)
406 // Sigma=inv(rooti)%*%t(inv(rooti))
407
408 // note: we assume that y is a matrix. if there is only one obs, y is a 1 x k matrix
409
410 mat X = ones<mat>(y.n_rows,1);
411 mat A(1,1); A.fill(lambda_struct.Amu);
412
413 List rout = rmultireg(y,X,trans(lambda_struct.mubar),A,lambda_struct.nu,lambda_struct.V);
414
415 murooti out_struct;
416 out_struct.mu = as<vec>(rout["B"]); //conversion from Rcpp to Armadillo requires explict declaration of variable type using as<>
417 out_struct.rooti = solve(chol(trimatu(as<mat>(rout["Sigma"]))),eye(y.n_cols,y.n_cols)); //trimatu interprets the matrix as upper triangular and makes solve more efficient
418
419 return(out_struct);
420 }
421
thetaStarDraw(ivec indic,std::vector<murooti> thetaStar_vector,mat const & y,mat ydenmat,vec const & q0v,double alpha,lambda const & lambda_struct,int maxuniq)422 thetaStarIndex thetaStarDraw(ivec indic, std::vector<murooti> thetaStar_vector, mat const& y, mat ydenmat, vec const& q0v, double alpha,
423 lambda const& lambda_struct, int maxuniq) {
424
425 // Wayne Taylor 2/4/2015
426
427 // indic is n x 1 vector of indicator of which of thetaStar is assigned to each observation
428 // thetaStar is list of the current components (some of which may never be used)
429 // y is n x d matrix of observations
430 // ydenmat is maxuniq x n matrix to store density evaluations - we assume first
431 // length(Thetastar) rows are filled in with density evals
432 // q0v is vector of bayes factors for new component and each observation
433 // alpha is DP process tightness prior
434 // lambda is list of priors for the base DP process measure
435 // maxuniq maximum number of mixture components
436 // yden is function to fill out an array
437 // thetaD is function to draw theta from posterior of theta given y and G0
438
439 int n = indic.size();
440 ivec ncomp, indicC;
441 int k, inc, cntNonzero;
442 std::vector<murooti> listofone_vector(1);
443 std::vector<murooti> thetaStarC_vector;
444
445 //draw theta_i given theta_-i
446 for(int i = 0; i<n; i++){
447 k = thetaStar_vector.size();
448 vec probs(k+1);
449 probs[k] = q0v[i]*(alpha/(alpha+(n-1)));
450
451 //same as to indicmi = indic[-i]
452 ivec indicmi = zeros<ivec>(n-1);
453 inc = 0;
454 for(int j = 0; j<(n-1); j++){
455 if(j == i) {inc = inc + 1;}
456 indicmi[j] = indic[inc];
457 inc = inc+1;
458 }
459
460 ncomp = numcomp(indicmi,k);
461
462 for(int comp = 0; comp<k; comp++){
463 probs[comp] = ydenmat(comp,i)*ncomp[comp]/(alpha+(n-1));
464 }
465
466 probs = probs/sum(probs);
467 indic[i] = rmultinomF(probs);
468
469 if(indic[i] == (k+1)){
470 if((k+1) > maxuniq) {
471 stop("max number of comps exceeded");
472 } else {
473 listofone_vector[0] = thetaD(y(i,span::all),lambda_struct);
474 thetaStar_vector.push_back(listofone_vector[0]);
475 ydenmat(k,span::all) = yden(listofone_vector,y);
476 }}
477 }
478
479 //clean out thetaStar of any components which have zero observations associated with them
480 //and re-write indic vector
481 k = thetaStar_vector.size();
482 indicC = zeros<ivec>(n);
483 ncomp = numcomp(indic,k);
484
485 cntNonzero = 0;
486 for(int comp = 0; comp<k; comp++){
487 if(ncomp[comp] != 0){
488 thetaStarC_vector.push_back(thetaStar_vector[comp]);
489 cntNonzero=cntNonzero+1;
490 for(int i = 0; i<n; i++){if(indic[i] == (comp+1)) indicC[i] = cntNonzero;} //same as indicC(indic==comp) = cntNonzero;
491 }
492 }
493
494 thetaStarIndex out_struct;
495 out_struct.indic = indicC;
496 out_struct.thetaStar_vector = thetaStarC_vector;
497
498 return(out_struct);
499 }
500
q0(mat const & y,lambda const & lambda_struct)501 vec q0(mat const& y, lambda const& lambda_struct){
502
503 // Wayne Taylor 2/4/2015
504
505 // function to compute a vector of int f(y[i]|theta) p(theta|lambda)dlambda
506 // here p(theta|lambda) is G0 the base prior
507
508 // implemented for a multivariate normal data density and standard conjugate prior:
509 // theta=list(mu,Sigma)
510 // f(y|theta,eta) is N(mu,Sigma)
511 // lambda=list(mubar,Amu,nu,V)
512 // mu|Sigma ~ N(mubar,Sigma (x) Amu^-1)
513 // Sigma ~ IW(nu,V)
514
515 // arguments:
516 // Y is n x k matrix of observations
517 // lambda=list(mubar,Amu,nu,V)
518
519 // output:
520 // vector of q0 values for each obs (row of Y)
521
522 // p. rossi 12/05
523 // here y is matrix of observations (each row is an obs)
524
525 int k = y.n_cols;
526 mat R = chol(lambda_struct.V);
527 double logdetR = sum(log(R.diag()));
528 double lnk1k2, constant;
529 mat transy, m, vivi, lnq0v;
530
531 if (k > 1) {
532 vec km1(k-1); for(int i = 0; i < (k-1); i++) km1[i] = i+1; //vector of 1:k SEE SEQ_ALONG
533 lnk1k2 = (k/2.0)*log(2.0)+log((lambda_struct.nu-k)/2)+lgamma((lambda_struct.nu-k)/2)-lgamma(lambda_struct.nu/2)+sum(log(lambda_struct.nu/2-km1/2));
534 } else {
535 lnk1k2 = (k/2.0)*log(2.0)+log((lambda_struct.nu-k)/2)+lgamma((lambda_struct.nu-k)/2)-lgamma(lambda_struct.nu/2);
536 }
537
538 constant = -(k/2.0)*log(2*M_PI)+(k/2.0)*log(lambda_struct.Amu/(1+lambda_struct.Amu)) + lnk1k2 + lambda_struct.nu*logdetR;
539
540 // note: here we are using the fact that |V + S_i | = |R|^2 (1 + v_i'v_i)
541 // where v_i = sqrt(Amu/(1+Amu))*t(R^-1)*(y_i-mubar), R is chol(V)
542 // and S_i = Amu/(1+Amu) * (y_i-mubar)(y_i-mubar)'
543
544 transy = trans(y);
545 transy.each_col() -= lambda_struct.mubar;
546
547 m = sqrt(lambda_struct.Amu/(1+lambda_struct.Amu))*trans(solve(trimatu(R),eye(y.n_cols,y.n_cols)))*transy; //trimatu interprets the matrix as upper triangular and makes solve more efficient
548
549 vivi = sum(square(m),0);
550
551 lnq0v = constant - ((lambda_struct.nu+1)/2)*(2*logdetR+log(1+vivi));
552
553 return(trans(exp(lnq0v)));
554 }
555
seq_rcpp(double from,double to,int len)556 vec seq_rcpp(double from, double to, int len){
557
558 // Wayne Taylor 1/28/2015
559
560 // Same as R::seq()
561
562 vec res(len);
563 res[len-1] = to; res[0] = from; //note the order of these two statements is important, when gridsize = 1 res[0] will be rewritten to the correct number
564 double increment = (res[len-1]-res[0])/(len-1);
565 for(int i = 1; i<(len-1); i++) res[i] = res[i-1] + increment;
566 return(res);
567 }
568
alphaD(priorAlpha const & priorAlpha_struct,int Istar,int gridsize)569 double alphaD(priorAlpha const& priorAlpha_struct, int Istar, int gridsize){
570
571 // Wayne Taylor 2/4/2015
572
573 // function to draw alpha using prior, p(alpha)= (1-(alpha-alphamin)/(alphamax-alphamin))**power
574
575 //same as seq
576 vec alpha = seq_rcpp(priorAlpha_struct.alphamin,priorAlpha_struct.alphamax-.000001,gridsize);
577
578 vec lnprob(gridsize);
579 for(int i = 0; i<gridsize; i++){
580 lnprob[i] = Istar*log(alpha[i]) + lgamma(alpha[i]) - lgamma(priorAlpha_struct.n+alpha[i]) + priorAlpha_struct.power*log(1-(alpha[i]-priorAlpha_struct.alphamin)/(priorAlpha_struct.alphamax-priorAlpha_struct.alphamin));
581 }
582
583 lnprob = lnprob - median(lnprob);
584 vec probs=exp(lnprob);
585 probs=probs/sum(probs);
586
587 return(alpha(rmultinomF(probs)-1));
588 }
589
GD(lambda const & lambda_struct)590 murooti GD(lambda const& lambda_struct){
591
592 // Wayne Taylor 2/4/2015
593
594 // function to draw from prior for Multivariate Normal Model
595
596 // mu|Sigma ~ N(mubar,Sigma x Amu^-1)
597 // Sigma ~ IW(nu,V)
598
599 // note: we must insure that mu is a vector to use most efficient lndMvn routine
600
601 int k = lambda_struct.mubar.size();
602
603 List Rout = rwishart(lambda_struct.nu,solve(trimatu(lambda_struct.V),eye(k,k))); //trimatu interprets the matrix as upper triangular and makes solve more efficient
604 mat Sigma = as<mat>(Rout["IW"]); //conversion from Rcpp to Armadillo requires explict declaration of variable type using as<>
605 mat root = chol(Sigma);
606 mat draws = rnorm(k);
607 mat mu = lambda_struct.mubar + (1/sqrt(lambda_struct.Amu))*trans(root)*draws;
608
609 murooti out_struct;
610 out_struct.mu = mu;
611 out_struct.rooti = solve(trimatu(root),eye(k,k)); //trimatu interprets the matrix as upper triangular and makes solve more efficient
612
613 return(out_struct);
614 }
615
616
lambdaD(lambda const & lambda_struct,std::vector<murooti> const & thetaStar_vector,vec const & alim,vec const & nulim,vec const & vlim,int gridsize)617 lambda lambdaD(lambda const& lambda_struct, std::vector<murooti> const& thetaStar_vector, vec const& alim, vec const& nulim, vec const& vlim, int gridsize){
618
619 // Wayne Taylor 2/4/2015
620
621 // revision history
622 // p. rossi 7/06
623 // vectorized 1/07
624 // changed 2/08 to paramaterize V matrix of IW prior to nu*v*I; then mode of Sigma=nu/(nu+2)vI
625 // this means that we have a reparameterization to v* = nu*v
626
627 // function to draw (nu, v, a) using uniform priors
628
629 // theta_j=(mu_j,Sigma_j) mu_j~N(0,Sigma_j/a) Sigma_j~IW(nu,vI)
630 // recall E[Sigma]= vI/(nu-dim-1)
631
632 vec lnprob, probs, rowSumslgammaarg;
633 int ind; //placeholder for matrix indexing
634 murooti thetaStari_struct; mat rootii; vec mui;
635 mat mout, rimu, arg, lgammaarg;
636 double sumdiagriri, sumlogdiag, sumquads, adraw, nudraw, vdraw;
637
638 murooti thetaStar0_struct = thetaStar_vector[0];
639 int d = thetaStar0_struct.mu.size();
640 int Istar = thetaStar_vector.size();
641
642 vec aseq = seq_rcpp(alim[0],alim[1],gridsize);
643 vec nuseq = d-1+exp(seq_rcpp(nulim[0],nulim[1],gridsize)); //log uniform grid
644 vec vseq = seq_rcpp(vlim[0],vlim[1],gridsize);
645
646 // "brute" force approach would simply loop over the
647 // "observations" (theta_j) and use log of the appropriate densities. To vectorize, we
648 // notice that the "data" comes via various statistics:
649 // 1. sum of log(diag(rooti_j)
650 // 2. sum of tr(V%*%rooti_j%*%t(rooti_j)) where V=vI_d
651 // 3. quadratic form t(mu_j-0)%*%rooti%*%t(rooti)%*%(mu_j-0)
652 // thus, we will compute these first.
653 // for documentation purposes, we leave brute force code in comment fields
654
655 // extract needed info from thetastar list
656
657 //mout has the rootis in form: [t(rooti_1), t(rooti_2), ...,t(rooti_Istar)]
658 mout = zeros<mat>(d,Istar*d);
659 ind = 0;
660 for(int i = 0; i < Istar; i++){
661 thetaStari_struct = thetaStar_vector[i];
662 rootii = thetaStari_struct.rooti;
663 ind = i*d;
664 mout.submat(0, ind,d-1,ind+d-1) = trans(rootii);
665 }
666 sumdiagriri = sum(sum(square(mout),0)); //sum_i trace(rooti_i*trans(rooti_i))
667
668 // now get diagonals of rooti
669 sumlogdiag = 0.0;
670 for(int i = 0; i < Istar; i++){
671 ind = i*d;
672 for(int j = 0; j < d; j++){
673 sumlogdiag = sumlogdiag+log(mout(j,ind+j));
674 }
675 }
676
677 //columns of rimu contain trans(rooti_i)*mu_i
678 rimu = zeros<mat>(d,Istar);
679 for(int i = 0; i < Istar; i++){
680 thetaStari_struct = thetaStar_vector[i];
681 mui = thetaStari_struct.mu;
682 rootii = thetaStari_struct.rooti;
683 rimu(span::all,i) = trans(rootii) * mui;
684 }
685 sumquads = sum(sum(square(rimu),0));
686
687 // draw a (conditionally indep of nu,v given theta_j)
688 lnprob = zeros<vec>(aseq.size());
689 // for(i in seq(along=aseq)){
690 // for(j in seq(along=thetastar)){
691 // lnprob[i]=lnprob[i]+lndMvn(thetastar[[j]]$mu,c(rep(0,d)),thetastar[[j]]$rooti*sqrt(aseq[i]))}
692 lnprob = Istar*(-(d/2.0)*log(2*M_PI))-.5*aseq*sumquads+Istar*d*log(sqrt(aseq))+sumlogdiag;
693 lnprob = lnprob-max(lnprob) + 200;
694 probs = exp(lnprob);
695 probs = probs/sum(probs);
696 adraw = aseq[rmultinomF(probs)-1];
697
698 // draw nu given v
699
700 lnprob = zeros<vec>(nuseq.size());
701 // for(i in seq(along=nuseq)){
702 // for(j in seq(along=thetastar)){
703 // Sigma_j=crossprod(backsolve(thetastar[[j]]$rooti,diag(d)))
704 // lnprob[i]=lnprob[i]+lndIWishart(nuseq[i],V,Sigma_j)}
705
706 //same as arg = (nuseq+1-arg)/2.0;
707 arg = zeros<mat>(gridsize,d);
708 for(int i = 0; i < d; i++) {
709 vec indvec(gridsize);
710 indvec.fill(-(i+1)+1);
711 arg(span::all,i) = indvec;
712 }
713 arg.each_col() += nuseq;
714 arg = arg/2.0;
715
716 lgammaarg = zeros<mat>(gridsize,d);
717 for(int i = 0; i < gridsize; i++){
718 for(int j = 0; j < d; j++){
719 lgammaarg(i,j) = lgamma(arg(i,j));
720 }}
721 rowSumslgammaarg = sum(lgammaarg,1);
722
723 lnprob = zeros<vec>(gridsize);
724 for(int i = 0; i<gridsize; i++){
725 lnprob[i] = -Istar*log(2.0)*d/2.0*nuseq[i] - Istar*rowSumslgammaarg[i] + Istar*d*log(sqrt(lambda_struct.V(0,0)))*nuseq[i] + sumlogdiag*nuseq[i];
726 }
727
728 lnprob = lnprob-max(lnprob)+200;
729 probs = exp(lnprob);
730 probs = probs/sum(probs);
731 nudraw = nuseq[rmultinomF(probs)-1];
732
733 // draw v given nu
734
735 lnprob = zeros<vec>(vseq.size());
736 // for(i in seq(along=vseq)){
737 // V=vseq[i]*diag(d)
738 // for(j in seq(along=thetastar)){
739 // Sigma_j=crossprod(backsolve(thetastar[[j]]$rooti,diag(d)))
740 // lnprob[i]=lnprob[i]+lndIWishart(nudraw,V,Sigma_j)}
741 // lnprob=Istar*nudraw*d*log(sqrt(vseq))-.5*sumdiagriri*vseq
742
743 lnprob = Istar*nudraw*d*log(sqrt(vseq*nudraw))-.5*sumdiagriri*vseq*nudraw;
744 lnprob = lnprob-max(lnprob)+200;
745 probs = exp(lnprob);
746 probs = probs/sum(probs);
747 vdraw = vseq[rmultinomF(probs)-1];
748
749 // put back into lambda
750 lambda out_struct;
751 out_struct.mubar = zeros<vec>(d);
752 out_struct.Amu = adraw;
753 out_struct.nu = nudraw;
754 out_struct.V = nudraw*vdraw*eye(d,d);
755
756 return(out_struct);
757 }
758
759 //Used in llnhlogit and simnhlogit---------------------------------------------------------------------------------
root(double c1,double c2,double tol,int iterlim)760 double root(double c1, double c2, double tol, int iterlim){
761
762 //function to find root of c1 - c2u = lnu
763
764 int iter = 0;
765 double uold = .1;
766 double unew = .00001;
767
768 while (iter <= iterlim && fabs(uold-unew) > tol){
769 uold = unew;
770 unew=uold + (uold*(c1 -c2*uold - log(uold)))/(1. + c2*uold);
771 if(unew < 1.0e-50) unew=1.0e-50;
772 iter=iter+1;
773 }
774
775 return(unew);
776 }
777
778 //[[Rcpp::export]]
callroot(vec const & c1,vec const & c2,double tol,int iterlim)779 vec callroot(vec const& c1, vec const& c2, double tol, int iterlim){
780
781 int n = c1.size();
782 vec u = zeros<vec>(n);
783
784 for(int i = 0; i<n; i++){
785 u[i] = root(c1[i],c2[i],tol,iterlim);
786 }
787
788 return(u);
789 }
790