
    J-je                     f   d Z ddlmZmZmZ ddlZddlZddlZddlZ	ddl
mZ ddlmZ ddlmZ ddlmZ [[[d d	Zd!d
Zd"dZ G d de      Z G d de      Z G d de      Z G d de      Z G d de      Z G d de      Z G d de      Z G d de      Z G d de      Z  G d de      Z!y)#zDUtility classes and functionalities loosely related to optimization
    )absolute_importdivisionprint_functionN)Pool   )
BlancClass)math)rangec                    ddl m} |M| || }} nF	 ddlm} |j	                         j                         j                  d   }|dd|f   |ddd
df   }} t        j                  |d      }|dvr	 ||z  }nddk  r	 |rt        j                  |      n\t        t        j                  t        j                   t        j                  t        j"                  ||dk7                                   }
t        j"                  |      d|
z  k  }|d|
z  k\  }|d|
z   k  }t        j                  ||         |
z
  ||<   t        j                  ||          |
z
   ||<   d||<   | t        d|j                  d   dz         } d|v r}|j%                  d      }t'        t        j(                  |      j*                        D ].  \  }	} |j,                  | |fd|	t        |      k  r||	   ndi| 0 |j/                  d       n* |j,                  | |fi | d|v r|j/                  d       |j1                         }g g }}|j3                         D ]b  }d||
z   z  }|dk  r
d| |
z   z  }n
|dk(  rd|
z  }d|v r/|d   dk(  r|dd |dd z   }|d   dk(  r|d   dk(  r|dd |dd z   }||gz  }||gz  }d |j5                  |       |j7                  |       |j9                  d       y#  t        j                  dd	      }Y xY w#  t        |j                  d         D 	cg c]  }	||	t        |      k  r|	nd    nc c}	w }}	||z  }Y xY w)a  signed semilogy plot.

    ``plt.yscale('symlog', linthreshy=min(abs(data[data != 0])))`` should
    do the same job as least as good.

    `y` (or `x` if `y` is `None`) is a data array, by default read from
    `outcmaesxmean.dat` or (first) from the default logger output file
    like::

        xy = cma.logger.CMADataLogger().load().data['xmean']
        x, y = xy[:, iabscissa], xy[:, 5:]
        semilogy_signed(x, y)

    Plotted is `y - yoffset` vs `x` for positive values as a semilogy plot
    and for negative values as a semilogy plot of absolute values with
    inverted axis.

    `minabsy` controls the minimum shown value away from zero, which can
    be useful if extremely small non-zero values occur in the data.

    r   pyplotNr   )loggerxmeanzoutcmaesxmean.dat)%)comments   T)copyNr         
   labelslabel皙?)
framealphaz$10^{%.2f}$z$-10^{%.2f}$z$\pm10^{%.2f}$.0)
matplotlibr    r   CMADataLoggerloaddatanploadtxtarrayr
   shapelenlog10intfloorminabspop	enumerateasarrayTplotlegendgca
get_yticks
set_yticksset_yticklabelsgrid)xyyoffsetminabsy	iabscissakwargspltr   xyimin_log	idx_zerosidx_posidx_negkwargs_labelsyiaxticksr   valss                        d/Users/jameslopez/projects/TradingBot25/.venv/lib/python3.12/site-packages/cma/optimization_tools.pysemilogy_signedrO      s^   . )y=aqAF$))+00277@ al#R12YqA
Ai	LA 
a#*bhhw"((266"((266!AqD'?";<=>  q	BK'I2w;GBK<G!G*%/AgJ88QwZK(723AgJAiLy!QWWQZ!^$6

8,rzz!}/EArCHHQaa#m:L6L-"2RVaZ`a 0

c
"A  fJJ#J& 
B6E}}g.7 cTG^4AAX"g-A!8B%3,crFQrsVO B%3,u|crFQrsVO1##  MM%vHHTNiFZZ 3fE	GLQWWUVZGXYGX!wAG$4q"=GXYGYLAs#   1K' 2L 'LM"L?>Mc           	      .   ||}t        j                  ||      \  }}|j                         }t        t	        |            D ]M  }t        t	        |d               D ]1  } | t        j
                  ||   |   ||   |   g            ||   |<   3 O |||fS )a  generate x,y,z-data for contour plot.

    `fct` is a 2-D function.
    `x`- and `y_range` are `iterable` (e.g. `list` or arrays)
    to define the meshgrid.

    CAVEAT: this function calls `fct` ``len(list(x_range)) * len(list(y_range))``
    times. Hence using `Sections` may be the better first choice to
    investigate an expensive function.

    Examples:

    >>> from cma import optimization_tools
    >>> import numpy as np
    ...
    >>> def plt_contour():  # def avoids doctest execution
    ...     from matplotlib import pyplot as plt
    ...
    ...     X, Y, Z = optimization_tools.contour_data(
    ...                   lambda x: sum([xi**2 for xi in x]),
    ...                   np.arange(0.90, 1.10, 0.02),
    ...                   np.arange(-0.10, 0.10, 0.02))
    ...     CS = plt.contour(X, Y, Z)
    ...     plt.gca().set_aspect('equal')
    ...     plt.clabel(CS)
    >>> def plt_surface():  # def avoids doctest execution
    ...     from matplotlib import pyplot as plt
    ...     from mpl_toolkits import mplot3d
    ...
    ...     X, Y, Z = optimization_tools.contour_data(
    ...                   lambda x: sum([xi**2 for xi in x]),
    ...                   np.arange(-1, 1.1, 0.02))
    ...     ax = plt.axes(projection='3d')
    ...     ax.plot_surface(X, Y, Z, cmap='viridis', edgecolor='none')

    See `cma.fitness_transformations.FixVariables` to create a 2-D
    function from a d-D function, e.g. like

    >>> import cma
    ...
    >>> fd = cma.ff.elli
    >>> x0 = np.zeros(22)
    >>> indices_to_vary = [2, 4]
    >>> f2 = cma.fitness_transformations.FixVariables(fd,
    ...          dict((i, x0[i]) for i in range(len(x0))
    ...                          if i not in indices_to_vary))
    >>> isinstance(f2, cma.fitness_transformations.FixVariables)
    True
    >>> isinstance(f2, cma.fitness_transformations.ComposedFunction)
    True
    >>> f2[0] is fd, len(f2) == 2
    (True, True)

    r   )r&   meshgridr   r
   r*   r2   )fctx_rangey_rangeXYZrC   js           rN   contour_datarY   e   s    n ;;w(DAq	A3q6]s1Q4y!A"**ad1gqtAw%789AaDG "  a7N    c                    t        j                  t        |             }t        j                  ddt	        |      dz   d      }|rxt        j
                  ||t        j                  dgt        j                  |      g      z  z
  ||||t        j                  t        j                  |      dgg      z  z   g      }nt        j
                  ||g      }|j                  |j                  d      }|rDt        j
                  |dd d|z
  |dd z  ||dd z  z   ||dd z  d|z
  |dd z  z   |dd g      }nt        j
                  |dd |dd g      }|j                  |j                  d      }||fS )	z\return x, y ECDF data for ECDF plot. Smoothing may look strange
    in a semilogx plot.
    r   r   T)endpointF)orderNr   )
