Raw File
/******************************************************************************** 
 *
 * 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)
 *
 ********************************************************************************/


extern "C"
{
#include "matrix.h"
#include "lh.h"
#include "lik_post.h"
#include "rand_draws.h"
#include "rand_pdf.h"
#include "all_draws.h"
#include "gen_covar.h"
#include "rhelp.h"
}
#include "corr.h"
#include "params.h"
#include "model.h"
#include "mr_exp_sep.h"
#include <math.h>
#include <stdlib.h>
#include <stdio.h>
#include <assert.h>
#include <string.h>
#include <string>
#include <fstream>
using namespace std;

#define BUFFMAX 256
#define PWR 2.0

/*
 * MrExpSep:
 * 
 * constructor function; should be the same as ExpSep, excepy
 * for nin calculation, and assignments of r, delta, and nugfine 
 */

MrExpSep::MrExpSep(unsigned int col, Base_Prior *base_prior)
  : Corr(col, base_prior)
{
  /* Sanity Checks */
  assert(base_prior->BaseModel() == MR_GP);
  assert( ((MrGp_Prior*) base_prior)->CorrPrior()->CorrModel() == MREXPSEP);

  /* set pointer to correllation priot from the base prior */
  prior = ((MrGp_Prior*) base_prior)->CorrPrior();
  assert(prior);

  /* let the prior choose the starting nugget value */
  nug = prior->Nug();

  /* calculate the true input dimension of X */
  nin = (int) col/2-1;

  /* allocate and initialize (from prior) the range params */
  d = new_dup_vector(((MrExpSep_Prior*)prior)->D(), 2*nin);

  /* start fully in the GP model, not the LLM */
  b = new_ones_ivector(2*nin, 1);
  pb = new_zero_vector(2*nin);
  
  /* memory allocated for effective range parameter -- deff = d*b */
  d_eff = new_dup_vector(d, 2*nin);

  /* counter of the number of d-rejections in a row */
  dreject = 0;

  /* get the autoregressive cofficient from the prior */
  r = ((MrGp_Prior*) base_prior)->R();

  /* get the fine variance discount factor, and observation
     nugget for thefine level proc -- both fro prior */
  delta = ((MrExpSep_Prior*)prior)->Delta();
  nugfine = ((MrExpSep_Prior*)prior)->Nugfine();
}


/*
 * MrExpSep (assignment operator):
 * 
 * used to assign the parameters of one correlation
 * function to anothers.  Both correlation functions
 * must already have been allocated
 */

Corr& MrExpSep::operator=(const Corr &c)
{
  MrExpSep *e = (MrExpSep*) &c;

  /* sanity check */
  assert(prior == ((MrGp_Prior*) base_prior)->CorrPrior());

  /* copy everything */
  log_det_K = e->log_det_K;
  linear = e->linear;
  nin = e->nin;
  dupv(d, e->d, 2*nin);
  dupv(pb, e->pb, 2*nin);
  dupv(d_eff, e->d_eff, 2*nin);
  dupiv(b, e->b, 2*nin);
  nug = e->nug;
  dreject = e->dreject;

  /* copy the covariance matrices */
  Cov(e);

  return *this;
}


/* 
 * ~MrExpSep:
 * 
 * destructor
 */

MrExpSep::~MrExpSep(void)
{
  free(d);
  free(b);
  free(pb);
  free(d_eff);
}

/* 
 * DrawNug:
 * 
 * draw for the nugget; 
 * rebuilding K, Ki, and marginal params, if necessary 
 * return true if the correlation matrix has changed;
 * false otherwise
 */

bool MrExpSep::DrawNug(unsigned int n, double **X, double **F, double *Z, double *lambda, 
		   double **bmu, double **Vb, double tau2, void *state)
{
  bool success = false;
  MrGp_Prior *gp_prior = (MrGp_Prior*) base_prior;

  /* allocate K_new, Ki_new, Kchol_new */
  if(! linear) assert(n == this->n);
  
  /* with probability 0.5, skip drawing the nugget */
  if(runi(state) > 0.5) return false;
  
  /* make the draw */
  double* new_nugs = 
    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, gp_prior->get_b0(), 
		       gp_prior->get_Ti(), gp_prior->get_T(), tau2, 
		       prior->NugAlpha(), prior->NugBeta(), 
		       ((MrExpSep_Prior*) prior)->Nugf_alpha(), 
		       ((MrExpSep_Prior*) prior)->Nugf_beta(), r, delta, 
		       gp_prior->s2Alpha(), gp_prior->s2Beta(), (int) linear, state);
  
  /* did we accept the draw? */
  if(new_nugs[0] != nug) {
	nug = new_nugs[0]; nugfine = new_nugs[1];
	success = true; 
	swap_new(Vb, bmu, lambda); 
  }
 
  /* clean up */
  free(new_nugs);

  return success;
  
}


/*
 * Update: (symmetric)
 * 
 * computes the internal correlation matrix K, 
 * (INCLUDES NUGGET)
 */

void MrExpSep::Update(unsigned int n, double **K, double **X)
{
  corr_symm(K, nin, X, n, d_eff, nug, nugfine, r, delta, PWR);
}


/*
 * Update: (symmetric)
 * 
 * takes in a (symmetric) distance matrix and
 * returns a correlation matrix (INCLUDES NUGGET)
 */

void MrExpSep::Update(unsigned int n, double **X)
{
  /* no need to update internal K if we're at LLM */
  if(linear) return;

  /* sanity check */
  assert(this->n == n);

  /* compute K */
  corr_symm(K, nin, X, n, d_eff, nug, nugfine, r, delta, PWR);
}



