void StudentTProcessNIG::precomputePrediction()
  {
    size_t n = mData.getNSamples();
    size_t p = mMean.nFeatures();

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

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

    mVf = mData.mY - prod(trans(mMean.mFeatM),mWMap);
    inplace_solve(mL,mVf,ublas::lower_tag());

    vectord v0 = mData.mY - prod(trans(mMean.mFeatM),mW0);
    //TODO: check for "cheaper" version
    //matrixd KK = prod(mL,trans(mL));
    matrixd KK = computeCorrMatrix();
    matrixd WW = zmatrixd(p,p);  //TODO: diagonal matrix
    utils::add_to_diagonal(WW,mInvVarW);
    const matrixd FW = prod(trans(mMean.mFeatM),WW);
    KK += prod(FW,mMean.mFeatM);
    matrixd BB(n,n);
    utils::cholesky_decompose(KK,BB);
    inplace_solve(BB,v0,ublas::lower_tag());
    mSigma = (mBeta/mAlpha + inner_prod(v0,v0))/(n+2*mAlpha);
    
    int dof = static_cast<int>(n+2*mAlpha);
    
    if ((boost::math::isnan(mWMap(0))) || (boost::math::isnan(mSigma)))
      {
	throw std::runtime_error("Error in precomputed prediction. NaN found.");
      }


    if (dof <= 0)  
      {
	dof = n;
	FILE_LOG(logERROR) << "ERROR: Incorrect alpha. Dof invalid."
			   << "Forcing Dof <= num of points.";
      }

    d_->setDof(dof);  
  }
  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;
  }
  double StudentTProcessNIG::negativeLogLikelihood()
  {
    matrixd KK = computeCorrMatrix();
    const size_t n = KK.size1();
    const size_t p = mMean.nFeatures();
    const size_t nalpha = (n+2*mAlpha);

    vectord v0 = mData.mY - prod(trans(mMean.mFeatM),mW0);
    matrixd WW = zmatrixd(p,p);  //TODO: diagonal matrix
    utils::add_to_diagonal(WW,mInvVarW);
    matrixd FW = prod(trans(mMean.mFeatM),WW);
    KK += prod(FW,mMean.mFeatM);
    matrixd BB(n,n);
    utils::cholesky_decompose(KK,BB);
    inplace_solve(BB,v0,ublas::lower_tag());
    double zz = inner_prod(v0,v0);
    double sigmaMap = (mBeta/mAlpha + zz)/nalpha;

    double lik = nalpha/2 * std::log(1+zz/(2*mBeta*sigmaMap));
    lik += utils::log_trace(BB);
    lik += n/2 * std::log(sigmaMap);
    return lik;
  }