
    J-jt                        d Z ddlmZmZmZ ddlZddlmZ ddlZ	ddl
Z
ddlmZ ddlmZ ddlmZmZ dd	lmZ dd
lmZ ddlmZ [[[ e       Z G d de      Z G d de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& G d" d#e      Z' G d$ d%e      Z( G d& d'e      Z)y)(zBWrapper for objective functions like noise, rotation, gluing args
    )absolute_importdivisionprint_functionN)partial   )utils)Mh)ConstRandnShiftRotation)BoundTransform)EvalParallel2)rangec                   :    e Zd ZdZdgZed        ZddZd Zd Z	y)	Functiona  a declarative base class, indicating that a derived class instance
    "is" a (fitness/objective) function.

    A `callable` passed to `__init__` is called as the fitness
    `Function`, otherwise the `_eval` method is called, if defined in the
    derived class, when the `Function` instance is called. If the input
    argument is a matrix or a list of vectors, the method is called for
    each vector individually like
    ``_eval(numpy.asarray(vector)) for vector in matrix``.

    >>> import cma
    >>> from cma.fitness_transformations import  Function
    >>> f = Function(cma.ff.rosen)
    >>> assert f.evaluations == 0
    >>> assert f([2, 3]) == cma.ff.rosen([2, 3])
    >>> assert f.evaluations == 1
    >>> assert f([[1], [2]]) == [cma.ff.rosen([1]), cma.ff.rosen([2])]
    >>> assert f.evaluations == 3
    >>> class Fsphere(Function):
    ...     def _eval(self, x):
    ...         return sum(x**2)
    >>> fsphere = Fsphere()
    >>> assert fsphere.evaluations == 0
    >>> assert fsphere([2, 3]) == 4 + 9 and fsphere([[2], [3]]) == [4, 9]
    >>> assert fsphere.evaluations == 3
    >>> Fsphere.__init__ = lambda self: None  # overwrites Function.__init__
    >>> assert Fsphere()([2]) == 4  # which is perfectly fine to do

    Details:

    - When called, a class instance calls either the function passed to
      `__init__` or, if none was given, tries to call any of the
      `function_names_to_evaluate_first_found`, first come first serve.
      By default, ``function_names_to_evaluate_first_found == ["_eval"]``.

    - This class cannot move to module `fitness_functions`, because the
      latter uses `fitness_transformations.rotate`.

    _evalc                 "    t         j                  S )zattributes which are searched for to be called if no function
        was given to `__init__`.

        The first present match is used.
        )r   '_function_names_to_evaluate_first_found)selfs    i/Users/jameslopez/projects/TradingBot25/.venv/lib/python3.12/site-packages/cma/fitness_transformations.py&function_names_to_evaluate_first_foundz/Function.function_names_to_evaluate_first_found;   s     ???    Nc                 0    t         j                  | |       y)zcallows to define the fitness_function to be called, doesn't
        need to be ever called
        N)r   
