code: def grad_optimize_ei(self, cand, comp, pend, vals, compute_grad=True):
      if pend.shape[0] == 0:
          best = np.min(vals)
          cand = np.reshape(cand, (-1, comp.shape[1]))
  
          # The primary covariances for prediction.
          comp_cov = self.cov(comp)
          cand_cross = self.cov(comp, cand)
  
          # Compute the required Cholesky.
          obsv_cov = comp_cov + self.noise * np.eye(comp.shape[0])
          obsv_chol = spla.cholesky(obsv_cov, lower=True)
  
          cov_grad_func = getattr(gp, "grad_" + self.cov_func.__name__)
          cand_cross_grad = cov_grad_func(self.ls, comp, cand)
  
          # Predictive things.
          # Solve the linear systems.
          alpha = spla.cho_solve((obsv_chol, True), vals - self.mean)
          beta = spla.solve_triangular(
              obsv_chol, cand_cross, lower=True
          )
  
          # Predict the marginal means and variances at candidates.
          func_m = np.dot(cand_cross.T, alpha) + self.mean
          func_v = self.amp2 * (1 + 1e-6) - np.sum(beta**2, axis=0)
  
          # Expected improvement
          func_s = np.sqrt(func_v)
          u = (best - func_m) / func_s
          ncdf = sps.norm.cdf(u)
          npdf = sps.norm.pdf(u)
          ei = func_s * (u * ncdf + npdf)
  
          if not compute_grad:
              return ei
  
          # Gradients of ei w.r.t. mean and variance
          g_ei_m = -ncdf
          g_ei_s2 = 0.5 * npdf / func_s
  
          # Apply covariance function
          grad_cross = np.squeeze(cand_cross_grad)
  
          grad_xp_m = np.dot(alpha.transpose(), grad_cross)
          grad_xp_v = np.dot(
              -2
              * spla.cho_solve(
                  (obsv_chol, True), cand_cross
              ).transpose(),
              grad_cross,
          )
  
          grad_xp = (
              0.5
              * self.amp2
              * (grad_xp_m * g_ei_m + grad_xp_v * g_ei_s2)
          )
          ei = -np.sum(ei)
  
          return ei, grad_xp.flatten()
  
      else:
          # If there are pending experiments, fantasize their outcomes.
          cand = np.reshape(cand, (-1, comp.shape[1]))
  
          # Create a composite vector of complete and pending.
          comp_pend = np.concatenate((comp, pend))
  
          # Compute the covariance and Cholesky decomposition.
          comp_pend_cov = self.cov(comp_pend) + self.noise * np.eye(
              comp_pend.shape[0]
          )
          comp_pend_chol = spla.cholesky(comp_pend_cov, lower=True)
  
          # Compute submatrices.
          pend_cross = self.cov(comp, pend)
          pend_kappa = self.cov(pend)
  
          # Use the sub-Cholesky.
          obsv_chol = comp_pend_chol[: comp.shape[0], : comp.shape[0]]
  
          # Solve the linear systems.
          alpha = spla.cho_solve((obsv_chol, True), vals - self.mean)
          beta = spla.cho_solve((obsv_chol, True), pend_cross)
  
          # Finding predictive means and variances.
          pend_m = np.dot(pend_cross.T, alpha) + self.mean
          pend_K = pend_kappa - np.dot(pend_cross.T, beta)
  
          # Take the Cholesky of the predictive covariance.
          pend_chol = spla.cholesky(pend_K, lower=True)
  
          # Make predictions.
          npr.set_state(self.randomstate)
          pend_fant = (
              np.dot(
                  pend_chol,
                  npr.randn(pend.shape[0], self.pending_samples),
              )
              + pend_m[:, None]
          )
  
          # Include the fantasies.
          fant_vals = np.concatenate(
              (
                  np.tile(
                      vals[:, np.newaxis], (1, self.pending_samples)
                  ),
                  pend_fant,
              )
          )
  
          # Compute bests over the fantasies.
          bests = np.min(fant_vals, axis=0)
  
          # Now generalize from these fantasies.
          cand_cross = self.cov(comp_pend, cand)
          cov_grad_func = getattr(gp, "grad_" + self.cov_func.__name__)
          cand_cross_grad = cov_grad_func(self.ls, comp_pend, cand)
  
          # Solve the linear systems.
          alpha = spla.cho_solve(
              (comp_pend_chol, True), fant_vals - self.mean
          )
          beta = spla.solve_triangular(
              comp_pend_chol, cand_cross, lower=True
          )
  
          # Predict the marginal means and variances at candidates.
          func_m = np.dot(cand_cross.T, alpha) + self.mean
          func_v = self.amp2 * (1 + 1e-6) - np.sum(beta**2, axis=0)
  
          # Expected improvement
          func_s = np.sqrt(func_v[:, np.newaxis])
          u = (bests[np.newaxis, :] - func_m) / func_s
          ncdf = sps.norm.cdf(u)
          npdf = sps.norm.pdf(u)
          ei = func_s * (u * ncdf + npdf)
  
          # Gradients of ei w.r.t. mean and variance
          g_ei_m = -ncdf
          g_ei_s2 = 0.5 * npdf / func_s
  
          # Apply covariance function
          # Squeeze can break the 1D case be careful
          if pend.shape[1] == 1:
              grad_cross = np.squeeze(cand_cross_grad, axis=(2,))
          else:
              grad_cross = np.squeeze(cand_cross_grad)
  
          grad_xp_m = np.dot(alpha.transpose(), grad_cross)
          grad_xp_v = np.dot(
              -2
              * spla.cho_solve(
                  (comp_pend_chol, True), cand_cross
              ).transpose(),
              grad_cross,
          )
  
          grad_xp = (
              0.5
              * self.amp2
              * (
                  grad_xp_m * np.tile(g_ei_m, (comp.shape[1], 1)).T
                  + (grad_xp_v.T * g_ei_s2).T
              )
          )
          ei = -np.mean(ei, axis=1)
          grad_xp = np.mean(grad_xp, axis=0)
  
          return ei, grad_xp.flatten()
  
imports: import os
  from ..None import gp
  import sys
  from ..None import util
  import tempfile
  import pickle
  import copy
  import numpy
  import numpy.random
  import scipy.linalg
  import scipy.stats
  import scipy.optimize
  import multiprocessing
  from ..helpers import *
  from ..Locker import *
  import logging
label_desc: Use image node_id 11 for calling the GPEIOptChooser obj's underlying member method code with example usage: obj.grad_optimize_ei(cand, comp, pend, vals, compute_grad) and returns: ei,  grad_xp, ei,  grad_xp, ei