TABLE OF CONTENTS
CMetropolisHastings/MH_BDM [ Functions ]
NAME
MH_BDM --- birth-death-move steps for spline knots
FUNCTION
Reversible-Jump MCMC steps for adding, deleting, or moving knots as part of the adaptive knot selection procedure. Can work with either the hazard or frailty curve, see also mh.bdm.
SYNOPSIS
2371 void MH_BDM(char which, curveP hazard, curveP frailty, regressionP regression)
INPUTS
which character, can be either 'h' or 'f', for hazard or frailty respectively hazard CCurve for the hazard frailty CCurve for the frailty regression CRegression structure
SOURCE
2375 { 2376 curveP theCurve; 2377 if(which == 'h') theCurve = hazard; 2378 if(which == 'f') theCurve = frailty; 2379 if(!theCurve->hasSpline) return; 2380 // Pointers to useful components 2381 int ord = theCurve->SplineOrd; 2382 int nknots = theCurve->SplineNknots; 2383 double * candknots = theCurve->SplineCandKnots; 2384 int ncandknots = theCurve->SplineNCandKnots; 2385 double * occ = theCurve->SplineCandOcc; // occupied candidate knots 2386 int * occind = malloc(nknots * sizeof(int)); 2387 // allocate temporary storage 2388 double * oldKnots = calloc(nknots+2*ord, sizeof(double)); 2389 double * oldPar = calloc(nknots+ord, sizeof(double)); 2390 double * knots2 = calloc(nknots+2*ord+1, sizeof(double)); 2391 double * params2 = calloc(nknots+ord+1, sizeof(double)); 2392 double * knots = theCurve->SplineKnots; 2393 double * params = theCurve->SplinePar; 2394 dcopyWrapper(nknots+2*ord,theCurve->SplineKnots,oldKnots); 2395 dcopyWrapper(nknots+ord,theCurve->SplinePar,oldPar); 2396 dcopyWrapper(nknots+2*ord,theCurve->SplineKnots,knots2); 2397 dcopyWrapper(nknots+ord,theCurve->SplinePar,params2); 2398 2399 int i=0; 2400 // compute probability of birth-death and move steps 2401 for(int j=ord;j<ncandknots+2*ord; j++) if(occ[j]==1) occind[i++]=j; 2402 double pk = EvalNknotsPrior( nknots, theCurve ); 2403 double pkp1 = (nknots < theCurve->SplineNknotsMax) ? EvalNknotsPrior(nknots+1, theCurve) : 0; 2404 double pkm1 = (nknots > 1) ? EvalNknotsPrior(nknots-1, theCurve) : 0; 2405 double pb = theCurve->SplineBDMConst[0] * dmin(1.0,pkp1/pk); // P(birth) 2406 double pd = theCurve->SplineBDMConst[0] * dmin(1.0,pkm1/pk); // P(death) 2407 double pm = dmax(0.0,1.0-pb-pd); // P(move) 2408 double u = runif(0,1); 2409 double baselik,candlik; 2410 // base likelihood 2411 if(theCurve->isHazard) baselik = LikelihoodSplineHazard(theCurve,frailty,regression); 2412 if(!theCurve->isHazard) baselik = LikelihoodSplineFrailty(hazard,theCurve,regression); 2413 if(u<pd){ // death step 2414 int j = (int) floor(runif(0,(double) nknots))+ord; // index of dying knot 2415 double x = knots[j]; // value of dying knot 2416 //Rprintf("Remove knot %d at %f (occ: %d)\n",j,knots[j],(int) occ[occind[j-ord]]); 2417 for(int i=0;i<nknots+ord;i++) if(i>=j-1) params2[i] = params2[i+1]; //remove params2[j]; 2418 for(int i=0;i<nknots+ord;i++) if(i>=j) knots2[i] = knots2[i+1]; //remove knots2[j2]; 2419 // update spline parameters for knot deletion 2420 if(ord>2) for(int j2=j-ord+1; j2<j-1; j2++){ 2421 double r2 = (x-knots2[j2])/(knots2[j2+ord-1]-knots2[j2]); 2422 double inner = 1/r2 * exp(params2[j2])-(1-r2)/r2*exp(params2[j2-1]); 2423 if(inner>0) params2[j2]=log(inner); else params2[j2] = theCurve->SplineMin[0]; 2424 } 2425 theCurve->SplineNknots--; theCurve->nj--; 2426 // Jacobian for the transformation 2427 double J = exp(params2[j-1]) / (exp(params[j-1]) - exp(params[j-2])); 2428 if(ord>2) for(int j2 = j-ord+2; j2<j-1; j2++){ 2429 double r2 = (x-knots2[j2])/(knots2[j2+ord-1]-knots2[j2]); 2430 J = J * exp(params2[j2])/(r2*exp(params[j2])); 2431 } 2432 // update the curve with the new knot set 2433 dcopyWrapper(nknots+2*ord, knots2,theCurve->SplineKnots); 2434 RemakeSplineBasis(theCurve,'d',j); 2435 // update curve with new parameters 2436 if(theCurve->isHazard) { 2437 UpdateSplinePar(theCurve,params2,-1); 2438 candlik = LikelihoodSplineHazard(theCurve,frailty,regression); 2439 } 2440 if(!theCurve->isHazard){ 2441 // for the frailty curve, make sure that the mean is 1 2442 double newmean = -exp(params2[j-2])*theCurve->SplineBasisExp[j-2]; 2443 for(int i=0;i<nknots+ord-1;i++) newmean += exp(params2[i])*theCurve->SplineBasisExp[i]; 2444 double newinner = -newmean/theCurve->SplineBasisExp[j-2]; 2445 if(newinner<0) candlik = -INFINITY; 2446 else{ 2447 params2[j-2] = log(newinner); 2448 UpdateSplinePar(theCurve,params2,-1); 2449 candlik = LikelihoodSplineFrailty(hazard,theCurve,regression); 2450 } 2451 } 2452 // prior ratio * Jacobian 2453 double ratio = sqrt(2*M_PI*theCurve->SplinePriorvar[0])*fabs(J); 2454 int acc = AcceptReject(baselik, candlik, ratio); 2455 if(acc){ 2456 // Update occupied index and candsd 2457 occ[occind[j-ord]] = 0; 2458 }else{ //undo damage 2459 theCurve->SplineNknots++; theCurve->nj++; 2460 dcopyWrapper(nknots+2*ord, oldKnots, theCurve->SplineKnots); 2461 RemakeSplineBasis(theCurve,'b',j); 2462 UpdateSplinePar(theCurve,oldPar,-1); 2463 } 2464 } 2465 if(u>pd & u<pd+pb){ 2466 // Birth 2467 int birthind = occind[0]; 2468 // choose a random unoccupied location for the knot to be born 2469 while(occ[birthind]) birthind = (int) floor(runif(0,(double) ncandknots))+ord; 2470 double x = candknots[birthind]; // value of the new knot 2471 int j = 0; while(knots[j]<x) j++; j--; // find the interval in which x lies 2472 //Rprintf("Birth at %f after knot %d\n",x,j); 2473 // update knot set and spline parameters 2474 for(int i=nknots+2*ord;i>j;i--) knots2[i]=knots2[i-1]; 2475 knots2[j+1]=x; 2476 for(int i=nknots+ord;i>j-ord+1;i--) params2[i]=params2[i-1]; 2477 for(int j2 = j-ord+2; j2<j+1; j2++){ 2478 double r2 = (x-knots[j2])/(knots[j2+ord-1]-knots[j2]); 2479 if(j2==j) r2 = runif(0,1); 2480 params2[j2] = log(r2*exp(params[j2])+(1-r2)*exp(params[j2-1])); 2481 } 2482 //Rprintf("Birthind,x,j: %d %f %d\n",birthind,x,j); 2483 theCurve->SplineNknots++; theCurve->nj++; 2484 // Jacobian of the transformation 2485 double J = (exp(params[j])-exp(params[j-1]))/exp(params2[j]); 2486 if(ord>2) for(int j2 = j-ord+2; j2<j; j2++){ 2487 double r2 = (x-knots[j2])/(knots[j2+ord-1]-knots[j2]); 2488 J = J * r2 * exp(params[j2])/exp(params2[j2]); 2489 } 2490 // update curve with new knots and parameters 2491 dcopyWrapper(nknots+2*ord+1, knots2,theCurve->SplineKnots); 2492 RemakeSplineBasis(theCurve,'b',j); 2493 if(theCurve->isHazard){ 2494 UpdateSplinePar(theCurve,params2,-1); 2495 candlik = LikelihoodSplineHazard(theCurve,frailty,regression); 2496 } 2497 if(!theCurve->isHazard){ 2498 // for frailty, make sure the mean is 1 2499 double newmean = -exp(params2[j])*theCurve->SplineBasisExp[j]; 2500 for(int i=0;i<nknots+ord+1;i++) newmean += exp(params2[i])*theCurve->SplineBasisExp[i]; 2501 double newinner = -newmean/theCurve->SplineBasisExp[j]; 2502 if(newinner<0) candlik = -INFINITY; 2503 else{ 2504 params2[j] = log(newinner); 2505 UpdateSplinePar(theCurve,params2,-1); 2506 candlik = LikelihoodSplineFrailty(hazard,theCurve,regression); 2507 } 2508 } 2509 // prior ratio * Jacobian 2510 double ratio = 1/sqrt(2*M_PI*theCurve->SplinePriorvar[0]) * fabs(J); 2511 int acc = AcceptReject(baselik, candlik, ratio); 2512 //Rprintf("Lik: %f %f %f %f %d\n",baselik,candlik, J, ratio,acc); 2513 if(acc){ 2514 // Update set of occupied candidate knots 2515 occ[birthind] = 1; 2516 }else{ //undo damage 2517 theCurve->SplineNknots--; theCurve->nj--; 2518 dcopyWrapper(nknots+2*ord, oldKnots, theCurve->SplineKnots); 2519 RemakeSplineBasis(theCurve,'d',j+1); 2520 UpdateSplinePar(theCurve,oldPar,-1); 2521 } 2522 } 2523 if(u>pb+pd) { // Move a knot 2524 // choose a random knot to move 2525 int moveind=0; 2526 moveind = (int) floor(runif(0,(double) nknots)); 2527 // find range of movement 2528 int leftknotind = (moveind == 0) ? ord : occind[moveind-1]+1; 2529 int rightknotind = (moveind == nknots-1) ? ncandknots + ord - 1 : occind[moveind+1]-1; 2530 // choose a candidate knot to place the new knot in 2531 int newknotind = (int) floor(runif((double) leftknotind,(double) rightknotind+1)); 2532 // if the knot doesn't stay the same, update the curve 2533 if(candknots[newknotind] != oldKnots[moveind+ord]){ 2534 theCurve->SplineKnots[moveind+ord] = candknots[newknotind]; 2535 // update spline basis with new knot position 2536 RemakeSplineBasis(theCurve,'m',moveind); 2537 if(theCurve->isHazard){ //hazard 2538 EvalSpline(theCurve,-1); 2539 candlik = LikelihoodSplineHazard(theCurve,frailty,regression); 2540 } 2541 if(!theCurve->isHazard){ //frailty 2542 // frailty needs to ensure the mean is 1 2543 double newmean = -exp(params2[moveind+ord])*theCurve->SplineBasisExp[moveind+ord]; 2544 for(int i=0;i<nknots+ord;i++) newmean += exp(params2[i])*theCurve->SplineBasisExp[i]; 2545 double newinner = -newmean/theCurve->SplineBasisExp[moveind+ord]; 2546 if(newinner<0) candlik = -INFINITY; 2547 else{ 2548 params2[moveind+ord] = log(newinner); 2549 UpdateSplinePar(theCurve,params2,-1); 2550 candlik = LikelihoodSplineFrailty(hazard,theCurve,regression); 2551 } 2552 } 2553 int acc = AcceptReject(baselik,candlik,1.0); 2554 //Rprintf("Lik: %f %f %d\n",baselik,candlik,acc); 2555 if(!acc){ 2556 // not accepted, undo the damage 2557 theCurve->SplineKnots[moveind+ord] = oldKnots[moveind+ord]; 2558 RemakeSplineBasis(theCurve,'m',moveind); 2559 if(theCurve->isHazard){ // hazard 2560 EvalSpline(theCurve,-1); 2561 }else{ // frailty 2562 UpdateSplinePar(theCurve,oldPar,-1); 2563 } 2564 }else{ // update occupied index 2565 occ[occind[moveind]]=0; 2566 occ[newknotind] = 1; 2567 } 2568 } 2569 } 2570 2571 free(oldKnots); 2572 free(oldPar); 2573 free(knots2); 2574 free(params2); 2575 free(occind); 2576 }