Revision de5c60ae1baa5bc3f87fadd41e625254d958afe1 authored by Yanwei (Wayne) Zhang on 05 March 2019, 09:50:03 UTC, committed by cran-robot on 05 March 2019, 09:50:03 UTC
1 parent 29e153f
Raw File
bcplm.c
/************************************************************/
/*    Markov Chain Monte Carlo algorithms for the Bayesian  */
/*  Compound Poisson Linear Model via density evaluation    */
/*              Author:  Wayne Zhang                        */
/*            actuary_zhang@hotmail.com                     */
/************************************************************/

/**
 * @file bcplm.c
 * @brief Functions for implementing the MCMC algorithm for 
 * Compound Poisson Linear Models using direct tweedie 
 * density evaluation
 * @author Wayne Zhang                         
 */

/** common R headers and macros that extract slots */ 
#include "common.h"
/** tweedie density evaluation functions */
#include "tweedie.h"
/** univariate/multivariate random walk Metropolis-Hastings algorithms */
#include "mh.h"
/** utility and inline functions */
#include "utilities.h"
/** declarations for R callable functions */
#include "bcplm.h"

/** cholmod_common struct initialized  */
extern cholmod_common c;

/** target acceptance rate for tuning the univariate scale parameter */
#define MH_ACC_TAR 0.5
/** threshold in specifying the interval of allowed acceptance rates */
#define MH_ACC_TOL 0.1
/** the number of mark times required for a parameter to be deemed as fully tuned */
#define MH_ACC_MARK 3
/** the shape parameter of the inverse-Gamma prior */
#define IG_SHAPE 0.001
/** the scale parameter of the inverse-Gamma prior */
#define IG_SCALE 0.001

/** positions in the dims vector in Bayesian models */
enum dimB {
  nO_POS = 0,			/**<number of observations */
  nB_POS,			/**<number of fixed effects */
  nP_POS,			/**<number of positive observations */
  nT_POS,                       /**<number of terms (grouping factors) in bcpglmm */
  nU_POS,                       /**<number of random coefficients */
  nA_POS,                       /**<number of parameters in Gibbs */
  chn_POS,			/**<number of chains */
  itr_POS,			/**<number of iterations */
  bun_POS,			/**<number of burn-in */
  thn_POS,			/**<number of thinning */
  kp_POS,			/**<number of simulations to keep in each chain */
  sims_POS,			/**<total number of simulations */
  rpt_POS,			/**<report frequency */
  tnit_POS,			/**<number of iterations used for tuning */
  ntn_POS,			/**<number of tuning loops */
  nmh_POS                       /**<number of M-H proposal variances to be tuned **/
};


/************************************************/
/*   Level 0 utility functions for printing    */  
/************************************************/

/**
 * utility function to print out acceptance rates
 *
 * @param n number of iterations
 * @param p the length of acc
 * @param acc a vector that stores acceptance times or percentages
 * @param pct indicating whether acc is the acceptance percentage or the unscaled acceptance times
 *
 */
static R_INLINE void print_acc(int n, int p, double *acc, int pct){
  double C = (pct) ? 100 : (100.0/n);
  Rprintf(_("Acceptance rate: min(%4.2f%%), mean(%4.2f%%), max(%4.2f%%)\n"),
	  dmin(acc, p) * C, mean(acc, p) * C, dmax(acc, p) * C);     
}

/**
 * utility function to print out division lines 
 */
static R_INLINE void print_line(){
  Rprintf("-----------------------------------------\n");
}


/************************************************/
/*   Level 1 utility functions for computing    */  
/*        full conditionals in bcplm            */
/************************************************/

/**
 * update the eta and mu slots in cpglm according to x
 *
 * @param x pointer to the vector of values for beta
 * @param da pointer to an SEXP struct
 *
 */

static void cpglm_fitted(double *x, SEXP da){
  int *dm = DIMS_SLOT(da) ;
  int nO = dm[nO_POS], nB = dm[nB_POS];
  double *X = X_SLOT(da),
    *beta = FIXEF_SLOT(da), *eta = ETA_SLOT(da),
    *mu = MU_SLOT(da), *offset = OFFSET_SLOT(da), 
    lp = LKP_SLOT(da)[0] ;
  if (x)  beta = x ;   /* point beta to x if x is not NULL */
  /* eta = X %*% beta */
  mult_mv("N", nO, nB, X, beta, eta) ;
  for (int i = 0; i < nO; i++){
    eta[i] += offset[i] ;
    mu[i] = link_inv(eta[i], lp);
  }
}

