Revision 63d8a43408637eef9a81e05ffd7e6ff3afa51947 authored by Robert B. Gramacy on 20 September 2006, 00:00:00 UTC, committed by Gabor Csardi on 20 September 2006, 00:00:00 UTC
1 parent 622e02d
Raw File
all_draws.c
/******************************************************************************** 
 *
 * Bayesian Regression and Adaptive Sampling with Gaussian Process Trees
 * Copyright (C) 2005, University of California
 * 
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 * 
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 * 
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 *
 * Questions? Contact Robert B. Gramacy (rbgramacy@ams.ucsc.edu)
 *
 ********************************************************************************/


#include <math.h>
#include "rand_pdf.h"
#include "rand_draws.h"
#include "matrix.h"
#include "linalg.h"
#include "gen_covar.h"
#include "lik_post.h"
#include "all_draws.h"
#include "rhelp.h"
#include <stdlib.h>
#include <stdio.h>
#include <assert.h>

#define DEBUG
#define GA 1.0 /* 5.0 */
#define PWR 2.0
#define LINEAR(gamma, min, max, d) min + max / (1.0 + exp(0.0-gamma*(d-0.5)));
#define NUGMIN 1e-10


void mle_beta(mle, n, col, F, Z)
unsigned int n, col;
double *Z, *mle;
double **F;
{
  double **aux1, **Vb;
  double *by;
  int info;
  
  /* zero out by and b */
  by = new_zero_vector(col); 
  zerov(mle, col);
  
  /* aux1 = F'F*/
  aux1 = new_zero_matrix(col, col);
  linalg_dgemm(CblasTrans,CblasNoTrans,col,col,n,
	       1.0,F,n,F,n,0.0,aux1,col);
  
  /* Vb = inv(F'*F) */
  Vb = new_id_matrix(col);
  info = linalg_dgesv(col, aux1, Vb);
  delete_matrix(aux1);
  
  /* by = Z*F */
  linalg_dgemv(CblasTrans, n,col,1.0,F,n,Z,1,0.0,by,1);
  
  /* mle = by*Vb */
  linalg_dsymv(col,1.0,Vb,col,by,1,0.0,mle,1);
  
  delete_matrix(Vb);
  free(by);
}



/*
 * compute_b_and_Vb_noK:
 * 
 * b and Vb are needed by compute_lambda and beta_draw
 * and others: b and Vb must be pre-allocated.
 * These are two of the three "margin" variables.
 * DOES NOT INVOLVE THE COVARIANCE MATRIX (K)
 *
 * Z[n], b0[col], b[col], TiB0[col], by[col], F[col][n], Ki[n][n], 
 * Ti[col][col], Vb[col][col];
 */

void compute_b_and_Vb_noK(Vb, b, by, TiB0, n, col, F, Z, Ti, tau2, b0, nug)
unsigned int n, col;
double *Z, *b0, *b, *TiB0, *by;
double **F, **Ti, **Vb;
double tau2, nug;
{
  double **aux1;
  int info;
	
  /* zero out by and b */
  zerov(by, col); zerov(b, col);
  
  /* aux1 = F'F/(1+g) + Ti/tau2 */
  aux1 = new_dup_matrix(Ti, col, col);
  linalg_dgemm(CblasTrans,CblasNoTrans, col,col,n,
	       1.0/(1.0+nug),F,n,F,n,1.0/tau2,aux1,col);
  
  /* Vb = inv(F'*F + Ti/tau2) */
  id(Vb, col);
  info = linalg_dgesv(col, aux1, Vb);
  delete_matrix(aux1);
  
  /* by = Z*F/(1+g) + b0'*Ti/tau2 */
  /* first set: by = b0'*Ti */
  linalg_dsymv(col,1.0,Ti,col,b0,1,0.0,by,1);
  /* save the result for later */
  dupv(TiB0, by, col);
  /* use vector stuff for the last part */
  linalg_dgemv(CblasTrans,n,col,1.0/(1.0+nug),F,n,Z,1,1.0/tau2,by,1);
  
  /* b = by*Vb */
  linalg_dsymv(col,1.0,Vb,col,by,1,0.0,b,1);
}


/*
 * compute_lambda_noK:
 * 
 * code for computing the lambda intermediate variable
 * required by functions which use a marginalized posterior:
 * (margin_lik, sigma_no_beta, etc...)
 * DOES NOT INVOLVE THE COVARIANCE MATRIX (K)
 *
 * Z[n], b0[col], b[col], F[col][n], Ki[n][n], Ti[col][col], Vb[col][col];
 */

double compute_lambda_noK(Vb, b, n, col, F, Z, Ti, tau2, b0, nug)
unsigned int n, col;
double *Z, *b0, *b;
double **F, **Ti, **Vb;
double tau2;
double nug;
{
  /*double TiB0[col], KiZ[n], by[col];*/
  double *TiB0, *by;
  double lambda, ZZ, BVBiB, b0Tib0;
  
  /* init alloc */
  TiB0 = new_vector(col);
  by = new_vector(col);
  
  compute_b_and_Vb_noK(Vb, b, by, TiB0, n, col, F, Z, Ti, tau2, b0, nug);
  
  /* lambda = Z*Z' + b0'*Ti*b0 - B'*VBi*B; */
  /* as performed in many steps below */
  
  /* ZZ = Z'Z/(1+g) */
  ZZ = linalg_ddot(n,Z,1,Z,1);
  ZZ = ZZ / (1.0 + nug);
  
  /* Tib0 = by ... we already did this above */
  /* b0Tib0 = b0 * by / tau2 */
  b0Tib0 = linalg_ddot(col, b0, 1, TiB0, 1) / tau2;
  free(TiB0);
  
  /* B' * Vbi * B = b * by */
  BVBiB = linalg_ddot(col,b,1,by,1);
  free(by);
  
  /* now for lambda */
  lambda = ZZ + b0Tib0 - BVBiB;
  
  return lambda;
}


/*
 * compute_b_and_Vb:
 * 
 * b and Vb are needed by compute_lambda and beta_draw
 * and others: b and Vb must be pre-allocated.
 * These are two of the three "margin" variables.
 *
 * Z[n], b0[col], b[col], TiB0[col], by[col], F[col][n], 
 * Ki[n][n], Ti[col][col], Vb[col][col]
 */