/*
 * Update: (non-symmetric)
 * 
 * takes in a distance matrix and returns a 
 * correlation matrix (DOES NOT INCLUDE NUGGET)
 */

void MrExpSep::Update(unsigned int n1, unsigned int n2, double **K, 
		    double **X, double **XX)
{
  corr_unsymm(K, nin+1, XX, n1, X, n2, d_eff, r, delta, PWR);
}


/*
 * propose_new_d:
 *
 * propose new d and b values.  Sometimes propose d's and b's for all
 * dimensions jointly, sometimes do just the d's with b==1, and
 * other times do only those with b==0.  I have found that this improves
 * mixing
 */

bool MrExpSep::propose_new_d(double* d_new, int * b_new, double *pb_new, 
			   double *q_fwd, double *q_bak, void *state)
{
  *q_bak = *q_fwd = 1.0;
  
  /* copy old values */
  dupv(d_new, d, 2*nin);
  dupv(pb_new, pb, 2*nin);
  dupiv(b_new, b, 2*nin);
  
  /* 1/3 of the time  -- just draw all the ds jointly */
  if(runi(state) < 0.3333333333) {
    
    /* RW proposal for all d-values */
    d_proposal(2*nin, NULL, d_new, d, q_fwd, q_bak, state);

    /* if we are allowing the LLM, then we need to draw the b_new
       conditional on d_new; otherwise just return */
    if(prior->LLM()) {
      if(runi(state) < 0.5) /* sometimes skip drawing the bs */
	return linear_rand_sep(b_new,pb_new,d_new,2*nin,prior->GamLin(),state);
      else return linear;
    } else return false;
    
    /* just draw the ds with bs == 1 or bs == 0, choosing one
       of those randomly */
  } else {
    
    /* choose bs == 1 or bs == 0 */
    FIND_OP find_op = NE;
    if(runi(state) < 0.5) find_op = EQ;
    
    /* find those ds which coincide with find_op */
    unsigned int len = 0;
    int* zero =  find(d_eff, 2*nin, find_op, 0.0, &len);

    /* if there are no d's which coincide with find_op, then
       there is nothing to propose, so just return with the
       current LLM setting */
    if(len == 0) { free(zero); return linear; }
    
    /* otherwise, draw length(zero) new d values, only at the
       indices of d_new indicated by zero */
    d_proposal(len, zero, d_new, d, q_fwd, q_bak, state);
    
    /* done if forcing Gp model (not allowing the LLM) */
    if(! prior->LLM()) { free(zero); return false; }

    /* otherwise, need to draw bs (booleans) conditional
       on the proposed d_new -- only do this 1/2 the time */
    
    /* sometimes skip drawing the bs */
    if(runi(state) < 0.5) {

      /* gather the ds, bs, and pbs into the "short" vectors,
         as indexed by the zero-vector */  
      double *d_short = new_vector(len);
      double *pb_short = new_zero_vector(len);
      int *b_short = new_ones_ivector(len, 0); /* make ones give zeros */
      copy_sub_vector(d_short, zero, d_new, len);

      /* draw new bs conditional on the new ds */
      linear_rand_sep(b_short,pb_short,d_short,len,prior->GamLin(),state);
      
      /* copy the new bs and pbs into the big "new" proposals */
      copy_p_vector(pb_new, zero, pb_short, len);
      copy_p_ivector(b_new, zero, b_short, len);

      /* clean up */
      free(d_short); free(pb_short); free(b_short); free(zero);
   
      /* only return true if we have actiually jumpted to the LLM;
	 i.e., only when all the b_new's are 0 */   
      for(unsigned int i=0; i<(2*nin); i++) if(b_new[i] == 1) return false;
      return true;

    } else {

      /* if we skipped drawing new b's, then clean-up and return
	 the previous LLM setting */
      free(zero);
      return linear;
    }
  }
}

/*
 * Draw:
 * 
 * draw parameters for a new correlation matrix;
 * returns true if the correlation matrix (passed in)
 * has changed; otherwise returns false
 */

