1 #include "GaussianProcess.hpp"
2 #include "math.h"
3 #include <iostream>
4 #include <iomanip>
5 #include <cassert>
6 #include <boost/random.hpp>
7 
8 //--------------------------------------------------------------------------------
GaussianProcess(int n,double & delta_input,BlackBoxBaseClass * blackbox_input)9 GaussianProcess::GaussianProcess ( int n, double &delta_input, BlackBoxBaseClass* blackbox_input) :
10   TriangularMatrixOperations ( n ),
11   dim( n )
12 {
13   lb.reserve( n+1 );
14   ub.reserve( n+1 );
15   gp_parameters.reserve(n+1);
16   for (int i = 0; i < n+1; i++) {
17     lb.push_back( 0e0  );
18     ub.push_back( 10e0 );
19     gp_parameters.push_back( 1e0 );
20   }
21   nb_gp_nodes = 0;
22   gp_pointer = NULL;
23   delta = &delta_input;
24   blackbox = blackbox_input;
25 }
26 //--------------------------------------------------------------------------------
27 
28 //--------------------------------------------------------------------------------
GaussianProcess(int n,double & delta_input,BlackBoxBaseClass * blackbox_input,std::vector<double> gp_parameters_input)29 GaussianProcess::GaussianProcess ( int n, double &delta_input, BlackBoxBaseClass* blackbox_input, std::vector<double> gp_parameters_input ) :
30   TriangularMatrixOperations ( n ),
31   dim( n )
32 {
33   if(gp_parameters_input.size() != n+1){
34     std::cout << "gp_parameters_input wrong size! Should be: " << n+1 << ", is: " << gp_parameters_input.size() << std::endl;
35     exit(-1);
36   }
37 
38   lb.reserve( n+1 );
39   ub.reserve( n+1 );
40   gp_parameters.reserve(n+1);
41   for (int i = 0; i < n+1; i++) {
42     lb.push_back( 0e0  );
43     ub.push_back( 10e0 );
44     gp_parameters.push_back( gp_parameters_input[i] );
45   }
46   nb_gp_nodes = 0;
47   gp_pointer = NULL;
48   delta = &delta_input;
49   blackbox = blackbox_input;
50 }
51 //--------------------------------------------------------------------------------
52 
53 
54 //--------------------------------------------------------------------------------
evaluate_kernel(std::vector<double> const & x,std::vector<double> const & y)55 double GaussianProcess::evaluate_kernel ( std::vector<double> const &x,
56                                           std::vector<double> const &y )
57 {
58   return evaluate_kernel ( x, y, gp_parameters );
59 /*
60   dist = 0e0;
61   for ( int i = 0; i < dim; ++i )
62     dist += pow( (x.at(i) - y.at(i)), 2e0) /  gp_parameters.at( i+1 );
63   kernel_evaluation = exp(-dist / 2e0 );
64 
65   return kernel_evaluation * gp_parameters.at( 0 ) ;
66 */
67 }
68 //--------------------------------------------------------------------------------
69 //--------------------------------------------------------------------------------
evaluate_kernel(std::vector<double> const & x,std::vector<double> const & y,std::vector<double> const & p)70 double GaussianProcess::evaluate_kernel ( std::vector<double> const &x,
71                                           std::vector<double> const &y,
72                                           std::vector<double> const &p )
73 {
74   dist = 0e0;
75   for ( int i = 0; i < dim; ++i )
76     dist += pow( (x.at(i) - y.at(i)), 2e0) /  p.at( i+1 );
77   kernel_evaluation = exp(-dist / 2e0 );
78 
79   return kernel_evaluation * p.at( 0 ) ;
80 }
81 //--------------------------------------------------------------------------------
82 
83 //--------------------------------------------------------------------------------
d_evaluate_kernel(std::vector<double> const & x,std::vector<double> const & y,std::vector<double> const & p,int j)84 double GaussianProcess::d_evaluate_kernel ( std::vector<double> const &x,
85                                             std::vector<double> const &y,
86                                             std::vector<double> const &p, int j )
87 {
88   dist = 0e0;
89   for ( int i = 0; i < dim; ++i )
90     dist += pow( (x.at(i) - y.at(i)), 2e0) /  p.at(i+1);
91   kernel_evaluation = exp(-dist / 2e0 );
92   if ( j == 0 ) {
93     return kernel_evaluation;
94   } else {
95     kernel_evaluation *= 2e0*pow( (x.at(j-1) - y.at(j-1)), 2e0) / pow( p.at(j-1), 2e0);
96     return kernel_evaluation * p.at(0) ;
97   }
98 
99 }
100 //--------------------------------------------------------------------------------
101 
test_for_parameter_estimation(const int & nb_values,const int & update_interval_length,const int & next_update,const std::vector<int> & update_at_evaluations)102 bool GaussianProcess::test_for_parameter_estimation(const int& nb_values,
103                                                 const int& update_interval_length,
104                                                 const int& next_update,
105                                                 const std::vector<int>& update_at_evaluations){
106   bool do_parameter_estimation = false;
107 
108   if ( nb_values >= next_update && update_interval_length > 0 ) {
109     do_parameter_estimation = true;
110     return do_parameter_estimation;
111   }
112   if ( update_at_evaluations.size( ) > 0 ) {
113     if ( nb_values >= update_at_evaluations[0] ) {
114       do_parameter_estimation = true;
115     }
116   }
117 
118   return do_parameter_estimation;
119 }
120 
121 
122 //--------------------------------------------------------------------------------
build(std::vector<std::vector<double>> const & nodes,std::vector<double> const & values,std::vector<double> const & noise)123 void GaussianProcess::build ( std::vector< std::vector<double> > const &nodes,
124                               std::vector<double> const &values,
125                               std::vector<double> const &noise )
126 {
127     //std::cout << "GP build [" << nodes.size() << "]" << std::endl;
128     //std::cout << "With Parameters: " << std::endl;
129     //for ( int i = 0; i < dim+1; ++i )
130     // std::cout << "gp_param = " << gp_parameters[i] << std::endl;
131     //std::cout << std::endl;
132 
133     nb_gp_nodes = nodes.size();
134     gp_nodes.clear();
135     //gp_noise.clear();
136     for ( int i = 0; i < nb_gp_nodes; ++i ) {
137       gp_nodes.push_back ( nodes.at(i) );
138       //gp_noise.push_back( noise.at(i) );
139     }
140 
141 //    auto minmax = std::minmax_element(values.begin(), values.end());
142 //    min_function_value = values.at((minmax.first - values.begin()));
143 //    max_function_value = values.at((minmax.second - values.begin()));
144 
145 //    std::cout << "[ " << min_function_value << ", " << max_function_value << " ]" << std::endl;
146 
147     L.clear();
148     L.resize( nb_gp_nodes );
149 
150     for (int i = 0; i < nb_gp_nodes; i++) {
151       for (int j = 0; j <= i; j++){
152         L.at(i).push_back (evaluate_kernel( gp_nodes[i], gp_nodes[j] ) );
153       }
154       L.at(i).at(i) += pow( noise.at(i) / 2e0 + noise_regularization, 2e0 );
155     }
156 
157     /*
158     for (int i = 0; i < nb_gp_nodes; i++) {
159       for (int j = 0; j <=i; j++){
160         std::cout << std::setprecision(16) << L[i][j] << ' ';
161       }
162       for (int j = i+1; j < nb_gp_nodes; j++){
163         std::cout << std::setprecision(16) << L[j][i] << ' ';
164       }
165 
166       std::cout << ';' << std::endl;
167     }
168     */
169 
170     CholeskyFactorization::compute( L, pos, rho, nb_gp_nodes );
171     assert( pos == 0 );
172 
173     scaled_function_values.resize(nb_gp_nodes);
174     for (int i = 0; i < nb_gp_nodes; i++) {
175       scaled_function_values.at(i) = values.at(i);
176 //      scaled_function_values.at(i) = values.at(i) - min_function_value;
177 //      scaled_function_values.at(i) /= 5e-1*( max_function_value-min_function_value );
178 //      scaled_function_values.at(i) -= 1e0;
179     }
180 
181     alpha = scaled_function_values;
182     forward_substitution( L, alpha );
183     backward_substitution( L, alpha );
184 
185     return;
186 }
187 //--------------------------------------------------------------------------------
188 
189 //--------------------------------------------------------------------------------
update(std::vector<double> const & x,double & value,double & noise)190 void GaussianProcess::update ( std::vector<double> const &x,
191                                double &value,
192                                double &noise )
193 {
194   //std::cout << "GP update [" << nb_gp_nodes+1 << "]" << std::endl;
195   K0.resize( nb_gp_nodes );
196   nb_gp_nodes += 1;
197   gp_nodes.push_back( x );
198   //gp_noise.push_back( noise );
199   scaled_function_values.push_back ( value );
200 //  scaled_function_values.push_back ( ( value -  min_function_value ) /
201 //                                     ( 5e-1*( max_function_value-min_function_value ) ) - 1e0 );
202 
203   for (int i = 0; i < nb_gp_nodes-1; i++)
204     K0.at(i) = evaluate_kernel( gp_nodes[i], x );
205 
206   forward_substitution( L, K0 );
207 
208   L.push_back ( K0 );
209 
210   L.at(L.size()-1).push_back(
211     sqrt( evaluate_kernel( x, x ) + pow( noise / 2e0 + noise_regularization, 2e0 ) -
212           VectorOperations::dot_product(K0, K0) ) );
213 
214   alpha = scaled_function_values;
215   forward_substitution( L, alpha );
216   backward_substitution( L, alpha );
217 
218   return;
219 }
220 //--------------------------------------------------------------------------------
221 
222 //--------------------------------------------------------------------------------
evaluate(std::vector<double> const & x,double & mean,double & variance)223 void GaussianProcess::evaluate ( std::vector<double> const &x,
224                                  double &mean, double &variance )
225 {
226   K0.resize( nb_gp_nodes );
227 
228   for (int i = 0; i < nb_gp_nodes; i++)
229     K0.at(i) = evaluate_kernel( gp_nodes[i], x );
230 
231   mean = VectorOperations::dot_product(K0, alpha);
232 //  mean = VectorOperations::dot_product(K0, alpha) + 1e0;
233 //  mean *= 5e-1*( max_function_value-min_function_value );
234 //  mean += min_function_value;
235 
236   forward_substitution( L, K0 );
237 
238   variance = evaluate_kernel( x, x ) - VectorOperations::dot_product(K0, K0);
239 
240   //std::cout << "GP evalute [" << gp_nodes.size() <<"] mean,variance " << mean << ", " << variance << std::endl;
241   return;
242 }
243 //--------------------------------------------------------------------------------
244 
245 //--------------------------------------------------------------------------------
evaluate(std::vector<double> const & x,double & mean)246 void GaussianProcess::evaluate ( std::vector<double> const &x,
247                                  double &mean)
248 {
249   K0.resize( nb_gp_nodes );
250 
251   for (int i = 0; i < nb_gp_nodes; i++)
252     K0.at(i) = evaluate_kernel( gp_nodes[i], x );
253 
254   mean = VectorOperations::dot_product(K0, alpha);
255 //  mean = VectorOperations::dot_product(K0, alpha) + 1e0;
256 //  mean *= 5e-1*( max_function_value-min_function_value );
257 //  mean += min_function_value;
258 
259   //std::cout << "GP evalute [" << gp_nodes.size() <<"] mean,variance " << mean << ", " << variance << std::endl;
260   return;
261 }
262 //--------------------------------------------------------------------------------
263 
264 //--------------------------------------------------------------------------------
evaluate(std::vector<double> const & x,std::vector<double> const & f_train,double & mean)265 void GaussianProcess::evaluate ( std::vector<double> const &x,
266                                  std::vector<double> const &f_train,
267                                  double &mean)
268 {
269   assert(f_train.size() == nb_gp_nodes);
270 
271   K0.resize( nb_gp_nodes );
272 
273   for (int i = 0; i < nb_gp_nodes; i++)
274     K0.at(i) = evaluate_kernel( gp_nodes[i], x );
275 
276   std::vector<double> local_f_train;
277   local_f_train.resize(nb_gp_nodes);
278   for (int i = 0; i < nb_gp_nodes; i++) {
279     local_f_train[i] = f_train[i];
280   }
281 
282   forward_substitution( L, local_f_train );
283   backward_substitution( L, local_f_train );
284 
285   mean = VectorOperations::dot_product(K0, local_f_train);
286 
287   return;
288 }
289 //--------------------------------------------------------------------------------
290 
291 
292 //--------------------------------------------------------------------------------
build_inverse()293 void GaussianProcess::build_inverse ()
294 {
295   L_inverse.resize(nb_gp_nodes);
296   for (int i = 0; i < nb_gp_nodes; i++){
297     L_inverse[i].resize(nb_gp_nodes);
298     for (int j = 0; j < nb_gp_nodes; j++){
299       if(i==j)
300         L_inverse[i][j] = 1;
301       else
302         L_inverse[i][j] = 0;
303     }
304   }
305   for (int i = 0; i < nb_gp_nodes; i++){
306     forward_substitution( L, L_inverse[i]);
307   }
308   for (int i = 0; i < nb_gp_nodes; i++){
309     backward_substitution( L, L_inverse[i]);
310   }
311   return;
312 }
313 //--------------------------------------------------------------------------------
314 
315 //--------------------------------------------------------------------------------
compute_var_meanGP(std::vector<double> const & xstar,std::vector<double> const & noise)316 double GaussianProcess::compute_var_meanGP ( std::vector<double>const& xstar, std::vector<double> const& noise)
317 {
318   std::vector<double> k_xstar_X(nb_gp_nodes);
319   std::vector<double> k_xstar_X_Kinv(nb_gp_nodes);
320   std::vector<double> k_xstar_X_Kinv_squared(nb_gp_nodes);
321   std::vector<double> gp_noise_squared(nb_gp_nodes);
322   double var_meanGP = 0;
323 
324   for(int i = 0; i < nb_gp_nodes; ++i){
325     k_xstar_X[i] = evaluate_kernel(xstar, gp_nodes[i]);
326   }
327 
328   VectorOperations::vec_mat_product(L_inverse, k_xstar_X, k_xstar_X_Kinv);
329 
330   for(int i = 0; i < nb_gp_nodes; ++i){
331     k_xstar_X_Kinv_squared[i] = k_xstar_X_Kinv[i]*k_xstar_X_Kinv[i];
332     gp_noise_squared[i] = noise[i]*noise[i];
333   }
334 
335   var_meanGP = VectorOperations::dot_product(k_xstar_X_Kinv_squared, gp_noise_squared);
336 
337   return var_meanGP;
338 }
339 //--------------------------------------------------------------------------------
340 
341 
342 //--------------------------------------------------------------------------------
compute_cov_meanGPMC(std::vector<double> const & xstar,int const & xstar_idx,double const & noise)343 double GaussianProcess::compute_cov_meanGPMC ( std::vector<double>const& xstar, int const& xstar_idx, double const& noise)
344 {
345   //std::vector<double> k_xstar_X(nb_gp_nodes);
346   double cov_meanGPMC = 0.;
347   double cov_term = 0.;
348   double L_inverse_term = 0.;
349   double kernel_term = 0.;
350   //std::cout << "Cov terms (idx, kernel, KK_inv, Prod): " << std::endl;
351   assert(xstar_idx < nb_gp_nodes);
352   for(int i = 0; i < nb_gp_nodes; ++i){
353     //k_xstar_X[i] = evaluate_kernel(xstar, gp_nodes[i]);
354     L_inverse_term = L_inverse[i][xstar_idx];
355     kernel_term = evaluate_kernel(xstar, gp_nodes[i]);
356     cov_term = kernel_term*L_inverse_term;
357     cov_meanGPMC += cov_term;
358     //std::cout << "(" << xstar_idx << ", "<< kernel_term << ", " << L_inverse_term << ", " << cov_term << ")" << std::endl;
359   }
360   cov_meanGPMC *= noise*noise;
361   return cov_meanGPMC;
362 }
363 //--------------------------------------------------------------------------------
364 
365 //--------------------------------------------------------------------------------
bootstrap_diffGPMC(std::vector<double> const & xstar,std::vector<std::vector<double>> const & samples,const unsigned int index,int max_bootstrap_samples,int inp_seed)366 double GaussianProcess::bootstrap_diffGPMC ( std::vector<double>const& xstar, std::vector<std::vector<double>>const& samples, const unsigned int index, int max_bootstrap_samples, int inp_seed)
367 {
368   double mean_xstar = 0.0;
369   double mean_bootstrap = 0.0;
370   double mean_bootstrap_eval = 0.0;
371   double bootstrap_estimate = 0.0;
372   int random_idx = -1;
373   std::vector<double> f_train_bootstrap(nb_gp_nodes);
374   std::vector<double> k_xstar_X_Kinv(nb_gp_nodes);
375   std::vector<double> k_xstar_X(nb_gp_nodes);
376   unsigned int nb_samples = samples[0].size();
377   std::vector<double> bootstrap_samples;
378   boost::random::uniform_int_distribution<> distr(0, nb_samples - 1);
379 
380   std::random_device rd; // obtain a random number from hardware
381   if(inp_seed == -1) {
382     inp_seed = rd();
383   }
384   //std::mt19937_64 bootstrap_eng(inp_seed);
385   boost::random::mt19937 bootstrap_eng(inp_seed);
386 
387   for(int i = 0; i < nb_gp_nodes; ++i){
388     k_xstar_X[i] = evaluate_kernel(xstar, gp_nodes[i]);
389   }
390 
391   vec_mat_product(L_inverse, k_xstar_X, k_xstar_X_Kinv); //k_xstar_X (K_XX - sigma^2 I)^{-1}
392   assert(samples.size() == nb_gp_nodes);
393 
394   bootstrap_samples.resize(nb_samples);
395   //#pragma omp parallel for private(bootstrap_samples, eng) reduction(+ : mean_bootstrap)
396   for(int i = 0; i < max_bootstrap_samples; ++i){
397     for(int j = 0; j < nb_gp_nodes; ++j){ //sample randomly from training data
398       for(int k = 0; k < nb_samples; ++k){
399         bootstrap_samples[k] = samples[j][distr(bootstrap_eng)];
400       }
401       f_train_bootstrap[j] = blackbox->evaluate_samples(bootstrap_samples, index, xstar);
402     }
403     mean_bootstrap += dot_product(k_xstar_X_Kinv, f_train_bootstrap); // k_xstar_X (K_XX - sigma^2 I)^{-1} f_train_bootstrap
404   }
405   mean_bootstrap /= max_bootstrap_samples;
406   evaluate(xstar, mean_xstar);
407   bootstrap_estimate = mean_bootstrap - mean_xstar;
408 
409   return bootstrap_estimate;
410 }
411 //--------------------------------------------------------------------------------
412 
413 //--------------------------------------------------------------------------------
estimate_hyper_parameters(std::vector<std::vector<double>> const & nodes,std::vector<double> const & values,std::vector<double> const & noise)414 void GaussianProcess::estimate_hyper_parameters ( std::vector< std::vector<double> > const &nodes,
415                                                   std::vector<double> const &values,
416                                                   std::vector<double> const &noise )
417 {
418   //std::cout << "GP Estimator" << std::endl;
419   nb_gp_nodes = nodes.size();
420   gp_nodes.clear();
421   gp_noise.clear();
422   for ( int i = 0; i < nb_gp_nodes; ++i ) {
423     gp_nodes.push_back ( nodes.at(i) );
424     gp_noise.push_back ( noise.at(i) );
425   }
426 
427   gp_pointer = this;
428 
429 //  auto minmax = std::minmax_element(values.begin(), values.end());
430 //  min_function_value = values.at((minmax.first - values.begin()));
431 //  max_function_value = values.at((minmax.second - values.begin()));
432   /*
433   auto minmax = std::minmax_element(values.begin(), values.end());
434   min_function_value = values.at((minmax.first - values.begin()));
435   max_function_value = fabs(values.at((minmax.second - values.begin())));
436   if ( fabs(min_function_value) > max_function_value )
437     max_function_value = fabs( min_function_value );
438   */
439   L.clear();
440   L.resize( nb_gp_nodes );
441   for ( int i = 0; i < nb_gp_nodes; ++i)
442     L.at(i).resize( i+1 );
443 
444   scaled_function_values.resize(nb_gp_nodes);
445   for ( int i = 0; i < nb_gp_nodes; ++i) {
446     scaled_function_values.at(i) = values.at(i);
447 //    scaled_function_values.at(i) = values.at(i) - min_function_value;
448 //    scaled_function_values.at(i) /= 5e-1*( max_function_value-min_function_value );
449 //    scaled_function_values.at(i) -= 1e0;
450   }
451 
452   double optval;
453   //adjust those settings to optimize GP approximation
454   //--------------------------------------------------
455 //  double max_noise = 0e0;
456 //  for (int i = 0; i < nb_gp_nodes; i++) {
457 //    if (gp_noise.at( i ) > max_noise)
458 //      max_noise = gp_noise.at( i );
459 //  }
460 
461   //My Version
462   /*lb[0] = 1e-3;
463       ub[0] = 1e3;
464       lb[0] = max_function_value - 1e2;
465       if ( lb[0] < 1e-3 ) lb[0] = 1e-3;
466       ub[0] = max_function_value + 1e2;
467       if ( ub[0] > 1e3 ) ub[0] = 1e3;
468       if ( ub[0] <= lb[0]) lb[0] = 1e-3;
469   double delta_threshold = *delta;
470   if (delta_threshold < 1e-2) delta_threshold = 1e-2;
471   for (int i = 0; i < dim; ++i) {
472       lb[i+1] = 1e-2 * delta_threshold; // 1e1
473       ub[i+1] = 2.0 * delta_threshold; // 1e2
474   }*/
475 
476 
477   //Florians old version1:
478   /*lb[0] = 1e-1;
479   ub[0] = 1e1;
480   lb[0] = max_function_value - 1e2;
481   if ( lb[0] < 1e-2 ) lb[0] = 1e-2;
482   ub[0] = max_function_value + 1e2;
483   double delta_threshold = *delta;
484   if (delta_threshold < 1e-2) delta_threshold = 1e-2;
485   for (int i = 0; i < dim; ++i) {
486       lb[i+1] = 1e-2 * delta_threshold; // 1e1
487       ub[i+1] = 2.0 * delta_threshold; // 1e2
488   }*/
489   //Florians old version2:
490   lb[0] = 1e-1; // * pow(1000e0 * max_noise / 2e0, 2e0);
491   ub[0] = 1e1;// * pow(1000e0 * max_noise / 2e0, 2e0);
492   double delta_threshold = *delta;
493   if (delta_threshold < 1e-2) delta_threshold = 1e-2;
494   for (int i = 0; i < dim; ++i) {
495       lb[i+1] = 1e1 * delta_threshold;
496       ub[i+1] = 1e2 * delta_threshold;
497   }
498 
499   if (gp_parameters[0] < 0e0) {
500     //gp_parameters[0] = max_function_value;
501     gp_parameters[0] = lb[0]*5e-1 + 5e-1*ub[0];
502     for (int i = 1; i < dim+1; ++i) {
503       gp_parameters[i] = (lb[i]*5e-1 + 5e-1*ub[i]);
504     }
505   } else {
506     for (int i = 0; i < dim+1; ++i) {
507       if ( gp_parameters[i] <= lb[i] ) gp_parameters[i] = 1.1 * lb[i];
508       if ( gp_parameters[i] >= ub[i] ) gp_parameters[i] = 0.9 * ub[i];
509     }
510   }
511   //--------------------------------------------------
512 
513   //initialize optimizer from NLopt library
514   int dimp1 = dim+1;
515 //  nlopt::opt opt(nlopt::LD_CCSAQ, dimp1);
516 //  nlopt::opt opt(nlopt::LN_BOBYQA, dimp1);
517 //
518   //nlopt::opt opt(nlopt::GN_DIRECT, dimp1); //Somehow GN_DIRECT is not deterministic, also nlopt::srand(seed) has no effect to fix that.
519   nlopt::opt opt(nlopt::LN_COBYLA, dimp1);
520 
521   //opt = nlopt_create(NLOPT_LN_COBYLA, dim+1);
522   opt.set_lower_bounds( lb );
523   opt.set_upper_bounds( ub );
524 
525   opt.set_max_objective( GaussianProcess::parameter_estimation_objective, gp_pointer);
526 
527  // opt.set_xtol_abs(1e-2);
528 //  opt.set_xtol_rel(1e-2);
529 //set timeout to NLOPT_TIMEOUT seconds
530   opt.set_maxtime(1.0);
531   //opt.set_maxeval(10000);
532   //perform optimization to get correction factors
533 
534   int exitflag=-20;
535   try {
536     nlopt::srand(1);
537     exitflag = opt.optimize(gp_parameters, optval);
538   } catch (...) {
539     gp_parameters[0] = lb[0]*5e-1 + 5e-1*ub[0];
540     for (int i = 1; i < dim+1; ++i) {
541       gp_parameters[i] = (lb[i]*5e-1 + 5e-1*ub[i]);
542     }
543   }
544 
545   //std::cout << "exitflag = "<< exitflag<<std::endl;
546   //std::cout << "OPTVAL .... " << optval << std::endl;
547   //for ( int i = 0; i < gp_parameters.size(); ++i )
548   //  std::cout << "gp_param = " << gp_parameters[i] << std::endl;
549   //std::cout << std::endl;
550 
551 
552   return;
553 }
554 //--------------------------------------------------------------------------------
estimate_hyper_parameters_induced_only(std::vector<std::vector<double>> const & nodes,std::vector<double> const & values,std::vector<double> const & noise)555 void GaussianProcess::estimate_hyper_parameters_induced_only ( std::vector< std::vector<double> > const &nodes,
556                                                   std::vector<double> const &values,
557                                                   std::vector<double> const &noise )
558 { this->estimate_hyper_parameters(nodes, values, noise);}
559 
estimate_hyper_parameters_ls_only(std::vector<std::vector<double>> const & nodes,std::vector<double> const & values,std::vector<double> const & noise)560 void GaussianProcess::estimate_hyper_parameters_ls_only ( std::vector< std::vector<double> > const &nodes,
561                                                   std::vector<double> const &values,
562                                                   std::vector<double> const &noise )
563 { this->estimate_hyper_parameters(nodes, values, noise);}
564 
565 //--------------------------------------------------------------------------------
parameter_estimation_objective(std::vector<double> const & x,std::vector<double> & grad,void * data)566 double GaussianProcess::parameter_estimation_objective(std::vector<double> const &x,
567                                                        std::vector<double> &grad,
568                                                        void *data)
569 {
570 
571   GaussianProcess *d = reinterpret_cast<GaussianProcess*>(data);
572 
573 
574 
575   for (int i = 0; i < d->nb_gp_nodes; ++i) {
576     for (int j = 0; j <= i; ++j)
577       d->L.at(i).at(j) = d->evaluate_kernel( d->gp_nodes[i], d->gp_nodes[j], x );
578     d->L.at(i).at(i) += pow( d->gp_noise.at(i) / 2e0 + d->noise_regularization, 2e0 );
579   }
580 
581 
582   d->CholeskyFactorization::compute( d->L, d->pos, d->rho, d->nb_gp_nodes );
583   //assert(d->pos == 0);
584   double result = 0;
585   if(d->pos == 0){ //result stays 0 if L is not spd
586     d->alpha = d->scaled_function_values;
587     d->forward_substitution( d->L, d->alpha );
588     d->backward_substitution( d->L, d->alpha );
589     result = -0.5*d->VectorOperations::dot_product(d->scaled_function_values, d->alpha) +
590                     -0.5*((double)d->nb_gp_nodes)*log( 2. * M_PI );
591     for (int i = 0; i < d->nb_gp_nodes; ++i)
592       result -= 0.5*log(d->L.at(i).at(i));
593   }
594 
595 
596 /*
597   //Eigen::ColPivHouseholderQR<Eigen::MatrixXd> S;
598   d->S = (d->L).fullPivHouseholderQr();
599   //d->S = (d->L).colPivHouseholderQr();
600   d->K0 = (d->S).solve(d->scaled_function_values);
601 
602 
603   double result = -0.5*(d->scaled_function_values).dot(d->K0) -
604                   0.5*log((d->S).absDeterminant() + 1e-16) -
605                   0.5*((double)d->nb_gp_nodes)*log(6.28);
606 
607 
608   if ( !grad.empty() ) {
609     for (int k = 0; k < d->dim+1; ++k) {
610       for (int i = 0; i < d->nb_gp_nodes; i++) {
611         for (int j = 0; j <= i; j++) {
612           d->dK(i, j) = d->d_evaluate_kernel( d->gp_nodes[i], d->gp_nodes[j], x, k);
613           if (i != j) d->dK(j, i) = d->dK(i, j);
614         }
615       }
616       grad[k] = 0.5*((d->K0*(d->K0.transpose()))*d->dK - d->S.solve(d->dK)).trace() -
617                 0.5*((double)d->nb_gp_nodes)*0e-6;
618     }
619   }
620 */
621   return result;
622 
623 }
624 
getGp_nodes() const625 const std::vector<std::vector<double>> &GaussianProcess::getGp_nodes() const {
626     return gp_nodes;
627 }
628 
get_induced_nodes(std::vector<std::vector<double>> &) const629 void GaussianProcess::get_induced_nodes(std::vector<std::vector<double> > &) const {
630     return;
631 }
632 
get_hyperparameters()633 std::vector<double> GaussianProcess::get_hyperparameters(){
634     return this->gp_parameters;
635 }
decrease_nugget()636 void GaussianProcess::decrease_nugget(){
637   return;
638 }
increase_nugget()639 bool GaussianProcess::increase_nugget(){
640   return true;
641 }
642 
get_gp_parameters() const643 const std::vector<double> &GaussianProcess::get_gp_parameters() const {
644   return gp_parameters;
645 }
646 //--------------------------------------------------------------------------------
647