U
    ÃmœdP;  ã                   @   s   d Z ddlZddlmZmZ e e¡jZ	dZ
dd„ Zddi dfd	d
„Zddi dfdd„Zddi fdd„Zddi fdd„Zddi fdd„Zedddddd�ee
ƒddi dfdd„ƒƒZedddddd�ee
ƒddi dfdd„ƒƒZed d!d!d"d#d�ee
ƒddi fd$d%„ƒƒZeZe j d&7  _ dS )'ay  numerical differentiation function, gradient, Jacobian, and Hessian

Author : josef-pkt
License : BSD

Notes
-----
These are simple forward differentiation, so that we have them available
without dependencies.

* Jacobian should be faster than numdifftools because it does not use loop over
  observations.
* numerical precision will vary and depend on the choice of stepsizes
é    N)ÚAppenderÚSubstitutiona  
    Calculate Hessian with finite difference derivative approximation

    Parameters
    ----------
    x : array_like
       value at which function derivative is evaluated
    f : function
       function of one array f(x, `*args`, `**kwargs`)
    epsilon : float or array_like, optional
       Stepsize used, if None, then stepsize is automatically chosen
       according to EPS**(1/%(scale)s)*x.
    args : tuple
        Arguments for function `f`.
    kwargs : dict
        Keyword arguments for function `f`.
    %(extra_params)s

    Returns
    -------
    hess : ndarray
       array of partial second derivatives, Hessian
    %(extra_returns)s

    Notes
    -----
    Equation (%(equation_number)s) in Ridout. Computes the Hessian as::

      %(equation)s

    where e[j] is a vector with element j == 1 and the rest are zero and
    d[i] is epsilon[i].

    References
    ----------:

    Ridout, M.S. (2009) Statistical applications of the complex-step method
        of numerical differentiation. The American Statistician, 63, 66-74
c                 C   sj   |d kr(t d|  t t | ¡d¡ }n>t |¡rHt |¡}| |¡ nt |¡}|j| jkrft	dƒ‚|S )Ng      ð?gš™™™™™¹?z6If h is not a scalar it must have the same shape as x.)
ÚEPSÚnpÚmaximumÚabsZisscalarÚemptyÚfillÚasarrayÚshapeÚ
ValueError)ÚxÚsÚepsilonÚnÚh© r   úR/home/sam/Atlas/atlas_env/lib/python3.8/site-packages/statsmodels/tools/numdiff.pyÚ_get_epsilon^   s     


r   r   Fc                 C   sB  t | ƒ}|| f| |Ž}t |¡j}t |f| t t| j¡¡}	t |ft¡}
|s°t| d||ƒ}t	|ƒD ]D}|| |
|< || |
 f| |Ž| ||  |	|dd…f< d|
|< qhntt| d||ƒd }t	|ƒD ]X}|| |
|< || |
 f| |Ž|| |
 f| |Ž d||   |	|dd…f< d|
|< qÊ|dk�r4|	j
S |	 ¡ j
S dS )aR  
    Gradient of function, or Jacobian if function f returns 1d array

    Parameters
    ----------
    x : ndarray
        parameters at which the derivative is evaluated
    f : function
        `f(*((x,)+args), **kwargs)` returning either one value or 1d array
    epsilon : float, optional
        Stepsize, if None, optimal stepsize is used. This is EPS**(1/2)*x for
        `centered` == False and EPS**(1/3)*x for `centered` == True.
    args : tuple
        Tuple of additional arguments for function `f`.
    kwargs : dict
        Dictionary of additional keyword arguments for function `f`.
    centered : bool
        Whether central difference should be returned. If not, does forward
        differencing.

    Returns
    -------
    grad : ndarray
        gradient or Jacobian

    Notes
    -----
    If f returns a 1d array, it returns a Jacobian. If a 2d array is returned
    by f (e.g., with a value for each observation), it returns a 3d array
    with the Jacobian of each observation with shape xk x nobs x xk. I.e.,
    the Jacobian of the first observation would be [:, 0, :]
    é   Ng        é   ç       @é   )Úlenr   Z
atleast_1dr   ÚzerosZpromote_typesÚfloatZdtyper   ÚrangeÚTÚsqueeze)r   Úfr   ÚargsÚkwargsÚcenteredr   Úf0ÚdimÚgradÚeiÚkr   r   r   Úapprox_fprimem   s.    !,ÿ
ÿ

