'pass objective function values to prepare for next
iteration. This core procedure of the CMA-ES algorithm updates
all state variables, in particular the two evolution paths, the
distribution mean, the covariance matrix and a step-size.
Arguments
`solutions`
list or array of candidate solution points (of
type `numpy.ndarray`), most presumably before
delivered by method `ask()` or `ask_and_eval()`.
`function_values`
list or array of objective function values
corresponding to the respective points. Beside for termination
decisions, only the ranking of values in `function_values`
is used.
`check_points`
If ``check_points is None``, only solutions that are not generated
by `ask()` are possibly clipped (recommended). ``False`` does not clip
any solution (not recommended).
If ``True``, clips solutions that realize long steps (i.e. also
those that are unlikely to be generated with `ask()`). `check_points`
can be a list of indices to be checked in solutions.
`copy`
``solutions`` can be modified in this routine, if ``copy is False``
Details
`tell()` updates the parameters of the multivariate
normal search distribution, namely covariance matrix and
step-size and updates also the attributes `countiter` and
`countevals`. To check the points for consistency is quadratic
in the dimension (like sampling points).
Bugs
The effect of changing the solutions delivered by `ask()` depends on whether
boundary handling is applied. With boundary handling, modifications are
disregarded. This is necessary to apply the default boundary handling that
uses unrepaired solutions but might change in future.
Example
import cma
func = cma.fcts.elli  # choose objective function
es = cma.CMAEvolutionStrategy(cma.np.random.rand(10), 1)
while not es.stop():
X = es.ask()
es.tell(X, [func(x) for x in X])
es.result()  # where the result can be found
:See: class `CMAEvolutionStrategy`, `ask()`, `ask_and_eval()`, `fmin()`'