initializer   fitness_functions     r   __init__zFunction.__init__D   s     	D"23r   c                 h    || _         d| _        t        j                   | _        d| _        d| _        y)z%initialization of `Function`
        r   TN)_Function__callableevaluationsnpinfftargettarget_hit_at_Function__initializedr   s     r   r   zFunction.initializeI   s0     +w!r   c           	      0   	 | j                   st        	 | j                  }|| j
                  D ]  }	 t        | |      } n |t        j                  |d         \  }}| xj                  t        |      z  c_	        |D cg c]$  } |t        j                  |      g|dd  i |& }}| j                  st        t        j                  |      | j                  k        r[| j                  t        |      z
  dz   t!        t        j                  |      | j                  k        j#                  d      z   | _         ||      S | xj                  dz  c_	        y # t        $ r t        j                  | d        Y jw xY w# t        $ r Y `w xY wc c}w )Nr   r   T)r$   AttributeErrorr   r   r   r   getattrr   as_vector_listr   lenr    asarrayr#   anyr"   listindex)	r   argskwargs	callable_nameXlist_revertxFs	            r   __call__zFunction.__call__R   ss   	,%%$$ &
 OO	CC 'd 3I D  "11$q':NA{A&HIJ12::a=>48>v>AJ%%#bjjmt||.K*L%)%5%5A%>%BT"**UV-[_[g[gJgEhEnEnosEt%t"q>!!)  	,d+	, &  Ks(   E F)FF ?F 	FFN)
__name__
__module____qualname____doc__r   propertyr   r   r   r6    r   r   r   r      s5    &N 07i+@ @4
""r   r   c                   $    e Zd ZdZddZd Zd Zy)ComposedFunctiona  compose an arbitrary number of functions.

    A class instance is a list of functions. Calling the instance executes
    the composition of these functions (evaluating from right to left as
    in math notation). Functions can be added to or removed from the list
    at any time with the obvious effect. To remain consistent (if needed),
    the ``list_of_inverses`` attribute must be updated respectively.

    >>> import numpy as np
    >>> from cma.fitness_transformations import ComposedFunction
    >>> f1, f2, f3, f4 = lambda x: 2*x, lambda x: x**2, lambda x: 3*x, lambda x: x**3
    >>> f = ComposedFunction([f1, f2, f3, f4])
    >>> assert isinstance(f, list) and isinstance(f, ComposedFunction)
    >>> assert f[0] == f1  # how I love Python indexing
    >>> assert all(f(x) == f1(f2(f3(f4(x)))) for x in np.random.rand(10))
    >>> assert f4 == f.pop()
    >>> assert len(f) == 3
    >>> f.insert(1, f4)
    >>> f.append(f4)
    >>> assert all(f(x) == f1(f4(f2(f3(f4(x))))) for x in range(5))

    A more specific example:

    >>> from cma.fitness_transformations import ComposedFunction
    >>> from cma.boundary_handler import BoundTransform
    >>> from cma import ff
    >>> f = ComposedFunction([ff.elli,
    ...                       BoundTransform([[0], [1]]).transform])
    >>> assert max(f([2, 3]), f([1, 1])) <= ff.elli([1, 1])

    Details:

    - This class can serve as basis for a more transparent
      alternative to a ``scaling_of_variables`` CMA option or for any
      necessary transformation of the fitness/objective function
      (genotype-phenotype transformation).

    - The parallelizing call with a list of solutions of the `Function`
      class is not inherited. The inheritence from `Function` is rather
      declarative than funtional and could be omitted.

    Nc                 h    t         j                  | |       t        j                  |        || _        y)zCaveat: to remain consistent, the ``list_of_inverses`` must be
        updated explicitly, if the list of function was updated after
        initialization.
        N)r,   r   r   list_of_inverses)r   list_of_functionsrA   s      r   r   zComposedFunction.__init__   s)    
 	d-.$ 0r   c                     t        j                  | |g|i | t        dt        |        dz
  d      D ]  } | |   |g|i |} |S )Nr   )r   r6   r   r)   r   r4   r.   r/   is        r   r6   zComposedFunction.__call__   sX    $3D3F3rCI:>2.AQ+D+F+A /r   c                     | j                   t        j                  d       yt        t	        | j                               D ]  } | j                   |   |g|i |} |S )zhevaluate the composition of inverses on ``x``.

        Return `None`, if no list was provided.
        Nzinverses were not given)rA   r   print_warningr   r)   rE   s        r   inversezComposedFunction.inverse   sb    
   ( 9:s40012A(%%a(<T<V<A 3r   r7   )r8   r9   r:   r;   r   r6   rI   r=   r   r   r?   r?   m   s    )T1
r   r?   c                       e Zd ZdZd Zd Zy)StackFunctiona  a function that returns ``f1(x[:n1]) + f2(x[n1:])``.

    >>> import functools
    >>> import numpy as np
    >>> import cma
    >>> def elli48(x):
    ...     return 1e-4 * functools.partial(cma.ff.elli, cond=1e8)(x)
    >>> fcigtab = cma.fitness_transformations.StackFunction(
    ...     elli48, cma.ff.sphere, 2)
    >>> x = [1, 2, 3, 4]
    >>> assert np.isclose(fcigtab(x), cma.ff.cigtab(np.asarray(x)))

