class_docstr: Class for fitting Gaussian processes. 
class_docstr_tok: ["Class","for","fitting","Gaussian","processes","."]
docstr: Fits a GP according to the tuning criterion. Returns the best GP along with the
  hyper-parameters. 
docstr_tok: ["Fits","a","GP","according","to","the","tuning","criterion",".","Returns","the","best","GP","along","with","the","hyper-parameters","."]
code: def fit_gp(self, num_samples=1, hp_tune_criterion=None):
      """Fits a GP according to the tuning criterion. Returns the best GP along with the
      hyper-parameters."""
      if hp_tune_criterion is None:
          hp_tune_criterion = self.options.hp_tune_criterion
      if hp_tune_criterion == "ml":
          if self.ml_hp_tune_opt_method in ["direct", "rand", "pdoo"]:
              best_cts_hps = None
              best_dscr_hps = None
              best_other_params = None
              best_hps_val = -np.inf
              for dscr_hps in itertools_product(*self.dscr_hp_vals):
                  (
                      opt_cts_val,
                      opt_cts_hps,
                      opt_other_params,
                  ) = self._optimise_cts_hps_for_given_dscr_hps(
                      dscr_hps
                  )
                  if opt_cts_val > best_hps_val:
                      best_cts_hps = list(opt_cts_hps)
                      best_dscr_hps = list(dscr_hps)
                      best_other_params = opt_other_params
                      best_hps_val = opt_cts_val
              opt_gp = self.build_gp(
                  best_cts_hps,
                  best_dscr_hps,
                  other_gp_params=best_other_params,
              )
              opt_hps = (best_cts_hps, best_dscr_hps)
              return "fitted_gp", opt_gp, opt_hps
          elif self.ml_hp_tune_opt_method == "rand_exp_sampling":
              (
                  sample_cts_hps,
                  sample_dscr_hps,
                  sample_other_gp_params,
                  sample_probs,
              ) = self._sample_cts_dscr_hps_for_rand_exp_sampling()
              return (
                  "sample_hps_with_probs",
                  sample_cts_hps,
                  sample_dscr_hps,
                  sample_other_gp_params,
                  sample_probs,
              )
      elif hp_tune_criterion == "post_sampling":
          (
              sample_cts_hps,
              sample_dscr_hps,
              sample_other_gp_params,
          ) = self._sample_cts_dscr_hps_for_post_sampling(num_samples)
          if num_samples == 1:
              opt_gp = self.build_gp(
                  sample_cts_hps[0],
                  sample_dscr_hps[0],
                  other_gp_params=sample_other_gp_params[0],
              )
              opt_hps = (sample_cts_hps, sample_dscr_hps)
              return "post_fitted_gp", opt_gp, opt_hps
          else:
              return (
                  "post_sample_hps_with_probs",
                  sample_cts_hps,
                  sample_dscr_hps,
                  sample_other_gp_params,
              )
  
imports: from __future__ import division
  from argparse import Namespace
  from itertools import product
  import sys
  import numpy
  from ..distributions.model import Model
  from ..distributions import continuous
  from ..distributions import discrete
  from ..utils.general_utils import stable_cholesky, draw_gaussian_samples, project_symmetric_to_psd_cone, solve_lower_triangular, solve_upper_triangular
  from ..utils.oper_utils import direct_ft_maximise, pdoo_maximise, random_maximise, random_sample_cts_dscr
  from ..utils.option_handler import get_option_specs, load_options
  from ..utils.reporters import get_reporter
label_desc: Use image node_id 20 for calling the GPFitter obj's underlying member method code with example usage: obj.fit_gp(num_samples, hp_tune_criterion) and returns: str,  opt_gp,  opt_hps, str,  sample_cts_hps,  sample_dscr_hps,  sample_other_gp_params,  sample_probs, str,  opt_gp,  opt_hps, str,  sample_cts_hps,  sample_dscr_hps,  sample_other_gp_params