int MrExpSep::Draw(unsigned int n, double **F, double **X, double *Z, 
		double *lambda, double **bmu, double **Vb, double tau2, void *state)
{
  int success = 0;
  bool lin_new;
  double q_fwd, q_bak;
  
  /* get more accessible pointers to the priors */
  MrExpSep_Prior* ep = (MrExpSep_Prior*) prior;
  MrGp_Prior *gp_prior = (MrGp_Prior*) base_prior;

  /* pointers to proposed settings of parameters */
  double *d_new = NULL;
  int *b_new = NULL;
  double *pb_new = NULL;
  
  /* when the LLM is active, sometimes skip this Draw
     and only draw the nugget;  this is done for speed,
     and to improve miding in the rest of the model */
  if(linear && runi(state) > 0.5) {
    return DrawNug(n, X, F, Z, lambda, bmu, Vb, tau2, state);}

  /* proposals happen when we're not forcing the LLM */
  if(prior->Linear()) lin_new = true;
  else {
    /* allocate new d, b, and pb */
    d_new = new_zero_vector((2*nin));
    b_new = new_ivector((2*nin)); 
    pb_new = new_vector((2*nin));

    /* make the RW proposal for d, and then b */
    lin_new = propose_new_d(d_new, b_new, pb_new, &q_fwd, &q_bak, state);
  }
  
  /* calculate the effective model (d_eff = d*b), 
     and allocate memory -- when we're not proposing the LLM */
  double *d_new_eff = NULL;
  if(! lin_new) {
    d_new_eff = new_zero_vector((2*nin));
    for(unsigned int i=0; i<(2*nin); i++) d_new_eff[i] = d_new[i]*b_new[i];
    
    /* allocate K_new, Ki_new, Kchol_new */
    allocate_new(n);

    /* sanity check */
    assert(n == this->n);
  }
  
  /* compute the acceptance ratio, unless we're forcing the LLM
     in which case we do nothing just return a successful "draw" */
  if(prior->Linear()) success = 1;
  else {
   
    /* compute prior ratio and proposal ratio */
    double pRatio_log = 0.0;
    double qRatio = q_bak/q_fwd;
    pRatio_log += ep->log_DPrior_pdf(d_new);
    pRatio_log -= ep->log_DPrior_pdf(d);
    
    /* MH acceptance ratio for the draw */
    success = d_draw(d_new_eff, 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, gp_prior->get_b0(), gp_prior->get_Ti(), 
		                gp_prior->get_T(), tau2, nug, nugfine, qRatio, 
				pRatio_log, gp_prior->s2Alpha(), gp_prior->s2Beta(), 
				(int) lin_new, state);
   

    /* see if the draw was acceptedl; if so, we need to copy (or swap)
       the contents of the new into the old  */
    if(success == 1) { 
      swap_vector(&d, &d_new);

      /* d_eff is zero if we're in the LLM */
      if(!lin_new) swap_vector(&d_eff, &d_new_eff);
      else zerov(d_eff, (2*nin));
      linear = (bool) lin_new;

      /* copy b and pb */
      swap_ivector(&b, &b_new);
      swap_vector(&pb, &pb_new);
      swap_new(Vb, bmu, lambda);
    }
  }

    /* if we're not forcing the LLM, then we have some cleaning up to do */
  if(! prior->Linear()) { free(d_new); free(pb_new); free(b_new); }

  /* if we didn't happen to jump to the LLM, 
     then we have more cleaning up to do */
  if(!lin_new) free(d_new_eff);
  
  /* something went wrong, abort;
     otherwise keep track of the number of d-rejections in a row */
  if(success == -1) return success;
  else if(success == 0) dreject++;
  else dreject = 0;

  /* abort if we have had too many rejections */
  if(dreject >= REJECTMAX) return -2;
  
  /* draw nuggets */
  bool changed = DrawNug(n, X, F, Z, lambda, bmu, Vb, tau2, state);
  bool deltasuccess = DrawDelta(n, X, F, Z, lambda, bmu, Vb, tau2, state);
  success = success || changed || deltasuccess;
 
  return success;
}


/*
 * Combine:
 * 
 * used in tree-prune steps, chooses one of two
 * sets of parameters to correlation functions,
 * and choose one for "this" correlation function
 */

void MrExpSep::Combine(Corr *c1, Corr *c2, void *state)
{
  get_delta_d((MrExpSep*)c1, (MrExpSep*)c2, state);
  CombineNug(c1, c2, state);
}


/*
 * Split:
 * 
 * used in tree-grow steps, splits the parameters
 * of "this" correlation function into a parameterization
 * for two (new) correlation functions
 */

void MrExpSep::Split(Corr *c1, Corr *c2, void *state)
{
  propose_new_d((MrExpSep*) c1, (MrExpSep*) c2, state);
  SplitNug(c1, c2, state);
}


/*
 * get_delta_d:
 * 
 * compute d from two ds residing in c1 and c2
 * and sample b conditional on the chosen d
 *
 * (used in prune)
 */

void MrExpSep::get_delta_d(MrExpSep* c1, MrExpSep* c2, void *state)
{
  /* ceate pointers to the two ds */
  double **dch = (double**) malloc(sizeof(double*) * 2);
  dch[0] = c1->d; dch[1] = c2->d;

  /* randomly choose one of the ds */
  int ii[2];
  propose_indices(ii, 0.5, state);

  /* and copy the chosen one */
  dupv(d, dch[ii[0]], (2*nin));

  /* clean up */
  free(dch);

  /* propose b conditional on the chosen d */
  linear = linear_rand_sep(b, pb, d, (2*nin), prior->GamLin(), state);

  /* compute d_eff = d * b for the chosen d and b */
  for(unsigned int i=0; i<(2*nin); i++) d_eff[i] = d[i] * b[i];
}


/*
 * propose_new_d:
 * 
 * propose new D parameters for possible
 * new children partitions. 
 */

void MrExpSep::propose_new_d(MrExpSep* c1, MrExpSep* c2, void *state)
{
  int i[2];
  double **dnew = new_matrix(2, (2*nin));

  /* randomply choose which of c1 and c2 will get a copy of this->d, 
     and which will get a random d from the prior */  
  propose_indices(i, 0.5, state);

  /* =from this->d */
  dupv(dnew[i[0]], d, (2*nin));

  /* from the prior */
  draw_d_from_prior(dnew[i[1]], state);

  /* copy into c1 and c2 */
  dupv(c1->d, dnew[0], (2*nin));
  dupv(c2->d, dnew[1], (2*nin));

  /* clean up */
  delete_matrix(dnew);

  /* propose new b for c1 and c2, conditional on the two new d parameters */  
  c1->linear = (bool) linear_rand_sep(c1->b, c1->pb, c1->d, (2*nin), prior->GamLin(), state);
  c2->linear = (bool) linear_rand_sep(c2->b, c2->pb, c2->d, (2*nin), prior->GamLin(), state);

  /* compute d_eff = b*d for the two new b and d pairs */
  for(unsigned int i=0; i<(2*nin); i++) {
    c1->d_eff[i] = c1->d[i] * c1->b[i];
    c2->d_eff[i] = c2->d[i] * c2->b[i];
  }
}