/**
 * Update the Xb, Zu, eta and mu slots in cpglmm according to x
 *
 * @param x pointer to the vector of values for beta or u
 * @param is_beta indicates whether x contains the values for beta or u. 
 *   1: x contains values of beta, and Zu is not updated. If x is null, the fixef slot is used; 
 *   0: x contains values of u, and Xb is not updated. If x is null, the u slot is used;
 *  -1: x is ignored, and the fixef and u slots are used.
 * @param da an SEXP object
 *
 */
static void cpglmm_fitted(double *x, int is_beta, SEXP da){    
  int *dm = DIMS_SLOT(da) ;
  int nO = dm[nO_POS], nB = dm[nB_POS], nU = dm[nU_POS];
  double  *X = X_SLOT(da), *eta = ETA_SLOT(da), 
    *mu = MU_SLOT(da), *beta = FIXEF_SLOT(da),
    *u = U_SLOT(da), *offset= OFFSET_SLOT(da), 
    *Xb = XB_SLOT(da), *Zu = ZU_SLOT(da), 
    lp = LKP_SLOT(da)[0], one[] = {1, 0}, zero[] = {0, 0};

  if (is_beta == -1) x = NULL ;            /* update from the fixef and u slots */

  /* update Xb */
  if (is_beta == 1 || is_beta == -1){      /* beta is updated */
    if (x)  beta = x ;                     /* point beta to x if x is not NULL */
    mult_mv("N", nO, nB, X, beta, Xb) ;    /* Xb = x * beta */
  }
  /* update Zu */
  if (is_beta == 0 || is_beta == -1){      /* u is updated */ 
    SEXP tmp;                              /* create an SEXP object to be coerced to CHM_DN */
    PROTECT(tmp = allocVector(REALSXP, nU));
    if (x) Memcpy(REAL(tmp), x, nU);      
    else Memcpy(REAL(tmp), u, nU);
    CHM_DN ceta, us = AS_CHM_DN(tmp);
    CHM_SP Zt = Zt_SLOT(da);
    R_CheckStack();
    ceta = N_AS_CHM_DN(Zu, nO, 1);          /* update Zu */
    R_CheckStack();                         /* Y = alpha * A * X + beta * Y */
    if (!M_cholmod_sdmult(Zt, 1 , one, zero, us, ceta, &c))
      error(_("cholmod_sdmult error returned"));
    UNPROTECT(1) ;
  }
  for (int i = 0; i < nO; i++){             /* update mu */
    eta[i] = Xb[i] + Zu[i] + offset[i];     /* eta = Xb + Z * u  + offset*/
    mu[i] = link_inv(eta[i], lp);
  }
}

/**
 * Update the Xb, Zu, eta and mu slots in bcplm using FIXEF and U 
 *
 * @param da a list object
 *
 */
static void update_mu(SEXP da){
  if (DIMS_SLOT(da)[nU_POS]) 
    cpglmm_fitted((double *) NULL, -1, da);
  else 
    cpglm_fitted((double *) NULL,  da);
}


/**
 * the data loglikelihood related to mu, assuming all but 
 * the mean parameters are constants
 *
 * @param da an SEXP struct
 *
 * @return the loglikelihood related to the mean
 */

static double llik_mu(SEXP da){  
  int *dm = DIMS_SLOT(da), *ygt0 = YPO_SLOT(da), k = 0;
  double *Y = Y_SLOT(da), *mu = MU_SLOT(da), *pwt = PWT_SLOT(da), 
    p = P_SLOT(da)[0], phi = PHI_SLOT(da)[0] ;
  double ld = 0.0, p2 = 2.0 - p, p1 = p - 1.0 ;

  for (int i = 0; i < dm[nO_POS]; i++)
    ld += pow(mu[i], p2) * pwt[i];
  ld /= - phi * p2 ;
  for (int i = 0; i < dm[nP_POS]; i++){
    k = ygt0[i] ;
    ld += - Y[k] * pow(mu[k], -p1) * pwt[k] / (phi * p1);
  }
  return ld ;
}