void compute_b_and_Vb(Vb, b, by, TiB0, n, col, F, Z, Ki, Ti, tau2, b0)
unsigned int n, col;
double *Z, *b0, *b, *TiB0, *by;
double **F, **Ki, **Ti, **Vb;
double tau2;
{
  double **KiF, **aux1;
  int info;

  /* KiF = Ki * F */
  KiF = new_zero_matrix(col, n);
  linalg_dsymm(CblasLeft,n,col,1.0,Ki,n,F,n,0.0,KiF,n);
  
  /* aux1 = F'*KiF + Ti/tau2 */
  aux1 = new_dup_matrix(Ti, col, col);
  linalg_dgemm(CblasTrans,CblasNoTrans,col,col,n,
	       1.0,F,n,KiF,n,1.0/tau2,aux1,col);
  
  /* Vb = inv(F'*KiF + Ti/tau2) */
  id(Vb, col);
  info = linalg_dgesv(col, aux1, Vb);
  delete_matrix(aux1);
  
  /* by = Z*KiF + b0'*Ti/tau2 */
  /* first set: by = b0'*Ti */
  zerov(by, col); 
  linalg_dsymv(col,1.0,Ti,col,b0,1,0.0,by,1);
  /* save the result for later */
  dupv(TiB0, by, col);
  /* use vector stuff for the last part */
  linalg_dgemv(CblasTrans,n,col,1.0,KiF,n,Z,1,1.0/tau2,by,1);
  delete_matrix(KiF);
  
  /* b = by*Vb */
  zerov(b, col);
  linalg_dsymv(col,1.0,Vb,col,by,1,0.0,b,1);
}


/*
 * compute_lambda:
 * 
 * code for computing the lambda intermediate variable
 * required by functions which use a marginalized posterior:
 * (margin_lik, sigma_no_beta, etc...)
 *
 * Z[n], b0[col], b[col]; F[col][n], Ki[n][n], Ti[col][col], Vb[col][col]
 */

double compute_lambda(Vb, b, n, col, F, Z, Ki, Ti, tau2, b0)
unsigned int n, col;
double *Z, *b0, *b;
double **F, **Ki, **Ti, **Vb;
double tau2;
{
  /*double TiB0[col], KiZ[n], by[col];*/
  double *TiB0, *KiZ, *by;
  double lambda, ZKiZ, BVBiB, b0Tib0;
  
  /* init alloc */
  TiB0 = new_vector(col);
  KiZ = new_vector(n);
  by = new_vector(col);
  
  compute_b_and_Vb(Vb, b, by, TiB0, n, col, F, Z, Ki, Ti, tau2, b0);
  
  /* lambda = Z*Ki*Z' + b0'*Ti*b0 - B'*VBi*B; */
  /* as performed in many steps below */
  
  /* KiZ = Ki * Z */
  zerov(KiZ, n);
  linalg_dsymv(n,1.0,Ki,n,Z,1,0.0,KiZ,1);
  /* ZKiZ = Z * KiZ */
  ZKiZ = linalg_ddot(n,Z,1,KiZ,1);
  free(KiZ);
  
  /* Tib0 = by ... we already did this above */
  /* b0Tib0 = b0 * by */
  b0Tib0 = linalg_ddot(col, b0, 1, TiB0, 1);
  free(TiB0);
  
  /* B' * Vbi * B = b * by */
  BVBiB = linalg_ddot(col,b,1,by,1);
  free(by);
  
  /* now for lambda */
  lambda = ZKiZ + b0Tib0/tau2 - BVBiB;
  
  return lambda;
}



/*
 * beta_draw_margin:
 * 
 * Gibbs draw for Beta given bmu and Vb marginalzed parameters
 *
 * b[col], bmu[col], Vb[col][col]
 */

unsigned int beta_draw_margin(b, col, Vb, bmu, s2, state)
unsigned int col;
double *b, *bmu; 
double **Vb;
double s2;
void *state;
{
  unsigned int i,j;
  /*double V[col][col];*/
  double **V;
  int info;
  
  /* compute s2*Vb */
  V = new_matrix(col, col);
  /*for(i=0; i<col; i++) for(j=0; j<col; j++) V[i][j] = s2*Vb[i][j];*/
  for(i=0; i<col; i++) for(j=0; j<=i; j++) V[i][j] = s2*Vb[i][j];
  
  /* get the draw */
  
  /* first: get the choleski decomposition */
  /* note that this changes the cov variable (s2*Vb) */
  info = linalg_dpotrf(col, V);
  
  /* now get the draw using the choleski decomposition */
  if(info != 0) zerov(b, col);
  else mvnrnd(b, bmu, V, col, state);
  
  delete_matrix(V);
  return info;
}


/*
 * beta_draw_noK:
 * 
 * Gibbs draw for Beta given the rest of the
 * parameters. (no dependance on K)
 *
 * Z[n], b0[col], b[col], F[col][n], Ti[col][col];
 */

void beta_draw_noK(b, n, col, F, Z, s2, Ti, tau2, b0, nug, state)
unsigned int n, col;
double *Z, *b0, *b; 
double **F, **Ti;
double s2, tau2;
double nug;
void *state;
{
  unsigned int i,j;
  /*double Vb[col][col];
    double mu[col], by[col], TiB0[col];*/
  double **Vb;
  double *mu, *by, *TiB0;
  int info;
  
  Vb = new_matrix(col,col);
  mu = new_vector(col);
  by = new_vector(col);
  TiB0 = new_vector(col);
  compute_b_and_Vb_noK(Vb, mu, by, TiB0, n, col, F, Z, Ti, tau2, b0, nug);
  free(TiB0);
  
  /* compute s2*Vb */
  /*for(i=0; i<col; i++) for(j=0; j<col; j++) Vb[i][j] = s2*Vb[i][j];*/
  for(i=0; i<col; i++) for(j=0; j<=i; j++) Vb[i][j] = s2*Vb[i][j];
  
  /* first: get the choleski decomposition */
  /* note that this changes the cov variable (s2*Vb) */
  info = linalg_dpotrf(col, Vb);
  
  /* now get the draw using the choleski decomposition */
  mvnrnd(b, mu, Vb, col, state);
  delete_matrix(Vb);
  free(mu);
  free(by);
}