r&   r2   sortedlinspacer*   r(   hstackdiffreshapesize)r%   smooth_cornersr;   r<   s       rN   	step_datarf      sq   
 	

6$< A
Aq#a&1*t4AHHa.299qc2771:5F+GGGABGGAJ;L1M MMO P HHaV			!&&	$AHHafq>1QsV;nqQRQSu>TT$q"v-^1Cqu0LLaPQPReU V !CR&!AB%)A			!&&	$Aa4KrZ   c                   8    e Zd ZdZd	dZd
dZd Zd Zd Zd Z	y)EvalParallel2a  A class and context manager for parallel evaluations.

    This class is based on the ``Pool`` class of the `multiprocessing` module.

    The interface in v2 changed, such that the fitness function can be
    given once in the constructor. Hence the number of processes has
    become the second (optional) argument of `__init__` and the function
    has become the second and optional argument of `__call__`.

    To be used with the `with` statement (otherwise `terminate` needs to
    be called to free resources)::

        with EvalParallel2(fitness_function) as eval_all:
            fvals = eval_all(solutions)

    assigns a callable `EvalParallel2` class instance to ``eval_all``.
    The instance can be called with a `list` (or `tuple` or any
    sequence) of solutions and returns their fitness values. That is::

        eval_all(solutions) == [fitness_function(x) for x in solutions]

    `EvalParallel2.__call__` may take three additional optional arguments,
    namely `fitness_function` (like this the function may change from call
    to call), `args` passed to ``fitness`` and `timeout` passed to the
    `multiprocessing.pool.ApplyResult.get` method which raises
    `multiprocessing.TimeoutError` in case.

    ``eval_all = EvalParallel2(fitness_function, 0)`` bypasses
    `multiprocessing`, hence the construct can be used even when
    `multiprocessing` fails on this `fitness_function` instantiation.

    Examples:

    >>> from cma.optimization_tools import EvalParallel2
    >>> for n_jobs in [None, -1, 0, 1, 2, 4]:
    ...     with EvalParallel2(cma.fitness_functions.elli, n_jobs) as eval_all:
    ...         res = eval_all([[1,2], [3,4]])
    >>> # class usage, don't forget to call terminate
    >>> ep = EvalParallel2(cma.fitness_functions.elli, 4)
    >>> [float(v) for v in ep([[1,2], [3,4], [4, 5]])]  # doctest:+ELLIPSIS
    [4000000.944...
    >>> ep.terminate()
    ...
    >>> # use with `with` statement (context manager)
    >>> es = cma.CMAEvolutionStrategy(3 * [1], 1, dict(verbose=-9))
    >>> with EvalParallel2(cma.fitness_functions.elli,
    ...                    number_of_processes=12) as eval_all:
    ...     while not es.stop():
    ...         X = es.ask()
    ...         es.tell(X, eval_all(X, args=(1e1,)))  # `eval_all` also accepts
    ...                                               # `fitness_function` as
    ...                                               # (optional) keyword argument
    >>> assert es.result[1] < 1e-13 and es.result[2] < 1500

    Parameters: the `EvalParallel2` constructor takes the number of
    processes as optional input argument, which is by default
    ``multiprocessing.cpu_count()``. If ``number_of_processes <= 0``, no
    `multiprocessing` is invoked and the fitness is computed directly in a
    regular loop.

    Limitations: the `multiprocessing` module, on which this class is based
    upon, may not work with certain class instance methods or Cython
    instances, or class instances that contain modules as it uses `pickle`.

    Details: in some cases the execution may be considerably slowed down,
    as for example in previous tests done with test suites from coco/bbob.

    Comparing setting ``number_of_processes = 0`` with
    ``number_of_processes = 1`` evaluates the overhead introduced by
    ``multiprocessing.Pool.apply_async``.
Nc                     || _         || _        | j                  | j                  dkD  rt        | j                        | _        y d | _        y r   )fitness_function	processesProcessingPoolpool)selfrj   number_of_processess      rN   __init__zEvalParallel2.__init__  s=     0,>>!T^^a%7&t~~6DIDIrZ   c                 8   |xs | j                   }|t        d      | j                  s|D cg c]  } ||g|  c}S d}t        j                  d   dk(  r4t        |t        | j                              rt        j                  |       |D cg c]"  }| j                  j                  ||f|z         $ }}	 |D cg c]  }|j                  |       c}S c c}w c c}w c c}w #  t        j                  d   dk(  xr t        j                  |        xY w)a  evaluate a list/sequence of solution-"vectors", return a list
        of corresponding f-values.

        `args` must be a tuple and is passed to `fitness_function` like
        ``fitness_function(solutions[0], *args)``. For example, a single
        argument, say `a1`, should be passed like ``args=(a1, )``.

        Raises `multiprocessing.TimeoutError` if `timeout` is given and
        exceeded.
        zN`fitness_function` was never given, must be passed in `__init__` or `__call__`z`fitness_function` must be a function, not a `lambda` or an instancemethod, in order to work with `multiprocessing` under Python 2r      )rj   