/**
 * compute the log prior distribution for a specified group  
 *
 * @param gn the group number
 * @param da an SEXP struct
 *
 * @return the log prior contribution of the specified group 
 */

static double prior_u_Gp(int gn, SEXP da){
  SEXP V = GET_SLOT(da, install("Sigma")); 
  int *Gp = Gp_SLOT(da), *nc = NCOL_SLOT(da), *nlev = NLEV_SLOT(da) ;
  double *v = REAL(VECTOR_ELT(V, gn)), *u = U_SLOT(da), ans = 0.0; 
  if (nc[gn] == 1) {                 /* univariate normal */
    for (int j = 0; j < nlev[gn]; j++)
      ans += -0.5 * u[Gp[gn] + j] * u[Gp[gn] + j] / v[0];
    return ans ;
  }
  else {                             /* multivariate normal */
    double *xv = Alloca(nc[gn], double), 
      *iv = Alloca(nc[gn] * nc[gn], double);
    R_CheckStack() ;    
    solve_po(nc[gn], v, iv) ;
    for (int j = 0; j < nlev[gn]; j++){
      for (int i = 0; i < nc[gn]; i++)
	xv[i] =  u[Gp[gn] + i * nlev[gn] + j] ;  
      ans += dmvnorm(nc[gn], xv, (double*) NULL, iv) ;
    }
    return ans ;
  }
}

/**
 * compute the contribution of the prior specification for u_k
 *
 * @param x vector of values for u_k
 * @param da an SEXP struct
 *
 * @return the loglikelihood related to the mean
 */

static double prior_uk(double x, SEXP da){
  int *dm = DIMS_SLOT(da), *Gp = Gp_SLOT(da), k = K_SLOT(da)[0];
  int gn = Gp_grp(k, dm[nT_POS], Gp); /* group number of u_k */
  double *u = U_SLOT(da), tmp = U_SLOT(da)[k], ans; 
  u[k] = x ;
  ans = prior_u_Gp(gn, da);           /* compute log prior for group gn */              
  u[k] = tmp ;
  return ans;
}

/************************************************/
/*   Level 2 utility functions to compute full  */
/*      conditionals used in the simulation     */  
/************************************************/

/**
 * the log posterior density of the index parameter p
 * (this is the same in both bcpglm and bcpglmm)
 *
 * @param x the value of p at which the log density is to be calculated
 * @param data a void struct, cocerced to SEXP internally
 *
 * @return log posterior density for p
 */
static double post_p(double x, void *data){
  SEXP da = data;
  double *Y = Y_SLOT(da), *mu = MU_SLOT(da), phi = PHI_SLOT(da)[0],
    *pwt = PWT_SLOT(da);
  return -0.5 * dl2tweedie(DIMS_SLOT(da)[nO_POS], Y, mu, phi, x, pwt) ;
}


/**
 * the log posterior density of the dispersion parameter phi
 * (this is the same in both bcpglm and bcpglmm)
 *
 * @param x the value of phi at which the log density is to be calculated
 * @param data a void struct, cocerced to SEXP internally
 *
 * @return log posterior density for phi
 */
static double post_phi(double x, void *data){
  SEXP da = data ;
  double *Y = Y_SLOT(da), *mu = MU_SLOT(da), p = P_SLOT(da)[0],
    *pwt = PWT_SLOT(da) ;
  return -0.5 * dl2tweedie(DIMS_SLOT(da)[nO_POS], Y, mu, x, p, pwt)  ;
}

/**
 * the log posterior density of beta_k, assuming Zu has been updated in cpglmm
 *
 * @param x the value of beta_k
 * @param data a void struct that is coerced to SEXP
 *
 * @return log posterior density for beta_k
 *
 */
static double post_betak(double x,  void *data){
  SEXP da = data ;
  int k = K_SLOT(da)[0], nU = DIMS_SLOT(da)[nU_POS]; 
  double pm = PBM_SLOT(da)[k], pv = PBV_SLOT(da)[k], 
    *l = CLLIK_SLOT(da), *beta = FIXEF_SLOT(da);
  double tmp = beta[k];
  beta[k] = x ;       /* update beta to compute mu */
  if (nU) cpglmm_fitted(beta, 1, da);
  else cpglm_fitted(beta, da) ;
  beta[k] = tmp ;     /* restore old beta values */
  *l = llik_mu(da) ;  /* this is stored and reused to speed up the simulation */
  return  *l - 0.5 * (x - pm) * (x - pm) / pv ;
}

