#include "RcppArmadillo.h" using namespace arma; // use the Armadillo library for matrix computations using namespace Rcpp; using namespace R; // [[Rcpp::depends(RcppArmadillo)]] //timing functions time_t itime; char buf[100]; void startMcmcTimer() { itime = time(NULL); Rcout << " MCMC Iteration (est time to end - min) \n"; } void infoMcmcTimer(int rep, int R) { time_t ctime = time(NULL); char buf[32]; double timetoend = difftime(ctime, itime) / 60.0 * (R - rep - 1) / (rep+1); sprintf(buf, " %d (%.1f)\n", rep+1, timetoend); Rcout << buf; } void endMcmcTimer() { time_t ctime = time(NULL); char buf[32]; sprintf(buf, " Total Time Elapsed: %.2f \n", difftime(ctime, itime) / 60.0); Rcout << buf; itime = 0; } //necessary functions for loop //wishart draws for rmultireg List rwishart(double nu, mat const& V){ int m = V.n_rows; mat T = zeros(m,m); for(int i = 0; i < m; i++) { T(i,i) = sqrt(rchisq(1,nu-i)[0]); //rchisq returns a vectorized object, so using [0] allows for the conversion to double } for(int j = 0; j < m; j++) { for(int i = j+1; i < m; i++) { T(i,j) = rnorm(1)[0]; //rnorm returns a NumericVector, so using [0] allows for conversion to double }} mat C = trans(T)*chol(V); mat CI = solve(trimatu(C),eye(m,m)); //trimatu interprets the matrix as upper triangular and makes solve more efficient // C is the upper triangular root of Wishart therefore, W=C'C // this is the LU decomposition Inv(W) = CICI' Note: this is // the UL decomp not LU! // W is Wishart draw, IW is W^-1 return List::create( Named("W") = trans(C) * C, Named("IW") = CI * trans(CI), Named("C") = C, Named("CI") = CI); } //rmultireg multiple regression List rmultireg_mod(mat const& Y, mat const& X, mat const& Bbar, mat const& A, double nu, mat const& V) { //Note that we rename the function to avoid problems in shared libraries/R environment // Keunwoo Kim 09/09/2014 // Purpose: draw from posterior for Multivariate Regression Model with natural conjugate prior // Arguments: // Y is n x m matrix // X is n x k // Bbar is the prior mean of regression coefficients (k x m) // A is prior precision matrix // nu, V are parameters for prior on Sigma // Output: list of B, Sigma draws of matrix of coefficients and Sigma matrix // Model: // Y=XB+U cov(u_i) = Sigma // B is k x m matrix of coefficients // Prior: // beta|Sigma ~ N(betabar,Sigma (x) A^-1) // betabar=vec(Bbar) // beta = vec(B) // Sigma ~ IW(nu,V) or Sigma^-1 ~ W(nu, V^-1) int n = Y.n_rows; int m = Y.n_cols; int k = X.n_cols; //first draw Sigma mat RA = chol(A); mat W = join_cols(X, RA); //analogous to rbind() in R mat Z = join_cols(Y, RA*Bbar); // note: Y,X,A,Bbar must be matrices! mat IR = solve(trimatu(chol(trans(W)*W)), eye(k,k)); //trimatu interprets the matrix as upper triangular and makes solve more efficient // W'W = R'R & (W'W)^-1 = IRIR' -- this is the UL decomp! mat Btilde = (IR*trans(IR)) * (trans(W)*Z); // IRIR'(W'Z) = (X'X+A)^-1(X'Y + ABbar) mat E = Z-W*Btilde; mat S = trans(E)*E; // E'E // compute the inverse of V+S mat ucholinv = solve(trimatu(chol(V+S)), eye(m,m)); mat VSinv = ucholinv*trans(ucholinv); List rwout = rwishart(nu+n, VSinv); // now draw B given Sigma // note beta ~ N(vec(Btilde),Sigma (x) Covxxa) // Cov=(X'X + A)^-1 = IR t(IR) // Sigma=CICI' // therefore, cov(beta)= Omega = CICI' (x) IR IR' = (CI (x) IR) (CI (x) IR)' // so to draw beta we do beta= vec(Btilde) +(CI (x) IR)vec(Z_mk) // Z_mk is m x k matrix of N(0,1) // since vec(ABC) = (C' (x) A)vec(B), we have // B = Btilde + IR Z_mk CI' mat CI = rwout["CI"]; //there is no need to use as(rwout["CI"]) since CI is being initiated as a mat in the same line mat draw = mat(rnorm(k*m)); draw.reshape(k,m); mat B = Btilde + IR*draw*trans(CI); return List::create( Named("B") = B, Named("Sigma") = rwout["IW"]); } //RI likelihood // [[Rcpp::export]] List RIDC2_lik(List Data, vec beta, double lambda, vec mu, mat states, int nobs, uvec simp_idx, uvec comp_idx, mat optimal_action_weight){ // Computes the joint likelihood of the RI choices of an individual int nstates = states.n_cols; double nalt = states.n_rows; // int nvar = beta.n_elem; // dim(optimal_action_weight)=c(nvar,nobs) vec lik(nobs); vec oldProbs = zeros(nalt); vec cProbs = oldProbs; mat oldCondProbs = zeros(nalt,nstates); mat cCondProbs = oldCondProbs; mat post = zeros(nalt,nstates); mat outprobs(nalt,nobs); for(int i=0;i(as(Data[i])["X"]); int y = as(as(Data[i])["y"]); int v = as(as(Data[i])["v"]); // GENERAL VERSION // complex element(s) of beta and complex column(s) of X (indicated by complex_idx) are separated from the rest // and then Omega is calculated accordingly mat X_simp(X.n_rows,simp_idx.n_elem); X_simp = X.cols(simp_idx); vec beta_simp(simp_idx.n_elem); beta_simp = beta.elem(simp_idx); // Calculate Omega (matrix of utility values at each state) | beta mat Xbeta = X.cols(simp_idx)*beta(simp_idx); mat Omega = zeros(nalt,nstates); for(int j=0;j::from(beta(comp_idx)) * states; //here beta(comp_idx) needs to converted to double for multiplication. change this when there are more than 1 simple attributes // Calculate P(v) | Omega, mu, lambda using BA algorithm // max_iter: maximal number of iterations // precision: threshold for the sum of squared differences int max_iter = 10000; double precision = 10e-7; // Transformation of the utility index matrix //mat Z = exp(Omega/lambda); //numerically stable mat G = Omega/lambda; rowvec maxl = max(Omega/lambda,0); //vectorwise maximum mat Z = zeros(nalt,nstates); for(int j=0;jprecision && counter(BAout["probs"])*0.8+0.1; oldlik(i) = BAout["lik"]; oldlpostbeta(i) = oldlik(i) + lndMvn(trans(betastar.row(i)), currmean,rooti); } startMcmcTimer(); //main iteration loop for(int reps=0;reps(BAout["probs"])*0.8+0.1;//randu();//0.25;//0.5*0.5;//randu();//weight;//(1.0/nalt); clik = BAout["lik"]; rooti=inv(chol(currvar)); clpostbeta = clik + lndMvn(betastarc, currmean,rooti); //rooti of currvar! //acceptance ratio ldiff = clpostbeta - oldlpostbeta(i); //alphaminv << 1.0 << exp(ldiff); //intializes variables in the alphaminv vec: c(1,exp(ldiff)) alphaminv = {1.0, exp(ldiff)}; alpha = min(alphaminv); if(alpha < 1.0) { unif = randu();//runif(1)[0]; //runif returns a NumericVector, so using [0] allows for conversion to double }else{ unif = 0.0; } if (unif <= alpha){ betastar.row(i) = trans(betastarc); oldlik(i) = clik; oldlpostbeta(i) = clpostbeta; } } //i-break if ((reps+1)%100==0) infoMcmcTimer(reps, R); //Hierarchical level //creating X matrix for rmultireg mat Xreg(nind,1,fill::ones); //please check input arguments for rmultireg, see lines 44ff List outreg = rmultireg_mod(betastar,Xreg,Bbar,Areg,NUreg,Vreg); hiermean.col(reps) = as(as(outreg)["B"]); currmean=as(as(outreg)["B"]); hiervar.slice(reps) = as(as(outreg)["Sigma"]); currvar=hiervar.slice(reps); betadraw.slice(reps) = betastar; //betadraw, vardraw are cubes/arrays with three dimensions!!!! likdraw.col(reps)=oldlik; } //R break endMcmcTimer(); return List::create( Named("betadraw") = betadraw, Named("lhdraw") = likdraw, Named("hiermean") = hiermean, Named("hiervar") = hiervar); }