c                 .    || _         || _        || _        y r7   )f1f2n1)r   rM   rN   rO   s       r   r   zStackFunction.__init__   s    r   c                 6   | j                   dk(  r | j                  |g|i |S t        |      | j                   k(  r | j                  |g|i |S  | j                  |d | j                    g|i | | j                  || j                   d  g|i |z   S )Nr   )rO   rN   r)   rM   )r   r4   r.   r/   s       r   r   zStackFunction._eval   s    77a<4771.t.v..q6TWW4771.t.v..twwq$''{4T4V4wtwwq{7\T7\U[7\\\r   N)r8   r9   r:   r;   r   r   r=   r   r   rK   rK      s    ]r   rK   c                       e Zd ZdZd Zd Zy)GlueArgumentsa&  deprecated, use `functools.partial` or
    `cma.fitness_transformations.partial` instead, which has the same
    functionality and interface.

    from a `callable` return a `callable` with arguments attached.


    An ellipsoid function with condition number ``1e4`` is created by
    ``felli1e4 = cma.s.ft.GlueArguments(cma.ff.elli, cond=1e4)``.

    >>> import cma
    >>> f = cma.fitness_transformations.GlueArguments(cma.ff.elli,
    ...                                               cond=1e1)
    >>> assert f([1, 2]) == 1**2 + 1e1 * 2**2

    c                     t        j                  dt               t        j	                  | |       || _        || _        || _        y)zdefine function, ``args``, and ``kwargs``.

        ``args`` are appended to arguments passed in the call, ``kwargs``
        are updated with keyword arguments passed in the call.
        zeGlueArguments is deprecated.
Use `functools.partial` (`cma.fitness_transformations.partial`) instead.N)warningswarnDeprecationWarningr   r   r   r.   r/   )r   r   r.   r/   s       r   r   zGlueArguments.__init__   sB     	 a(	* 	$ 01 0	r   c                     t        | j                        }|j                  |       t        j                  |      }t        j                  | |g|| j                  z   i |S )zbcall function with at least one additional argument and
        attached args and kwargs.
        )dictr/   updater    r*   r   r6   r.   )r   r4   r.   r/   joined_kwargss        r   r6   zGlueArguments.__call__   s\     T[[)V$JJqM  q 2D499,< 2#02 	2r   Nr8   r9   r:   r;   r   r6   r=   r   r   rR   rR      s     2r   rR   c                       e Zd ZdZd Zy)FBoundTransforma^  shortcut for ``ComposedFunction([f, BoundTransform(bounds).transform])``,
    see also below.

    Maps the argument into bounded or half-bounded (feasible) domain
    before evaluating ``f``.

    Example with lower bound at 0, which becomes the image of -0.05 in
    `BoundTransform.transform`:

    >>> import cma, numpy as np
    >>> f = cma.fitness_transformations.FBoundTransform(cma.ff.elli,
    ...                                                 [[0], None])
    >>> assert all(f[1](np.random.randn(200)) >= 0)
    >>> assert all(f[1]([-0.05, -0.05]) == 0)
    >>> assert f([-0.05, -0.05]) == 0

    A slightly more verbose version to implement the lower bound at zero
    in the very same way:

        >>> import cma
        >>> felli_in_bound = cma.s.ft.ComposedFunction(
        ...    [cma.ff.elli, cma.BoundTransform([[0], None]).transform])

    c                 |    t        |      | _        t        j                  | || j                  j                  g       y)zC`bounds[0]` are lower bounds, `bounds[1]` are upper bounds
        N)r   bound_tfr?   r   	transform)r   r   boundss      r   r   zFBoundTransform.__init__  s3     'v.!!$%t}}'>'>?	Ar   Nr8   r9   r:   r;   r   r=   r   r   r]   r]      s    0Ar   r]   c                       e Zd ZdZddZy)Rotateda  return a rotated version of a function for testing purpose.

    This class is a convenience shortcut for the litte more verbose
    composition of a function with a rotation:

    >>> import cma
    >>> from cma import fitness_transformations as ft
    >>> f1 = ft.Rotated(cma.ff.elli)
    >>> f2 = ft.ComposedFunction([cma.ff.elli, ft.Rotation()])
    >>> assert f1([2]) == f2([2])  # same rotation only in 1-D
    >>> assert f1([1, 2]) != f2([1, 2])

    Nc                 P    |t        |      }t        j                  | ||g       y)zZoptional argument ``rotate(x)`` must return a (stable) rotation
        of ``x``.
        N)seed)r   r?   r   )r   frotaterf   s       r   r   zRotated.__init__"  s'     >4(F!!$F4r   )NNrb   r=   r   r   rd   rd     s    5r   rd   c                       e Zd ZdZddZy)Shiftedak  compose a function with a shift in x-space.

    >>> import cma
    >>> f = cma.s.ft.Shifted(cma.ff.elli)

    Details: this class solely provides as default second argument to
    `ComposedFunction`, namely a random shift in search space.
    ``shift=lambda x: x`` would provide "no shift", ``None``
    expands to ``cma.transformations.ConstRandnShift()``.
    Nc                 L    |