ValueErrorrm   sysversion_info
isinstancetyperp   warningswarnapply_asyncget)	rn   	solutionsrj   argstimeoutr;   warning_strjobsjobs	            rN   __call__zEvalParallel2.__call__  s*    ,Dt/D/D# C D Dyy8AB	1$Q..	BB; A!#*D,?@k*"$"A 		%%&6tD" 	 $	045CGGG$55 C$ 6	Q1$C{)Cs)   C'C;C) ?C$C) $C) )0Dc                     | j                   sy| j                   j                          | j                   j                          y)zfree allocated processing poolN)rm   	terminatejoinrn   s    rN   r   zEvalParallel2.terminate,  s*    yy				rZ   c                     | S N r   s    rN   	__enter__zEvalParallel2.__enter__4  s	     rZ   c                 $    | j                          y r   r   )rn   exc_type	exc_value	tracebacks       rN   __exit__zEvalParallel2.__exit__9  s    rZ   c                 $    | j                          y)z<though generally not recommended `__del__` should be OK hereNr   r   s    rN   __del__zEvalParallel2.__del__<  s    rZ   )NN)Nr   N)
__name__
__module____qualname____doc__rp   r   r   r   r   r   r   rZ   rN   rh   rh      s'    FN>
rZ   rh   c                   @    e Zd ZdZdej
                  dfdZddZd Zy)BestSolutionzlcontainer to keep track of the best solution seen.

    Keeps also track of the genotype, if available.
    Nc                    || _         d| _        ||t        j                  ur|nt        j
                  | _        || _        || _        d| _	        	 t               | _        || j                  _         || j                  _        y)z|initialize the best solution with ``x``, ``f``, and ``evals``.

        Better solutions have smaller ``f``-values.
        Nr   )r;   x_genor&   nanr	   inffevalsevalsallcompared_BlancClasslast)rn   r;   r   r   s       rN   rp   zBestSolution.__init__E  sd    
 mTXX
=M					rZ   c                    t        |t              r| j                  |j                  | _        n2|j                  &t        | j                  |j                  f      | _        |j                  Q|j                  t
        j                  k  r4| j                  |j                  g||j                  g|j                         | xj                  |j                  z  c_
        | S |J | xj                  t        |      z  c_
        	 t        j                  |      }|t        j                  u ryt        ||   t               r||   nt#        ||         }|t
        j                  k  r|| j                  k  s| j                  ||   | _        || _        |?|j%                  | j                        $|| j                     j%                  d      | _        nd| _        |sdn|t        |      z
  t!        |      z   dz   | _	        || _        n	|r|| _        ||   | j(                  _        || j(                  _        y# t        $ r Y yw xY w)az  checks for better solutions in list ``arx``.

        Based on the smallest corresponding value in ``arf``,
        alternatively, `update` may be called with a `BestSolution`
        instance like ``update(another_best_solution)`` in which case
        the better solution becomes the current best.

        ``xarchive`` is used to retrieve the genotype of a solution.
        Ngenor   )rv   r   r   maxr   r	   r   updater;   r   r   r*   r&   	nanargminrs   r   r,   floatr{   r   r   )rn   arxxarchivearfr   minidxminarfs          rN   r   zBestSolution.updateT  s    c<(}}$ #) #T]]CLL$A Buu SUUTXX%5SUUGXw		BMMS\\)MKS!	\\#&F RVV *3v; <V%FBT DHH&466/TVV^[DFDF#TVV(<(H&tvv.226:"%*C0@3v;0NQR0RDJ!DM!DM&k				'  		s   H4 4	I ?I c                 H    | j                   | j                  | j                  fS )zreturn ``(x, f, evals)`` )r;   r   r   r   s    rN   r{   zBestSolution.get  s    vvtvvtzz))rZ   NNN)	r   r   r   r   r	   r   rp   r   r{   r   rZ   rN   r   r   @  s$      +X*rZ   r   c                   $    e Zd ZdZd ZddZd Zy)BestSolution2z=minimal tracker of a smallest f-value with variable meta-infoc                 v    t         j                  | _        d | _        d | _        d | _        d| _        	 d | _        y r   )r	   r   r   r;   infocount_savedcountpreviousr   s    rN   rp   zBestSolution2.__init__  s4    	
