/* ========================================================================== amcmc.c -- a C program (called from R) for doing adaptive MCMC Copyright (c) 2007 by Jeffrey S. Rosenthal (probability.ca/jeff) (Last modified March 2009.) Instructions for use at: probability.ca/amcmc Licensed for general copying, distribution and modification according to the GNU General Public License (www.gnu.org/copyleft/gpl.html). ========================================================================== */ #include #include #include #include #define TARGACCEPT 0.44 #define MAXK 1000 double drand48(); extern double myfunctional(), mydensity(); extern int mydim(); int cdensityflag; int cfunctionalflag; int K; int vectorlength; SEXP amcmc(SEXP densfn, SEXP functional, SEXP Karg, SEXP numbatchesarg, SEXP batchlengtharg, SEXP logvalarg, SEXP adaptvalarg, SEXP burninfracarg, SEXP initvalarg, SEXP verbosearg, SEXP cdensityarg, SEXP cfunctionalarg, SEXP vectorlengtharg, SEXP writearg, SEXP env) { SEXP Rreturnval; double returnval, Revalfn(); int ifloor(), imax(), divisible(); double valsum = 0.0; int tmpK = ifloor( REAL(Karg)[0] ); int NUMBATCHES = ifloor( REAL(numbatchesarg)[0] ); int BATCHLENGTH = ifloor( REAL(batchlengtharg)[0] ); int ADAPTFLAG = ifloor( REAL(adaptvalarg)[0] ); int LOGFLAG = ifloor( REAL(logvalarg)[0] ); int tmpcdensityflag = ifloor( REAL(cdensityarg)[0] ); int tmpcfunctionalflag = ifloor( REAL(cfunctionalarg)[0] ); int tmpvectorlength = ifloor( REAL(vectorlengtharg)[0] ); int writeflag = ifloor( REAL(writearg)[0] ); double burninfrac = REAL(burninfracarg)[0]; double initval = REAL(initvalarg)[0]; int VERBOSELEVEL = ifloor( REAL(verbosearg)[0] ); int i, j, ii, jj, kk, PRINTLENGTH; int batchnum, numit, numcounted, accepted, acount[MAXK]; double t[MAXK]; double newt[MAXK]; double logsigma[MAXK]; double logalpha, sqnorm(), min(), normal(), targlogdens(), adaptamount(); double funcest, funcsum, funcval, curlogdens, newlogdens; int functionalready; double begintime, endtime, currtime, burnintime; struct timeval tmptv; FILE *fp, *fps; cdensityflag = tmpcdensityflag; cfunctionalflag = tmpcfunctionalflag; vectorlength = tmpvectorlength; if (cdensityflag > 0) K = mydim(); else if (vectorlength > 0) K = vectorlength; else K = tmpK; PRINTLENGTH = imax(100, NUMBATCHES/1000); if (VERBOSELEVEL >= 3) PRINTLENGTH = PRINTLENGTH / 10; gettimeofday (&tmptv, (struct timezone *)NULL); begintime = 1.0 * tmptv.tv_sec + 0.000001 * tmptv.tv_usec; /* printf("\nBeginning variable-at-time adaption run.\n"); */ if (VERBOSELEVEL >= 1) { printf("\nStarting C function 'amcmc'.\nK = %d. NUMBATCHES = %d. BATCHLENGTH = %d. LOGFLAG = %d. ADAPTFLAG = %d.\n", K, NUMBATCHES, BATCHLENGTH, LOGFLAG, ADAPTFLAG); printf("burninfrac = %f. cdensityflag = %d. cfunctionalflag = %d.\n", burninfrac, cdensityflag, cfunctionalflag); printf("\n"); } /* INITIALISATIONS. */ numit = numcounted = 0; for (kk=0; kk 0.01) { fprintf(stderr, "\nERROR: t and newt not synchronised.\n\n"); exit(1); } } for (ii=1; ii<=BATCHLENGTH; ii++) { numit++; /* funcval = log(1.0+sqnorm(t)); */ for (kk=0; kk= 4) printf("Coord %d from %f to %f (ls=%f, la=%f) is ... ", kk, t[kk], newt[kk], logsigma[kk], logalpha); accepted = ( log(drand48()) < logalpha ); if (accepted) { t[kk] = newt[kk]; acount[kk] = acount[kk] + 1; curlogdens = newlogdens; functionalready = 0; if (VERBOSELEVEL >= 4) printf("accepted!\n"); } else { newt[kk] = t[kk]; if (VERBOSELEVEL >= 4) printf("rejected!\n"); } } /* End of kk for loop. */ /* funcval = log(1.0+sqnorm(t)); */ /* printf("t[0] = %f ... in C: %f ... in R: %f\n", t[0], myfunctional(t), Revalfn(functional, t, env) ); */ if (numit > burnintime) { if (functionalready==0) { /* Need to re-evaluate functional. */ if (cfunctionalflag==1) funcval = myfunctional(t); else funcval = Revalfn(functional, t, env); functionalready = 1; } if (VERBOSELEVEL >= 5) printf("EVALUATING: t[0] = %f, funcval = %f\n", t[0], funcval); funcsum = funcsum + funcval; numcounted++; } } /* End of ii for loop. */ /* Update various estimates etc. */ funcest = funcsum / numcounted; /* DO THE ADAPTING. */ if(ADAPTFLAG > 0) { for (jj=0; jj BATCHLENGTH * TARGACCEPT) logsigma[jj] = logsigma[jj] + adaptamount(batchnum); else if (acount[jj] < BATCHLENGTH * TARGACCEPT) logsigma[jj] = logsigma[jj] - adaptamount(batchnum); } } /* OUTPUT VALUES TO SCREEN. */ if (VERBOSELEVEL >= 2) { if (divisible(batchnum, PRINTLENGTH)) { for(jj=0; jj= 1) { printf("\nFinishing C function 'amcmc'. Number of variables = %d.\n", K); /* printf("Batch size = %d full scans.\n", BATCHLENGTH); */ /* printf("Printed to screen every %d batches.\n", PRINTLENGTH); */ printf("Did %d batches, each consisting of %d updates of each variable.\n", NUMBATCHES, BATCHLENGTH); printf("Ellapsed time = %.2f seconds.\n\n", endtime-begintime); } if (writeflag) { fprintf(fp, "),\nnrow=%d)\n\n", K); fclose(fp); fprintf(fps, "),\nnrow=%d)\n\n", K); fclose(fps); } returnval = funcest; /* return(returnval) */ PROTECT(Rreturnval = NEW_NUMERIC(1)); NUMERIC_POINTER(Rreturnval)[0] = returnval; UNPROTECT(1); return( Rreturnval ); } /* ADAPTAMOUNT */ double adaptamount( int iteration ) { double min(); /* return( 1.0 / imax(100, sqrt(iteration)) ); */ return( min( 0.01, 1.0 / sqrt((double)iteration) ) ); /* return(0.01); */ } double Revalfn(SEXP fn, double *arg, SEXP env) { SEXP R_fcall, argg, tmpval[MAXK], tmpsex; double m, *p_tmp[MAXK]; int iii; if (vectorlength > 0) { PROTECT(argg = allocVector(REALSXP, K)); for (iii=0; iii 0) return( tmpval ); else return( log( tmpval ) ); } /* SQNORM */ double sqnorm( double t[] ) { int ii; double ss; ss = 0.0; for (ii=0; iin2) return(n1); else return(n2); }