def tell(self, solutions, function_values, check_points=None, copy=False):

    if self.flgtelldone:
        raise _Error('tell    should    only    be    called    once    per    iteration')
    lam = len(solutions)
    if (lam != array(function_values).shape[0]):
        raise _Error(('for    each    candidate    solution    ' + 'a    function    value    must    be    provided'))
    if ((lam + self.sp.lam_mirr) < 3):
        raise _Error((('population    size    ' + str(lam)) + '    is    too    small    when    option    CMA_mirrors    *    popsize    <    0.5'))
    if (not np.isscalar(function_values[0])):
        if np.isscalar(function_values[0][0]):
            if (self.countiter <= 1):
                print('WARNING:    function    values    are    not    a    list    of    scalars    (further    warnings    are    suppressed)')
            function_values = [val[0] for val in function_values]
        else:
            raise _Error('objective    function    values    must    be    a    list    of    scalars')
    N = self.N
    sp = self.sp
    if ((11 < 3) and (lam != sp.popsize)):
        print('WARNING:    population    size    has    changed,    recomputing    parameters')
        self.sp.set(self.opts, lam)
    if (lam < sp.mu):
        raise _Error('not    enough    solutions    passed    to    function    tell    (mu>lambda)')
    self.countiter += 1
    self.countevals += (sp.popsize * self.evaluations_per_f_value)
    self.best.update(solutions, self.sent_solutions, function_values, self.countevals)
    flgseparable = ((self.opts['CMA_diagonal'] is True) or (self.countiter <= self.opts['CMA_diagonal']))
    if ((not flgseparable) and (len(self.C.shape) == 1)):
        self.B = np.eye(N)
        self.C = np.diag(self.C)
        idx = np.argsort(self.D)
        self.D = self.D[idx]
        self.B = self.B[:, idx]
        self.Zneg = np.zeros((N, N))
    fit = self.fit
    fit.bndpen = self.boundPenalty.update(function_values, self)(solutions, self.sent_solutions, self.gp)
    fit.idx = np.argsort((array(fit.bndpen) + array(function_values)))
    fit.fit = array(function_values, copy=False)[fit.idx]
    self.out['recent_x'] = array(solutions[fit.idx[0]])
    self.out['recent_f'] = fit.fit[0]
    fit.hist.insert(0, fit.fit[0])
    if ((self.countiter % 5) == 0):
        fit.histbest.insert(0, fit.fit[0])
        fit.histmedian.insert(0, (np.median(fit.fit) if (len(fit.fit) < 21) else fit.fit[(self.popsize // 2)]))
    if (len(fit.histbest) > 20000.0):
        fit.histbest.pop()
        fit.histmedian.pop()
    if (len(fit.hist) > (10 + ((30 * N) / sp.popsize))):
        fit.hist.pop()
    if self.opts['CMA_AII']:
        self.aii.tell(solutions, function_values)
        self.flgtelldone = True
        self.mean = self.aii.mean
        self.dC = (self.aii.sigmai ** 2)
        self.sigma = self.aii.sigma
        self.D = (1e-11 + ((self.aii.r ** 2) ** 0.5))
        self.more_to_write += [self.aii.sigma_r]
        return
    pop = []
    for s in solutions:
        if use_sent_solutions:
            x = self.sent_solutions.pop(s, None)
            if (x is not None):
                pop.append(x['geno'])
            else:
                pop.append(self.gp.geno(s, copy=copy))
                if (check_points in (None, True, 1)):
                    self.repair_genotype(pop[(-1)])
        else:
            pop.append(self.gp.geno(s, copy=copy))
            if (check_points in (None, True, 1)):
                self.repair_genotype(pop[(-1)])
    mold = self.mean
    sigma_fac = 1
    if (check_points not in (None, False, 0, [], ())):
        try:
            if len(check_points):
                idx = check_points
        except:
            idx = xrange(sp.popsize)
        for k in idx:
            self.repair_genotype(pop[k])
    if (type(pop) is not array):
        pop = array(pop, copy=False)
    pop = pop[fit.idx]
    if (self.opts['CMA_elitist'] and (self.best.f < fit.fit[0])):
        if (self.best.x_geno is not None):
            xp = [self.best.x_geno]
            self.clip_or_fit_solutions(xp, [0])
            pop = array(([xp[0]] + list(pop)))
        else:
            print('genotype    for    elitist    not    found')
    self.mean = (mold + (self.sp.cmean * (sum((sp.weights * pop[0:sp.mu].T), 1) - mold)))
    if ((11 < 3) and self.opts['vv'] and check_points):
        cmean = (self.sp.cmean / min(1, ((sqrt((self.opts['vv'] * N)) + 2) / ((sqrt(self.sp.mueff) / self.sp.cmean) * self.mahalanobisNorm((self.mean - mold))))))
    else:
        cmean = self.sp.cmean
    if (11 < 3):
        self.more_to_write += [((((sqrt(sp.mueff) * (sum((((1.0 / self.D) * dot(self.B.T, (self.mean - mold))) ** 2)) ** 0.5)) / self.sigma) / sqrt(N)) / cmean)]
    (cc, c1, cmu) = (sp.cc, sp.c1, sp.cmu)
    if flgseparable:
        (cc, c1, cmu) = (sp.cc_sep, sp.c1_sep, sp.cmu_sep)
    self.ps = (((1 - sp.cs) * self.ps) + (((sqrt(((sp.cs * (2 - sp.cs)) * sp.mueff)) / self.sigma) / cmean) * dot(self.B, ((1.0 / self.D) * dot(self.B.T, ((self.mean - mold) / self.sigma_vec))))))
    hsig = (((sum((self.ps ** 2)) / (1 - ((1 - sp.cs) ** (2 * self.countiter)))) / self.N) < (2 + (4.0 / (N + 1))))
    if (11 < 3):
        if (self.countiter == 1):
            print('parameters    modified')
    c1a = (c1 - ((((1 - (hsig ** 2)) * c1) * cc) * (2 - cc)))
    if (11 < 3):
        self.out['hsigcount'] += (1 - hsig)
        if (not hsig):
            self.hsiglist.append(self.countiter)
    if (11 < 3):
        if (not hsig):
            print((str(self.countiter) + ':    hsig-stall'))
    if (11 < 3):
        hsig = 1
        if (self.countiter == 1):
            print('hsig=1')
    self.pc = (((1 - cc) * self.pc) + (((hsig * ((sqrt(((cc * (2 - cc)) * sp.mueff)) / self.sigma) / cmean)) * (self.mean - mold)) / self.sigma_vec))
    if sp.CMA_on:
        assert ((c1 + cmu) <= 1)
        if (not flgseparable):
            Z = ((pop[0:sp.mu] - mold) / (self.sigma * self.sigma_vec))
            Z = dot(((cmu * sp.weights) * Z.T), Z)
            if self.sp.neg.cmuexp:
                tmp = ((pop[(- sp.neg.mu):] - mold) / (self.sigma * self.sigma_vec))
                self.Zneg *= (1 - self.sp.neg.cmuexp)
                self.Zneg += (dot((sp.neg.weights * tmp.T), tmp) - self.C)
            if (11 < 3):
                Z = np.zeros((N, N))
                for k in xrange(sp.mu):
                    z = (pop[k] - mold)
                    Z += np.outer((((cmu * sp.weights[k]) / ((self.sigma * self.sigma_vec) ** 2)) * z), z)
            self.C *= ((1 - c1a) - cmu)
            self.C += (np.outer((c1 * self.pc), self.pc) + Z)
            self.dC = np.diag(self.C)
        else:
            assert ((c1 + cmu) <= 1)
            Z = np.zeros(N)
            for k in xrange(sp.mu):
                z = ((pop[k] - mold) / (self.sigma * self.sigma_vec))
                Z += ((sp.weights[k] * z) * z)
            self.C = (((((1 - c1a) - cmu) * self.C) + ((c1 * self.pc) * self.pc)) + (cmu * Z))
            self.dC = self.C
            self.D = sqrt(self.C)
            self.itereigenupdated = self.countiter
    if ((1 < 3) and np.isfinite(sp.dampsvec)):
        if (self.countiter == 1):
            print('WARNING:    CMA_dampsvec    option    is    experimental')
        sp.dampsvec *= np.exp((sp.dampsvec_fading / self.N))
        self.sigma_vec *= np.exp((((sp.cs / sp.dampsvec) / 2) * ((self.ps ** 2) - 1)))
        self.more_to_write += [exp(np.mean((((self.ps ** 2) - 1) ** 2)))]
    if (1 < 3):
        self.sigma *= (sigma_fac * np.exp(min((1, ((sp.cs / sp.damps) * ((sqrt(sum((self.ps ** 2))) / self.const.chiN) - 1))))))
    else:
        self.sigma *= (sigma_fac * np.exp(min((1000, (((sp.cs / sp.damps) / 2) * ((sum((self.ps ** 2)) / N) - 1))))))
    if (11 < 3):
        lengths = array([(sum((z ** 2)) ** 0.5) for z in self.arz[fit.idx[:self.sp.mu]]])
        self.sigma *= (np.exp(((self.sp.mueff ** 0.5) * dot(self.sp.weights, ((lengths / self.const.chiN) - 1)))) ** (2 / (N + 1)))
    if ((11 < 3) and self.opts['vv']):
        if (self.countiter < 2):
            print('constant    sigma    applied')
            print(self.opts['vv'])
        self.sigma = (((self.opts['vv'] * self.sp.mueff) * (sum((self.mean ** 2)) ** 0.5)) / N)
    if ((self.sigma * (min(self.dC) ** 0.5)) < self.opts['minstd']):
        self.sigma = (self.opts['minstd'] / (min(self.dC) ** 0.5))
    mindx = (eval(self.opts['mindx']) if (type(self.opts['mindx']) == type('')) else self.opts['mindx'])
    if ((self.sigma * min(self.D)) < mindx):
        self.sigma = (mindx / min(self.D))
    if (self.sigma > (1000000000.0 * self.sigma0)):
        alpha = (self.sigma / max(self.D))
        self.multiplyC(alpha)
        self.sigma /= (alpha ** 0.5)
        self.opts['tolupsigma'] /= (alpha ** 0.5)
    if ((11 < 3) and (self.opts['verb_log'] > 0) and ((self.countiter < 4) or ((self.countiter % self.opts['verb_log']) == 0))):
        CMADataLogger(self.opts['verb_filenameprefix']).register(self, append=True).add()
    self.flgtelldone = True
