
    J-jL                     P   d Z ddlmZmZmZ ddlZddlZddl	m
Z
 [[[d ZddZd Zeej                  j                  fd	Zed
 ej                  j                  fdZd Z ej&                  dd       ddZddZd Zd ZddZdZd Z G d de      Zd Z G d de      ZeZy) zT various math utilities, notably `eig` and a collection of simple
functions in `Mh`
    )absolute_importdivisionprint_functionN   )rangec                 <    t        | t              r| S t        |       S )a  remove np type of a number, return `int` or `float`.

    Return the unchanged argument iff ``isinstance(float_, int)``.

    Remark that `np.float64` is an instance of `float` however `np.int64`
    is not an instance if `int` (for good reasons). That is,
    ``isinstance(np.array([1])[0], int) is False`` while
    ``isinstance(np.array([1.])[0], float) is True``, as of numpy 2.x in 2025.
    )
isinstanceintfloat)float_s    `/Users/jameslopez/projects/TradingBot25/.venv/lib/python3.12/site-packages/cma/utilities/math.pyifloatr      s      ,6?%-?    c                     t        | t              rMt        |       |k  r?t        | d   t              s,t	        | d         | d   ur| D cg c]  }t        |       c}S | S c c}w )z(make print([np.float64(3.3)]) look nicerr   )r	   listlenr
   r   r   )limaxlenis      r   lifloatr      s[    2tRF!22a5#&5A<r!u+D#%&2aq	2&&I 's   	A c                     t        |       dz  S )N      ?)r   )xs    r   	_sqrt_lenr   !   s    q63;r   c                 t     || |      }|D ])  }| ||      t        j                  |dz        dz  z  z  }+ |S )ap  `n` iid `dim`-dimensional vectors with length ``norm_(vector)``.

    The vectors are uniformly distributed on a hypersphere surface.

    CMA-ES diverges with popsize 100 in 15-D without option
    'CSA_clip_length_value': [0,0].

    >>> from cma.utilities.math import randhss
    >>> dim = 3
    >>> assert dim - 1e-7 < sum(randhss(1, dim)[0]**2) < dim + 1e-7

       r   )npsum)ndimnorm_randnarvvs         r   randhssr%   $   sB     3-C	U1Xq!tc))) Jr   c                     d| z  S )N      ? )ds    r   <lambda>r*   7   s    b1fr   c                     t        | |||      }t        d ||      f      }|dkD  r:|dkD  rt        d|z        |D ]"  }|d|dz  z
  dz  z  }|| |d|      d   z  z  }$ |S )z`n` iid vectors uniformly distributed on the hypersphere surface with
    mixing in of normal distribution, which can be beneficial in smaller
    dimension.
    r   r   zc(dim)=%f should be <=1r   r   )r%   min
ValueError)r   r    r!   cr"   r#   r$   s          r   randhss_mixinr/   6   s     !S%
'CQ#KA1uq56:;;A!ad(S AU1c]1%%%A  Jr   c                    t        | j                  d         D ].  }| ||f   dz  }| dd|fxx   |z  cc<   | |ddfxx   |z  cc<   0 | | j                  z   dz  } t        j                  t        j
                  |       d      sJ | S )z:change C in place into a correlation matrix, AKA whiteningr   r   N       @r   )r   shapeTr   allclosediag)r.   r   facs      r   to_correlation_matrixr7   F   s    1771:1gsl	!Q$3	!Q$3  
QSSCA;;rwwqz1%%%Hr   oncez3using exponential smoothing with .* rolling average)messagec                    |dk(  r| S t        |t              rxt        |t        |       f      }t	        j
                  t        d|      D cg c]  }t	        j                  | d|        c}t	        j                  | |d|z  gz  d      g      S |t        |      k(  r$t        j                  dj                  |             dd|z  z
  }t	        j                  t        t        |             D cg c]\  }t        t        |dz         D cg c]  }||z  | ||z
     z   c}      t        t        |dz         D cg c]  }||z  	 c}      z  ^ c}}      S c c}w c c}w c c}w c c}}w )u=  rolling average without biasing boundary effects.

    The first entries give the average over all first
    values (until the window width is reached).

    If `w` is not an integer, expontential smoothing with weights
    proportionate to ``(1 - 1/w)**i`` summing to one is executed, thereby
    putting about 1 - exp(-1) ≈ 0.63 of the weight sum on the last `w`
    entries.

    Details: the average is mainly based on `np.convolve`, whereas
    exponential smoothing is for the time being numerically inefficient and
    scales quadratically with the length of `x`.
r   Nvalid)modez^using exponential smoothing with time horizon {0}. 
Use `int` type to get the rolling average.)r	   r
   r,   r   r   hstackr   meanconvolve	_warningswarnformatasarrayr   )r   wr   r$   js        r   moving_averagerF   R   sW    	Av	As	CFyy5A;?;a2771Ra5>;?++aa!eW7CE F 	F A;NN //5vay: AIzz$)#a&M3$1q uQU|D|!1q1v|DE"%A,#?,QAqD,#?@A$13 4 	4 @  E#?3s*   E0E(

EE(
:E#E(

E(
c                    |d}t        j                  |      }t        j                  t        |            }d|z  }t	        t        |            D ]k  }|||   z  }t	        |dz         D ]P  }|||   z  } | ||z   |z          | ||z         z
   | ||z         z
   | |      z   |dz  z  |||f<   |||f   |||f<   R m |S )z Hessian estimate for `f` at `x0`ư>r   r   r   )r   rC   eyer   r   )	fx0epseHr   eirE   ejs	            r   HessianrQ   q   s    
{	BB
s2wA	AA3r7^1Q4ZqsAqtBR"o"r'
2QrBwZ?!B%G3PQ6QAacF1gAadG   Hr   c                 z    t        j                  t        j                  t        j                  |       fi |      S )zreturn geometric standard deviation of `vals`.

    The gsd is invariant under linear scaling and independent
    of the choice of the log-exp base.

    ``kwargs`` are passed to `np.std`, in particular `ddof`.
    )r   expstdlog)valskwargss     r   geometric_sdrX      s)     66"&&0011r   c           	      2   t        j                  | dkD        st        j                  | dk        rt        dj                  |             d } |d       dz  } || t        j                  dt        j
                  |        dz        z        || dz  z  z   S )a  return an approximation of the inverse cdf value of a standard normal distribution,

    assuming 0 < p <= 1/2. This is the "sigma" for which the tail
    distribution has probability `p` (AKA quantile or percentile point
    function).

    For ``p=1/2`` we have ``sigma = 0``. The approximation ``0.79 + 1.49 x
    sqrt(-log(p)) + alpha x sqrt(p)``, where alpha=0.637... is such that
    p=1/2 maps to sigma=0, has a sigma error within [-0.02, 0.029] for ``p
    >= 1e-12`` and for ``p >= 1e-22`` with an additional correction as
    applied. The error is less than 0.0121 for all p <= 0.1. The relative
    sigma error for p->1/2 and hence sigma->0 is < 0.11.

    The input `p` may be an `np.array`.

    The following is the Python code to assess the accuracy::

        %pylab
        import scipy
        from scipy import stats
        import cma

        normal_ppf = cma.utilities.math.normal_ppf

        pp = np.logspace(-15, np.log10(0.5), 5400)  # target tail probabilities

        if 1 < 3:  # sigma vs p
            figure(53)
            gcf().clear()
            grid(True, which='both')
            xlabel('tail probability')
            ylabel('sigma')
            semilogx(pp, normal_ppf(pp), label='approximation')
            semilogx(pp, scipy.stats.norm.ppf(pp), label='true')
            legend()
            # semilogx(pp, -sqrt(7 * log(1/pp/4 + pp)) / 2)
            # semilogx(pp, -scipy.stats.norm.ppf(pp/2))
            # semilogx(pp, sqrt(7 * log((1/pp + pp) / 2)) / 2)
        if 1 < 3:  # Delta sigma vs p
            figure(54)
            gcf().clear()
            grid(True, which='both')
            xlabel('tail probability')
            ylabel('sigma difference (error)')
            semilogx(pp, normal_ppf(pp) - scipy.stats.norm.ppf(pp),
                    label='absolute')
            abs_error = max(np.abs(normal_ppf(pp) - scipy.stats.norm.ppf(pp)))
            semilogx(pp, (normal_ppf(pp) - scipy.stats.norm.ppf(pp)) / np.maximum(1e-12, -scipy.stats.norm.ppf(pp)),
                    label='relative')
            rel_error = max((normal_ppf(pp) - scipy.stats.norm.ppf(pp))
                              / np.maximum(1e-12, -scipy.stats.norm.ppf(pp)))
            ylim(-max(np.abs(ylim())), max(np.abs(ylim())))
            text(xlim()[0], ylim()[0] * 0.98,
                ' the largest absolute and relative errors are {} and {}'
                .format(np.round(abs_error, 6), np.round(rel_error, 6)))
            legend()
        if 11 < 3:
            figure(55)
            gcf().clear()
            grid(True, which='both')
            xlabel('tail probability')
            ylabel('sigma ratio')
            semilogx(pp, normal_ppf(pp) / scipy.stats.norm.ppf(pp))
        if 11 < 3:
            figure(56)
            gcf().clear()
            ylabel('probability ratio')
            xlabel('sigma')
            plot(stats.norm.ppf(pp), stats.norm.cdf(normal_ppf(pp)) / pp)
            grid(True, which='both')
        if 1 < 3:  # true p of sigma vs p input
            figure(56)
            gcf().clear()
            ylabel('true probability ratio')
            xlabel('tail probability (input)')
            semilogx(pp, pp / stats.norm.cdf(normal_ppf(pp)))
            grid(True, which='both')

    The approximation is by construction exact for p=1/2. For small
    probabilities (sigma < -7), the probability is quite sensitive: roughly
    speaking, a Delta sigma of 0.05 / 0.25 / 1 changes the probability by a
    factor of 1.4 / 3 / 50, respectively.
    r   r   z&0 < p <= 1/2 is required but p was {0}c                 `    ddt        j                  t        j                  |              z  z
  S )zia sigma approximation with an error in ]-0.013, 0.008[ for 1e-12 <= p <= 1e-4 where sigma < -3.5
        gHzG?gףp=
?)r   sqrtrU   )ps    r   valznormal_ppf.<locals>.val   s'     dRWWbffQiZ0000r   g;f?r      )r   anyr-   rB   maximumrU   )r\   r]   r6   s      r   
normal_ppfra      s    h 
vva#g"&&a.AHHKLL1 H*z
!Cq2::a"&&)b11 3, r   c                     	 ddl }||}t	         |j
                  j                  j                  | || z
  g|||z
  ggfi |j                        S # t        $ r t        j                  d       Y yw xY w)a
  test (success) frequency nsucc1 of n1 against nsucc2 of n2.

    By default, ``n2 = n1``, hence `n2` can be omitted in this case. The
    frequency data ``nsucc1, n1, nsucc2, n2`` and the `kwargs` are passed to
    `scipy.stats.contingency.chi2_contingency` for a chi-square test of
    independence.

    Return the probability that both success "frequencies" stem from the same
    underlying distribution (H0). More specifically, return the probability
    (upper bound) to observe the given or a greater discrepancy between the two
    success frequency data, given the data stem from the same distribution
    (formally, are independent of the "row" index (1, 2), hence "test of
    independence").

    Example: when testing 3 versus 8 successes observed in 25 trials
    respectively, we find that p = 0.17 = 17% or about 1/6 under H0::

        import cma
        cma.utilities.math.testchisquare(3, 25, 8)

        0.17207161769462614

    Details: testing the successes ``nsucc1, nsucc2`` is equivalent to testing the
    respective failures ``n1 - nsucc1, n2 - nsucc2``.

    With ``n1 = n2 = 15``, we test ``nsucc1 = [0, 1, ...]`` against several ``nsucc2``::

        import cma
        t = cma.utilities.math.testchisquare  # scipy needs to be installed

        n = 15
        print('nsucc   nfail   p')
        for p1 in range(6):
            for delta in [4, 5, 6]:
                p2 = p1 + (p1 > 1) + delta
                print(' {} {} (= {} {}) {:.2}'.format(
                        p1, p2, n-p1, n-p2, t(p1, n, p2)))
            print(' ')

        nsucc   nfail   p
         0 4 (= 15 11) 0.11
         0 5 (= 15 10) 0.05
         0 6 (= 15 9) 0.022
         
         1 5 (= 14 10) 0.17
         1 6 (= 14 9) 0.084
         1 7 (= 14 8) 0.039
         
         2 7 (= 13 8) 0.11
         2 8 (= 13 7) 0.053
         2 9 (= 13 6) 0.023
         
         3 8 (= 12 7) 0.13
         3 9 (= 12 6) 0.062
         3 10 (= 12 5) 0.027
         
         4 9 (= 11 6) 0.14
         4 10 (= 11 5) 0.067
         4 11 (= 11 4) 0.028
         
         5 10 (= 10 5) 0.14
         5 11 (= 10 4) 0.067
         5 12 (= 10 3) 0.027

    Testing 1 (of n=15) versus 6 yields p=0.084 (4-th row), testing 1 versus 7
    yields p=0.039. The shown p-values are monotonuously increasing(!) with
    increasing n: with n = 7, the mentioned p-values are smaller (about 0.033
    and 0.007, respectively), with ``n -> infinity`` they reach about 0.13 and
    0.077, respectively.

    Remark: under H0, p~U[0,1], hence E ln(p) = -1 and the geometric average p
    equals 1/e.
r   N6Please 'pip install scipy' to run the statistical test)	scipy.statsImportErrorr@   rA   r   statscontingencychi2_contingencypvalue)nsucc1n1nsucc2n2rW   scipys         r   testchisquarero      s    T 
z9((99 "v+.f0EF" ""(&* *  OPs   A A10A1i  c                 B   	 ddl }t	        |       t	        |      z  t
        k  }|j                  d|rdnd       |j                  dd       t         |j                  j                  | |fi |j                        S # t        $ r t        j                  d       Y yw xY w)	aD  return p-value computed with `mannwhitneyu` from `scipy.stats`.

    ``testranksum(data1, data2)`` returns the probability that `data1` and
    `data2`, or more discrepant data, are generated while P(d1 < d2) = P(d1 >
    d2) = 1/2 is true (AKA H0).

    This function calls `scipy.stats.mannwhitneyu` passing data and `kwargs`,
    setting by default ``alternative='two-sided'`` and ``method='exact' if
    len(data1) * len(data2) < 55000 else 'auto'``. Pass ``method='auto'`` when
    execution speed is an issue.

    The minimal data sizes to possibly get p < 1% two-sided are::

        import cma
        ranksum = cma.utilities.math.testranksum
        [(n, 1e-4 * int(0.5 + 1e4 *  # round and remove np type
             ranksum(range(n[0]), range(n[0], n[0] + n[1]))))
                for n in [[5, 5], [4, 6], [3, 9], [2, 19], [1, 200]]]
        # n1, n2, p-value
        [([5, 5], 0.0079),
         ([4, 6], 0.0095),
         ([3, 9], 0.0091),
         ([2, 19], 0.0095),
         ([1, 200], 0.01)]

    The probabilities are exactly doubled with ``'alterative='less'`` passed as
    argument.

    Details: the above threshold for ``method='exact'`` can be changed by
    assigning `cma.utilities.math._testranksum_method_exact_threshold`.

    Remark: under H0, p~U[0,1], hence E ln(p) = -1 and the geometric average p
    equals 1/e.
r   Nrc   methodexactautoalternativez	two-sided)rd   re   r@   rA   r   #_testranksum_method_exact_threshold
setdefaultr   rf   mannwhitneyuri   )data1data2rW   rn   rr   s        r   testranksumrz   G  s    F JU#&IIE
h5f=
m[1)))%A&AHHII  OPs   A= =BBc                   2    e Zd ZdZd Zd Zd Zed        Zy)UpdatingAveragez=use instead of a `list` when too many values must be averagedc                      d| _         d| _        y )Nr   )countr   selfs    r   __init__zUpdatingAverage.__init__v  s    
r   c                      | |       y Nr(   r   r]   s     r   appendzUpdatingAverage.appendy  s	    S	r   c                 X    | xj                   |z  c_         | xj                  dz  c_        y)z"add a value to compute the averager   Nr   r~   r   s     r   __call__zUpdatingAverage.__call__{  s    C

