code: def make_gp_funs(cov_func, num_cov_params):
      
  
      def unpack_kernel_params(params):
          mean        = params[0]
          cov_params  = params[2:]
          noise_scale = np.exp(params[1]) + 0.0001
          return mean, cov_params, noise_scale
  
      def predict(params, x, y, xstar):
          """Returns the predictive mean and covariance at locations xstar,
             of the latent function value f (without observation noise)."""
          mean, cov_params, noise_scale = unpack_kernel_params(params)
          cov_f_f = cov_func(cov_params, xstar, xstar)
          cov_y_f = cov_func(cov_params, x, xstar)
          cov_y_y = cov_func(cov_params, x, x) + noise_scale * np.eye(len(y))
          pred_mean = mean +   np.dot(solve(cov_y_y, cov_y_f).T, y - mean)
          pred_cov = cov_f_f - np.dot(solve(cov_y_y, cov_y_f).T, cov_y_f)
          return pred_mean, pred_cov
  
      def log_marginal_likelihood(params, x, y):
          mean, cov_params, noise_scale = unpack_kernel_params(params)
          cov_y_y = cov_func(cov_params, x, x) + noise_scale * np.eye(len(y))
          prior_mean = mean * np.ones(len(y))
          return mvn.logpdf(y, prior_mean, cov_y_y)
  
      return num_cov_params + 2, predict, log_marginal_likelihood
docs: Functions that perform Gaussian process regression.
         cov_func has signature (cov_params, x, x')