t               }t        j                  | ||g       y)z.``shift(x)`` must return a (stable) shift of xN)r
   r?   r   )r   rg   shifts      r   r   zShifted.__init__5  s#    =#%E!!$E
3r   r7   rb   r=   r   r   rj   rj   *  s    	4r   rj   c                   (    e Zd ZdZ	 	 ddZd Zd Zy)ScaleCoordinatesa  compose a (fitness) function with a preceding scaling and offset.

    Scaling interface
    -----------------
    After ``fun2 = cma.ScaleCoordinates(fun, multipliers, zero)``, we have
    ``fun2(x) == fun(multipliers * (x - zero))``, where the vector size of
    `multipliers` and `zero` is adapated to the size of `x`, in case by
    recycling their last entry. This awkwardly asks to pass the `zero`
    argument of the preimage space where it has little meaning. Hence more
    conveniently,
    ``fun2 = cma.ScaleCoordinates(fun, multipliers, lower=lower)`` gets
    ``fun2(x) == fun(multipliers * x + lower)``.

    Domain interface (lower and upper variable values)
    --------------------------------------------------
    Let ``u`` and ``l`` be vectors (or a scalar) of (approximate) lower and
    upper variable values, respectively. After
    ``fun2 = cma.ScaleCoordinates(fun, upper=u, lower=l)`` we have
    ``fun2(x) == fun(l + (u - l) * x)``. Now, passing 0 as ``x[i]`` to
    ``fun2`` evaluates ``fun`` at ``l[i]`` while passing 1 evaluates
    ``fun`` at ``u[i]``.

    To match the size of ``x``, the sizes of ``u`` and ``l`` are shortened
    or their last entry is recycled if necessary.

    The default value for `lower` is zero in which case `upper` just
    becomes a scaling multiplier.

    Bounding the search domain of ``fun2`` to ``[0, 1]`` now bounds ``fun``
    to the domain ``[l, u]``. The ``'bounds'`` option of `CMAOptions`
    allows to set these bounds.

    More general, the affine transformation is defined such that
    ``x[i]==from_lower_upper[0]`` evaluates ``fun`` at ``l[i]`` and
    ``x[i]==from_lower_upper[1]`` evaluates ``fun`` at ``u[i]`` where
    ``from_lower_upper == [0, 1]`` by default.

    Examples and Doctest
    --------------------

    >>> import numpy as np
    >>> import cma
    >>> fun = cma.ScaleCoordinates(cma.ff.sphere, upper=[30, 1])
    >>> bool(fun([1, 1]) == 30**2 + 1**2)
    True
    >>> fun.transform([1, 1]).tolist(), fun.transform([0.2, 0.2]).tolist()
    ([30.0, 1.0], [6.0, 0.2])
    >>> fun.inverse(fun.transform([0.1, 0.3])).tolist()
    [0.1, 0.3]
    >>> fun = cma.ScaleCoordinates(cma.ff.sphere, upper=[31, 3], lower=[1, 2])
    >>> bool(-1e-9 < fun([1, -1]) - (31**2 + 1**2) < 1e-9)
    True
    >>> f = cma.ScaleCoordinates(cma.ff.sphere, [100, 1])
    >>> assert f[0] == cma.ff.sphere  # first element of f-composition
    >>> assert f(range(1, 6)) == 100**2 + sum([x**2 for x in range(2, 6)])
    >>> assert f([2.1]) == 210**2 == f(2.1)
    >>> assert f(20 * [1]) == 100**2 + 19
    >>> assert np.all(f.inverse(f.scale_and_offset([1, 2, 3, 4])) ==
    ...               np.asarray([1, 2, 3, 4]))
    >>> f = cma.ScaleCoordinates(f, [-2, 7], [2, 3, 4]) # last is recycled
    >>> bool(f([5, 6]) == sum(x**2 for x in [100 * -2 * (5 - 2), 7 * (6 - 3)]))
    True

    See also these [Practical Hints](https://cma-es.github.io/cmaes_sourcecode_page.html#practical)
    for encoding variables.
    Nc           	      <   t         j                  | || j                  g       | j                  | _        || _        || _        || _        || _        || _        d }||t        d      |dvr%t        j                  dj                  ||             t        j                  | j                  t              | _        |l|i || j                  | j                        \  | _        | _        t        j                  | j                         | j                  z  | _        n|||t        d      |d| _        |d	| _        |'t        j                  | j                        d