a
r   c                 4    | j                   | j                  z  S )zcurrent average valuer   r   s    r   valuezUpdatingAverage.value  s     xx$**$$r   N)	__name__
__module____qualname____doc__r   r   r   propertyr   r(   r   r   r|   r|   t  s(    G % %r   r|   c           	         d }d }t        | d         }ddk  r`t        j                  | D cg c]  }|dd 	 c}      }|d   j                  }t        j                  |      }t        j                  |      }n7| D cg c]  }t        |      D cg c]  }||   	 c}  }}}|dgz  }|dgz  } |||||        |||||       t        j                  |      t        j                  |      fS c c}w c c}w c c}}w )a  eigendecomposition of a symmetric matrix, much slower than
    `numpy.linalg.eigh`, return ``(EVals, Basis)``, the eigenvalues
    and an orthonormal basis of the corresponding eigenvectors, where

        ``Basis[i]``
            the i-th row of ``Basis``
        columns of ``Basis``, ``[Basis[j][i] for j in range(len(Basis))]``
            the i-th eigenvector with eigenvalue ``EVals[i]``

    c                 
   d}t        |       D ]  }|| dz
     |   ||<    t        | dz
  dd      D ]%  }d}|s$d}t        |      D ]  }	|t        ||	         z   } nt        t        |d|             }|dk(  r;||dz
     ||<   t        |      D ]   }||dz
     |   ||<   d||   |<   d||   |<   " n|s,t        |      D ]  }	||	xx   |z  cc<   |||	   ||	   z  z  } n*|d |xxx |z  ccc t        j                  |d | |d |       }||dz
     }
|dz  }|
dkD  r| }||z  ||<   ||
|z  z
  }|
|z
  ||dz
  <   |st        |      D ]  }d||<   	 nd|d | t        |      D ]  }||   }
|
||   |<   ||   ||   |   |
z  z   }|sAt        |dz   |      D ])  }	|||	   |   ||	   z  z  }||	xx   ||	   |   |
z  z  cc<   + |||<   d||dz   |xxx |j
                  |   |dz   | |
z  z  ccc |t        j                  |j
                  |   |dz   | ||dz   |       z   ||<    d}
|s,t        |      D ]  }||xx   |z  cc<   |
||   ||   z  z  }
 n-|d |xxx |z  ccc |
t        j                  |d | |d |       z  }
|
||z   z  }|s$t        |      D ]  }||xx   |||   z  z  cc<    n|d |xxx ||d | z  z  ccc t        |      D ]  }||   }
||   }|s1t        ||      D ]!  }	||	   |xx   |
||	   z  |||	   z  z   z  cc<   # n*|j
                  |   ||xxx |
||| z  |||| z  z   z  ccc ||dz
     |   ||<   d||   |<    |||<   ( t        | dz
        D ]}  }||   |   || dz
     |<   d||   |<   ||dz      }|dk7  r|s%t        |dz         D ]  }	||	   |dz      |z  ||	<    n!|j
                  |dz      d |dz    |z  |d |dz    t        |dz         D ]  }|sVd}t        |dz         D ]  }	|||	   |dz      ||	   |   z  z  } t        |dz         D ]  }	||	   |xx   |||	   z  z  cc<    [t        j                  |j
                  |dz      d|dz    |j
                  |   d|dz          }|j
                  |   d |dz   xxx ||d |dz    z  z  ccc  |s t        |dz         D ]  }	d||	   |dz   <    fd|j
                  |dz      d |dz     |s*t        |       D ]  }|| dz
     |   ||<   d|| dz
     |<    n|| dz
     d |  |d |  d|| dz
     d |  d|| dz
     | dz
  <   d|d<   y )NFr   r           r   r'   )r   absr   r   dotr3   )r   Vr)   rM   num_optrE   r   hscalekrJ   ghhs                r   tred2zeig.<locals>.tred2  sy    qAQU8A;AaD 
 q1ua$AAqA!C!I-E " C!AK(|Qx!qAQU8A;AaD!AaDG!AaDG " "1X!QqTAaD[( & bqEUNEq!uae,Aa!eHsFq5Aqy!AIq5!a%"1X"! &  AbqE qA!AAaDG!qtAw{*A"!&q1uaA1a1Q4/AaDAaDGaK/D "1  !!!a%
acc!fQU1o&99
 266!##a&Qq/1QU1:#FF! " "1X!	QqTAaD[( & bqEQJE"1q!u--A!a%["1X!QqT	) & bqER!BQ%Z'EqA!A!A"!&q!AaDGAaD1qt8(;<G "- AqAaF
Q1QZ(?@QU8A;AaD!AaDG " AaDk %t q1uAA$q'Aa!eHQKAaDG!a%ACx"1q5\ tAE{Q! * !"AE
6AE 2Q 6Afq1uIq1uA"!&q1uA1a!eqtAw!66A ".!&q1uAaDGq1Q4x/G ". FF133q1u:aA#6AqQHAvA!aQi-7 & q1uA"%AaDQK & &)AE
6AE"5 : 1XQx{!!!a%  a!eHRaLAbqEAa!eHRaL!a%Q!r   c           	         d}|st        d|       D ]  }||   ||dz
  <    n|d|  |d| dz
   d|| dz
  <   d}d}d}t        |       D ]  }	t        |t        ||	         t        ||	         z         }|	}
|
| k  r t        ||
         ||z  k  rn|
dz  }
|
| k  r |
|	kD  r*d}	 |dz  }||	   }||	dz      |z
  d||	   z  z  }|dz  dz   dz  }|dk  r| }||	   ||z   z  ||	<   ||	   ||z   z  ||	dz   <   ||	dz      }|||	   z
  }|s"t        |	dz   |       D ]  }||xx   |z  cc<    n||	dz   | xxx |z  ccc ||z   }||
   }d	}|}|}||	dz      }d}d}t        |
dz
  |	dz
  d
      D ]#  }|}|}|}|||   z  }||z  }|dz  ||   dz  z   dz  }||z  ||dz   <   ||   |z  }||z  }|||   z  ||z  z
  }||||z  |||   z  z   z  z   ||dz   <   |sMt        |       D ]>  }||   |dz      }|||   |   z  ||z  z   ||   |dz   <   |||   |   z  ||z  z
  ||   |<   @ |j                  |dz      j	                         }||j                  |   z  ||z  z   |j                  |dz   <   ||j                  |   z  ||z  z
  |j                  |<   & | |z  |z  |z  ||	   z  |z  }||z  ||	<   ||z  ||	<   t        ||	         ||z  k  rn'||	   |z   ||	<   d||	<    ddk  rt        | dz
        D ]n  }|}||   }t        |dz   |       D ]  }||   |k  s|}||   } ||k7  s4||   ||<   |||<   t        |       D ]   }||   |   }||   |   ||   |<   |||   |<   " p y y )NFr   r   r   g      <r1   r   r   r'   r         )r   maxr   r3   copy)r   r)   rM   r   r   r   rJ   tst1rL   lmiiterr   r\   rdl1r   r.   c2c3el1ss2r   r   rE   s                             r   tql2zeig.<locals>.tql2?  s    1a[Q4!a% ! 1QAaAJ!a%qA tS1YQqT23DAa%qt9d
*Q a% 1uQJE !A1q5A#!*5AACA1uBQ41q5>AaD tq1u~Aa!eHAE(CAaDA"!&q1uaAaDAID "1 !a%
a
AA !AABBAE(CAB #1q5!a%4!HETAaD!G^c1#$q5!a%aD1HE!Hq1u,#$qAEA!H,<'=#=!a%  '%*1X$%aDQK./!A$q'kAE.A!QU*+ad1g+A*=!Q &.
 "#QU!2B)*QSSVa"f)<ACCAJ%&QZ!b&%8ACCF1 58 R"s*QqT1C7Aq5AaDq5AaD 1Q4yC$J.I N Q4!8AaDAaDq x 61q5\aDq1uaAtaxaD )
 6Q4AaDAaD"1XaDG"#A$q'!Q"#!Q & " r   r   r   r   Nr   )r   r   arraysizezerosr   )	Cr   r   Nr   r   r)   rM   r   s	            r   eigr     s    LMf~$B 	AaD	A	AvHHA&AqadA&'aDIIHHQKHHQK/01q!E!H%HqadH%q1HH	!Q1Aq!88A;## '
 &1s   C1?C;C6C;6C;c                      e Zd ZdZed        Zed#d       Zed#d       Zeej                  j                  fd       Zed        Zed        Zed        Zed	        Zed
        Zed        Zed$d       Zed%d       Zed&d       Zed%d       ZdddddddZ e eg d            Zed        Zeg ddfd       Zeej6                  fd       Zeej6                  fd       Zed'd       Zed         Zed!        Z ed(d"       Z!y))MathHelperFunctionszstatic convenience math helper functions, if the function name
    is preceded with an "a", a numpy array is returned

    TODO: there is probably no good reason why this should be a class and not a
    module.

    c                 4    t         j                  |  |        S r   )r   apos)r   uppers     r   aclampzMathHelperFunctions.aclamp  s    #((!eV444r   c                     | dk  r
d| z  d|z  }} | |z
  |cxk  xr | |z   k  nc xs d|z
  | z  |cxk  xr d|z   | z  k  S c S Nr   r   r   r(   )abrL   s      r   equals_approximatelyz(MathHelperFunctions.equals_approximately  sW    q5626qAC!%a#g%MAGq=1+LC1}+LM+LMr   c                    t        j                  |       t        j                  |      }} t        j                  | dk        d   }t        |      rd| |   z  d||   z  c| |<   ||<   t	        t        j
                  | |z
  |k        xr t        j
                  || |z   k        xs> t        j
                  d|z
  | z  |k        xr t        j
                  |d|z   | z  k              S r   )r   r   nonzeror   boolall)r   r   rL   idxs       r   vequals_approximatelyz)MathHelperFunctions.vequals_approximately  s    xx{BHHQK1jjQ"s8!C&["qv+NAcFAcFRVVAGaK(@RVVACK-@ QC1}q01ObffQ!c'Q=N6OR 	Rr   c                      ||       \  }}t        j                  |t        j                  |      |z  j                        S )z)matrix exponential for a symmetric matrix)r   r   rS   r3   )Ar   DBs       r   expmszMathHelperFunctions.expms  s4    
 1v1vva"&&)a-**++r   c                 T    t        j                  t        j                  | |            S r   )r   r   r   r   )vecvec_or_scalars     r   amaxzMathHelperFunctions.amax  s    xx+//]CDDr   c                     |}t        j                  |      r| D cg c]  }t        ||       }}|S t        t	        |             D cg c]  }t        | |   ||          }}|S c c}w c c}w r   )r   isscalarr   r   r   )r   r   r   r   r   r   s         r   r   zMathHelperFunctions.max  sp    ;;q>$'(CqQCA(  -2#s*,=>,=qSVQqT",=A> )>s   A&	A+c                 @    ||k  sJ t        |t        | |f      f      S r   )r,   r   )r]   min_valmax_vals      r   minmaxzMathHelperFunctions.minmax  s)    '!!!GS#w0122r   c                 ~    t        j                  | D cg c]  }t        |t        ||f      f       c}      S c c}w r   )r   r   r,   r   )r]   r   r   r$   s       r   aminmaxzMathHelperFunctions.aminmax  s6    xxCHCqgsAw<'89:CHIIHs   :c                 T    t        j                  t        j                  | |            S r   )r   r   r   r,   )r   vec_or_scalar2s     r   aminzMathHelperFunctions.amin   s    xx+//~NOOr   c                 .   t         j                  } ||       r ||      rt        | |      S  ||       r|| }}  ||      r| D cg c]  }t        ||       c}S t        t	        |             D cg c]  }t        | |   ||          c}S c c}w c c}w r   )r   r   r,   r   r   )r   r   issr   r   s        r   r,   zMathHelperFunctions.min  s    kkq6c!fq!9q6aqAq6'()q!C1Iq))-238_=_C!adO_== *=s   B1Bc                 *    t        | |z        d|z  z  S )Nr   )r   )r   expos     r   normzMathHelperFunctions.norm  s    39~D))r   c                 8    |dk(  r| dkD  | z  S || |kD  | |z
  z  z   S )z4clips argument (scalar or array) from below at lowerr   r(   )r   lowers     r   r   zMathHelperFunctions.apos  s1     A:EQ;AI!e)444r   Nc                     |t        j                  |      dz   }t        j                  |       |z
  }~ t        j                  |      |z
  }|dkD  ||k  |dz  dz  z  ||kD  |z  ||dz  z
  z  z   z  S )aY  Huber-like smooth penality which starts at lower.

        The penalty is zero below lower and affine linear above upper.

        Return::

            0, if x <= lower
            quadratic in x, if lower <= x <= upper
            affine linear in x with slope upper - lower, if x >= upper

        `upper` defaults to ``lower + 1``.

        r   r   r   r   rC   )r   r   r   zus        r   apenalty_quadlinz$MathHelperFunctions.apenalty_quadlin  s~     =JJu%)EJJqME!JJu%A16a1fqj1QUaK1q1u94MMNNr   c                     t        j                  |       }||dz  k  |dz  |d|z  z  z   z  ||dz  k\  t        j                  |       z  z   |z   S )a  y-shifted Huber function, return huber(x, delta) + delta/2 + eps.

        `huber2` maps `x` to ``abs(x) + eps`` if ``abs(x) >= delta`` and
        otherwise to a quadratic law of `x` mapping 0 to ``delta/2 + eps``
        which makes the first derivative of `huber2` continuous.

        Details: `x` may be scalar or a `numpy` array. Setting eps =
        -delta/2 recovers the Huber loss.

        >>> import numpy as np
        >>> import cma
        >>> hus = cma.utilities.math.Mh.huber2(np.asarray([
        ...     -1, -0.8, -0.6, -0.4, -0.2, 0, 0.2, 0.4, 0.6, 0.8, 1, 1.2, 1.4, 1.6, 1.8, 2]), 0.5)
        >>> ' '.join(['{0:.2}'.format(n) for n in hus])
        '1.0 0.8 0.6 0.41 0.29 0.25 0.29 0.41 0.6 0.8 1.0 1.2 1.4 1.6 1.8 2.0'

    r   )r   squarer   )r   deltarL   x2s       r   huber2zMathHelperFunctions.huber2/  s]    & YYq\eQh519rQY/?#?@uax266!9,-/23 	4r   gQ63E?g(?gM63E?g:\?w@@)r   r   r            )er   gR63E?g'?gR63E?g:\?r   r   gڑv)m@g:@ggX@gS@gH	@gѫ¢_$@gK@gygg@g|5x@goƓ@gu@@gwf@g r15@g@gvC@gFܻ@g=k@gGڕd@gWk@gN?nnq3@gxԗ@g|rAX@gvC[@gn$@gʃÚ@g[9+s@g$@gFj('@g7-~@gU޵|@gsD*@g@~@g8M@gv#@gH}ʾt@g@gYg@gḱa@g]%@g*RRw@g
OhF@g{d>ߠ@g\4@g?$@g}hm@gm@g,qQ@gDB@g@g֜o@gR<^2@g_U@g<@g9@gr@gۏ^@gxp@g˥O@g  @g1rH/ @g8JO @g"n @g>EOF @gm @gnl @gg @g,="!@gHQ%!@gdKC!@gl`!@g<8~!@g[d!@gb`!@ga-!@g!@gk>"@g 0~*"@g: לF"@go>b"@g)xO~"@gh\?"@gL\"@guR"@g8 T"@gY#@g-ܚ!#@gr8eVK<#@g(:V#@gUb>q#@gn#@g#@g2Π#@g"|#@gX7#@c                     	 t         j                  |    S # t        $ r? | dkD  sJ |        | }|dz  ddd|z  z  z
  dd|dz  z  z  z   z  t         j                  | <   Y nw xY wt         j                  |    S )a^  approximation of the expectation of norm(randn(dimension)).

        The exact value can be computed by::

            from scipy.special import gamma
            return 2**0.5 * gamma((self.dimension+1) / 2) / gamma(self.dimension / 2)

        The approximation obeys ``chin < chin_hat < (1 + 5e-5) * chin``.

        >>> import cma.utilities.math as um
        ...
        >>> um.Mh.chiN(3) == 1.595769121605731
        True
        >>> um.Mh.chiN(100) == 9.97503163955105
        True
        >>> 31.6148721 < um.Mh.chiN(1000) < 31.6148722
        True
        >>> len(um.MathHelperFunctions._chiN_dict)  # internal checking
        102
        >>> assert all([-1 / (10*(N+1)**2) < um.Mh.chiN(N) - N**0.5 * (1 - 1. / (4 * N) + 1. / (26 * N**2)) 
        ...            < 1 / (10*(N+1)**2) for N in range(1, len(um.MathHelperFunctions._chiN_dict))])

        r   r   r   r'   r      r   )r   
_chiN_dictKeyError)	dimensionr   s     r   chiNzMathHelperFunctions.chiNL  s    2	?&11)<< 	?q=+)+=A 3!bAEl*R219-==>  **95		? #--i88s    AAA)r      2   K   d   Fc                    t        j                  |      r|gn|}|st        |       } t        |       }g }|D ]{  }||z  dz  dz
  }|dk  r|j	                  | d          (||dz
  k\  r|j	                  | d          Et        |      }|j	                  |dz   |z
  | |   z  ||z
  | |dz      z  z          } t        j                  |      r|d   S |S )z``prctile(data, 50)`` returns the median, but p_vals can
        also be a sequence.

        Provides for small samples or extremes IMHO better values than
        matplotlib.mlab.prctile or np.percentile, however also slower.

        r   r   r   r   r   )r   r   sortedr   r   r
   )	datap_valssorted_psr   r)   r\   fir   s	            r   prctilezMathHelperFunctions.prctilen  s     V,fX&$<DIAQs"BQwa!q1ub"G!a%"*Q/26T!a%[2HHI  {{6*qt11r   c                 t     || ddg      \  }}t        j                  |      t        j                  |      z
  S )zinterquartile ranger   r   r   )r   percentile_functionq25q75s       r   iqrzMathHelperFunctions.iqr  3     'tb"X6Szz#C00r   c                 t     || ddg      \  }}t        j                  |      t        j                  |      z
  S )zreturn 10% to 90% range width
   Z   r   )r   r  q10q90s       r   interdecilerangez$MathHelperFunctions.interdecilerange  r  r   c                     t        j                  |       } | |z
  ||z
  z  }t        j                  | |z
  d|z
  z  || z
  |z  z        S )a  map [lower, upper] -> R such that

        ::

            upper - 10^-x  ->   x, and
            lower + 10^-x  ->  -x

        for large enough x. By default, simplifies close to `log10(x / (1 - x))`.

        >>> from cma.utilities.math import Mh
        >>> l, u = -1, 2
        >>> print(Mh.logit10([l+0.01, 0.5, u-0.01], l, u))
        [-1.9949189  0.         1.9949189]

        r   )r   rC   log10)r   r   r   r   s       r   logit10zMathHelperFunctions.logit10  sL    " JJqMY55=)xxUac*eai!^;<<r   c                 v    t        |       t        j                  j                  d      d   | dz  k  rdz   S dz   S )z9return stochastic round: int(nb) + (rand()<remainder(nb))r   r   )r
   r   randomrand)nbs    r   sroundzMathHelperFunctions.sround  s8     2wryy~~a03rAv>!FFAFFr   c                  :   t         j                  j                         t         j                  j                         z  } t        |       dkD  rLt         j                  j                         t         j                  j                         z  } t        |       dkD  rL| dz  S )Ni  r   )r   r  r"   r   )r   s    r   cauchy_with_variance_onez,MathHelperFunctions.cauchy_with_variance_one  sc    IIOO		 11!ftm		!BIIOO$55A !ftm2vr   c                 T   	 t        |       }|dk(  r>t        j                  t	        |       D cg c]  }t
        j                          c}      S |dk(  rAt        j                  t	        | d         D cg c]  }t
        j                          c}      S |dk(  r]t        j                  t	        | d         D cg c]0  }t	        | d         D cg c]  }t
        j                          c}2 c}}      S t        d      # t        $ r d}Y w xY wc c}w c c}w c c}w c c}}w )Nr   r   r   z#len(size) cannot be larger than two)r   	TypeErrorr   r   r   r   r  r-   )r   r   _i_js       r   standard_finite_cauchyz*MathHelperFunctions.standard_finite_cauchy  s#   	D	A 688V[\`VabVaPR0IIKVabcc!V88V[\`ab\cVdeVdPR0IIKVdeff!V88#(a>3#1R X]]abc]dWefWeQS1JJLWef#13 4 4 BCC  	A	 cef 3s4   D D4D;D$
D+D$
DDD$
)g-q=)r   )r   )r   N)r   r   )r   )"r   r   r   r   staticmethodr   r   r   r   linalgeighr   r   r   r   r   r   r,   r   r   r   r   r   dict	enumerater   r  
percentiler  r  r  r  r  r  r(   r   r   r   r     s    5 5N N R R YY^^ , , E E  3 3 J JP P
> 
> * *5 5 O O( 4 4, (O%,<',>@J i  !W  J  9  9B 15 2 20 &(mm 1 1 35== 1 1 G G( G G  
 D Dr   r   )r   )   )rH   r   ) r   
__future__r   r   r   warningsr@   numpyr   python3for2r   r   r   r   r  r"   r%   r/   r7   filterwarningsrF   rQ   rX   ra   ro   ru   rz   objectr|   r   r   Mhr(   r   r   <module>r+     s    A @   X~
@ $299?? $ !*$BIIOO  	  
IK4>2`NS*j ', #+JZ%f %$G$R
pD& pDd r   