-rZ   Nc                    | xj                   dz  c_         | j                   dk(  sCt        j                  |      rt        j                  | j                        r|| j                  k  rjt	        | j
                        | _        | j                  d= t        j                  |      | _        || _	        |r ||      n|| _
        | j                   | _        | S )z`info` may be a dictionary with everything we want to know,
        `info_construct` may be used to finalize versatile elements of
        `info`, like make a copy of an array within the info dictionary
        r   r   )r   r&   isfiniter   dict__dict__r   _umifloatr;   r   r   )rn   r   r;   r   info_constructs        rN   r   zBestSolution2.update  s    
 	

a
::?r{{1~r{{4667JaRVRXRXj /DMj)ZZ]DFDF0>t,DDI#zzDrZ   c                 ,    t        | j                        S r   )strr   r   s    rN   __str__zBestSolution2.__str__  s    4==!!rZ   r   )r   r   r   r   rp   r   r   r   rZ   rN   r   r     s    G"rZ   r   c                       e Zd Zd ZddZy)BestFeasibleSolutionc                 J    t         j                  |        d | _        d | _        y r   )r   rp   gal_penaltiesr   s    rN   rp   zBestFeasibleSolution.__init__  s    t$ rZ   Nc                     t        d |D              r| S t        j                  | ||||       | j                  | j                  k(  r4t        j                  |      | _        t        j                  |      | _        | S )z=g and al_penalties are lists of constraint and penalty valuesc              3   &   K   | ]	  }|d kD    yw)r   Nr   ).0gis     rN   	<genexpr>z.BestFeasibleSolution.update.<locals>.<genexpr>  s     ""rAvs   )	anyr   r   r   r   r   lifloatr   r   )rn   r   r   r   r;   r   r   s          rN   r   zBestFeasibleSolution.update  sb    """KT1a~>tzz)[[^DF #L 9DrZ   )NNNN)r   r   r   rp   r   r   rZ   rN   r   r     s    !rZ   r   c                   0    e Zd ZdZdd fdZd Zd Zd Zy)ExponentialSmoothingznot in use (yet)

    Exponentially smoothened vector, new data are added via
    calling the class instance. The `normalizer` is applied to
    the weight ``1 / time_constant`` used for the new data.

    Nc                     | S r   r   r;   s    rN   <lambda>zExponentialSmoothing.<lambda>  s    rZ   c                     || _         | j                   '| j                   dk  rt        d| j                   z        || _        d | _        d| _        y )Nr   ztime_constant = %d must be >=1r   )time_constantrs   
normalizervaluesr   )rn   r   r   s      rN   rp   zExponentialSmoothing.__init__  sO    *)d.@.@1.D=@R@RRSS$
rZ   c                     t        j                  |t              | _        | j                  dt        |      dz  z   | _        y y )N)dtyper         ?)r&   r(   r   r   r   r*   )rn   vs     rN   _init_zExponentialSmoothing._init_  s9    hhq.%!"SVS[D &rZ   c                      | j                   |   S r   r   )rn   rC   s     rN   __getitem__z ExponentialSmoothing.__getitem__  s    {{1~rZ   c                 p   | j                   | j                  |       | xj                  dz  c_        t        j                  | j                  | j
                  f      }| xj                   dd|z  z
  z  c_         | xj                   | j                  d|z        t        j                  |      z  z  c_         | S )Nr   )r   r   r   r&   r.   r   r   r2   )rn   r   tcs      rN   r   zExponentialSmoothing.__call__  s    ;;KKN

a
VVTZZ!3!345q1r6z!tq2v.A>>rZ   )r   r   r   r   rp   r   r   r   r   rZ   rN   r   r     s"     &*k 1
rZ   r   c                   4     e Zd ZdZd fd	Zed        Z xZS )EvolutionPathNnot in use (yet)

    A variance-neutral exponentially smoothened vector.
    c                 0    t         t        |   |d        y )Nc                 8    t        j                  | d| z
  z        S )Nrr   )r&   sqrtr   s    rN   r   z(EvolutionPath.__init__.<locals>.<lambda>  s    RWWQ!a%[%9rZ   )superr   rp   )rn   r   	__class__s     rN   rp   zEvolutionPath.__init__  s    mT+9	;rZ   c                     | j                   S r   r   r   s    rN   pathzEvolutionPath.path  s    {{rZ   r   )r   r   r   r   rp   propertyr   __classcell__)r   s   @rN   r   r     s!    ;  rZ   r   c                   4    e Zd Zed        Zed        ZddZy)BinaryEvolutionPathc                 z    t        j                  dddt        j                  | j                        dz  z  z         S )a*  propability of path entries to be larger than one,

        given the input is ``sign(randn())``. Check out::

            n = int(1e4)
            greater_than_one = []
            ar_tc = [1.2, 1.5, 1.9, 2, 4, 8, 16, 32, 100]
            for tc in ar_tc:
                p = cma.optimization_tools.EvolutionPath(tc)
                for i in range(int(10 * tc)):
                    p(np.sign(np.random.randn(n)))
                # plot(*step_data(p.path))
                greater_than_one += [(np.mean(p.path > 1) + np.mean(p.path < -1)) / 2]

        g      ?g|N?g?gffffff?)r&   minimumr2   r   r   s    rN   'probability_larger_than_one_from_binaryz;BinaryEvolutionPath.probability_larger_than_one_from_binary  s>    " zz$ 3"**T-?-?"@#"EE!F G 	GrZ   c                 `    t        j                  | j                        dkD  | j                  z
  S )zreturn one of two possible values with expectation of zero.

        the maximum for the larger value is 1 - 0.15865525393145707 for tc to infty.
        r   )r&   r/   r   r   r   s    rN   raw_binary_sz BinaryEvolutionPath.raw_binary_s  s'     t{{#a'4+W+WWWrZ   c                 >    | j                   }||dkD  xx   |z  cc<   |S )z9how many increments for one decrement in stationary stater   )r   )rn   odds_of_incrementrM   s      rN   binary_szBinaryEvolutionPath.binary_s  s%    	!a%%%rZ   N)r   )r   r   r   r   r   r   r   r   rZ   rN   r   r     s1    G G& X XrZ   r   c                       e Zd ZdZddZd Zy)OldEvolutionPathr   Nc                     t        j                  |      | _        d| _        || _        |dt        |      dz  z   | _        y y )Nr   r   r   )r&   r2   r   r   r   r*   )rn   p0r   s      rN   rp   zOldEvolutionPath.__init__  s@    JJrN	