z   | _        t        j                   t        j                  | j                  t              | j                  z
  d	k        d	   }t#        |      r9t        dj                  | j                  | j                  t%        |                   || j                  | j                        \  | _        | _        | j                  d
   | j                  d	   z
  }	t        j                  | j                  t              | j                  z
  |	z  | _        | j                  d	   | j                  dz  | j                  z  z
  | _        | j                  d
   | j                  dz  | j                  z  z
  }
t'        j(                  | j
                  |
      s/t        j                  dj                  |
| j
                               |pt        j                  |t              | _        |%t        j                  dj                  ||             |&t        j                  dj                  ||             yyy)a=  
        :param fitness_function: a `callable` object
        :param multipliers: coordinate-wise multipliers.
        :param zero: defines a new zero in preimage space, that is,
            calling the `ScaleCoordinates` instance returns
            ``fitness_function(multipliers * (x - zero))``.
        :param upper: variable value to which from_lower_upper[1] maps.
        :param lower: variable value to which from_lower_upper[0] maps.

        Only either `multipliers` or 'upper` can be passed. If `zero` is
        passed then `upper` and `lower` are ignored. The arguments
        ``multipliers``, ``zero``, ``upper`` and ``lower`` can be vectors
        or scalars, superfluous trailing elements are ignored and the last
        element is recycled if needed to fit the length of the later given
        input.

        `from_lower_upper` is `(0, 1)` by default and defines the preimage
        values which are mapped to `lower` and `upper`, respectively
        (unless `multipliers` or `zero` are given). These two preimage
        values are always the same for all coordinates.

        Details
        -------
        The `upper` and `lower` and `from_lower_upper` parameters are used
        to assign `multipliers` and `zero` such that the transformation is
        then always computed from the latter two only.
        c                     	 t        |       t        |      }}||k  rt        j                  | |      } | |fS ||k  rt        j                  ||       }| |fS #  Y | |fS xY w)z:align shorter to longer array such that a1*a2 doesn't bailas_)r)   r   recycled)a1a2l1l2s       r   alignz(ScaleCoordinates.__init__.<locals>.align  sr    4R#b'B 73B r6M "W3Br6M D r6Ms   A ANz5Either `multipliers` or `upper` argument must be None)Nr   r   z?from_lower_upper={0} ignored because multipliers={1} were given)dtypezLEither `multipliers` or `zero` or `upper` or `lower` argument must be given.ry   r   r   zz`upper` value(s) must be stricly larger than `lower` value(s); values were:
 upper={0}
 lower={1}
 offending indices = {2}rD   zzero computed from upper and lower differ
 from upper={0}
 from lower={1}
 This may be a bug or due to small numerical deviationsz/lower={0} is ignored because zero={1} was givenz/upper={0} is ignored because zero={1} was given)r?   r   scale_and_offsetr`   
multiplierzerolowerupperfrom_lower_upper
ValueErrorrT   rU   formatr    r*   floatwherer)   r,   _Mhvequals_approximately)r   r   multipliersr}   r   r~   r   rx   idxdxzero_from_uppers              r   r   zScaleCoordinates.__init__~  s   : 	!!$!4#8#89	;..%	

 0
	 "  !XYY~5_%v&6DF jjFDO| 1.3DOOTZZ.P+ jj44tF	\}  "< = ='(.%}
}ZZ

3a7
((2::djj>KqPQRSTC3x  ">
 #)&TZZc"KM M &+4::tzz%B"DJ
&&q)D,A,A!,DDB!zz$**EBTZZOSUUDO--a04??B3F3SSDI"33A6"9Ltzz9YYO,,TYYH Z  &votyyA	C
 

4u5DI O%veT24 O%veT24 ! r   c                 H   t        j                        fd}| j                  6| j                  * || j                         || j                        z
  z  S | j                   || j                        z
  S | j                   || j                        z  S )Nc                 2    t        j                  |       S Nrq   r   rs   vecr4   s    r   rz,ScaleCoordinates.scale_and_offset.<locals>.r      >>#1--r   r    r*   r}   r|   r   r4   r   s    ` r   r{   z!ScaleCoordinates.scale_and_offset  s    JJqM	.99 T__%@$//"a!DII,&67A
 	 YY"AdiiL A  __($//"Q&Ar   c                 H   t        j                        fd}| j                  6| j                  * || j                        z   || j                        z   S | j                   || j                        z   S | j                   || j                        z  S )z\inverse of coordinate-wise affine transformation
        ``y / multipliers + zero``
        c                 2    t        j                  |       S r   r   r   s    r   r   z#ScaleCoordinates.inverse.<locals>.r  r   r   r   r   s    ` r   rI   zScaleCoordinates.inverse  s     JJqM	.99 T__%@Adoo&&4995A
 	 YY"AdiiL A  __(Adoo&&Ar   )NNNNry   )r8   r9   r:   r;   r   r{   rI   r=   r   r   rn   rn   ;  s$    AD AE:@b4H