/*
 * d_draw:
 * 
 * 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 MrExpSep::d_draw(double *d, unsigned int n, unsigned int col, double **F, 
		     double **X, double *Z, double log_det_K, double lambda, 
		     double **Vb, double **K_new, double **Ki_new, 
		     double **Kchol_new, double *log_det_K_new, 
		     double *lambda_new, double **VB_new, double *bmu_new, 
		     double *b0, double **Ti, double **T, double tau2,
		     double nug, double nugfine, double qRatio, double pRatio_log, 
		     double a0, double g0, int lin, 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 */
    corr_symm(K_new, nin+1, X, n, d, nug, nugfine, r, delta, 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 = 0.0;
    for(unsigned int 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);
  }
  
  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(alpha != alpha) return -1;
  if(alpha >= 1 || runi(state) < alpha) return 1;
  else return 0;
}


bool MrExpSep::DrawDelta(unsigned int n, double **X, double **F, double *Z,
		       double *lambda, double **bmu, 
		       double **Vb, double tau2, void *state)
{
  bool success = false;
  
  MrGp_Prior *gp_prior = (MrGp_Prior*) base_prior;
  MrExpSep_Prior *ep = (MrExpSep_Prior*) prior;
  unsigned int m = 0;

  double* b0 = gp_prior->get_b0();
  double a0 = gp_prior->s2Alpha();
  double g0 = gp_prior->s2Beta();
  
  /* allocate K_new, Ki_new, Kchol_new */
  if(! linear) assert(n == this->n);
  
  if(runi(state) > 0.5) return false;
  
  double q_fwd;
  double q_bak;
  double pdelta;
  double pnewdelta;

  /* make the draw */

    double newdelta = unif_propose_pos(delta, &q_fwd, &q_bak, state);
    // printf("%g %g\n", delta, newdelta);
  	/* new covariace matrix based on new nug */

    if(linear) {
      log_det_K_new = 0.0;
      for(unsigned int 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, gp_prior->get_Ti(), tau2, b0, nug);
    }
    else{
      corr_symm(K_new, nin+1, X, n, d, nug, nugfine, r, newdelta, 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, gp_prior->get_Ti(), tau2, b0);
    }
    
    if((gp_prior->get_T())[0][0] == 0) m = col;
    
    pnewdelta = gamma_mixture_pdf(newdelta, ep->Delta_alpha(), ep->Delta_beta());
    pnewdelta += post_margin(n,col,lambda_new,Vb_new,log_det_K_new,a0-m,g0);
    pdelta = gamma_mixture_pdf(delta, ep->Delta_alpha(), ep->Delta_beta());
    pdelta += post_margin(n,col,*lambda,Vb,log_det_K,a0-m,g0);
    
    /* accept or reject */
    double alpha = exp(pnewdelta - pdelta)*(q_bak/q_fwd);
    
    if(runi(state) < alpha) { 
      success = true;
      delta = newdelta;
      swap_new(Vb, bmu, lambda); 
    }
    
    return success;
}


/*
 * draw_d_from_prior:
 *
 * get draws of separable d parameter from
 * the prior distribution
 */

void MrExpSep::draw_d_from_prior(double *d_new, void *state)
{
  if(prior->Linear()) dupv(d_new, d, (2*nin));
  else ((MrExpSep_Prior*)prior)->DPrior_rand(d_new, state);
}

/*
 * corr_symm:
 * 
 * compute a (symmetric) correllation matrix from a seperable
 * exponential correllation function
 *
 * X[n][m], K[n][n]
 */

void MrExpSep::corr_symm(double **K, unsigned int m, double **X, unsigned int n,
			 double *d, double nug, double nugfine, double r, 
			 double delta, double pwr)
{
  unsigned int i,j,k/*, across*/;
  double diff, fine;
  i = k = j = 0;
  
  for(i=0; i<n; i++) {
    if(X[i][0] == 0) K[i][i] = 1.0 + nug;
    else K[i][i] = r*r + delta + nugfine;
    for(j=i+1; j<n; j++) {
      K[j][i] = 0.0;
      fine = 0.0;
      if(X[i][0] == 0 && X[j][0] == 0){
	
	for(k=1; k<m; k++) {
	  if(d[k-1] == 0.0) continue;
	  diff = X[i][k] - X[j][k];
	  K[j][i] += diff*diff/d[k-1];
	}
	K[j][i] = exp(0.0-K[j][i]);
	K[i][j] = K[j][i];
      }
      if(X[i][0]==1 && X[j][0]==1){
	
	for(k=1; k<m; k++) {
	  diff = X[i][k] - X[j][k];
	  if(d[k-1] == 0.0) continue;
	  K[j][i] += diff*diff/d[k-1];
	  if(d[m+k-2] == 0.0) continue;
	  fine += diff*diff/(d[m+k-2]);
	}
	K[j][i] = r*r*exp(0.0-K[j][i]) + delta*exp(0.0-fine);
	K[i][j] = K[j][i];
      }
      // Correlation across fidelities
      if( X[i][0] != X[j][0] ) {
	
	for(k=1; k<m; k++) {
	  if(d[k-1] == 0.0) continue;
	  diff = X[i][k] - X[j][k];
	  K[j][i] += diff*diff/d[k-1];
	}
	K[j][i] = r*exp(0.0-K[j][i]);
	K[i][j] = K[j][i];
      }
    }
  }
  
}