/**
 * the log posterior density of u_k, assuming Xb has been updated
 *
 * @param x vector of values for u_k
 * @param data a void struct that is coerced to SEXP
 *
 * @return the log posterior density for u_k
 * 
 */
static double post_uk(double x,  void *data){
  SEXP da = data ;
  int k = K_SLOT(da)[0];
  double *u = U_SLOT(da),  *l = CLLIK_SLOT(da), tmp = U_SLOT(da)[k];    
  u[k] = x ;          /* update u to compute mu */
  cpglmm_fitted(u, 0, da) ;
  u[k] = tmp ;        /* restore old u values */
  *l = llik_mu(da);  
  return *l + prior_uk(x, da);
}


/************************************************/
/*   Level 3 utility functions for simulating   */  
/*          the parameters in bcplm             */
/************************************************/

/**
 * Simulate beta using the naive Gibbs update
 *
 * @param da an SEXP struct
 *
 */
static void sim_beta(SEXP da){
  int *dm = DIMS_SLOT(da), *k = K_SLOT(da);
  int nB = dm[nB_POS];
  double *beta = FIXEF_SLOT(da), *mh_sd = MHSD_SLOT(da), *l = CLLIK_SLOT(da), 
    *pm = PBM_SLOT(da), *pv = PBV_SLOT(da), *acc = ACC_SLOT(da);
  double xo, xn, l1, l2, A;

  /* initialize llik_mu*/
  *l = llik_mu(da);
  for (int j = 0; j < nB; j++){
    *k = j;
    xo = beta[j];
    xn = rnorm(xo, mh_sd[j]);
    l1 = *l;
    l2 = post_betak(xn, da);
    A = exp(l2 - l1 + 0.5 * (xo - pm[j]) * (xo - pm[j]) / pv[j]);
    /* determine whether to accept the sample */
    if (A < 1 && runif(0, 1) >= A){ /* not accepted */
      *l = l1;       /* revert the likelihood (this is updated in post_betak) */
    }
    else {
      beta[j] = xn;
      acc[j]++;    
    }
  }                  /* update the mean using the new beta */                    
  if (dm[nU_POS]) cpglmm_fitted(beta, 1, da);
  else cpglm_fitted(beta, da);  
}

/**
 * Simulate phi and p using the univariate RW M-H update.
 *
 * @param da a bcplm_input object
 *
 */

static void sim_phi_p(SEXP da){
  int *dm = DIMS_SLOT(da);
  int nB = dm[nB_POS]; 
  double *p = P_SLOT(da), *phi = PHI_SLOT(da), 
    *mh_sd = MHSD_SLOT(da), *acc = ACC_SLOT(da), 
    xn = 0.0;
  /* update phi */
  acc[nB] += metrop_tnorm_rw(*phi, mh_sd[nB], 0, BDPHI_SLOT(da)[0], 
			&xn, post_phi, (void *) da);
  *phi = xn ;
  /* update p */
  acc[nB + 1] += metrop_tnorm_rw(*p, mh_sd[nB + 1], BDP_SLOT(da)[0], 
			BDP_SLOT(da)[1], &xn, post_p, (void *) da);	
  *p = xn ;
}


/**
 * Simulate u using the naive Gibbs method. Block M-H update
 * generally does not work well and hence is not implemented.
 *
 * @param da a bcplm_input object
 *
 */