r   rn   c                   "    e Zd ZdZd Zd Zd Zy)FixVariablesa9  Insert variables with given values, thereby reducing the
    dimensionality of the resulting composed function.

    The constructor takes ``index_value_pairs``, a `dict` or `list` of
    pairs, as input and returns a function with smaller preimage space
    than input function ``f``.

    Fixing variable 3 and 5 works like

        >>> from cma.fitness_transformations import FixVariables
        >>> index_value_pairs = [[2, 0.2], [4, 0.4]]
        >>> fun = FixVariables(cma.ff.elli, index_value_pairs)
        >>> fun[1](4 * [1]) == [ 1.,  1.,  0.2,  1.,  0.4, 1.]
        True

    Or starting from a given current solution in the larger space from
    which we pick the fixed values:

        >>> from cma.fitness_transformations import FixVariables
        >>> current_solution = [0.1 * i for i in range(5)]
        >>> fixed_indices = [2, 4]
        >>> index_value_pairs = [[i, current_solution[i]]  # fix these
        ...                                     for i in fixed_indices]
        >>> fun = FixVariables(cma.ff.elli, index_value_pairs)
        >>> fun[1](4 * [1]) == [ 1.,  1.,  0.2,  1.,  0.4, 1.]
        True
        >>> assert (current_solution ==  # list with same values
        ...            fun.transform(fun.insert_variables(current_solution)))
        >>> assert (current_solution ==  # list with same values
        ...            fun.insert_variables(fun.transform(current_solution)))

    Details: this might replace the ``fixed_variables`` option in
    `CMAOptions` in future, but hasn't been thoroughly tested yet.

    Supersedes `ExpandSolution`.

    c                 h    t         j                  | || j                  g       t        |      | _        y)zfreturn `f` with reduced dimensionality.

        ``index_value_pairs``:
            variables
        N)r?   r   insert_variablesrX   index_value_pairs)r   rg   r   s      r   r   zFixVariables.__init__#  s-     	!!$D,A,A(BC!%&7!8r   c                     t        t        |            D cg c]  }|| j                  vr||    }}t        |t              r|S t        j                  |      S c c}w )a;  transform `x` such that it could be used as argument to `self`.

        Return a list or array, usually dismissing some elements of
        `x`. ``fun.transform`` is the inverse of
        ``fun.insert_variables == fun[1]``, that is
        ``np.all(x == fun.transform(fun.insert_variables(x))) is True``.
        )r   r)   r   