/*
 * sigma2_draw_no_b_noK:
 * 
 * Uses code from margin_lik_c in order to obtain draws 
 * for sigma^2 without dependence on beta (or K)
 *
 * Z[n], b0[col], F[col][n], Ti[col][col];
 */

double sigma2_draw_no_b_noK(n, col, F, Z, Ti, tau2, b0, alpha0, beta0, state)
unsigned int n, col;
double *Z, *b0; 
double **F, **Ti;
double alpha0, beta0, tau2;
void *state;
{
  double **Vb;
  double *b;
  double alpha, g, lambda, x;
  
  Vb = new_matrix(col, col);
  b = new_vector(col);
  lambda = compute_lambda_noK(Vb, b, n, col, F, Z, Ti, tau2, b0, 1.0);
  delete_matrix(Vb);
  free(b);
  
  /* alpha = (alpha0 + length(Z) + length(b))/2; */
  alpha = (alpha0 + n)/2;
  
  /* g = (gamma0 + BLAH)/2; */
  g = (beta0 + lambda)/2;
  
  /* s2 = 1/gamrnd(alpha, 1/g, 1) */
  /* return 1.0 / (1.0/g * rgamma(alpha)); */
  inv_gamma_mult_gelman(&x, alpha, g, 1, state);
  return x;
}


/*
 * sigma2_draw2_no_b_margin:
 * 
 * draw sigma^2 without dependence on beta
 */

double sigma2_draw_no_b_margin(n, col, lambda, alpha0, beta0, state)
unsigned int n, col;
double alpha0, beta0, lambda;
void *state;
{
  double alpha, g, x;

  /* alpha = (alpha0 + length(Z) + length(b))/2; */
  alpha = (alpha0 + n)/2;

  /* just in case */
  if(lambda < 0) lambda = 0;

  /* g = (gamma0 + BLAH)/2; */
  g = (beta0 + lambda)/2;

  /* s2 = 1/gamrnd(alpha, 1/g, 1) */
  /* return 1.0 / (1.0/g * rgamma(alpha)); */
  inv_gamma_mult_gelman(&x, alpha, g, 1, state);
  /* myprintf(stderr, "alpha = %g, beta = %g  =>  x = %g\n", alpha, g, x); */
  return x;
}


/* 
 * tau2_draw:
 * 
 * draws from tau^2 given the rest of the parameters
 * NOTE: this code was not augmented to use Fb or ZmFb as arguments
 * because it was not in general use in the code when these
 * more global changes were made.
 *
 * b0[col], b[col], Ti[col][col];
 */

double tau2_draw(col, Ti, s2, b, b0, alpha0, beta0, state)
unsigned int col;
double *b, *b0;
double **Ti;
double alpha0, beta0, s2;
void *state;
{
  /*double bmb0[col], Tibmb0[col];*/
  double *bmb0, *Tibmb0;
  double right, alpha, g, x;
  
  /* bmb0 = b-b0 */
  bmb0 = new_dup_vector(b, col);
  linalg_daxpy(col,-1.0,b0,1,bmb0,1);
  
  /* right = (bmb0)' * Ti * (bmb0) */
  Tibmb0 = new_zero_vector(col);
  linalg_dsymv(col,1.0,Ti,col,bmb0,1,0.0,Tibmb0,1);
  right = linalg_ddot(col,bmb0,1,Tibmb0,1) / s2;
  free(bmb0);
  free(Tibmb0);
  
  /* alpha and beta of gamma distribution */
  alpha = (alpha0 + col)/2;
  g = (beta0 + right)/2;

  /* s2 = 1/gamrnd(alpha, 1/g, 1) */
  /* return 1.0 / (1.0/g * rgamma(alpha)); */
  inv_gamma_mult_gelman(&x, alpha, g, 1, state);
  return x;
}


/*
 * gamma_mixture_pdf:
 * 
 * PDF: mixture prior for d and nug,
 * works in log space -- returns the log density value
 */

double gamma_mixture_pdf(d, alpha, beta)
double d;
double alpha[2], beta[2];
{
  double p1, p2;
  gampdf_log_gelman(&p1, &d, alpha[0], beta[0], 1);
  gampdf_log_gelman(&p2, &d, alpha[1], beta[1], 1);
  return log(0.5*(exp(p1)+exp(p2)));
}


/*
 * log_d_prior_pdf:
 * 
 * PDF: mixture prior for d
 * returns the log pdf
 */

double log_d_prior_pdf(d, alpha, beta)
double d;
double alpha[2], beta[2];
{
  return gamma_mixture_pdf(d, alpha, beta);
}


/*
 * d_prior_rand:
 * 
 * rand draws from mixture prior for d
 */

double d_prior_rand(alpha, beta, state)
double alpha[2], beta[2];
void *state;
{
  return gamma_mixture_rand(alpha, beta, state);
}


/*
 * linear_rand:
 * 
 * rand draws for the linearization boolean for d
 */

int linear_rand(d, n, gamlin, state)
unsigned int n;
double *d, *gamlin;
void *state;
{
  double p;
  if(gamlin[0] == 0) return 0;
  if(gamlin[0] < 0) return 1;
  p = linear_pdf(d, n, gamlin);
  if(runi(state) < p) return 1;
  else return 0;
}


/*
 * linear_rand_sep:
 * 
 * rand draws for the linearization boolean for d
 * draws are returned via b (pre-allocated)
 * b has indicators OPPOSITE of the return value
 * (e.g. b[i]=0 -> linear d[i], b[i]=1 -> GP)
 */

int linear_rand_sep(b, pb, d, n, gamlin, state)
unsigned int n;
double *d, *gamlin, *pb;
int *b;
void *state;
{
  int bb;
  unsigned int i;
  assert(b);  assert(d);
  if(gamlin[0] == 0) {
    for(i=0; i<n; i++) b[i] = 1;	
    return 0;
  }
  if(gamlin[0] < 0) {
    for(i=0; i<n; i++) b[i] = 0;
    return 1;
  }
  linear_pdf_sep(pb, d, n, gamlin);
  bb = 1;
  for(i=0; i<n; i++) {
    if(runi(state) < pb[i]) b[i] = 0;
    else b[i] = 1;
    bb *= !(b[i]);
  }
  return (bb);
}