* !"SWc\!1D !rZ   c                    | xj                   dz  c_         t        d| j                   z  d| j                  z  f      }| xj                  d|z
  z  c_        | xj                  |d|z
  z  dz  t	        j
                  |      z  z  c_        y )Nr         ?rr   r   )r   r   r   r   r&   r2   )rn   r   cs      rN   r   zOldEvolutionPath.update
  sk    

a
TZZd&8&8!89:		QU			a1q5kC'"**Q-77	rZ   r   )r   r   r   r   rp   r   r   rZ   rN   r   r     s    28rZ   r   c                   \    e Zd ZdZg dej
                  dddfdZddZd Zdd	Z	d
 Z
d Zy)NoiseHandlera  Noise handling according to [Hansen et al 2009, A Method for
    Handling Uncertainty in Evolutionary Optimization...]

    The interface of this class is yet versatile and subject to changes.

    The noise handling follows closely [Hansen et al 2009] in the
    measurement part, but the implemented treatment is slightly
    different: for ``noiseS > 0``, ``evaluations`` (time) and sigma are
    increased by ``alpha``. For ``noiseS < 0``, ``evaluations`` (time)
    is decreased by ``alpha**(1/4)``.

    The (second) parameter ``evaluations`` defines the maximal number
    of evaluations for a single fitness computation. If it is a list,
    the smallest element defines the minimal number and if the list has
    three elements, the median value is the start value for
    ``evaluations``.

    `NoiseHandler` serves to control the noise via steps-size
    increase and number of re-evaluations, for example via `fmin` or
    with `ask_and_eval`.

    Examples
    --------
    Minimal example together with `fmin` on a non-noisy function:

    >>> import cma
    >>> res = cma.fmin(cma.ff.elli, 7 * [1], 1, noise_handler=cma.NoiseHandler(7))  #doctest: +ELLIPSIS
    (4_w,9)-aCMA-ES (mu_w=2.8,...
    >>> assert res[1] < 1e-8
    >>> res = cma.fmin(cma.ff.elli, 6 * [1], 1, {'AdaptSigma':cma.sigma_adaptation.CMAAdaptSigmaTPA},
    ...          noise_handler=cma.NoiseHandler(6))  #doctest: +ELLIPSIS
    (4_w,...
    >>> assert res[1] < 1e-8

    in dimension 7 (which needs to be given tice). More verbose example
    in the optimization loop with a noisy function defined in ``func``:

    >>> import cma, numpy as np
    >>> func = lambda x: cma.ff.sphere(x) * (1 + 4 * np.random.randn() / len(x))  # cma.ff.noisysphere
    >>> es = cma.CMAEvolutionStrategy(np.ones(10), 1)  #doctest: +ELLIPSIS
    (5_w,10)-aCMA-ES (mu_w=3.2,...
    >>> nh = cma.NoiseHandler(es.N, maxevals=[1, 1, 30])
    >>> while not es.stop():
    ...     X, fit_vals = es.ask_and_eval(func, evaluations=nh.evaluations)
    ...     es.tell(X, fit_vals)  # prepare for next iteration
    ...     es.sigma *= nh(X, fit_vals, func, es.ask)  # see method __call__
    ...     es.countevals += nh.evaluations_just_done  # this is a hack, not important though
    ...     es.logger.add(more_data = [nh.evaluations, nh.noiseS])  # add a data point
    ...     es.disp()
    ...     # nh.maxevals = ...  it might be useful to start with smaller values and then increase
    ...                # doctest: +ELLIPSIS
    Iterat...
    >>> print(es.stop())
    ...                # doctest: +ELLIPSIS
    {...
    >>> print(es.result[-2])  # take mean value, the best solution is totally off
    ...                # doctest: +ELLIPSIS
    [...
    >>> assert sum(es.result[-2]**2) < 1e-9
    >>> print(X[np.argmin(fit_vals)])  # not bad, but probably worse than the mean
    ...                # doctest: +ELLIPSIS
    [...

    >>> # es.logger.plot()


    The command ``logger.plot()`` will plot the logged data.

    The noise options of fmin` control a `NoiseHandler` instance
    similar to this example. The command ``cma.CMAOptions('noise')``
    lists in effect the parameters of `__init__` apart from
    ``aggregate``.

    Details
    -------
    The parameters reevals, theta, c_s, and alpha_t are set differently
    than in the original publication, see method `__init__`. For a
    very small population size, say popsize <= 5, the measurement
    technique based on rank changes is likely to fail.

    Missing Features
    ----------------
    In case no noise is found, ``self.lam_reeval`` should be adaptive
    and get at least as low as 1 (however the possible savings from this
    are rather limited). Another option might be to decide during the
    first call by a quantitative analysis of fitness values whether
    ``lam_reeval`` is set to zero. More generally, an automatic noise
    mode detection might also set the covariance matrix learning rates
    to smaller values.

    :See also: `fmin`, `CMAEvolutionStrategy.ask_and_eval`

    )r   r   r   NgHz>Fc                 V   || _         || _        || _        d| _        d| _        dd|dz   z  z   | _        dd|dz   z  z   | _        | j                  dz  | _        ddk  r#|d	   d
kD  rd| _        | j                  dz  | _        d| _        	 d| _	        t        t        j                  |            | _        t        |d      rWt        |      dkD  r!t!        |      | _	        | j                  | _        t        |      d	kD  rt        j"                  |      | _        || _        d| _        d| _        y)a  Parameters are:

        ``N``
            dimension, (only) necessary to adjust the internal
            "alpha"-parameters
        ``maxevals``
            maximal value for ``self.evaluations``, where
            ``self.evaluations`` function calls are aggregated for
            noise treatment. With ``maxevals == 0`` the noise
            handler is (temporarily) "switched off". If `maxevals`
            is a list, min value and (for >2 elements) median are
            used to define minimal and initial value of
            ``self.evaluations``. Choosing ``maxevals > 1`` is only
            reasonable, if also the original ``fit`` values (that
            are passed to `__call__`) are computed by aggregation of
            ``self.evaluations`` values (otherwise the values are
            not comparable), as it is done within `fmin`.
        ``aggregate``
            function to aggregate single f-values to a 'fitness', e.g.
            ``np.median``.
        ``reevals``
            number of solutions to be reevaluated for noise
            measurement, can be a float, by default set to ``2 +
            popsize/20``, where ``popsize = len(fit)`` in
            ``__call__``. zero switches noise handling off.
        ``epsilon``
            multiplier for perturbation of the reevaluated solutions
        ``parallel``
            a single f-call with all resampled solutions

        :See also: `fmin`, `CMAOptions`, `CMAEvolutionStrategy.ask_and_eval`

        r   g333333?r   g       @r   g      пr   r   rr   g NgmCg      ?g+__contains__Nr   )
lam_reevalepsilonparallelthetacum
alphasigma
alphaevalsalphaevalsdownevaluationsminevalsr,   r&   r   maxevalshasattrr*   r.   medianmeanf_aggregateevaluations_just_donenoiseS)rn   Nr  	aggregatereevalsr  r  s          rN   rp   zNoiseHandler.__init__q  s   F " 
cQVn,cQVn,"oo56hqkD(!DO"&//6"9DPBFF8,-8^,8}q  #H#'== 8}q #%99X#6 $%&"rZ   c                     d| _         | j                  r| j                  dk(  ry| j                  |||||      }t	        |      sy| j                          | j                         S )a  proceed with noise measurement, set anew attributes ``evaluations``
        (proposed number of evaluations to "treat" noise) and ``evaluations_just_done``
        and return a factor for increasing sigma.

        Parameters
        ----------
        ``X``
            a list/sequence/vector of solutions
        ``fit``
            the respective list of function values
        ``func``
            the objective function, ``fit[i]`` corresponds to
            ``func(X[i], *args)``
        ``ask``
            a method to generate a new, slightly disturbed solution. The
            argument is (only) mandatory if ``epsilon`` is not zero, see
            `__init__`.
        ``args``
            optional additional arguments to ``func``

        Details
        -------
        Calls the methods `reeval`, `update_measure` and ``treat` in
        this order. ``self.evaluations`` is adapted within the method
        `treat`.

        r   r   )r  r  r  reevalr*   update_measuretreat)rn   rU   fitfuncaskr}   ress          rN   r   zNoiseHandler.__call__  sY    8 &'"}}1 4kk!S$T23xzz|rZ   c                    | j                   dkD  r?t        | j                  | j                  z  | j                  f      | _        | j
                  S t        | j                  | j                  z  | j                  f      | _        y)zadapt self.evaluations depending on the current measurement
        value and return ``sigma_fac in (1.0, self.alphasigma)``

        r   r   )	r  r.   r	  r  r  r  r   r  r
  r   s    rN   r  zNoiseHandler.treat  sh    
 ;;?"D$4$4t$F#VWD??""D$4$4t7J7J$JDMM#Z[DrZ   c                    t        |      | _        t        |      | _        | j                  |      | _        t        | j                        s| j                  S | j                  rt        | j                        nd}| j                  t        j                  n| j                  }| j                  D ]  }||   }	| j                  r| j                  r/ | | |||	| j                        g|       | j                  |<   O |t        |      D 
cg c]   }
 | |d|	| j                        d   g| " c}
      | j                  |<    |t        |      D 
