Skip to main content
  • Home
  • Development
  • Documentation
  • Donate
  • Operational login
  • Browse the archive

swh logo
SoftwareHeritage
Software
Heritage
Archive
Features
  • Search

  • Downloads

  • Save code now

  • Add forge now

  • Help

  • dd9e837
  • /
  • src
  • /
  • bcplm.c
Raw File Download

To reference or cite the objects present in the Software Heritage archive, permalinks based on SoftWare Hash IDentifiers (SWHIDs) must be used.
Select below a type of object currently browsed in order to display its associated SWHID and permalink.

  • content
  • directory
content badge
swh:1:cnt:364441d9b3dfafcccc1ad36d27572af00425b977
directory badge
swh:1:dir:38733194ca6dcbf9bd971e3c209c7fa4d2e0f08d

This interface enables to generate software citations, provided that the root directory of browsed objects contains a citation.cff or codemeta.json file.
Select below a type of object currently browsed in order to generate citations for them.

  • content
  • directory
(requires biblatex-software package)
Generating citation ...
(requires biblatex-software package)
Generating citation ...
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();
  }
  UNPROTECT(1) ;
  if (nR)  Rprintf(_("Markov Chain Monte Carlo ends!\n"));
  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

Software Heritage — Copyright (C) 2015–2026, The Software Heritage developers. License: GNU AGPLv3+.
The source code of Software Heritage itself is available on our development forge.
The source code files archived by Software Heritage are available under their own copyright and licenses.
Terms of use: Archive access, API— Content policy— Contact— JavaScript license information— Web API