r(   c           
      C   s”   t  | ¡} d}|| f| |Ž}|sNt| d||ƒ}|| | f| |Ž| | }	nBt| d||ƒd }|| | f| |Ž|| | f| |Ž d|  }	|	S )a'  
    Gradient of function vectorized for scalar parameter.

    This assumes that the function ``f`` is vectorized for a scalar parameter.
    The function value ``f(x)`` has then the same shape as the input ``x``.
    The derivative returned by this function also has the same shape as ``x``.

    Parameters
    ----------
    x : ndarray
        Parameters at which the derivative is evaluated.
    f : function
        `f(*((x,)+args), **kwargs)` returning either one value or 1d array
    epsilon : float, optional
        Stepsize, if None, optimal stepsize is used. This is EPS**(1/2)*x for
        `centered` == False and EPS**(1/3)*x for `centered` == True.
    args : tuple
        Tuple of additional arguments for function `f`.
    kwargs : dict
        Dictionary of additional keyword arguments for function `f`.
    centered : bool
        Whether central difference should be returned. If not, does forward
        differencing.

    Returns
    -------
    grad : ndarray
        Array of derivatives, gradient evaluated at parameters ``x``.
    r   r   r   r   )r   r
   r   )
r   r   r   r    r!   r"   r   r#   Úepsr%   r   r   r   Ú_approx_fprime_scalar§   s    
ÿÿr*   c                    sR   t ˆƒ}tˆdˆ|ƒ‰t |¡d ˆ }‡ ‡‡‡‡fdd„t|ƒD ƒ}t |¡jS )aÈ  
    Calculate gradient or Jacobian with complex step derivative approximation

    Parameters
    ----------
    x : ndarray
        parameters at which the derivative is evaluated
    f : function
        `f(*((x,)+args), **kwargs)` returning either one value or 1d array
    epsilon : float, optional
        Stepsize, if None, optimal stepsize is used. Optimal step-size is
        EPS*x. See note.
    args : tuple
        Tuple of additional arguments for function `f`.
    kwargs : dict
        Dictionary of additional keyword arguments for function `f`.

    Returns
    -------
    partials : ndarray
       array of partial derivatives, Gradient or Jacobian

    Notes
    -----
    The complex-step derivative has truncation error O(epsilon**2), so
    truncation error can be eliminated by choosing epsilon to be very small.
    The complex-step derivative avoids the problem of round-off error with
    small epsilon because there is no subtraction.
    r   ù              ð?c                    s.   g | ]&\}}ˆˆ| fˆ žˆŽj ˆ|  ‘qS r   )Úimag)Ú.0ÚiZih©r    r   r   r!   r   r   r   Ú
<listcomp>û   s   ÿz$approx_fprime_cs.<locals>.<listcomp>)r   r   r   ÚidentityÚ	enumerateÚarrayr   )r   r   r   r    r!   r   Z
incrementsÚpartialsr   r/   r   Úapprox_fprime_csÕ   s    !ÿr5   c                 C   sN   t  | ¡} | jd }t| d||ƒ}d| }|| | f|ž|Žj| }t  |¡S )a¾  
    Calculate gradient for scalar parameter with complex step derivatives.

    This assumes that the function ``f`` is vectorized for a scalar parameter.
    The function value ``f(x)`` has then the same shape as the input ``x``.
    The derivative returned by this function also has the same shape as ``x``.

    Parameters
    ----------
    x : ndarray
        Parameters at which the derivative is evaluated.
    f : function
        `f(*((x,)+args), **kwargs)` returning either one value or 1d array.
    epsilon : float, optional
        Stepsize, if None, optimal stepsize is used. Optimal step-size is
        EPS*x. See note.
    args : tuple
        Tuple of additional arguments for function `f`.
    kwargs : dict
        Dictionary of additional keyword arguments for function `f`.

    Returns
    -------
    partials : ndarray
       Array of derivatives, gradient evaluated for parameters ``x``.

    Notes
    -----
    The complex-step derivative has truncation error O(epsilon**2), so
    truncation error can be eliminated by choosing epsilon to be very small.
    The complex-step derivative avoids the problem of round-off error with
    small epsilon because there is no subtraction.
    éÿÿÿÿr   r+   )r   r
   r   r   r,   r3   )r   r   r   r    r!   r   r)   r4   r   r   r   Ú_approx_fprime_cs_scalar  s    %