cg c]  }
 ||	g|  c}
      | j                  |<    |t        | j                        z  | _        | j                  | j                  | j                  fS c c}
w c c}
w )zstore two fitness lists, `fit` and ``fitre`` reevaluating some
        solutions in `X`.
        ``self.evaluations`` evaluations are done for each reevaluated
        fitness value.
        See `__call__`, where `reeval` is called.

        r   r   )listr  fitreindicesidxr*   r  r,   r	  r&   r  r  r  r
   r  )rn   rU   r  r  r  r}   r   faggrC   X_i_ks              rN   r  zNoiseHandler.reeval  s    9#Y
<<$488}88O)-)9)9D$$%q ,,4ryy$:J:JAA$C||==$(c%dll.K)Sd)S$TDJJqM$(6;El*D6B +/s1c4<</H/K*Sd*S6B*D %EDJJqM !%u%N2d3&6&6%N O

1  &+S]%:"xxTXX--*D &Os   %F<
G
c                 (   t        | j                        }t        j                  | j                  | j                  z         }t        j                  |      j                  d|f      }|d   |d   z
  t        j                  |d   |d   z
        z
  }t        j                  dd|z        }| j                  D cg c]  }dt        j                  j                  t        j                  ||d|f   dz   |d|f   |d|f   kD  z
  z
        | j                  dz        t        j                  j                  t        j                  ||d|f   dz   |d|f   |d|f   kD  z
  z
        | j                  dz        z   z   }}t        j                  || j                           t        j                  j                  |d      z
  }| xj                  | j                   t        j"                  |      | j                  z
  z  z  c_        | j                  |fS c c}w )zupdated noise level measure using two fitness lists ``self.fit`` and
        ``self.fitre``, return ``self.noiseS, all_individual_measures``.

        Assumes that ``self.idx`` contains the indices where the fitness
        lists differ.

        rr   r   r   r   2   )r*   r  r&   argsortr   rc   signaranger"  r   Mhprctiler/   r  amaxr  r  r  )	rn   lamr"  ranks	rankDeltarrC   limitsrM   s	            rN   r  zNoiseHandler.update_measure  s    $((mjjDJJ./

3''C1!HuQx'"''%(U1X2E*FF	 IIaS!
 "XX	' &	 qE!Q$K!OuQPQT{UZ[\^_[_U`G`4a/b(c&*jj2o7qE!Q$K!OuQPQT{UZ[\^_[_U`G`4a/b(c&*jj2o77 8 &	 	 ' FF9TXX&'#&&++fa*@@txx2771:#;<<{{A~'s   9CHc           	      0   d| j                   r| j                   ndt        |      dz  z   z  }t        |      |dz  t        j                  j                         kD  z   }d}|dk(  rp||dz  z
  }t        j                  t        j                  |      |d       |z   }t        j                  t        t        d|            t        |d||z
         z         S |dk(  rst        j                  t        j                  |            }t        j                  dt        |      t        |      |z  z
  |      }||D cg c]  }t        |       c}   S |dk(  r4t        j                  t        j                  |      dd|dz   z         d| S t        d|z        c c}w )	zreturn the set of indices to be reevaluated for noise
        measurement.

        Given the first values are the earliest, this is a useful policy
        also with a time changing objective.

        r   rr      r   Nr   r   z+unrecognized choice value %d for noise reev)r  r*   r,   r&   randomrandr(  r2   r  r
   r`   rs   )	rn   r  lam_reevchoicen_firstsort_idx
idx_sortedlinsprC   s	            rN   r!  zNoiseHandler.indices  su    T__$//!"SX]!24x=X\RYY^^5E$EFQ;Q.Gzz"**S/'(";<wFH::d5G#45 !Hw,>!?@A B Bq[BJJsO4JKK3s8c#h.A#A8LEu5u!s1vu566q[::bjjo.AqHqL/ABCIXNNJ%& ' ' 6s   5F)Nr   )r   )r   r   r   r   r&   r  rp   r   r  r  r  r!  r   rZ   rN   r   r     s<    \@ $-		teAF#J
.84'rZ   r   c                   t    e Zd ZdZ	 	 ddZd ed  ed      D              dfdZdd	 fd
Zd Z	ddZ
ddZy)Sectionsa  plot sections through an objective function.

    A first rational thing to do, when facing an (expensive) application.
    By default 6 points in each coordinate are evaluated. The data is saved
    and reloaded by default. A change of basis will invalide the loaded
    result. This class is still experimental.

    Examples
    --------
    ::

        import cma, numpy as np
        s = cma.Sections(cma.ff.rosen, np.zeros(3)).do(plot=False)
        s.do(plot=False)  # evaluate the same points again, i.e. check for noise
        try:
            s.plot()
        except:
            print('plotting failed: matplotlib.pyplot package missing?')

    Details
    -------
    Data are saved after each function call during `do`. The filename
    is attribute ``name`` and by default ``str(func)``, see `__init__`.

    A random (orthogonal) basis can be generated with
    ``cma.transformations.Rotation()(np.eye(3))``.

    CAVEAT: The default name is unique in the function name, but it
    should be unique in all parameters of `__init__` but `plot_cmd`
    and `load`. If, for example, a different basis is chosen, either
    the name must be changed or the ``.pkl`` file containing the
    previous data must first be renamed or deleted.

    ``s.res`` is a dictionary with an entry for each "coordinate" ``i``
    and with an entry ``'x'``, the middle point. Each entry ``i`` is
    again a dictionary with keys being different dx values and the
    value being a sequence of f-values. For example ``s.res[2][0.1] ==
    [0.01, 0.01]``, which is generated using the difference vector ``s
    .basis[2]`` like

    ``s.res[2][dx] += func(s.res['x'] + dx * s.basis[2])``.

    :See also: `__init__`

    NTc                    |ddl m} || _        || _        || _        |r|n:t        |      j                  dd      j                  dd      j                  dd      | _        || _        |t        j                  t        |            n|| _        	 |xr | j                          t        | j                  d	   |k7        ri | _        || j                  d	<   yt!        | j                  d
z          y#  i | _        || j                  d	<   Y yxY w)a  
        Parameters
        ----------
        ``func``
            objective function
        ``x``
            point in search space, middle point of the sections
        ``args``
            arguments passed to `func`
        ``basis``
            evaluated points are ``func(x + locations[j] * basis[i])
            for i in len(basis) for j in len(locations)``,
            see `do()`
        ``name``
            filename where to save the result
        ``plot_cmd``
            command used to plot the data, typically matplotlib pyplots
            `plot` or `semilogy`
        ``load``
            load previous data from file ``str(func) + '.pkl'``

        Nr   )r4    _>r"   <r;   z loaded)matplotlib.pyplotr4   r  r}   r;   r   replacenameplot_cmdr&   eyer*   basisr$   r   r  print)rn   r  r;   r}   rI  rF  rG  r$   s           rN   rp   zSections.__init__i  s    0 :		 Dc$i&7&7S&A&I&I#r&R&Z&Z[^`b&c	 ',}RVVCF^%
		 TYY[488C=A%& !dii)+,	DHDHHSMs   AC0 C0 0D
r   c              #   ,   K   | ]  }|d z
  dz    yw)g      @r   Nr   )r   rC   s     rN   r   zSections.<genexpr>  s     /Px!SAxs      c                    |s| j                          y| j                  }t        t        | j                              D ]  }||vri ||<   |D ]  }| j
                  || j                  |   z  z   }|}|||   vrg ||   |<   |}	|	dkD  s;|	dz  }	||   |   j                   | j                  |g| j                          |r| j                          | j                          |	dkD  r_  | S )aJ  generates, plots and saves function values ``func(y)``,
        where ``y`` is 'close' to `x` (see `__init__()`). The data are stored in
        the ``res`` attribute and the class instance is saved in a file
        with (the weired) name ``str(func)``.

        Parameters
        ----------
        ``repetitions``
            for each point, only for noisy functions is >1 useful. For
            ``repetitions==0`` only already generated data are plotted.
        ``locations``
            coordinated wise deviations from the middle point given in
            `__init__`

        Nr   r   )