static void sim_u(SEXP da){
  int *dm = DIMS_SLOT(da), *k = K_SLOT(da);
  int nB = dm[nB_POS], nU = dm[nU_POS];
  double *u = U_SLOT(da), *l = CLLIK_SLOT(da), 
    *mh_sd = MHSD_SLOT(da) + nB + 2, /* shift the proposal variance pointer */
    *acc = ACC_SLOT(da) + nB + 2;    /* shift the acc pointer */
  double xo, xn, l1, l2, A;

  /* initialize llik_mu*/
  *l = llik_mu(da);
  for (int j = 0; j < nU; j++){
    *k = j ;
    xo = u[j];
    xn = rnorm(xo, mh_sd[j]);
    l1 = *l;
    l2 = post_uk(xn, da);
    A = exp(l2 - (l1 + prior_uk(xo, da)));  
    /* determine whether to accept the sample */
    if (A < 1 && runif(0, 1) >= A){ 
      *l = l1;  /* revert llik_mu (this is updated in post_uk) */
    }
    else{
      u[j] = xn;
      acc[j]++;    
    }
  }
  cpglmm_fitted(u, 0, da) ;  /* update the mean using the new u */
}

/**
 * Simulate the variance components. If there is only one random effect 
 * per level, the posterior is the inverse Gamma. Otherwise, the posterior 
 * is the inverse Wishart.  
 *
 * @param da a bcplm_input object
 *
 */

static void sim_Sigma(SEXP da){
  SEXP V = GET_SLOT(da, install("Sigma")) ;
  int *dm = DIMS_SLOT(da), *Gp = Gp_SLOT(da),  
    *nc = NCOL_SLOT(da), *nlev = NLEV_SLOT(da); 
  int nT = dm[nT_POS], mc = imax(nc, nT);
  double *v, su, *u = U_SLOT(da), 
    *scl = Alloca(mc * mc, double);
  R_CheckStack();

  for (int i = 0; i < nT; i++){
    v = REAL(VECTOR_ELT(V, i));
    if (nc[i] == 1){         /* simulate from the inverse-Gamma */
      su = sqr_length(u + Gp[i], nlev[i]);                    
      v[0] = 1/rgamma(0.5 * nlev[i] + IG_SHAPE, 1.0/(su * 0.5 + IG_SCALE));      
    }
    else {                   /* simulate from the inverse-Wishart */
      mult_xtx(nlev[i], nc[i], u + Gp[i], scl);            /* t(x) * (x) */
      for (int j = 0; j < nc[i]; j++) scl[j * j] += 1.0;   /* add prior (identity) scale matrix  */
      solve_po(nc[i], scl, v);
      rwishart(nc[i], (double) (nlev[i] + nc[i]), v, scl);
      solve_po(nc[i], scl, v);                  
    }
  }
}

/************************************************/
/* Additional utility functions for implementing*/  
/*        the MCMC sampler in bcplm             */
/************************************************/

/**
 * Set parameters to the k_th initial values provided in the inits slot
 *
 * @param da a bcplm_input object
 * @param k indicates the k_th set of initial values
 *
 * \note the order of the parameters in inits is: beta, phi, p, u and Sigma
 */

static void get_init(SEXP da, int k){
  
  SEXP inits = GET_SLOT(da, install("inits"));  /* inits is a list */
  int *dm = DIMS_SLOT(da);
  int nB = dm[nB_POS], nU = dm[nU_POS], nT = dm[nT_POS];
  double *init = REAL(VECTOR_ELT(inits, k));

  /* set beta, phi, p*/
  Memcpy(FIXEF_SLOT(da), init, nB) ;
  *PHI_SLOT(da) = init[nB] ;
  *P_SLOT(da) = init[nB + 1] ;

  /* set U and Sigma */
  if (nU) {
    SEXP V = GET_SLOT(da, install("Sigma"));
    int pos = 0, st = nB + 2, *nc = NCOL_SLOT(da) ;
    double *v ;
    Memcpy(U_SLOT(da), init + st, nU);
    /* set Sigma */
    for (int i = 0; i < nT; i++){
      v = REAL(VECTOR_ELT(V, i)) ;
      Memcpy(v, init + st + nU + pos, nc[i] * nc[i]) ;
      pos += nc[i] * nc[i] ;
    }    
  }
}

/**
 * Save parameters to the ns_th row of the simulation results
 *
 * @param da a bcplm_input object 
 * @param ns indicates the ns_th row
 * @param nS number of rows in sims 
 * @param sims a long vector to store simulations results 
 *
 */