/*
 * linear_pdf:
 *
 * returns the the probability (not the log) of interpreting
 * the passed-in d value as 0
 *
 */

double linear_pdf(double *d, unsigned int n, double *gamlin)
{
  unsigned int i;
  double p = 1.0;
  assert(d);
  assert(gamlin[0] > 0 && gamlin[1] >= 0 && gamlin[1] <= 1 && 
	 gamlin[2] >= 0 && gamlin[2] <= 1);
  for(i=0; i<n; i++) p *= LINEAR(gamlin[0], gamlin[1], gamlin[2], d[i]);
  return p;
}


/*
 * linear_pdf_sep:
 *
 * passes back through pb (pre-allocated), 
 * the the probability (not the log) of interpreting
 * the EACH OF THE passed-in d value as 0
 * product is returned in order to be mode like linear_pdf
 *
 */

double linear_pdf_sep(double *pb, double *d, unsigned int n, double *gamlin)
{
  unsigned int i;
  double p = 1.0;
  assert(d && pb);
  assert(gamlin[0] > 0 && gamlin[1] >= 0 && gamlin[1] <= 1 && 
	 gamlin[2] >= 0 && gamlin[2] <= 1);
  for(i=0; i<n; i++) {
    pb[i] = LINEAR(gamlin[0], gamlin[1], gamlin[2], d[i]);
    p *= pb[i];
  }
  return p;
}



/*
 * d_proposal:
 * 
 * proposing a new d value, taking into 
 * account possible ZERO proposals
 */

void d_proposal(n, p, d, dold, q_fwd, q_bak, state)
unsigned int n;
int *p;
double *d, *dold;
double *q_fwd, *q_bak;
void *state;
{
  unsigned int i;
  double qf, qb;
  assert(n>0);
  for(i=0; i<n; i++) {
    if(p == NULL) d[0] = unif_propose_pos(dold[0], &qf, &qb, state);
    else d[p[i]] = unif_propose_pos(dold[p[i]], &qf, &qb, state);
    *q_fwd *= qf; *q_bak *= qb;
  }
}


/*
 * log_nug_prior_pdf:
 * 
 * PDF: zero and mixture prior for nug;
 * returns the log pdf value
 */

double log_nug_prior_pdf(nug, alpha, beta)
double nug;
double alpha[2], beta[2];
{
  return gamma_mixture_pdf(nug-NUGMIN, alpha, beta);
}


/*
 * nug_prior_rand:
 *
 * rand draws from mixture prior for d and nug
 */

double nug_prior_rand(alpha, beta, state)
double alpha[2], beta[2];
void *state;
{
  return gamma_mixture_rand(alpha, beta, state) + NUGMIN;
}



/*
 * gamma_mixture_rand:
 * 
 * rand draws from mixture prior for d and nug
 */

double gamma_mixture_rand(alpha, beta, state)
double alpha[2], beta[2];
void *state;
{
  double draw;
  if(runi(state)<0.5) {
    gamma_mult_gelman(&draw, alpha[0], beta[0], 1, state);
    if(draw == 0) {
      draw = alpha[0]/beta[0];
      warning("bad Gamma draw, using mean");
    }
  } else {
    gamma_mult_gelman(&draw, alpha[1], beta[1], 1, state);
    if(draw == 0) {
      draw = alpha[1]/beta[1];
      warning("bad Gamma draw, using mean");
    }
  }
  assert(draw > 0); /* && draw > 2e-20); */
  return draw;
}


/*
 * unif_propose_pos:
 * 
 * propose a new positive "ret" based on an old value "last"
 * by proposing uniformly in [3last/4, 4last/3], and return
 * the forward and backward probabilities
 */

#define PNUM 3.0
#define PDENOM 4.0

double unif_propose_pos(last, q_fwd, q_bak, state)
double last;
double *q_fwd, *q_bak;
void *state;
{
  double left, right, ret;
  
  /* propose new d, and compute proposal probability */
  left = PNUM*last/PDENOM;
  right = PDENOM*last/PNUM;
  assert(left > 0 && left < right);
  runif_mult(&ret,left, right, 1, state);
  *q_fwd = 1.0/(right - left);
  
  /* compute backwards probability */
  left = PNUM*ret/PDENOM;
  right = PDENOM*ret/PNUM;
  assert(left >= 0 && left < right);
  *q_bak = 1.0/(right - left);
  assert(*q_bak > 0);
  
  if(ret > 10e10) {
    warning("unif_propose_pos (%g) is bigger than max", ret);
    ret = 10;
  }
  assert(ret > 0);
  return ret;
}
 

/*
 * nug_draw:
 *
 * unif_propose_pos with adjustment for NUGMIN
 */


double nug_draw(last, q_fwd, q_bak, state)
double last;
double *q_fwd, *q_bak;
void *state;
{
  return unif_propose_pos(last-NUGMIN, q_fwd, q_bak, state) + NUGMIN;
}



/*
 * mixture_priors_ratio:
 * 
 * evaluationg the posterior for proposed alpha and beta 
 * values: parameters for the hierarchical d prior
 *
 * works in log space -- but returns in real (exponentiated)
 * probabilities
 */

double mixture_priors_ratio(double *alpha_new, double *alpha, double *beta_new, 
			    double *beta, double *d, unsigned int n, 
			    double *alpha_lambda, double *beta_lambda)
{
  int i;
  double log_p, p, p_new;
  log_p = 0;
  for(i=0; i<n; i++) {
    log_p += gamma_mixture_pdf(d[i], alpha_new, beta_new) 
      - gamma_mixture_pdf(d[i], alpha, beta);
  }
  for(i=0; i<2; i++) {
    if(alpha[i] != alpha_new[i]) {
      gampdf_log_gelman(&p_new, &(alpha_new[i]), GA, alpha_lambda[i], 1);
      gampdf_log_gelman(&p, &(alpha[i]), GA, alpha_lambda[i], 1);
      log_p += p_new - p;
    }
  }
  for(i=0; i<2; i++) {
    if(beta[i] != beta_new[i]) {
      gampdf_log_gelman(&p_new, &(beta_new[i]), GA, beta_lambda[i], 1);
      gampdf_log_gelman(&p, &(beta[i]), GA, beta_lambda[i], 1);
      log_p += p_new - p;
    }
  }
  return exp(log_p);
}


