BayesOpt / src / gaussian_process_normal.cpp

/*
-------------------------------------------------------------------------
   This file is part of BayesOpt, an efficient C++ library for 
   Bayesian optimization.

   Copyright (C) 2011-2013 Ruben Martinez-Cantin <rmcantin@unizar.es>
 
   BayesOpt is free software: you can redistribute it and/or modify it 
   under the terms of the GNU General Public License as published by
   the Free Software Foundation, either version 3 of the License, or
   (at your option) any later version.

   BayesOpt 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 General Public License for more details.

   You should have received a copy of the GNU General Public License
   along with BayesOpt.  If not, see <http://www.gnu.org/licenses/>.
------------------------------------------------------------------------
*/

#include <cstdlib>
#include <boost/math/special_functions/fpclassify.hpp>
#include <boost/numeric/ublas/banded.hpp>
#include "log.hpp"
#include "cholesky.hpp"
#include "trace_ublas.hpp"
#include "elementwise_ublas.hpp"
#include "gauss_distribution.hpp"
#include "gaussian_process_normal.hpp"

namespace bayesopt
{

  namespace ublas = boost::numeric::ublas; 
  
  GaussianProcessNormal::GaussianProcessNormal(size_t dim, 
					 bopt_params params):
    HierarchicalGaussianProcess(dim,params),
    mSigma(params.sigma_s), 
    mW0(params.mean.n_coef), mInvVarW(params.mean.n_coef), 
    mD(params.mean.n_coef,params.mean.n_coef)
  {  
    mW0 = utils::array2vector(params.mean.coef_mean,params.mean.n_coef);
    for (size_t ii = 0; ii < params.mean.n_coef; ++ii)
      {
	double varii = params.mean.coef_std[ii] * params.mean.coef_std[ii];
	mInvVarW(ii) = 1/varii;
      }
     d_ = new GaussianDistribution();
  }  // Constructor



  GaussianProcessNormal::~GaussianProcessNormal()
  {
    delete d_;
  } // Default destructor


  ProbabilityDistribution* 
  GaussianProcessNormal::prediction(const vectord &query)
  {
    double kq = (*mKernel)(query, query);;
    vectord kn = computeCrossCorrelation(query);
    vectord phi = mMean->getFeatures(query);
  
    vectord v(kn);
    inplace_solve(mL,v,ublas::lower_tag());

    vectord rq = phi - prod(v,mKF);

    vectord rho(rq);
    inplace_solve(mD,rho,ublas::lower_tag());
    
    double yPred = inner_prod(phi,mWMap) + inner_prod(v,mVf);
    double sPred = sqrt( mSigma * (kq - inner_prod(v,v) 
			        + inner_prod(rho,rho)));

    if ((boost::math::isnan(yPred)) || (boost::math::isnan(sPred)))
      {
	FILE_LOG(logERROR) << "Error in prediction. NaN found.";
	exit(EXIT_FAILURE);
      }
					

    d_->setMeanAndStd(yPred,sPred);
    return d_;
  }


  double GaussianProcessNormal::negativeLogLikelihood()
  {
    matrixd KK = computeCorrMatrix();
    const size_t n = KK.size1();
    const size_t p = mMean->nFeatures();
  
    vectord v0 = mGPY - prod(trans(mFeatM),mW0);
    matrixd WW = zmatrixd(p,p);  //TODO: diagonal matrix
    utils::addToDiagonal(WW,mInvVarW);
    matrixd FW = prod(trans(mFeatM),WW);
    KK += prod(FW,mFeatM);
    matrixd BB(n,n);
    utils::cholesky_decompose(KK,BB);
    inplace_solve(BB,v0,ublas::lower_tag());
    double zz = inner_prod(v0,v0);

    double lik = 1/(2*mSigma) * zz;
    lik += utils::log_trace(BB);
    return lik;
  }



  int GaussianProcessNormal::precomputePrediction()
  {
    size_t n = mGPXX.size();
    size_t p = mMean->nFeatures();

    mKF = trans(mFeatM);
    inplace_solve(mL,mKF,ublas::lower_tag());
    //TODO: make one line
    matrixd DD(p,p);
    DD = prod(trans(mKF),mKF);
    utils::addToDiagonal(DD,mInvVarW);
    utils::cholesky_decompose(DD,mD);

    vectord vn = mGPY;
    inplace_solve(mL,vn,ublas::lower_tag());
    mWMap = prod(mFeatM,vn) + utils::ublas_elementwise_prod(mInvVarW,mW0);
    utils::cholesky_solve(mD,mWMap,ublas::lower());

    mVf = mGPY - prod(trans(mFeatM),mWMap);
    inplace_solve(mL,mVf,ublas::lower_tag());

    if (boost::math::isnan(mWMap(0)))
      {
	FILE_LOG(logERROR) << "Error in precomputed prediction. NaN found.";
	return -1;
      }
    return 0;
  }

} //namespace bayesopt
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.