isinstancer,   r    r*   )r   r4   rF   ress       r   r`   zFixVariables.transform,  sZ     #3q6] 4]D222 t] 4 D)s>rzz#>4s   Ac                    t        | j                        dk(  r|S t        |      }t        | j                        D ]!  }|j	                  || j                  |          # t        |t              st        j                  |      }|S )z%return `x` with inserted fixed valuesr   )r)   r   r,   sortedinsertr   r    r*   )r   r4   yrF   s       r   r   zFixVariables.insert_variables7  sm    t%%&!+HG../AHHQ..q12 0!T"

1Ar   N)r8   r9   r:   r;   r   r`   r   r=   r   r   r   r     s    $J9
?	r   r   c                       e Zd ZdZddZd Zy)	ExpensifyzIAdd waiting time to each evaluation, to simulate "expensive"
    behaviorc                 J    t         j                  |        || _        || _        y)zadd time in secondsN)r   r   timecallable)r   r0   r   s      r   r   zExpensify.__init__E  s    $	!r   c                     t        j                  | j                          t        j                  | g|i |  | j                  |i |S r7   )r   sleepr   r6   r   )r   r.   r/   s      r   r6   zExpensify.__call__J  s@    

499$000t}}d-f--r   N)r   r[   r=   r   r   r   r   B  s    "
.r   r   c                       e Zd ZdZddZd Zy)SomeNaNFitnessz:transform ``fitness_function`` to return sometimes ``NaN``c                 J    t         j                  |        || _        || _        y r7   )r   r   r   p)r   r   probability_of_nans      r   r   zSomeNaNFitness.__init__Q  s    $ 0#r   c                     t        j                  | |g|  t        j                  j	                  d      | j
                  k  rt        j                  S  | j                  |g| S )Nr   )r   r6   r    randomrandr   nanr   )r   r4   r.   s      r   r6   zSomeNaNFitness.__call__U  sQ    $)D)99>>!&66M(4((2T22r   N)g?r[   r=   r   r   r   r   O  s    D$3r   r   c                   &    e Zd ZdZd d fdZd Zy)NoisyFitnessz<apply noise via ``f += rel_noise(dim) * f + abs_noise(dim)``c                 J    dt         j                  j                         z  | z  S Ng?r    r   randndims    r   <lambda>zNoisyFitness.<lambda>_  s    sRYY__->'>'Dr   c                 D    dt         j                  j                         z  S r   r   r   s    r   r   zNoisyFitness.<lambda>`  s    sRYY__->'>r   c                 L    t         j                  | |       || _        || _        y)a  attach relative and absolution noise to ``fitness_function``.

        Relative noise is by default computed using the length of the
        input argument to ``fitness_function``. Both noise functions take
        ``dimension`` as input.

        >>> import cma
        >>> from cma.fitness_transformations import NoisyFitness
        >>> fn = NoisyFitness(cma.ff.elli)
        >>> assert fn([1, 2]) != cma.ff.elli([1, 2])
        >>> assert fn.evaluations == 1

        N)r   r   	rel_noise	abs_noise)r   r   r   r   s       r   r   zNoisyFitness.__init__^  s#      	$ 01""r   c                    t        j                  | |g| }| j                  r7||| j                  t        |            z  z  }t	        j
                  |      sJ | j                  r|| j                  t        |            z  }|S r7   )r   r6   r   r)   r    isscalarr   )r   r4   r.   rg   s       r   r6   zNoisyFitness.__call__r  so    dA-->>T^^CF+++A;;q>!>>>A''Ar   Nr[   r=   r   r   r   r   \  s    FD>#(r   r   c                   <    e Zd ZdZej
                  dfdZd Zd Zy)IntegerMixedFunction2au  compose fitness function with some integer variables using `np.round` by default.

    >>> import numpy as np
    >>> import cma
    >>> f = cma.s.ft.IntegerMixedFunction2(cma.ff.elli, [0, 3, 5])
    >>> assert f([-0.2, 2]) == f([0.4, 2]) != f([0.8, 2])
    >>> f = cma.s.ft.IntegerMixedFunction2(cma.ff.elli, [0])
    >>> assert f([-0.2, 2]) == f(np.array([0.4, 2])) != f(np.array([0.8, 2]))

    Related: Option ``'integer_variables'`` of `cma.CMAOptions` sets
    ``'minstd'`` of integer variables, see
    `cma.options_parameters.integer_std_lower_bound` and rounds the better
    solutions, see `cma.integer_centering`.
    Tc                 r    t         j                  | || j                  g       || _        || _        || _        y)zapply operator(x[i]) for i in integer_variable_indices before to call function(x).

        If `copy`, return a copy iff a value is changed.
        N)r?   r   _flatteninteger_variable_indicesoperatorcopy)r   functionr   r   r   s        r   r   zIntegerMixedFunction2.__init__  s3    
 	!!$4==(AB(@% 	r   c                     || j                      }t        j                  |      }t        j                  ||k(        s2| j                  rt        j
                  |d      }||| j                   <   |S NTr   )r   r    roundallr   array)r   r4   values
new_valuess       r   	_flatten2zIntegerMixedFunction2._flatten2  s]    4001XXf%
vvjF*+yyHHQT*/9Ad++,r   c                 h   t        |t        j                        r| j                  |      S d}t	        | j
                        D ]l  }|t        |       k  r|t        |      k\  r |S | j                  ||         }||   |k7  sA|s%| j                  rt        j                  |d      }d}|||<   n |S )NFTr   )
r   r    ndarrayr   r   r   r)   r   r   r   )r   r4   copiedrF   ms        r   r   zIntegerMixedFunction2._flatten  s    a$>>!$$556ACF7{CF{  ad#Atqy$)).A!F! 7 r   N)	r8   r9   r:   r;   r    r   r   r   r   r=   r   r   r   r   {  s$     EGHHSW r   r   c                   6    e Zd ZdZej
                  dfdZd Zy)IntegerMixedFunctionaf  DEPRECATED compose fitness function with some integer variables using `np.floor` by default.

    >>> import cma
    >>> f = cma.s.ft.IntegerMixedFunction(cma.ff.elli, [0, 3, 6])
    >>> assert f([0.2, 2]) == f([0.4, 2]) != f([1.2, 2])

    It is advisable to set minstd of integer variables to
    ``1 / (2 * len(integer_variable_indices) + 1)``, in which case in
    an independent model at least 33% (1 integer variable) -> 39% (many
    integer variables) of the solutions should have an integer mutation
    on average. Option ``integer_variables`` of `cma.CMAOptions`
    implements this simple measure.
    Tc                 r    t         j                  | || j                  g       || _        || _        || _        y)zQapply operator(x[i]) for i in integer_variable_indices before to call function(x)N)r?   r   r   r   r   copy_arg)r   r   r   r   r   s        r   r   zIntegerMixedFunction.__init__  s1    !!$4==(AB(@%  r   c                    | j                   rt        j                  |d      }nt        j                  |      }t	        | j
                        D ]:  }|t        |       k  r|t        |      k\  r |S | j                  ||         ||<   < |S r   )r   r    r   r*   r   r   r)   r   )r   r4   rF   s      r   r   zIntegerMixedFunction._flatten  s}    ==&A

1A556ACF7{CF{ ==1&AaD 7 r   N)r8   r9   r:   r;   r    floorr   r   r=   r   r   r   r     s     EGHHW[ !r   r   )*r;   
__future__r   r   r   rT   	functoolsr   numpyr    r   	utilitiesr   utilities.mathr	   r   transformationsr
   r   boundary_handlerr   optimization_toolsr   utilities.python3for2r   rh   objectr   r,   r?   rK   rR   r]   rd   rj   rn   r   r   r   r   r   r   r=   r   r   <module>r      s    @ @      % 6 , - (X~	Y"v Y"vDx DL]H ]2&2H &2PA& A@5 5,4 4"@' @DC# CJ. .3X 38 >/, /b+ r   