code: def optimize_hypers(self, comp, vals):
      self.mean = np.mean(vals)
      diffs = vals - self.mean
  
      state = {}
  
      def jitter_chol(covmat):
          passed = False
          jitter = 1e-8
          val = 0
          while not passed:
              if jitter > 100000:
                  val = spla.cholesky(np.eye(covmat.shape[0]))
                  break
              try:
                  val = spla.cholesky(
                      covmat + jitter * np.eye(covmat.shape[0]),
                      lower=True,
                  )
                  passed = True
              except ValueError:
                  jitter = jitter * 1.1
                  print(
                      "Covariance matrix not PSD, adding jitter:",
                      jitter,
                  )
                  passed = False
          return val
  
      def memoize(amp2, noise, ls):
          if (
              "corr" not in state
              or state["amp2"] != amp2
              or state["noise"] != noise
              or np.any(state["ls"] != ls)
          ):
              # Get the correlation matrix
              (corr, grad_corr) = self.cov_func(
                  ls, comp, None, grad=True
              )
  
              # Scale and add noise & jitter.
              covmat = amp2 * (
                  corr + 1e-6 * np.eye(comp.shape[0])
              ) + noise * np.eye(comp.shape[0])
  
              # Memoize
              state["corr"] = corr
              state["grad_corr"] = grad_corr
              state["chol"] = jitter_chol(covmat)
              state["amp2"] = amp2
              state["noise"] = noise
              state["ls"] = ls
  
          return (state["chol"], state["corr"], state["grad_corr"])
  
      def nlogprob(hypers):
          amp2 = np.exp(hypers[0])
          noise = np.exp(hypers[1])
          ls = np.exp(hypers[2:])
  
          chol = memoize(amp2, noise, ls)[0]
          solve = spla.cho_solve((chol, True), diffs)
          lp = -np.sum(np.log(np.diag(chol))) - 0.5 * np.dot(
              diffs, solve
          )
          return -lp
  
      def grad_nlogprob(hypers):
          amp2 = np.exp(hypers[0])
          noise = np.exp(hypers[1])
          ls = np.exp(hypers[2:])
  
          chol, corr, grad_corr = memoize(amp2, noise, ls)
          solve = spla.cho_solve((chol, True), diffs)
          inv_cov = spla.cho_solve((chol, True), np.eye(chol.shape[0]))
  
          jacobian = np.outer(solve, solve) - inv_cov
  
          grad = np.zeros(self.D + 2)
  
          # Log amplitude gradient.
          grad[0] = (
              0.5
              * np.trace(
                  np.dot(jacobian, corr + 1e-6 * np.eye(chol.shape[0]))
              )
              * amp2
          )
  
          # Log noise gradient.
          grad[1] = (
              0.5
              * np.trace(np.dot(jacobian, np.eye(chol.shape[0])))
              * noise
          )
  
          # Log length scale gradients.
          for dd in range(self.D):
              grad[dd + 2] = (
                  1
                  * np.trace(
                      np.dot(
                          jacobian,
                          -amp2
                          * grad_corr[:, :, dd]
                          * comp[:, dd][:, np.newaxis]
                          / (np.exp(ls[dd])),
                      )
                  )
                  * np.exp(ls[dd])
              )
  
          # Roll in the prior variance.
          # grad -= 2*hypers/self.hyper_prior
  
          return -grad
  
      # Initial length scales.
      self.ls = np.ones(self.D)
      # Initial amplitude.
      self.amp2 = np.std(vals)
      # Initial observation noise.
      self.noise = 1e-3
  
      hypers = np.zeros(self.ls.shape[0] + 2)
      hypers[0] = np.log(self.amp2)
      hypers[1] = np.log(self.noise)
      hypers[2:] = np.log(self.ls)
  
      # Use a bounded bfgs just to prevent the length-scales and noise from
      # getting into regions that are numerically unstable
      b = [(-10, 10), (-10, 10)]
      for i in range(comp.shape[1]):
          b.append((-10, 5))
  
      hypers = spo.fmin_l_bfgs_b(
          nlogprob, hypers, grad_nlogprob, args=(), bounds=b, disp=0
      )
  
      # hypers = spo.fmin_bfgs(nlogprob, hypers, grad_nlogprob, maxiter=100)
      hypers = hypers[0]
      # hypers = spo.fmin_bfgs(nlogprob, hypers, grad_nlogprob, maxiter=100)
  
      self.amp2 = np.exp(hypers[0])
      self.noise = np.exp(hypers[1])
      self.ls = np.exp(hypers[2:])
  
file_path: auptimizer/src/aup/Proposer/spearmint/gp.py
imports: import numpy
  import scipy.linalg
  import scipy.optimize
  import scipy.io
label_desc: Use image node_id 5 for calling the GP obj's underlying member method code with example usage: obj.optimize_hypers(comp, vals) and returns: val, state,  state,  state, unknown, unknown