r7   c                 C   sò   t | ƒ}t| d||ƒ}t |¡}t ||¡}t | ƒ}t|ƒD ]°}	t|	|ƒD ] }
t || d||	dd…f   ||
dd…f  f| |Ž|| d||	dd…f   ||
dd…f  f| |Ž jd ||	|
f  ¡||	|
f< ||	|
f ||
|	f< qJq<|S )a£  Calculate Hessian with complex-step derivative approximation

    Parameters
    ----------
    x : array_like
       value at which function derivative is evaluated
    f : function
       function of one array f(x)
    epsilon : float
       stepsize, if None, then stepsize is automatically chosen

    Returns
    -------
    hess : ndarray
       array of partial second derivatives, Hessian

    Notes
    -----
    based on equation 10 in
    M. S. RIDOUT: Statistical Applications of the Complex-step Method
    of Numerical Differentiation, University of Kent, Canterbury, Kent, U.K.

    The stepsize is the same for the complex and the finite difference part.
    r   r+   Nr   )r   r   r   ÚdiagÚouterr   r   r,   ©r   r   r   r    r!   r   r   ÚeeÚhessr.   Újr   r   r   Úapprox_hess_cs0  s(    
2.ÿÿþ
þÿr>   Ú3zFreturn_grad : bool
        Whether or not to also return the gradient
z7grad : nparray
        Gradient if return_grad == True
Ú7zB1/(d_j*d_k) * ((f(x + d[j]*e[j] + d[k]*e[k]) - f(x + d[j]*e[j])))
)ÚscaleZextra_paramsZextra_returnsZequation_numberZequationc                 C   s$  t | ƒ}t| d||ƒ}t |¡}|| f| |Ž}	t |¡}
t|ƒD ](}|| ||d d …f  f| |Ž|
|< qBt ||¡}t|ƒD ]€}t||ƒD ]p}|| ||d d …f  ||d d …f  f| |Ž|
|  |
|  |	 |||f  |||f< |||f |||f< qŽq€|�r|
|	 | }||fS |S d S )Nr   ©r   r   r   r8   r   r   r9   )r   r   r   r    r!   Úreturn_gradr   r   r;   r#   Úgr.   r<   r=   r%   r   r   r   Úapprox_hess1]  s0    

&.ÿÿÿ
ÿrE   z7grad : ndarray
        Gradient if return_grad == True
Ú8zã1/(2*d_j*d_k) * ((f(x + d[j]*e[j] + d[k]*e[k]) - f(x + d[j]*e[j])) -
                 (f(x + d[k]*e[k]) - f(x)) +
                 (f(x - d[j]*e[j] - d[k]*e[k]) - f(x + d[j]*e[j])) -
                 (f(x - d[k]*e[k]) - f(x)))
c              	   C   sš  t | ƒ}t| d||ƒ}t |¡}|| f| |Ž}	t |¡}
t |¡}t|ƒD ]L}|| ||d d …f  f| |Ž|
|< || ||d d …f  f| |Ž||< qLt ||¡}t|ƒD ]È}t||ƒD ]¸}|| ||d d …f  ||d d …f  f| |Ž|
|  |
|  |	 || ||d d …f  ||d d …f  f| |Ž ||  ||  |	 d|||f   |||f< |||f |||f< q¼q®|�r’|
|	 | }||fS |S d S )Nr   r   rB   )r   r   r   r    r!   rC   r   r   r;   r#   rD   Zggr.   r<   r=   r%   r   r   r   Úapprox_hess2ƒ  sD    


$&.ÿÿÿ.þýýýýrG   Ú4Ú Ú9a	  1/(4*d_j*d_k) * ((f(x + d[j]*e[j] + d[k]*e[k]) - f(x + d[j]*e[j]
                                                     - d[k]*e[k])) -
                 (f(x - d[j]*e[j] + d[k]*e[k]) - f(x - d[j]*e[j]
                                                     - d[k]*e[k]))c                 C   sB  t | ƒ}t| d||ƒ}t |¡}t ||¡}t|ƒD �]}	t|	|ƒD ]ö}
t || ||	d d …f  ||
d d …f  f| |Ž|| ||	d d …f  ||
d d …f  f| |Ž || ||	d d …f  ||
d d …f  f| |Ž|| ||	d d …f  ||
d d …f  f| |Ž  d||	|
f   ¡||	|
f< ||	|
f ||
|	f< qDq4|S )Né   g      @)r   r   r   r8   r9   r   r   r:   r   r   r   Úapprox_hess3±  s&    
..ÿ..ÿþüÿrL   z&
    This is an alias for approx_hess3)Ú__doc__Únumpyr   Zstatsmodels.compat.pandasr   r   Zfinfor   r)   r   Z_hessian_docsr   r(   r*   r5   r7   r>   rE   rG   rL   Zapprox_hessr   r   r   r   Ú<module>   sR   -):ÿ
.,/-÷÷û
