docs: def update_exponential(self, Z, eta, BDpair=None):
          """exponential update of C that guarantees positive definiteness, that is,
          instead of the assignment ``C = C + eta * Z``,
          we have ``C = C**.5 * exp(eta * C**-.5 * Z * C**-.5) * C**.5``.
  
          Parameter `Z` should have expectation zero, e.g. sum(w[i] * z[i] * z[i].T) - C
          if E z z.T = C.
  
          Parameter `eta` is the learning rate, for ``eta == 0`` nothing is updated.
  
          This function conducts two eigendecompositions, assuming that
          B and D are not up to date, unless `BDpair` is given. Given BDpair,
          B is the eigensystem and D is the vector of sqrt(eigenvalues), one
          eigendecomposition is omitted.
  
          Reference: Glasmachers et al 2010, Exponential Natural Evolution Strategies
  
          """
          if eta == 0:
              return
          if BDpair:
              B, D = BDpair
          else:
              D, B = self.opts['CMA_eigenmethod'](self.C)
              self.count_eigen += 1
              D **= 0.5
          Cs = dot(B, (B * D).T)   # square root of C
          Csi = dot(B, (B / D).T)  # square root of inverse of C
          self.C = dot(Cs, dot(Mh.expms(eta * dot(Csi, dot(Z, Csi)),
                                        self.opts['CMA_eigenmethod']), Cs))
          self.count_eigen += 1