/*
 * mixture_hier_prior_log:
 *
 * return the sum of the log priors for each of the two
 * alpha[2] and beta[2] parameters which are exponentially 
 * distributed with rates alpha_lambda[2] and beta_lambda[2]
 */

double mixture_hier_prior_log(double *alpha, double *beta, double *beta_lambda,
			      double *alpha_lambda)
{
  double lpdf;
  unsigned int i;

  lpdf = 0.0;

  for(i=0; i<2; i++) {
    lpdf += hier_prior_log(alpha[i], beta[i], alpha_lambda[i], beta_lambda[i]);
  }

  return lpdf;
}


/*
 * hier_prior_log:
 *
 * return the sum of the log priors for each of the two
 * alpha and beta parameters which are exponentially 
 * distributed with rates alpha_lambda and beta_lambda
 */

double hier_prior_log(double alpha, double beta, double beta_lambda,
			      double alpha_lambda)
{
  double p, lpdf;

  lpdf = 0.0;

  gampdf_log_gelman(&p, &alpha, GA, alpha_lambda, 1);
  lpdf += p;
  gampdf_log_gelman(&p, &beta, GA, beta_lambda, 1);
  lpdf += p;

  return lpdf;
}


/*
 * sigma2_prior_draw:
 * 
 * draw from the hierarchical inverse gamma prior for
 * the sigma^2 parameter
 */

void sigma2_prior_draw(a0, g0, s2, n, a0_lambda, g0_lambda, state)
unsigned int n;
double a0_lambda, g0_lambda;
double *a0, *g0, *s2;
void *state;
{
  double q_fwd, q_bak, a, log_p, lp;
  double a0_new, g0_new;
  unsigned int i;
  
  /* proposing a new alpha */
  a0_new = 2+unif_propose_pos(*a0-2, &q_fwd, &q_bak, state);
  log_p = 0.0;
  for(i=0; i<n; i++) {
    invgampdf_log_gelman(&lp, &(s2[i]), a0_new/2, (*g0)/2, 1); log_p += lp;
    invgampdf_log_gelman(&lp, &(s2[i]), (*a0)/2, (*g0)/2, 1); log_p -= lp;
  }
  gampdf_log_gelman(&lp, &a0_new, 1.0, a0_lambda, 1); log_p += lp;
  gampdf_log_gelman(&lp, a0, 1.0, a0_lambda, 1); log_p -= lp;
  a = exp(log_p) * q_bak/q_fwd;
  if(a > 1) a = 1;
  if(runi(state) < a) *a0 = a0_new;
  
  /* proposing a new beta */
  g0_new = unif_propose_pos(*g0, &q_fwd, &q_bak, state);
  log_p = 0.0;
  for(i=0; i<n; i++) {
    invgampdf_log_gelman(&lp, &(s2[i]), (*a0)/2, g0_new/2, 1); log_p += lp;
    invgampdf_log_gelman(&lp, &(s2[i]), (*a0)/2, (*g0)/2, 1); log_p -= lp;
  }
  gampdf_log_gelman(&lp, &g0_new, 1.0, g0_lambda, 1); log_p += lp;
  gampdf_log_gelman(&lp, g0, 1.0, g0_lambda, 1); log_p -= lp;
  a = exp(log_p) * q_bak/q_fwd;
  /*myprintf(stderr, "g0=%g, g0_new=%g, ag=%g\n", *g0, g0_new, a);*/
  if(a > 1) a = 1;
  if(runi(state) < a) *g0 = g0_new;
}


/*
 * mixture_priors_draw:
 * 
 * propose changes to the parameters to the
 * hierarchial prior for d
 *
 * d[n]
 */

void mixture_priors_draw(alpha, beta, d, n, alpha_lambda, beta_lambda, state)
unsigned int n;
double alpha[2], beta[2], alpha_lambda[2], beta_lambda[2]; 
double *d;
void *state;
{
  double q_fwd, q_bak, a;
  double alpha_new[2], beta_new[2];

  alpha_new[1] = alpha[1];
  beta_new[1] = beta[1];
  alpha_new[0] = unif_propose_pos(alpha[0], &q_fwd, &q_bak, state);
  beta_new[0] = unif_propose_pos(beta[0], &q_fwd, &q_bak, state);
  if(beta_new[0] > alpha_new[0]) {
    a = mixture_priors_ratio(alpha_new, alpha, beta_new, beta, 
			     d, n, alpha_lambda, beta_lambda);
    a = a*(q_bak/q_fwd);
    if(a > 1) a = 1;
    if(runi(state) >= a) {
      alpha_new[0] = alpha[0];
      beta_new[0] = beta[0];
    }
  }
  
  alpha_new[1] = unif_propose_pos(alpha[1], &q_fwd, &q_bak, state);
  beta_new[1] = unif_propose_pos(beta[1], &q_fwd, &q_bak, state);
  if(beta_new[1] > alpha_new[1]) {
    a = mixture_priors_ratio(alpha_new, alpha, beta_new, beta, 
			     d, n, alpha_lambda, beta_lambda);
    a = a*(q_bak/q_fwd);
    if(a > 1) a = 1;
    if(runi(state) >= a) {
      alpha_new[1] = alpha[1];
      beta_new[1] = beta[1];
    }
  }
}


/*
 * d_draw_margin:
 * 
 * draws for d given the rest of the parameters
 * except b and s2 marginalized out
 *
 * F[col][n], DIST[n][n], Kchol[n][n], K_new[n][n], Ti[col][col], T[col][col]
 * Vb[col][col], Vb_new[col][col], Ki_new[n][n], Kchol_new[n][n] b0[col], Z[n]
 *
 *  return 1 if draw accepted, 0 if rejected, -1 if error
 */

int d_draw_margin(n, col, d, dlast, F, Z, DIST, log_det_K, lambda, Vb, 
	K_new, Ki_new, Kchol_new, log_det_K_new, lambda_new, Vb_new, bmu_new, 
	b0, Ti, T, tau2, nug, qRatio, d_alpha, d_beta, a0, g0, lin, state)