static void set_sims(SEXP da, int ns, int nS, double *sims){

  int *dm = DIMS_SLOT(da) ;
  int pos = 0, nB = dm[nB_POS], nU = dm[nU_POS],
    nT = dm[nT_POS];
  double *beta = FIXEF_SLOT(da), *u = U_SLOT(da);

  for (int j = 0; j < nB; j++)  
    sims[j * nS + ns] = beta[j] ;
  sims[nB * nS + ns] = *PHI_SLOT(da) ;
  sims[(nB + 1) * nS + ns] = *P_SLOT(da) ;

  /* set U and Sigma */
  if (nU) {
    SEXP V = GET_SLOT(da, install("Sigma"));
    int *nc = NCOL_SLOT(da), st = nB + 2;
    double *v; 
    for (int j = 0; j < nU; j++)
      sims[(j + st) * nS + ns] = u[j] ; 
    for (int i = 0; i < nT; i++){
      v = REAL(VECTOR_ELT(V, i));
      for (int j = 0; j < nc[i] * nc[i]; j++)
	sims[(st + nU + pos + j) * nS + ns] = v[j] ;
      pos += nc[i] * nc[i] ;
    }
  } 
}


/**
 * update the proposal standard deviations 
 *
 * @param p the number of parameters to be tuned
 * @param acc pointer to the acceptance rate in the M-H update
 * @param mh_sd pointer to the vector of proposal standard deviations
 * @param mark pointer to the vector of marks
 *
 */
static R_INLINE void tune_var(int p, double *acc, double *mh_sd, int *mark) {
  double acc_bd;
  for (int j = 0; j < p; j++){
    acc_bd = fmin2(fmax2(acc[j], 0.01), 0.99); /* bound the empirical acceptance */
    if (acc[j] < (MH_ACC_TAR - MH_ACC_TOL))
      mh_sd[j] /= 2 - acc_bd/MH_ACC_TAR;
    else if (acc[j] > (MH_ACC_TAR - MH_ACC_TOL))	    
      mh_sd[j] *= 2 - (1 - acc_bd)/(1 - MH_ACC_TAR);      
    else mark[j]++;      
  }  
}



/************************************************/
/*         MCMC simulations for cplm            */
/************************************************/

/**
 * main workhorse for the MCMC simulation
 *
 * @param da a bcplm_input object
 * @param nit number of iterations
 * @param nbn number of burn-in
 * @param nth thinning rate
 * @param nS the number of rows of sims
 * @param nR report interval
 * @param sims a 2d array to store simulation results
 *
 * \note It's assumed that eta and mu are already updated. Also,
 * nS is passed as an argument rather than determined from da. 
 * This is because the tuning process uses a different number of 
 * simulations than the n.keep element in the dims slot. 
 *
 */

static void do_mcmc(SEXP da, int nit, int nbn, int nth, int nS, 
		    int nR, double *sims){

  int *dm = DIMS_SLOT(da);
  int nU = dm[nU_POS], nmh = dm[nmh_POS],
    ns = 0, do_print = 0;
  /* initialize acc */
  double *acc = ACC_SLOT(da);
  AZERO(acc, nmh);

  /* run MCMC simulatons */
  GetRNGstate();
  for (int iter = 0; iter < nit; iter++){
    do_print = (nR > 0 && (iter + 1) % nR == 0);
    if (do_print) Rprintf(_("Iteration: %d \n "), iter + 1);

    /* update parameters */
    sim_beta(da);
    sim_phi_p(da);
    if (nU){
      sim_u(da);
      sim_Sigma(da);
    }
        
    /* store results  */
    if (iter >= nbn &&  (iter + 1 - nbn) % nth == 0 ){
      ns = (iter + 1 - nbn) / nth - 1;
      set_sims(da, ns, nS, sims);
    } 

    /* print out acceptance rate if necessary */
    if (do_print) print_acc(iter + 1, nmh, acc, 0);
    R_CheckUserInterrupt();
  }
  PutRNGstate();
  /* compute acceptance percentage */
  for (int i = 0; i < nmh; i++) acc[i] /= nit ;
}


/**
 * tune the proposal variances 
 *
 * @param da an input list object
 *
 */
