/** 
* @file GPRegressionOptimizationProblem.h
* @author Erik Rodner
* @date 12/09/2009

*/
#ifndef _NICE_OBJREC_GPREGRESSIONOPTIMIZATIONPROBLEMINCLUDE
#define _NICE_OBJREC_GPREGRESSIONOPTIMIZATIONPROBLEMINCLUDE

#include "core/vector/VVector.h"
#include "vislearning/math/kernels/ParameterizedKernel.h"
#include "core/optimization/gradientBased/OptimizationProblemFirst.h"

#include "vislearning/math/kernels/KernelData.h"

#include "vislearning/math/kernels/TraceApproximation.h"

#include "modelselcrit/GPMSCLooEstimates.h"

namespace OBJREC {
  
/** @class GPRegressionOptimizationProblem
 * Hyperparameter Optimization Problem for GP Regression 
 *
 * @author Erik Rodner
 */
class GPRegressionOptimizationProblem : public NICE::OptimizationProblemFirst
{

    protected:
		KernelData *kernelData;
		
		NICE::VVector y;

		double bestAvgLooError;
		NICE::Vector bestLooParameters;
		
		ParameterizedKernel *kernel;

		bool verbose;

		/** An !additional! model selection criterion (e.g. loo), which is used
 		 * to select parameters from the set of parameters generated during optimization.
		 * We restrict ourselves to loo-based model selection criterions because
		 * they are easy to compute with matrices and vectors precomputed by
		 * this optimization anyway (inverse kernel matrix, cholesky decomp, etc.)
		 * Recommendation: give it a try! */
		const GPMSCLooLikelihoodRegression *modelselcrit;


		/** Use this method to set the stochastic trace approximation method,
		 *  this method is highly instable, but you can try to skip the trace term
		 *  by setting numTraceSamples to zero, which assumes a constant volume kernel matrix. 
		 *  Recommendation: you shouldn't use this option, unless you like a kind of random search
		 *  for hyper-parameters. */
		const TraceApproximation *traceApproximation;
		
		
    public:
  
  	
     	GPRegressionOptimizationProblem ( KernelData *kernelData, const NICE::Vector & y, 
			ParameterizedKernel *kernel, bool verbose = false, 
			const GPMSCLooLikelihoodRegression *modelselcrit = NULL, 
			const TraceApproximation *traceApproximation = NULL );

		GPRegressionOptimizationProblem ( KernelData *kernelData, const NICE::VVector & y, 
			ParameterizedKernel *kernel, bool verbose = false, 
			const GPMSCLooLikelihoodRegression *modelselcrit = NULL,
			const TraceApproximation *traceApproximation = NULL );

		double computeObjective();

		void computeGradient( NICE::Vector& newGradient );

		void setParameters ( const NICE::Vector & newParameters ) { parameters() = newParameters; };

		void useLooParameters ();
		
		void update();
};

}

#endif