unsigned int n, col;
int lin;
double **F, **DIST, **K_new, **Ti, **T, **Vb, **Vb_new, **Ki_new, **Kchol_new;
double *b0, *Z;
double d_alpha[2], d_beta[2];
double qRatio;
double d, dlast, nug, a0, g0, lambda, tau2, log_det_K;
double *lambda_new, *bmu_new, *log_det_K_new;
void *state;
{
  double pd, pdlast, alpha;
  unsigned int m = 0;

  /* check if we are sticking with linear model */
  assert(dlast != 0.0);
  
  /* Knew = dist_to_K(dist, d, nugget);
     compute lambda, Vb, and bmu, for the NEW d */
  if(! lin) {	/* regular */
    dist_to_K_symm(K_new, DIST, d, nug, n);
    inverse_chol(K_new, Ki_new, Kchol_new, n);
    *log_det_K_new = log_determinant_chol(Kchol_new, n);
    *lambda_new = compute_lambda(Vb_new, bmu_new, n, col, 
				 F, Z, Ki_new, Ti, tau2, b0);
  } else {	/* linear */
    *log_det_K_new = n*log(1.0 + nug);
    *lambda_new = compute_lambda_noK(Vb_new, bmu_new, n, col,
				     F, Z, Ti, tau2, b0, nug);
  }
  
  if(T[0][0] == 0) m = col;
  
  /* start computation of posterior distribution */
  pd = post_margin(n,col,*lambda_new,Vb_new,*log_det_K_new,a0-m,g0);
  pd += log_d_prior_pdf(d, d_alpha, d_beta);
  pdlast = post_margin(n,col,lambda,Vb,log_det_K,a0-m,g0);
  pdlast += log_d_prior_pdf(dlast, d_alpha, d_beta);
  
  /* compute acceptance prob */
  /*alpha = exp(pd - pdlast + plin)*(q_bak/q_fwd);*/
  alpha = exp(pd - pdlast)*qRatio;
  if(isnan(alpha)) return -1;
  if(alpha >= 1 || runi(state) < alpha) return 1;
  else return 0;
}


/*
 * d_sep_draw_margin:
 * 
 * draws for d given the rest of the parameters except b and s2 marginalized out
 *
 *  F[col][n], Kchol[n][n], K_new[n][n], Ti[col][col], T[col][col] Vb[col][col], 
 *  Vb_new[col][col], Ki_new[n][n], Kchol_new[n][n], b0[col], Z[n], dlast[col-1],
 *  d_alpha[col-1][2], d_beta[col-1][2]
 *
 *  return 1 if draw accepted, 0 if rejected, -1 if error
 */

int d_sep_draw_margin(d, n, col, F, X, Z, log_det_K, lambda, Vb, 
	K_new, Ki_new, Kchol_new, log_det_K_new, lambda_new, Vb_new, 
	bmu_new, b0, Ti, T, tau2, nug, qRatio, pRatio_log, a0, g0, 
	lin, state)
unsigned int n, col;
int lin;
double **F, **X, **K_new, **Ti, **T, **Vb, **Vb_new, **Ki_new, **Kchol_new;
double *b0, *Z, *d, *log_det_K_new;
double nug, a0, g0, lambda, tau2, log_det_K, qRatio, pRatio_log;
double *lambda_new, *bmu_new;
void *state;
{
  double pd, pdlast, alpha;
  unsigned int m = 0;
  
  /* Knew = dist_to_K(dist, d, nugget)
     compute lambda, Vb, and bmu, for the NEW d */
  if(! lin) {	/* regular */
    exp_corr_sep_symm(K_new, col-1, X, n, d, nug, PWR);
    inverse_chol(K_new, Ki_new, Kchol_new, n);
    *log_det_K_new = log_determinant_chol(Kchol_new, n);
    *lambda_new = compute_lambda(Vb_new, bmu_new, n, col, 
				 F, Z, Ki_new, Ti, tau2, b0);
  } else {	/* linear */
    *log_det_K_new = n*log(1.0 + nug);
    *lambda_new = compute_lambda_noK(Vb_new, bmu_new, n, col, 
				     F, Z, Ti, tau2, b0, nug);
  }
  
  if(T[0][0] == 0) m = col;
  
  /* posteriors */
  pd = post_margin(n,col,*lambda_new,Vb_new,*log_det_K_new,a0-m,g0);
  pdlast = post_margin(n,col,lambda,Vb,log_det_K,a0-m,g0);
  
  /* compute acceptance prob */
  /*alpha = exp(pd - pdlast + plin)*(q_bak/q_fwd);*/
  alpha = exp(pd - pdlast + pRatio_log)*qRatio;
  if(isnan(alpha)) return -1;
  if(alpha >= 1 || runi(state) < alpha) return 1;
  else return 0;
}

/*
 * matern d_draw_margin:
 * 
 * draws for d given the rest of the parameters
 * except b and s2 marginalized out
 *
 * F[col][n], DIST[n][n], Kchol[n][n], K_new[n][n], Ti[col][col], T[col][col]
 * Vb[col][col], Vb_new[col][col], Ki_new[n][n], Kchol_new[n][n] b0[col], Z[n]
 *
 *  return 1 if draw accepted, 0 if rejected, -1 if error
 */

int matern_d_draw_margin(n, col, d, dlast, F, Z, DIST, log_det_K, lambda, Vb, K_new,
			 Ki_new, Kchol_new, log_det_K_new, lambda_new, Vb_new, bmu_new, 
			 b0, Ti, T, tau2, nug, nu, bk, nb, qRatio, d_alpha, d_beta, a0, 
			 g0, lin, state)