/*
 * corr_unsymm:
 * 
 * compute a correllation matrix from a seperable
 * exponential correllation function, do not assume
 * symmetry
 * X1[n1][m], X2[n2][m], K[n2][n1], d[m]
 */

void MrExpSep::corr_unsymm(double **K, unsigned int m, 
		   double **X1, unsigned int n1, double **X2, unsigned int n2,
		   double *d, double r, double delta, double pwr)
{

  unsigned int i,j,k/*, across*/;
  double diff, fine;
  i = k = j = 0;
  for(i=0; i<n1; i++) {
    for(j=0; j<n2; j++) {
      K[j][i] = 0.0;
      fine = 0.0;
      if(X1[i][0] == 0 && X2[j][0] == 0){
	for(k=1; k<m; k++) {
	  if(d[k-1] == 0.0) continue;
	  diff = X1[i][k] - X2[j][k];
	  K[j][i] += diff*diff/d[k-1];
	}
	K[j][i] = exp(0.0-K[j][i]);
      }
      if(X1[i][0]==1 && X2[j][0]==1){
	for(k=1; k<m; k++) {
	  diff = X1[i][k] - X2[j][k];
	  if(d[k-1] == 0.0) continue;
	  K[j][i] += diff*diff/d[k-1];
	  if(d[m+k-2] == 0.0) continue;
	  fine += diff*diff/(d[m+k-2]);
	}
	K[j][i] = r*r*exp(0.0-K[j][i]) + delta*exp(0.0-fine);
      }
      // Correlation across fidelities
      if( X1[i][0] != X2[j][0] ) {
	for(k=1; k<m; k++) {
	  if(d[k-1] == 0.0) continue;
	  diff = X1[i][k] - X2[j][k];
	  K[j][i] += diff*diff/d[k-1];
	}
	K[j][i] = r*exp(0.0-K[j][i]);
      }
    }
  }
}

/*
 * return a string depecting the state
 * of the (parameters of) correlation function
 */

char* MrExpSep::State(void)
{
  char buffer[BUFFMAX];

  /* slightly different format if the nugget is going
     to get printed also */
// #ifdef PRINTNUG
  string s = "(d=[";
// #else
//  string s = "[";
// #endif

  /* if linear, then just put a zero and be done;
     otherwise, print the col d-values */ 
  if(linear) sprintf(buffer, "0]");
  else {
    for(unsigned int i=0; i<(2*nin-1); i++) {

      /* if this dimension is under the LLM, then show 
	 d_eff (which should be zero) / d */
      if(b[i] == 0.0) sprintf(buffer, "%g/%g ", d_eff[i], d[i]);
      else sprintf(buffer, "%g ", d[i]);
      s.append(buffer);
    }

    /* do the same for the last d, and then close it off */
    if(b[nin*2-1] == 0.0) sprintf(buffer, "%g/%g],", d_eff[nin*2-1], d[nin*2-1]);
    else sprintf(buffer, "%g],", d[nin*2-1]);
  }
  s.append(buffer);

  /* print the nugget */
  sprintf(buffer, "\n\t g=[%g", nug);
  s.append(buffer);
//#ifdef PRINTNUG
  /* print the fine nugget */
  sprintf(buffer, " %g]", nugfine);
  s.append(buffer);
//#endif
  /* print the delta parameter */
  sprintf(buffer, ", delta=%g)", delta);
  s.append(buffer); 
  
  /* copy the string to an allocaated char* */
  char* ret_str = (char*) malloc(sizeof(char) * (s.length()+1));
  strncpy(ret_str, s.c_str(), s.length());
  ret_str[s.length()] = '\0';
  return ret_str;
}


/*
 * log_Prior:
 * 
 * compute the (log) prior for the parameters to
 * the correlation function (e.g. d and nug). Does not
 * include hierarchical prior params; see log_HierPrior
 * below
 */

double MrExpSep::log_Prior(void)
{
  /* start with the prior log_pdf value for the nugget(s) */
  double prob = log_NugPrior();

  /* add in the log_pdf value for each of the ds */
  prob += ((MrExpSep_Prior*)prior)->log_Prior(d, b, pb, linear);

  return prob;
}


/*
 * sum_b:
 *
 * return the count of the number of linearizing
 * booleans set to one (the number of linear dimensions)
 */ 

unsigned int MrExpSep::sum_b(void)
{
  unsigned int bs = 0;
  for(unsigned int i=0; i<(2*nin); i++) if(!b[i]) bs ++;

  /* sanity check */
  if(bs == (2*nin)) assert(linear);

  return bs;
}


/*
 * ToggleLinear:
 *
 * make linear if not linear, otherwise
 * make not linear
 */

void MrExpSep::ToggleLinear(void)
{
  if(linear) { /* force a full GP model */
    linear = false;
    for(unsigned int i=0; i<(2*nin); i++) b[i] = 1;
  } else { /* force a full LLM */
    linear = true;
    for(unsigned int i=0; i<(2*nin); i++) b[i] = 0;
  }

  /* set d_Eff = d * b */
  for(unsigned int i=0; i<(2*nin); i++) d_eff[i] = d[i] * b[i];
}


/*
 * D:
 *
 * return the vector of range parameters for the
 * separable exponential family of correlation function
 */

double* MrExpSep::D(void)
{
  return d;
}


/*
 * R:
 *
 * return the default auto-correlation between fidelities. 
 */