r4   r  r
   r*   rI  r;   appendr  r}   save)
rn   repetitions	locationsr4   r  rC   dxxxxkeyns
             rN   dozSections.do  s      IIKhhs4::'A|A  VVb4::a=00s1v%#%CF4L!eFAF4L''			"(Atyy(AB		IIK !e   (" rZ   c                     | S r   r   )r<   s    rN   r   zSections.<lambda>  s    qrZ   c                    ddl m} |s| j                  }d}|j                         j	                          | j
                  }| j                         \  }}t        j                  }|D ]  }	t        |t        ||	         f      } |dk  rd|z
  nd}
t        d |j                         D              D ]  }	||	t        |      z     }t        ||	   j                               } |||D cg c]&  } |t        j                  ||	   |         |
z         ( c}|dz          |j                  |d    |t        j                  ||	   |d                  |	       t        ||	         dk  s |||	    |t        j                   ||	         |
z         |t        ||	         d	k  rd
ndz           |j#                  dt%        |
      z          |j'                          |j)                          |j+                          | S c c}w )z&plot the data we have, return ``self``r   r   bgrcmykg&.>c              3   B   K   | ]  }t        |t              s|  y wr   )rv   r,   )r   ks     rN   r   z Sections.plot.<locals>.<genexpr>  s     D:aAs1C:s   -r   !   r   or   zf + )r!   r   rG  gcfclearr  	flattenedr	   r   r.   r_   keysr*   r&   r  textr(   ylabelr   drawionshow)rn   rG  tfr   colorsr  flatxflatfminfrC   addfcolorr   r;   s                 rN   r4   zSections.plot  s   %}}H