unsigned int n, col;
int lin;
double **F, **DIST, **K_new, **Ti, **T, **Vb, **Vb_new, **Ki_new, **Kchol_new;
double *b0, *Z, *bk;
double d_alpha[2], d_beta[2];
double qRatio;
double d, dlast, nug, nu, a0, g0, lambda, tau2, log_det_K;
double *lambda_new, *bmu_new, *log_det_K_new;
long nb;
void *state;
{
  double pd, pdlast, alpha;
  unsigned int m = 0;
  
  /* check if we are sticking with linear model */
  assert(dlast != 0.0);
  
  /* Knew = dist_to_K(dist, d, nugget);
     compute lambda, Vb, and bmu, for the NEW d */
  if(! lin) {	/* regular */
    matern_dist_to_K_symm(K_new, DIST, d, nu, bk, nb, nug, n);
    inverse_chol(K_new, Ki_new, Kchol_new, n);
    *log_det_K_new = log_determinant_chol(Kchol_new, n);
    *lambda_new = compute_lambda(Vb_new, bmu_new, n, col, 
				 F, Z, Ki_new, Ti, tau2, b0);
  } else {	/* linear */
    *log_det_K_new = n*log(1.0 + nug);
    *lambda_new = compute_lambda_noK(Vb_new, bmu_new, n, col,
				     F, Z, Ti, tau2, b0, nug);
  }
  
  if(T[0][0] == 0) m = col;
  
  /* start computation of posterior distribution */
  pd = post_margin(n,col,*lambda_new,Vb_new,*log_det_K_new,a0-m,g0);
  pd += log_d_prior_pdf(d, d_alpha, d_beta);
  pdlast = post_margin(n,col,lambda,Vb,log_det_K,a0-m,g0);
  pdlast += log_d_prior_pdf(dlast, d_alpha, d_beta);
  
  /* compute acceptance prob */
  /*alpha = exp(pd - pdlast + plin)*(q_bak/q_fwd);*/
  alpha = exp(pd - pdlast)*qRatio;
  if(isnan(alpha)) return -1;
  if(alpha >= 1 || runi(state) < alpha) return 1;
  else return 0;
}


/*
 * nug_draw_margin:
 * 
 * draws for nug given the rest of the parameters
 * except b and s2 marginalized out
 *
 * F[col][n], K[n][n], Kchol[n][n], K_new[n][n], Ti[col][col], T[col][col],
 * Vb[col][col], Vb_new[col][col], Ki_new[n][n], Kchol_new[n][n] b0[col], Z[n]
 */

double nug_draw_margin(n, col, nuglast, F, Z, K, log_det_K, lambda, Vb, 
	K_new, Ki_new, Kchol_new, log_det_K_new, lambda_new, Vb_new, bmu_new, 
	b0, Ti, T, tau2, nug_alpha, nug_beta, a0, g0, linear, state)
unsigned int n, col;
int linear;
double **F, **K, **K_new, **Ti, **T, **Vb, **Vb_new, **Ki_new, **Kchol_new;
double *b0, *Z, *log_det_K_new; 
double nug_alpha[2], nug_beta[2];
double nuglast, a0, g0, lambda, tau2, log_det_K;
double *lambda_new, *bmu_new;
void *state;
{
  double q_fwd, q_bak, nug, pnug, pnuglast, alpha;
  unsigned int i;
  unsigned int m = 0;
  
  /* propose new d, and compute proposal probability */
  nug = nug_draw(nuglast, &q_fwd, &q_bak, state);
  
  /* new covariace matrix based on new nug */
  if(linear) {
    *log_det_K_new = n * log(1.0 + nug);
    *lambda_new = compute_lambda_noK(Vb_new, bmu_new, n, col, 
				     F, Z, Ti, tau2, b0, nug);
  } else  {
    dup_matrix(K_new, K, n, n);
    for(i=0; i<n; i++) K_new[i][i] += (nug - nuglast);
    inverse_chol(K_new, Ki_new, Kchol_new, n);
    *log_det_K_new = log_determinant_chol(Kchol_new, n);
    *lambda_new = compute_lambda(Vb_new, bmu_new, n, col, 
				 F, Z, Ki_new, Ti, tau2, b0);
  }
  
  if(T[0][0] == 0) m = col;
  
  /* posteriors */
  pnug = log_nug_prior_pdf(nug, nug_alpha, nug_beta);
  pnug += post_margin(n,col,*lambda_new,Vb_new,*log_det_K_new,a0-m,g0);
  pnuglast = log_nug_prior_pdf(nuglast, nug_alpha, nug_beta);
  pnuglast += post_margin(n,col,lambda,Vb,log_det_K,a0-m,g0);
  
  /* accept or reject */
  alpha = exp(pnug - pnuglast)*(q_bak/q_fwd);
  if(alpha >= 1) return nug;
  else {
    if(runi(state) > alpha) return nuglast;
    else return nug;
  }
}


/*
 * mr_nug_draw_margin:
 * 
 * draws for nug given the rest of the parameters
 * except b and s2 marginalized out
 *
 * F[col][n], K[n][n], Kchol[n][n], K_new[n][n], Ti[col][col], T[col][col],
 * Vb[col][col], Vb_new[col][col], Ki_new[n][n], Kchol_new[n][n] b0[col], Z[n]
 */

double* mr_nug_draw_margin(n, col, nug, nugfine, X, F, Z, K, log_det_K, lambda, Vb, 
			   K_new, Ki_new, Kchol_new, log_det_K_new, lambda_new, Vb_new, 
			   bmu_new, b0, Ti, T, tau2, nug_alpha, nug_beta, nugf_alpha, 
			   nugf_beta, r, delta, a0, g0, linear, state)