double MrExpSep::R(void)
{
  return r;
}


/*
 * Delta:
 *
 *
 * return the fine fidelity discount factor, delta.
 */

double MrExpSep::Delta(void)
{
  return delta;
}

/*
 * Nugfine:
 *
 *
 * return the fine fidelity observational error
 */

double MrExpSep::Nugfine(void)
{
  return nugfine;
}


/* 
 * Trace:
 *
 * return the current values of the parameters
 * to this correlation function
 */

double* MrExpSep::Trace(unsigned int* len)
{
  *len = 0;

  /* FOR TADDY TO FILL IN */

  return NULL;
}


/*
 * MrExpSep_Prior:
 *
 * constructor for the prior parameterization of the separable
 * exponential power distribution function 
 */

MrExpSep_Prior::MrExpSep_Prior(const unsigned int col) : Corr_Prior(col)
{
  corr_model = MREXPSEP;

  /* calculate effective number of input dimension */
  nin = col/2-1;

  /* default starting values and initial parameterization */
  d = ones((2*nin), 0.5);
  d_alpha = new_zero_matrix((2*nin), 2);
  d_beta = new_zero_matrix((2*nin), 2);
  default_d_priors();	/* set d_alpha and d_beta */
  default_d_lambdas();	/* set d_alpha_lambda and d_beta_lambda */

  /* defauly starting values for mr-specific parameters;
     these should probably be moved into a default_*
     function like the others */
  r = 1.0;
  delta = 1.0;
  nugfine = 0.01;
  delta_alpha = ones(2,1.0);
  delta_beta = ones(2,20.0);
  nugf_alpha = ones(2,1.0);
  nugf_beta = ones(2,1.0);
}


/*
 * Dup:
 *
 * duplicate this prior for the isotropic exponential
 * power family
 */

Corr_Prior* MrExpSep_Prior::Dup(void)
{
  return new MrExpSep_Prior(this);
}


/*
 * MrExpSep_Prior (new duplicate)
 *
 * duplicating constructor for the prior distribution for 
 * the separable exponential correlation function
 */

MrExpSep_Prior::MrExpSep_Prior(Corr_Prior *c) : Corr_Prior(c)
{
  MrExpSep_Prior *e = (MrExpSep_Prior*) c;

  /* sanity check */
  assert(e->corr_model == MREXPSEP);

  /* copy all parameters of the prior */
  corr_model = e->corr_model;
  dupv(gamlin, e->gamlin, 3);
  nin = e->nin;
  d = new_dup_vector(e->d, (2*nin));
  fix_d = e->fix_d;
  d_alpha = new_dup_matrix(e->d_alpha, (2*nin), 2);
  d_beta = new_dup_matrix(e->d_beta, (2*nin), 2);
  dupv(d_alpha_lambda, e->d_alpha_lambda, 2);
  dupv(d_beta_lambda, e->d_beta_lambda, 2);
  r = e->r;
  delta = e->delta;
  nugfine = e->nugfine;
  delta_alpha = new_dup_vector(e->delta_alpha, 2);
  delta_beta = new_dup_vector(e->delta_beta, 2);
  nugf_alpha = new_dup_vector(e->nugf_alpha, 2);
  nugf_beta = new_dup_vector(e->nugf_beta, 2);
}


/*
 * ~MrExpSep_Prior:
 *
 * destructor for the prior parameterization of the separable
 * exponential power distribution function
 */

MrExpSep_Prior::~MrExpSep_Prior(void)
{
  free(d);
  delete_matrix(d_alpha);
  delete_matrix(d_beta);
  free(delta_alpha);
  free(delta_beta);
  free(nugf_alpha);
  free(nugf_beta);
}


/*
 * read_double:
 *
 * read the double parameter vector giving the user-secified
 * prior parameterization specified in R
 */

void MrExpSep_Prior::read_double(double *dparams)
{
  /* read the parameters that have to to with the nugget */
  read_double_nug(dparams);

  /* read the starting value(s) for the range parameter(s) */
  for(unsigned int i=0; i<(2*nin); i++) d[i] = dparams[1];
  /*myprintf(stdout, "starting d=");
    printVector(d, (2*nin), stdout); */

  /* reset the d parameter to after nugget and gamlin params */
  dparams += 13;
 
  /* read d gamma mixture prior parameters */
  double alpha[2], beta[2];
  get_mix_prior_params_double(alpha, beta, dparams, "d");
  for(unsigned int i=0; i<nin; i++) {
    dupv(d_alpha[i], alpha, 2);
    dupv(d_beta[i], beta, 2);
  }
  dparams += 4;
  get_mix_prior_params_double(alpha, beta, dparams, "d");
  for(unsigned int i=0; i<nin; i++) {
    dupv(d_alpha[i+nin], alpha, 2);
    dupv(d_beta[i+nin], beta, 2);
  }
  //printMatrix(d_alpha, 2*nin, 2, stdout);
  //printMatrix(d_beta, 2*nin, 2, stdout);
  dparams +=4;
 
  get_mix_prior_params_double(alpha, beta, dparams, "d");
  dupv(delta_alpha, alpha, 2);
  dupv(delta_beta, beta, 2);
  //printVector(delta_alpha, 2, stdout);
  //printVector(delta_beta, 2, stdout);
  dparams +=4;
 
  get_mix_prior_params_double(alpha, beta, dparams, "d");
  dupv(nugf_alpha, alpha, 2);
  dupv(nugf_beta, beta, 2);

  dparams += 4; /* reset */

  /* d hierarchical lambda prior parameters */
  if((int) dparams[0] == -1)
    { fix_d = true;  /* myprintf(stdout, "fixing d prior\n"); */}
  else {
    fix_d = false;
    get_mix_prior_params_double(d_alpha_lambda, d_beta_lambda, dparams, "d lambda");
  }
  dparams += 4; /* reset */
}


