docs: def update(self, function_values, es):
          """updates the weights for computing a boundary penalty.
  
          Arguments
          ---------
          `function_values`
              all function values of recent population of solutions
          `es`
              `CMAEvolutionStrategy` object instance, in particular
              mean and variances and the methods from the attribute
              `gp` of type `GenoPheno` are used.
  
          """
          if self.bounds is None or (self.bounds[0] is None and
                                     self.bounds[1] is None):
              return self
  
          N = es.N
          # ## prepare
          # compute varis = sigma**2 * C_ii
          varis = es.sigma**2 * array(N * [es.C] if isscalar(es.C) else (# scalar case
                                  es.C if isscalar(es.C[0]) else  # diagonal matrix case
                                  [es.C[i][i] for i in xrange(N)]))  # full matrix case
  
          # relative violation in geno-space
          dmean = (es.mean - es.gp.geno(self.repair(es.gp.pheno(es.mean)))) / varis**0.5
  
          # ## Store/update a history of delta fitness value
          fvals = sorted(function_values)
          l = 1 + len(fvals)
          val = fvals[3 * l // 4] - fvals[l // 4]  # exact interquartile range apart interpolation
          val = val / np.mean(varis)  # new: val is normalized with sigma of the same iteration
          # insert val in history
          if isfinite(val) and val > 0:
              self.hist.insert(0, val)
          elif val == inf and len(self.hist) > 1:
              self.hist.insert(0, max(self.hist))
          else:
              pass  # ignore 0 or nan values
          if len(self.hist) > 20 + (3 * N) / es.popsize:
              self.hist.pop()
  
          # ## prepare
          dfit = np.median(self.hist)  # median interquartile range
          damp = min(1, es.sp.mueff / 10. / N)
  
          # ## set/update weights
          # Throw initialization error
          if len(self.hist) == 0:
              raise _Error('wrongful initialization, no feasible solution sampled. ' +
                  'Reasons can be mistakenly set bounds (lower bound not smaller than upper bound) or a too large initial sigma0 or... ' +
                  'See description of argument func in help(cma.fmin) or an example handling infeasible solutions in help(cma.CMAEvolutionStrategy). ')
          # initialize weights
          if dmean.any() and (not self.weights_initialized or es.countiter == 2):  # TODO
              self.gamma = array(N * [2 * dfit])  ## BUGBUGzzzz: N should be phenotypic (bounds are in phenotype), but is genotypic
              self.weights_initialized = True
          # update weights gamma
          if self.weights_initialized:
              edist = array(abs(dmean) - 3 * max(1, N**0.5 / es.sp.mueff))
              if 1 < 3:  # this is better, around a factor of two
                  # increase single weights possibly with a faster rate than they can decrease
                  #     value unit of edst is std dev, 3==random walk of 9 steps
                  self.gamma *= exp((edist > 0) * np.tanh(edist / 3) / 2.)**damp
                  # decrease all weights up to the same level to avoid single extremely small weights
                  #    use a constant factor for pseudo-keeping invariance
                  self.gamma[self.gamma > 5 * dfit] *= exp(-1. / 3)**damp
                  #     self.gamma[idx] *= exp(5*dfit/self.gamma[idx] - 1)**(damp/3)
          es.more_to_write += list(self.gamma) if self.weights_initialized else N * [1.0]
          # ## return penalty
          # es.more_to_write = self.gamma if not isscalar(self.gamma) else N*[1]
          return self