static void tune_mcmc(SEXP da){
  int *dm = DIMS_SLOT(da);
  int nmh = dm[nmh_POS],
    etn = ceil(dm[tnit_POS] * 1.0 / dm[ntn_POS]) ;  // # iters per tuning loop;
  double *mh_sd = MHSD_SLOT(da), *acc = ACC_SLOT(da), 
    *sims = Calloc(etn * dm[nA_POS], double);
  int nmark = 0, *mark = Calloc(nmh, int);
  AZERO(mark, nmh);

  /* run MCMC and tune parameters */
  if (dm[rpt_POS]) Rprintf(_("Tuning phase...\n"));
  for (int i = 0; i < dm[ntn_POS]; i++) {
    do_mcmc(da, etn, 0, 1, etn, 0, sims);      /* run mcmc */    
    tune_var(nmh, acc, mh_sd, mark);           /* adjust proposal sd's */
    /* determine whether the parameters are fully tuned */
    nmark = 0;
    for (int j = 0; j < nmh; j++)
      if (mark[j] >= 3) nmark++;
    if (nmark == nmh) break;
  }
  if (dm[rpt_POS]){
    print_acc(1, nmh, acc, 1);
    print_line();
  }
  Free(sims);
  Free(mark);
}

/**
 * implement MCMC for compound Poisson linear models
 *
 * @param da an bcplm_input object
 *
 * @return the simulated values
 *
 */

SEXP bcplm_mcmc (SEXP da){
  /* get dimensions */
  int *dm = DIMS_SLOT(da) ;
  int nR = dm[rpt_POS];
  SEXP ans, ans_tmp;

  /* tune the scale parameter for M-H update */
  if (dm[tnit_POS]) {
    update_mu(da);                    /* update eta mu*/
    tune_mcmc(da);
  }
    
  /* run Markov chains */
  PROTECT(ans = allocVector(VECSXP, dm[chn_POS])) ;

  for (int k = 0; k < dm[chn_POS]; k++){
    if (nR) Rprintf(_("Start Markov chain %d\n"), k + 1);   
    get_init(da, k) ;                /* initialize the chain */
    update_mu(da) ;                  /* update eta and mu */ 
  
    /* run MCMC and store result */
    PROTECT(ans_tmp = allocMatrix(REALSXP, dm[kp_POS], dm[nA_POS]));
    do_mcmc(da, dm[itr_POS], dm[bun_POS], dm[thn_POS], 
	    dm[kp_POS], nR, REAL(ans_tmp));
    SET_VECTOR_ELT(ans, k, ans_tmp);
    UNPROTECT(1);
    if (nR) print_line();
  }
  if (nR)  Rprintf(_("Markov Chain Monte Carlo ends!\n"));
  UNPROTECT(1);
  return ans;
    
}


/************************************************/
/*      Export R Callable functions             */
/************************************************/


/**
 * R callable function to update the mean in a bcplm object
 *
 * @param da  an bcplm_input object
 *
 */
SEXP bcplm_update_mu(SEXP da){
  update_mu(da);
  return R_NilValue;
}


/**
 * R callable function to compute the conditional posterior of p
 *
 * @param x value at which to evaluate the density
 * @param da  an bcplm_input object
 *
 * @return the log of the conditional posterior of p 
 */
SEXP bcplm_post_p(SEXP x, SEXP da){
  return ScalarReal(post_p(REAL(x)[0], (void *) da));
}


/**
 * R callable function to compute the conditional posterior of phi
 *
 * @param x value at which to evaluate the density
 * @param da  an bcplm_input object
 *
 * @return the log of the conditional posterior of phi
 */
SEXP bcplm_post_phi(SEXP x, SEXP da){
  return ScalarReal(post_phi(REAL(x)[0], (void *) da));
}


/**
 * R callable function to compute the conditional posterior of betak
 *
 * @param x value at which to evaluate the density
 * @param da  an bcplm_input object
 *
 * @return the log of the conditional posterior of betak
 */
SEXP bcplm_post_betak(SEXP x, SEXP da){
  return ScalarReal(post_betak(REAL(x)[0], (void *) da));
}


/**
 * R callable function to compute the conditional posterior of uk
 *
 * @param x value at which to evaluate the density
 * @param da  an bcplm_input object
 *
 * @return the log of the conditional posterior of uk
 */
SEXP bcplm_post_uk(SEXP x, SEXP da){
  return ScalarReal(post_uk(REAL(x)[0], (void *) da));
}
back to top