hh~~'uxxAc%(m,-D "dltd{D388:DDA1s6{?+EQ'CSCHCq2biiAq	2T9:CH%RU+VKKBBIIc!fSWo$>!?C58}r!q2bhhuQx&84&?#@%RUV[\]V^R_bdRd3jmBno E 	fs4y()

 Is   '+G:c                 4   i }i }| j                   D ]  }t        |t              sg ||<   g ||<   t        | j                   |         D ]J  }t        | j                   |   |         D ]*  }||   j	                  |       ||   j	                  |       , L  ||fS )zreturn flattened data ``(x, f)`` such that for the sweep
        through coordinate ``i`` we have for data point ``j`` that
        ``f[i][j] == func(x[i][j])``

        )r  rv   r,   r_   rN  )rn   rj  rk  rC   r;   ds         rN   ra  zSections.flattened  s     A!S!aa,A#DHHQKN3a*a* 4 -	  e|rZ   c                     ddl }|r|n| j                  }| j                  }| `|j                  | t	        |dz   d             || _        | S )zsave to filer   N.pklwb)picklerF  r  dumpopen)rn   rF  rt  funs       rN   rO  zSections.save  sE    tiiID$tf}d34	rZ   c                     ddl }|r|n| j                  }|j                  t        |dz   d            }|j                  | _        | S )zload from filer   Nrr  rb)rt  rF  r$   rv  r  )rn   rF  rt  rM   s       rN   r$   zSections.load  s;    tKKTF]D1255rZ   )r   NNNTr   )r   r   r   r   rp   tupler
   rV  r4   ra  rO  r$   r   rZ   rN   r>  r>  ;  sP    ,Z ;?%)*X %/PuQx/P*PW[ &P ![ 6$rZ   r>  )NNr   Nr   r   )r   )"r   
__future__r   r   r   rt   rx   r	   numpyr&   multiprocessingr   rl   utilities.utilsr   r   	utilitiesr   utilities.python3for2r
   rO   rY   rf   objectrh   r   r   r   r   r   r   r   r   r>  r   rZ   rN   <module>r     s    @ @ 
    2 6 " (X~Sj>B.AF AFB*6 B*H"F "4= 6 B( #- #J8v 8"i'6 i'V	v rZ   