/*
 * read_ctrlfile:
 *
 * read prior parameterization from a control file
 *
 * THIS IS ENTIRELY UNCHECKED -- EVENTUALLY NEED TO PORT 
 * THE MR STUFF TO THE ADAPTIVE SAMPLING CODE
 */

void MrExpSep_Prior::read_ctrlfile(ifstream *ctrlfile)
{
  char line[BUFFMAX], line_copy[BUFFMAX];

  /* read the parameters that have to do with the
   * nugget first */
  read_ctrlfile_nug(ctrlfile);

  /* read the d parameter from the control file */
  ctrlfile->getline(line, BUFFMAX);
  d[0] = atof(strtok(line, " \t\n#"));
  for(unsigned int i=1; i<(2*nin); i++) d[i] = d[0];
  myprintf(stdout, "starting d=", d);
  printVector(d, (2*nin), stdout);

  /* read d and nug-hierarchical parameters (mix of gammas) */
  double alpha[2], beta[2];
  ctrlfile->getline(line, BUFFMAX);
  get_mix_prior_params(alpha, beta, line, "d");
  for(unsigned int i=0; i<(2*nin); i++) {
    dupv(d_alpha[i], alpha, 2);
    dupv(d_beta[i], beta, 2);
  }

  ctrlfile->getline(line, BUFFMAX);
  get_mix_prior_params(alpha, beta, line, "d");
    dupv(delta_alpha, alpha, 2);
    dupv(delta_beta, beta, 2);
  
  ctrlfile->getline(line, BUFFMAX);
  get_mix_prior_params(alpha, beta, line, "d");
    dupv(nugf_alpha, alpha, 2);
    dupv(nugf_beta, beta, 2);
  

  /* d hierarchical lambda prior parameters */
  ctrlfile->getline(line, BUFFMAX);
  strcpy(line_copy, line);
  if(!strcmp("fixed", strtok(line_copy, " \t\n#")))
    { fix_d = true; myprintf(stdout, "fixing d prior\n"); }
  else {
    fix_d = false;
    get_mix_prior_params(d_alpha_lambda, d_beta_lambda, line, "d lambda");  
  }
}


/*
 * default_d_priors:
 * 
 * set d prior parameters
 * to default values
 */

void MrExpSep_Prior::default_d_priors(void)
{
  for(unsigned int i=0; i<(2*nin); i++) {
    d_alpha[i][0] = 1.0;
    d_beta[i][0] = 20.0;
    d_alpha[i][1] = 10.0;
    d_beta[i][1] = 10.0;
  }
}


/*
 * default_d_lambdas:
 * 
 * set d (lambda) hierarchical prior parameters
 * to default values
 */

void MrExpSep_Prior::default_d_lambdas(void)
{
  d_alpha_lambda[0] = 1.0;
  d_beta_lambda[0] = 10.0;
  d_alpha_lambda[1] = 1.0;
  d_beta_lambda[1] = 10.0;
  fix_d = false;
}


/*
 * D:
 *
 * return the default range parameter vector 
 */

double* MrExpSep_Prior::D(void)
{
  return d;
}

/*
 * R:
 *
 * return the default auto-correlation between fidelities. 
 */

double MrExpSep_Prior::R(void)
{
  return r;
}

/*
 * Delta:
 *
 *
 * return the fine fidelity discount factor, delta.
 */

double MrExpSep_Prior::Delta(void)
{
  return delta;
}

/*
 * Nugfine
 *
 *
 * return the fine fidelity observation error.
 */

double MrExpSep_Prior::Nugfine(void)
{
  return nugfine;
}

/*
 * DAlpha:
 *
 * return the default/starting alpha matrix for the range 
 * parameter mixture gamma prior
 */

double** MrExpSep_Prior::DAlpha(void)
{
  return d_alpha;
}


/*
 * DBeta:
 *
 * return the default/starting beta matrix for the range 
 * parameter mixture gamma prior
 */

double** MrExpSep_Prior::DBeta(void)
{
  return d_beta;
}


/*
 * DeltaAlpha:
 *
 * return the default/starting alpha matrix for the scaled variance 
 * parameter mixture gamma prior
 */

double* MrExpSep_Prior::Delta_alpha(void)
{
  return delta_alpha;
}


/*
 * DeltaBeta:
 *
 * return the default/starting beta matrix for the scaled variance
 * parameter mixture gamma prior
 */

double* MrExpSep_Prior::Delta_beta(void)
{
  return delta_beta;
}


/*
 * NugfAlpha:
 *
 * return the default/starting alpha for the fine nugget 
 * parameter mixture gamma prior
 */

double* MrExpSep_Prior::Nugf_alpha(void)
{
  return nugf_alpha;
}


/*
 * NugfBeta:
 *
 * return the default/starting beta matrix for the fine nugget
 * parameter mixture gamma prior
 */

double* MrExpSep_Prior::Nugf_beta(void)
{
  return nugf_beta;
}


/*
 * Draw:
 * 
 * draws for the hierarchical priors for the MrExpSep
 * correlation function which are contained in the params module
 *
 * inputs are howmany number of corr modules 
 */

