#include #include #include #include #include /* Define variables rr and qq for adapting proposals during pilot tuning */ #define rr 1.0 #define qq 1.25 #define newgs 10.0 /* Define function MCMCloop to draw samples from the posterior distribution Parameters that are returned: eta_z = Correlation between consecutive movement directions in centre of attraction state z m_z = Intercept term for strength of bias to centre of attraction z r_z = Strength of bias as a function of distance to centre of attraction z q_z = Strength of bias as a function of distance^2 to centre of attraction z X_z = Location of the X coordinate for centre of attraction z Y_z = Location of the Y coordinate for centre of attraction z a = Scale parameter of the Weibull distribution for step length (for centres of attraction, when delta_t > d_z) b = Shape parameter of the Weibull distriubtion for step length (for centres of attraction, when delta_t > d_z) a2 = Scale parameter of the Weibull distribution for step length (when delta_t < d_z) b2 = Shape parameter of the Weibull distriubtion for step length (when delta_t < d_z) d_z = Change-point distance of Weibull distribution parameters for centre of attraction states upsilon = Correlation between consecutive movement directions in an exploratory state phi_0 = Initial movement direction tau = Variance of the Normal(0,tau) prior distributions for r_z and q_z sigma2_x = Variance of the N(0,sigma2_x) observation error term in the x direction sigma2_y = Variance of the N(0,sigma2_y) observation error term in the y direction X_t = Predicted location of the X coordinate at time t Y_t = Predicted location of the Y coordinate at time t psi = State transition probabilities z_t = State assignment for each time step t centre_loc = Vector indicating which predicted locations (X_t, Y_t) are the current centres of attraction Model = Vector indicating the model structure; '1' indicates a (state-specific) parameter currently in the model from the full set ordered by eta_z, q_z, m_z, and upsilon (z = 1,...,c). For example, for c=3, 0111000101 indicates eta_2, eta_3, q_1, m_2, and upsilon are currently in the model sigma_scale = Scale parameter for the inverse gamma prior on sigma2_x and sigma2_y sigma_shape = Shape parameter for the inverse gamma prior on sigma2_x and sigma2_y tau_scale = Scale parameter for the inverse gamma prior on tau tau_shape = Shape parameter for the inverse gamma prior on tau bupper = Upper limit for Unif(0,bupper) prior on Weibull shape parameter (b) Other variables returned: loglike = Value of the likelihood function gs = Vector of values for (adaptive) proposal distributions arate = Metropolis-Hasting acceptance rate Data: x_ti = Observed location of the X coordinate at time t, i (includes missing locations where i=0) y_ti = Observed location of the Y coordinate at time t, i (includes missing locations where i=0) N = Number of predicted locations (T+1) fparms = Number of parameters, excluding z_t, psi, (X_t, Y_t), and missing (x_ti, y_ti) numbercentres = Number of potential centres of attraction (c) numberexplore = Number of potential exploratory states (h) ssidx = Vector for looping over the observed location (x_ti, y_ti) within each time step t j_ti = Vector indicating the proportion of each interval (t-1,t) at which the ith observation (x_ti,y_ti) was obtained. For any interval where i=0, j_ti = -1. nvt = Number of vertices for the polygon evaluated in PNPOLY() function nogo1x = X coordinates of vertices for polygon indicating inland areas nogo1y = Y coordinates of vertices for polygon indicating inland areas nogo2x = X coordinates of vertices for polygon indicating inland areas nogo2y = Y coordinates of vertices for polygon indicating inland areas nogo3x = X coordinates of vertices for polygon indicating inland areas nogo3y = Y coordinates of vertices for polygon indicating inland areas nogo4x = X coordinates of vertices for polygon indicating inland areas nogo4y = Y coordinates of vertices for polygon indicating inland areas maxdist = Maximum distance between observed locations; used to scale distances within GETRHO() function maxstep = Maximum step length Markov chain specifications: iter = Number of iterations of the Markov chain thin = Number of iterations for thinning of the Markov chain adapt = Number of iterations for pilot tuning bin = Number of iterations between each pilot tune taccept = Target acceptance rate for Metropolis-Hastings updates txyaccept = Target acceptance rate for (X_t,Y_t) MH block updates tcentreaccept = Target acceptance rate for (X_z,Y_z) MH updates print_iteration_count = Indicator for whether to print iteration count (=1) or not (=0) */ void MCMCloop(double *eta_z, double *m_z, double *r_z, double *q_z, double *X_z, double *Y_z, double *a, double *b, double *a2, double *b2, double *d_z, double *upsilon, double *phi_0, double *tau, double *sigma2_x, double *sigma2_y, double *X_t, double *Y_t, double *psi, int *z_t, int *centre_loc, int *Model, double *sigma_scale, double *sigma_shape, double *tau_scale, double *tau_shape, double *b_upper, double *loglike, double *gs, double *arate, double *x_ti, double *y_ti, int *N, int *fparms, int *numbercentres, int *numberexplore, int *ssidx, double *j_ti, int *nvt, double *nogo1x, double *nogo1y, double *nogo2x, double *nogo2y, double *nogo3x, double *nogo3y, double *nogo4x, double *nogo4y, double *maxdist, double *maxstep, int *iter, int *thin, int *adapt, int *bin, double *taccept, double *txyaccept, double *tcentreaccept, int *print_iteration_count) { /* Declare functions */ double LIKE(); /* Calculates joint likelihood */ double LIKEXY(); /* Calculates conditional likelihood for updating each position (X_t, Y_t) */ void GETZ(); /* Updates state assigments (z_t) for each time step */ double ZPRIOR(); /* Calculates prior density for z_ts */ void GETPSI(); /* Updates state transition probabilities (psi) */ double DINVGAMMA(); /* Inverse Gamma probability density function */ int PNPOLY(); /* Tests whether locations lie within n-sided polygon) */ int PROPCENTRE(); /* Proposes new position for centres of attraction from predicted locations (X_t, Y_t) */ int GETMk(); /* Calculate number of locations (X_t, Y_t) within some distance of centre of attraction (X_z, Y_z) */ double GETSTEP(); /* Calculate step length between two locations */ /* Declare and initialize variables */ int niter, th, ada, n; niter = *iter; /* Number of iterations in the Markov chain */ th = *thin; /* Number of iterations for thinning */ ada = *adapt; /* Number of iterations for pilot tuning */ n = *bin; /* Number of iterations between each pilot tune */ int nsteps, firstparms, ncentres, nexplore; nsteps = *N; /* Number of predicted locations (T+1) */ firstparms = *fparms; /* Number of parameters, excluding z_t, psi, (X_t, Y_t), and missing (x_ti, y_ti) */ ncentres = *numbercentres; /* Number of potential centres of attraction */ nexplore = *numberexplore; /* Number of potential exploratory states */ int states = ncentres+nexplore; /* Total number of potential states */ double sigmascale, sigmashape, tauscale, taushape, bupper, mdist, mstep, targetaccept, targetxyaccept, targetcentreaccept; sigmascale = *sigma_scale; /* Scale parameter for inverse gamma prior on sigma2_x and sigma2_y */ sigmashape = *sigma_shape; /* Shape parameter for inverse gamma prior on sigma2_x and sigma2_y */ tauscale = *tau_scale; /* Scale parameter for inverse gamma prior on tau */ taushape = *tau_shape; /* Shape parameter for inverse gamma prior on tau */ bupper = *b_upper; /* Upper limit for Unif(0,bupper) prior on Weibull shape parameter (b) */ mdist = *maxdist; /* Maximum distance between observed locations; used to scale distances within GETRHO() function */ mstep = *maxstep; /* Maximum possible step length */ targetaccept = *taccept; /* Target acceptance rate for Metropolis-Hastings updates */ targetxyaccept = *txyaccept; /* Target acceptance rate for (X_t,Y_t) MH updates */ targetcentreaccept = *tcentreaccept; /* Target acceptance rate for (X_z,Y_z) MH updates */ double ll; /* Current value for log-likelihood */ double nl, ol; /* Proposed and current likelihood for use in Metropolis Hastings ratio */ double nprior, oprior, nprop, oprop; /* Proposed and current prior/proposal densities for use in MH ratio */ double npropz, opropz; /* Proposed and current prior/proposal densities for z_ts */ int nvert; /* Number of vertices for the polygons evaluated in PNPOLY() function */ nvert = *nvt; /* Declare variables to store current (s) values of parameters */ double eta_zs[ncentres], m_zs[ncentres], r_zs[ncentres], q_zs[ncentres], upsilons[nexplore]; double X_zs[ncentres], Y_zs[ncentres], X_ts[nsteps], Y_ts[nsteps]; double as[states], a2s[ncentres], bs[states], b2s[ncentres], d_zs[ncentres], phi_0s, taus, sigma2_xs, sigma2_ys; /* Declare variables for proposed (star) values of parameters */ double eta_zstar[ncentres], m_zstar[ncentres], r_zstar[ncentres], q_zstar[ncentres], upsilonstar[nexplore]; double X_zstar[ncentres], Y_zstar[ncentres], X_tstar[nsteps], Y_tstar[nsteps]; double astar[states], a2star[ncentres], bstar[states], b2star[ncentres], d_zstar[ncentres], phi_0star, taustar, sigma2_xstar, sigma2_ystar; double psis[(states)*(states)]; /* Vector storing current values of state transition probabilities (psi) */ double pvect[states]; /* Row vector of state transition probabilities from state z, psi[z,.], returned by function GETPSI() */ int z_ts[nsteps]; /* Vector of current state assignments for time steps 0,...,T */ int z_tstar[nsteps]; /* Vector of proposed state assignments for time steps 0,...,T */ double zdens[nsteps]; /* Vector for storing conditional density of state assignments for time steps 0,...,T */ int centre_locs[ncentres]; /* Vector indicating which predicted locations (X_t, Y_t) are the current centres of attraction */ int centre_locstar[ncentres]; /* Vector indicating which predicted locations (X_t, Y_t) are the proposed centres of attraction */ double centredist; /* Variable indicating the distance from predicted location to centre of attraction z */ /* Miscellaneous variables */ int i, g, j, jj; /* For loops */ int parm1, parm2; /* For specifying parameter numbers for (X_t, Y_t) updates */ double phi_0temp; /* Temporary proposal phi_0 */ double w_n=0.0; /* Denominator for calculating acceptance rate */ double invgs, sha, sca; /* Random walk proposal parameters */ int Mk[ncentres], Mkstar[ncentres]; /* Number of current (or proposed) locations within some distance of current (or proposed) centre of attraction */ int centre_ind=0; /* Centre indicator for when location (X_t, Y_t) is a centre of attraction (centre_ind=1,...,ncentres) or not (centre_ind=0) */ /* Initial parameter values */ for (j=0; j < ncentres; j++) { eta_zs[j]=eta_z[j]; m_zs[j]=m_z[j]; r_zs[j]=r_z[j]; q_zs[j]=q_z[j]; X_zs[j]=X_z[j]; Y_zs[j]=Y_z[j]; a2s[j]=a2[j]; b2s[j]=b2[j]; d_zs[j]=d_z[j]; centre_locs[j]=centre_loc[j]; } for (j=0; j < (states); j++) { as[j]=a[j]; bs[j]=b[j]; } for (j=0; j0) { /* Check that 0 < eta_zstar < 1. Otherwise, reject */ nl= LIKE(eta_zstar, m_zs, r_zs, q_zs, X_zs, Y_zs, as, a2s, bs, b2s, d_zs, upsilons, phi_0s, sigma2_xs, sigma2_ys, X_ts, Y_ts, x_ti, y_ti, z_ts, Model_eta, Model_q, Model_upsilon, nsteps, ncentres, ssidx, j_ti, mdist, mstep); if(runif(0.0,1.0)= mstep) */ centredist = 1/gs[4*ncentres+j]; centre_locstar[j] = PROPCENTRE(j, z_ts, nsteps, X_zs, Y_zs, X_ts, Y_ts, centredist, centre_locs[j]); X_zstar[j] = X_ts[centre_locstar[j]]; Y_zstar[j] = Y_ts[centre_locstar[j]]; /* Propose new state assingnments (z_tstar) for proposed centre of attraction location */ GETZ(eta_zs, m_zs, r_zs, q_zs, X_zstar, Y_zstar, as, a2s, bs, b2s, d_zs, upsilons, phi_0s, X_ts, Y_ts, z_tstar, centre_locstar, psis, Model_eta, Model_q, Model_upsilon, nsteps, ncentres, states, mdist, zdens); npropz=0.0; for(jj=0; jj0) { /* Check that 0 < upsilonstar < 1. Otherwise, reject. */ nl= LIKE(eta_zs, m_zs, r_zs, q_zs, X_zs, Y_zs, as, a2s, bs, b2s, d_zs, upsilonstar, phi_0s, sigma2_xs, sigma2_ys, X_ts, Y_ts, x_ti, y_ti, z_ts, Model_eta, Model_q, Model_upsilon, nsteps, ncentres, ssidx, j_ti, mdist, mstep); if(runif(0.0,1.0)(6*ncentres-1)) ? targetaccept : targetcentreaccept)))); /* Tune gs for centre of attraction locations using targetcentreaccept */ } ap[j] = 0.0; /* Reset numerator of acceptance rate to zero */ } /* Ensure 1/gs for centre of attraction location updates doesn't exceed maxdist */ for (j=(4*ncentres); j<(6*ncentres); j++) { gs[j]=(((1/gs[j])>mdist) ? (1/mdist) : gs[j]); } /* Recalculate Mk based on new centredist */ for(j=0; j= 1.0) { dens = -HUGE_VAL; } else { dens=log((1.0/(2.0*PI)) * (1 - pow(rho,2.0)) / (1+pow(rho,2.0) - 2*rho*cos(phi-lambda))); } return(dens); } /* Define function RMULTINOM to draw from a multinomial distribution */ void RMULTINOM(int n, double* prob, int K, int* rN) { int k; double pp; double p_tot = 0.0; for(k = 0; k < K; k++) { pp = prob[k]; p_tot += pp; rN[k] = 0; } if(fabs((double) p_tot - (double) 0.) == (double) 0.) { Rprintf("error: RMULTINOM probability sum should be >0, but is %f \n", (double) p_tot); return; } else { /* Generate the first K-1 obs. via binomials */ for(k = 0; k < K-1; k++) { if(prob[k]) { pp = prob[k] / p_tot; rN[k] = ((pp < 1.) ? (int) rbinom((double) n, pp) : n); n -= rN[k]; } else rN[k] = 0; if(n <= 0) /* we have all*/ return; p_tot -= prob[k]; /* i.e. = sum(prob[(k+1):K]) */ } rN[K-1] = n; } return; } /* Define function GETDENOM to calculate the sum of a vector */ double GETDENOM(double *prob, int dim) { int j; double denom=0.0; for(j=0; jPI) { if(prevphi>PI) { prevphi= -(2*PI-prevphi); } if(mu>PI) { mu = -(2*PI-mu); } } lambda=eta_z[state]*Model_eta[state]*prevphi+(1-eta_z[state]*Model_eta[state])*mu; if(lambda<0) {lambda=2*PI+lambda;} } else { rho = upsilon[state-ncentres]*Model_upsilon[state-ncentres]; lambda=prevphi; scale=a[state]; shape=b[state]; } if(step < mstep) { liken += DWCAUCHY(phi,lambda,rho) + dweibull(step,shape,scale,1) + LIKEOBS(ssidx[j],ssidx[j+1],j_ti,X_ts[j],X_ts[j+1],Y_ts[j],Y_ts[j+1],x_ti,sigma2_x,y_ti,sigma2_y); } else { liken = -HUGE_VAL; } prevphi=phi; } liken = ((isfinite(liken)) ? liken : (-HUGE_VAL)); return(liken); } /* Define function LIKEXY to update locations (X_ts, Y_ts) */ double LIKEXY(int i, int blk, double *eta_z, double *m_z, double *r_z, double *q_z, double *X_z, double *Y_z, double *a, double *a2, double *b, double *b2, double *d_z, double *upsilon, double phi_0, double sigma2_x, double sigma2_y, double *X_ts, double *Y_ts, double *x_ti, double *y_ti, int *z_ts, int *Model_eta, int *Model_q, int *Model_upsilon, const int nsteps, int ncentres, const int *ssidx, const double *j_ti, const double mdist, double mstep) { int j, state; double step, phi, rho, delta_t, mu=0.0; double scale, shape; double liken = 0.0; double prevphi=phi_0; double lambda; if(i>1) { step = GETSTEP(X_ts[i-1],Y_ts[i-1],X_ts[i-2],Y_ts[i-2]); prevphi = GETDIR(X_ts[i-1],Y_ts[i-1],X_ts[i-2],Y_ts[i-2],step); } for(j=i-1; (j < i+blk+2) && (j=0)) { step = GETSTEP(X_ts[j+1],Y_ts[j+1],X_ts[j],Y_ts[j]); phi = GETDIR(X_ts[j+1],Y_ts[j+1],X_ts[j],Y_ts[j],step); state = z_ts[j+1]-1; /* Specify parameters for wrapped Cauchy distribution based on whether exploratory state or not */ if(statePI) { if(prevphi>PI) { prevphi= -(2*PI-prevphi); } if(mu>PI) { mu = -(2*PI-mu); } } lambda=eta_z[state]*Model_eta[state]*prevphi+(1-eta_z[state]*Model_eta[state])*mu; if(lambda<0) {lambda=2*PI+lambda;} } else { rho = upsilon[state-ncentres]*Model_upsilon[state-ncentres]; lambda=prevphi; scale=a[state]; shape=b[state]; } if(step < mstep) { liken += DWCAUCHY(phi,lambda,rho) + dweibull(step,shape,scale,1) + LIKEOBS(ssidx[j],ssidx[j+1],j_ti,X_ts[j],X_ts[j+1],Y_ts[j],Y_ts[j+1],x_ti,sigma2_x,y_ti,sigma2_y); } else { liken = -HUGE_VAL; } prevphi=phi; } } liken = ((isfinite(liken)) ? liken : (-HUGE_VAL)); return(liken); } /* Define function GETZ to update state assignments (z_ts) for each time step from the full conditional posterior distribution */ void GETZ(double *eta_zs, double *m_zs, double *r_zs, double *q_zs, double *X_zs, double *Y_zs, double *as, double *a2s, double *bs, double *b2s, double *d_zs, double *upsilons, double phi_0s, double *X_ts, double *Y_ts, int *z_ts, int *centre_locs, double *psis, int *Model_eta, int *Model_q, int *Model_upsilon, const int nsteps, int ncentres, int states, const double mdist, double *zdens) { int j, jj, k, state; int rN[states]; double step, phi, rho, delta_t=0.0, mu=0.0; double shape, scale; double pi[states],p[states]; /* Parameters of the full conditional categorical distribution for z_0 and z_t */ double newp[states]; double mp[states]; double prevphi=phi_0s; double lambda; for(jj=0; jjPI) { if(prevphi>PI) { prevphi= -(2*PI-prevphi); } if(mu>PI) { mu = -(2*PI-mu); } } lambda=eta_zs[state]*Model_eta[state]*prevphi+(1-eta_zs[state]*Model_eta[state])*mu; if(lambda<0) {lambda=2*PI+lambda;} } else { rho = upsilons[state-ncentres]*Model_upsilon[state-ncentres]; lambda=prevphi; scale=as[state]; shape=bs[state]; } newp[jj] = exp(DWCAUCHY(phi,lambda,rho) + dweibull(step,shape,scale,1)); if(j==(nsteps-2)) { mp[jj]=psis[jj+(z_ts[j]-1)*(states)] * newp[jj]; } else { mp[jj]=psis[jj+(z_ts[j]-1)*(states)] * newp[jj]* psis[z_ts[j+2]-1+jj*(states)]; } } prevphi=phi; for (jj=0; jj < (states); jj++) { /* Normalize so state probabilities sum to 1 */ p[jj]= (isfinite(mp[jj]) ? mp[jj] : 0.0); } RMULTINOM(1,p,(states),rN); /* Draw new state from full conditional (categorical) distribution for z_t */ for (k=0; k < (states); k++) { if((ktesty) != (verty[j]>testy)) && (testx < (vertx[j]-vertx[i]) * (testy-verty[i]) / (verty[j]-verty[i]) + vertx[i]) ) c = !c; } return c; } /* Propose new position (newpos) for centre of attraction (X_z, Y_z) from discrete uniform distribution over all positions within specified distance (centredist) of current centre of attraction */ int PROPCENTRE(int centre, int *z_ts, int nsteps, double *X_z, double *Y_z, double *X_t, double *Y_t, double centredist, int centreloc) { int j, count=0, timesteps[nsteps], newpos=centreloc; for (j=0; j