unsigned int n, col;
int linear;
double **F, **K, **K_new, **Ti, **T, **Vb, **Vb_new, **Ki_new, **Kchol_new, **X;
double *b0, *Z, *log_det_K_new; 
double nug_alpha[2], nug_beta[2], nugf_alpha[2], nugf_beta[2];
double nug, nugfine, a0, g0, lambda, tau2, log_det_K, r, delta;
double *lambda_new, *bmu_new;
void *state;
{
  double q_fwd, q_bak, q_fwdf, q_bakf, pnug, pnuglast, alpha;
  unsigned int i;
  unsigned int m = 0;
  double* newnugs = new_vector(2);
  
  /* propose new d, and compute proposal probability */
  newnugs[0] = nug_draw(nug, &q_fwd, &q_bak, state);
  newnugs[1] = nug_draw(nugfine, &q_fwdf, &q_bakf, state);
  
  /* new covariace matrix based on new nug */
  if(linear) {
    *log_det_K_new = 0.0;
    for(i=0; i<n; i++){
      if(X[i][0]==1) *log_det_K_new += log(r*r + delta + nugfine);
      else *log_det_K_new += log(1.0 + nug);
    }
    *lambda_new = compute_lambda_noK(Vb_new, bmu_new, n, col, 
				     F, Z, Ti, tau2, b0, nug);
  } else  {
    dup_matrix(K_new, K, n, n);
    for(i=0; i<n; i++){
      if(X[i][0]==1) K_new[i][i] += (newnugs[1] - nugfine);
      else K_new[i][i] += (newnugs[0] - nug);
    }
    inverse_chol(K_new, Ki_new, Kchol_new, n);
    *log_det_K_new = log_determinant_chol(Kchol_new, n);
    *lambda_new = compute_lambda(Vb_new, bmu_new, n, col, 
				 F, Z, Ki_new, Ti, tau2, b0);
  }
  
  if(T[0][0] == 0) m = col;
  
  /* posteriors */
  pnug = log_nug_prior_pdf(newnugs[0], nug_alpha, nug_beta);
  pnug += log_nug_prior_pdf(newnugs[1], nugf_alpha, nugf_beta);
  pnug += post_margin(n,col,*lambda_new,Vb_new,*log_det_K_new,a0-m,g0);
  pnuglast = log_nug_prior_pdf(nug, nug_alpha, nug_beta);
  pnuglast += log_nug_prior_pdf(nugfine, nugf_alpha, nugf_beta);
  pnuglast += post_margin(n,col,lambda,Vb,log_det_K,a0-m,g0);
  
  /* accept or reject */
  alpha = exp(pnug - pnuglast)*(q_bak*q_bakf)/(q_fwd*q_fwdf);
  
  if(runi(state) > alpha){
    /* printf("nugs %g %g\n",nug, nugfine); */
    /*printVector(newnugs, 2, stdout); */
    newnugs[0] = nug;
    newnugs[1] = nugfine;
  }
  return newnugs;
}


/*
 * Ti_draw:
 * 
 * draws for Ti given the rest of the parameters
 *
 * b0[col], s2[ch] b[ch][col], V[col][col], Ti[col][col]
 */

void Ti_draw(Ti, col, ch, b, bmle, b0, rho, V, s2, tau2, state)
unsigned int col, ch, rho;
double *b0, *s2, *tau2;
double **b, **V, **Ti, **bmle;
void *state;
{
  double **sbb0, **S;
  double *bmb0;
  int i, nu, info;
  
  /* sbb0 = zeros(length(b0)); */
  sbb0 = new_zero_matrix(col, col);
  S = new_id_matrix(col);
  
  /* for i=1:length(s2) sbb0 = sbb0 + (b(:,i)-b0) * (b(:,i)-b0)'/s2(i); end */
  bmb0 = new_vector(col);
  for(i=0; i<ch; i++) {
    dupv(bmb0, b[i], col);
    if(bmle != NULL) dupv(b0, bmle[i], col);
    linalg_daxpy(col, -1.0, b0, 1, bmb0, 1);
    linalg_dgemm(CblasNoTrans,CblasNoTrans,col,col,
		 1,1.0/(s2[i]*tau2[i]),&bmb0,col,&bmb0,1,1.0,sbb0,col);
  }
  free(bmb0);
  
  /* S = inv(sbb0 + rho * V); */
  /* first sbb0 = sbb0 + rho * V */
  linalg_daxpy(col*col, rho, *V, 1, *sbb0, 1);
  
  /* then invert: S = inv(sbb0) */
  info = linalg_dgesv(col, sbb0, S);
  delete_matrix(sbb0);
  
  nu = rho +ch;
  wishrnd(Ti, S, col, nu, state);
  delete_matrix(S);
}


/*
 * b0_draw:
 *
 * Gibbs draws for b0
 *
 * b0[col], s2[ch], mu[col], b[ch][col], Ti[col][col], Ci[col][col]
 */

void b0_draw(b0, col, ch, b, s2, Ti, tau2, mu, Ci, state)
unsigned int col, ch;
double *b0, *s2, *mu, *tau2;
double **b, **Ti, **Ci;
void *state;
{
  int i, info;
  double s2i_sum, s2i;
  double **Vb0i, **Vb0;
  double *b_s2i_sum, *left, *right, *bm;
  
  /* ss2i = 1./ss2; */
  /* s2i_sum = sum(ss2i); */
  /* b_s2i_sum = b_s2i_sum + bb(:,i) * ss2i(i); */
  b_s2i_sum = new_zero_vector(col);
  s2i_sum = 0;
  for(i=0; i<ch; i++) {
    s2i = 1.0/(s2[i]*tau2[i]);
    s2i_sum += s2i;
    linalg_daxpy(col, s2i, b[i], 1, b_s2i_sum, 1);
  }
  
  /* some initialization */
  Vb0i = new_dup_matrix(Ci, col, col);
  Vb0 = new_id_matrix(col);
  
  /* Vb0 = inv(Ci + Ti*s2i_sum); */	
  /* first: Vb0i = Ci + Ti*s2i_sum; */	
  linalg_daxpy(col*col, s2i_sum, *Ti, 1, *Vb0i, 1);
  linalg_dgesv(col, Vb0i, Vb0);
  delete_matrix(Vb0i);
  
  /* b = Vb0 * (Ci*mu + Ti*b_s2i_sum); */
  /* in the sequence below */
  /* first zero some stuff out */
  left = new_zero_vector(col); 
  right = new_zero_vector(col);
  bm = new_zero_vector(col);
  
  /* then: right = Ti * b_s2i_sum */
  linalg_dsymv(col,1.0,Ti,col,b_s2i_sum,1,0.0,right,1);
  free(b_s2i_sum);
  /* and: left =  Ci * mu */
  linalg_dsymv(col,1.0,Ci,col,mu,1,0.0,left,1);
  /* and: right = left + right */
  linalg_daxpy(col, 1.0, left, 1, right, 1);
  free(left);
  /* b = Vb0 * (Ci*mu + Ti*b_s2i_sum); */
  linalg_dsymv(col,1.0,Vb0,col,right,1,0.0,bm,1);
  free(right);
  /* done */
	
  /* first: get the choleski decomposition */
  /* note that this changes the cov variable (Vb0) */
  info = linalg_dpotrf(col, Vb0);

  /* now get the draw using the choleski decomposition */
  mvnrnd(b0, bm, Vb0, col, state);
  delete_matrix(Vb0);
  free(bm);
}
back to top