void MrExpSep_Prior::Draw(Corr **corr, unsigned int howmany, void *state)
{
  /* don't do anything if we're fixing the prior for d */
  if(!fix_d) {

    /* for gathering the d-s of each of the corr models;
       repeatedly used for each dimension */
    double *d = new_vector(howmany);

    /* for each dimension */
    for(unsigned int j=0; j<(2*nin); j++) {

      /* gather all of the d->parameters for the jth dimension
	 from each of the "howmany" corr modules */
      for(unsigned int i=0; i<howmany; i++) 
	d[i] = (((MrExpSep*)(corr[i]))->D())[j];

      /* use those gathered d values to make a draw for the 
	 parameters for the prior of the jth d */
      mixture_priors_draw(d_alpha[j], d_beta[j], d, howmany, 
			  d_alpha_lambda, d_beta_lambda, state);
    }

    /* clean up */
    free(d);
  }
  
  /* hierarchical prior draws for the nugget */
  DrawNug(corr, howmany, state);
}


/*
 * newCorr:
 *
 * construct and return a new separable MrExponential correlation
 * function with this module governing its prior parameterization
 */

Corr* MrExpSep_Prior::newCorr(void)
{
  return new MrExpSep(col, base_prior);
}


/*
 * log_Prior:
 * 
 * compute the (log) prior for the parameters to
 * the correlation function (e.g. d and nug)
 */

double MrExpSep_Prior::log_Prior(double *d, int *b, double *pb, bool linear)
{
  double prob = 0;

  /* if forcing the LLM, just return zero 
     (i.e. prior=1, log_prior=0) */
  if(gamlin[0] < 0) return prob;

  /* sum the log priors for each of the d-parameters */
  for(unsigned int i=0; i<(2*nin); i++)
    prob += log_d_prior_pdf(d[i], d_alpha[i], d_beta[i]);

  /* if not allowing the LLM, then we're done */
  if(gamlin[0] <= 0) return prob;

  /* otherwise, get the prob of each of the booleans */
  double lin_pdf = linear_pdf_sep(pb, d, (2*nin), gamlin);

  /* either use the calculated lin_pdf value */
  if(linear) prob += log(lin_pdf);
  else {
    /* or the sum of the individual pbs */
    for(unsigned int i=0; i<(2*nin); i++) {

      /* probability of linear, or not linear */
      if(b[i] == 0) prob += log(pb[i]);
      else prob += log(1.0 - pb[i]);
    }
  }
  return prob;
}


/*
 * log_Dprior_pdf:
 *
 * return the log prior pdf value for the vector
 * of range parameters d
 */

double MrExpSep_Prior::log_DPrior_pdf(double *d)
{
  double p = 0;
  for(unsigned int i=0; i<(2*nin); i++) {
    p += log_d_prior_pdf(d[i], d_alpha[i], d_beta[i]);
  }
  return p;
}


/*
 * DPrior_rand:
 *
 * draw from the joint prior distribution for the
 * range parameter vector d
 */

void MrExpSep_Prior::DPrior_rand(double *d_new, void *state)
{
  for(unsigned int j=0; j<(2*nin); j++) 
    d_new[j] = d_prior_rand(d_alpha[j], d_beta[j], state);
}

/* 
 * BasePrior:
 *
 * return the prior for the Base (eg Gp) model
 */

Base_Prior* MrExpSep_Prior::BasePrior(void)
{
  return base_prior;
}


/*
 * SetBasePrior:
 *
 * set the base_prior field
 */

void MrExpSep_Prior::SetBasePrior(Base_Prior *base_prior)
{
  this->base_prior = base_prior;
}

/*
 * Print:
 * 
 * pretty print the correllation function parameters out
 * to a file 
 */

void MrExpSep_Prior::Print(FILE *outfile)
{
  myprintf(stdout, "corr prior: separable power\n");

  /* print nugget stuff first */
  PrintNug(outfile);

  /* range parameter */
  /* myprintf(outfile, "starting d=\n");
     printVector(d, (2*nin), outfile); */

  /* range gamma prior, just print once */
  myprintf(outfile, "d[a,b][0]=[%g,%g],[%g,%g]\n",
	   d_alpha[0][0], d_beta[0][0], d_alpha[0][1], d_beta[0][0]);

  /* print many times, one for each ninension instead? */
  /*for(unsigned int i=0; i<(2*nin); i++) {
       myprintf(outfile, "d[a,b][%d]=[%g,%g],[%g,%g]\n", i,
	     d_alpha[i][0], d_beta[i][0], d_alpha[i][1], d_beta[i][0]);
    }*/
 
  /* range gamma hyperprior */
  if(fix_d) myprintf(outfile, "d prior fixed\n");
  else {
    myprintf(stdout, "d lambda[a,b][0,1]=[%g,%g],[%g,%g]\n", 
	     d_alpha_lambda[0], d_beta_lambda[0], d_alpha_lambda[1], 
	     d_beta_lambda[1]);
  }
}


/*
 * log_HierPrior:
 *
 * return the log prior of the hierarchial parameters
 * to the correllation parameters (i.e., range and nugget)
 */

double MrExpSep_Prior::log_HierPrior(void)
{
 double lpdf;
 
 lpdf = 0.0;

  /* mixture prior for the range parameter, d */
  if(!fix_d) {
    for(unsigned int i=0; i<col-1; i++)
      lpdf += mixture_hier_prior_log(d_alpha[i], d_beta[i], 
				     d_alpha_lambda, d_beta_lambda);
  }

  /* mixture prior for the nugget */
  lpdf += log_NugHierPrior();

  return lpdf;
}
back to top