
    M/Phh;                        d Z ddlZddlmZmZ  ej        e          j        Z	dZ
d Zddi dfdZddi dfd	Zddi fd
Zddi fdZddi fdZ eddddd           ee
          ddi dfd                        Z eddddd           ee
          ddi dfd                        Z eddddd           ee
          ddi fd                        ZeZexj         dz  c_         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                    |Ht           d|z  z  t          j        t          j        t          j        |                     d          z  }nqt          j        |          r*t          j        |          }|                    |           n3t          j        |          }|j        | j        k    rt          d          t          j        |          S )Ng      ?g?z6If h is not a scalar it must have the same shape as x.)
EPSnpmaximumabsasarrayisscalaremptyfillshape
ValueError)xsepsilonnhs        Y/var/www/html/test/jupyter/venv/lib/python3.11/site-packages/statsmodels/tools/numdiff.py_get_epsilonr   ^   s    "q&MBJrvbjmm'<'<cBBB;w 	1AFF7OOOO
7##Aw!'!!  "0 1 1 1:a==     Fc                    t          |           } || f|z   i |}t          j        |          j        }t          j        |f|z   t          j        t          | j                            }	t          j        |ft                    }
|sWt          | d||          }t          |          D ]4}||         |
|<    || |
z   f|z   i ||z
  ||         z  |	|ddf<   d|
|<   5nit          | d||          dz  }t          |          D ]D}||         |
|<    || |
z   f|z   i | || |
z
  f|z   i |z
  d||         z  z  |	|ddf<   d|
|<   E|dk    r|	j
        S |	                                j
        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   
atleast_1dr   zerospromote_typesfloatdtyper   rangeTsqueeze)r   fr   argskwargscenteredr   f0dimgradeiks               r   approx_fprimer0   m   s   B 	AA	
aT$Y	"6	"	"B
-


!C8QD3J 0 @ @AAD	1$		B q!Wa00q 	 	AAJBqE!qtgn8882=wqzIDAAAJBqEE	
 q!Wa0025q 	 	AAJBqE!qtgdl6v66!qtgdl6v6679:WQZIDAAAJBqEEAvvv||~~r   c                    t          j        |           } d} || f|z   i |}|s(t          | d||          } || |z   f|z   i ||z
  |z  }	n:t          | d||          dz  } || |z   f|z   i | || |z
  f|z   i |z
  d|z  z  }	|	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-   s
             r   _approx_fprime_scalarr3      s    > 	
1A	A	
aT$Y	"6	"	"B ;1a!,,QsUHtO///"4;1a!,,r1QsUHTM-f--QsUHTM-f--.23c'; Kr   c                      t                     }t           d|          t          j        |          dz  z  } fdt	          |          D             }t          j        |          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                 P    g | ]"\  }} |z   gR i j         |         z  #S r   )imag).0iihr(   r   r'   r)   r   s      r   
<listcomp>z$approx_fprime_cs.<locals>.<listcomp>   sW     4 4 4Ar !B$((((((-
: 4 4 4r   )r   r   r   identity	enumeratearrayr%   )r   r'   r   r(   r)   r   
incrementspartialss   `````   r   approx_fprime_csrA      s    B 	AA1a!,,GQ"$w.J4 4 4 4 4 4 4 4&z224 4 4H 8Hr   c                     t          j        |           } | j        d         }t          | d||          }d|z  } || |z   g|R i |j        |z  }t          j        |          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   r5   )r   r
   r   r   r7   r>   )r   r'   r   r(   r)   r   r2   r@   s           r   _approx_fprime_cs_scalarrD     st    J 	
1A	A1a!,,G
w,CqS*4***6**/'9H8Hr   c                    t          |           }t          | d||          }t          j        |          }t          j        ||          }t          |           }t          |          D ]}	t          |	|          D ]}
t          j         || d||	ddf         z  z   ||
ddf         z   f|z   i | || d||	ddf         z  z   ||
ddf         z
  f|z   i |z
  j        dz  ||	|
f         z            ||	|
f<   ||	|
f         ||
|	f<   |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   r5   Nr   )r   r   r   diagouterr$   r&   r7   r   r'   r   r(   r)   r   r   eehessr9   js              r   approx_hess_csrL   0  sW   4 	AAQ7A&&A	B8Aq>>DAA1XX $ $q! 	$ 	$Aa"R111X+o1aaa402T9EfEEAR1aaa4[2ad8!; =d B ( &( (()-b115ad< DAJ
 adDAJJ	$ Kr   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])))
)scaleextra_paramsextra_returnsequation_numberequationc           	      P   t          |           }t          | d||          }t          j        |          } || f|z   i |}	t          j        |          }
t          |          D ]} || ||d d f         z   f|z   i ||
|<   t          j        ||          }t          |          D ]o}t          ||          D ]\} || ||d d f         z   ||d d f         z   f|z   i ||
|         z
  |
|         z
  |	z   |||f         z  |||f<   |||f         |||f<   ]p|r|
|	z
  |z  }||fS |S )Nr   r   r   r   rF   r    r$   rG   )r   r'   r   r(   r)   return_gradr   r   rI   r+   gr9   rJ   rK   r-   s                  r   approx_hess1rX   ]  s    	AAQ7A&&A	B	
aT$Y	"6	"	"B
A1XX 2 2qAbAAAhJ=%1&11!8Aq>>D1XX $ $q! 	$ 	$A!q2ad8|bAAAh684?KFKKA$!"1&(*+,0AJ7DAJadDAJJ	$  BzTzr   z7grad : ndarray
        Gradient if return_grad == True
8z1/(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           
      .   t          |           }t          | d||          }t          j        |          } || f|z   i |}	t          j        |          }
t          j        |          }t          |          D ]:} || ||d d f         z   f|z   i ||
|<    || ||d d f         z
  f|z   i |||<   ;t          j        ||          }t          |          D ]}t          ||          D ]} || ||d d f         z   ||d d f         z   f|z   i ||
|         z
  |
|         z
  |	z    || ||d d f         z
  ||d d f         z
  f|z   i |z   ||         z
  ||         z
  |	z   d|||f         z  z  |||f<   |||f         |||f<   |r|
|	z
  |z  }||fS |S )Nr   r   rU   )r   r'   r   r(   r)   rV   r   r   rI   r+   rW   ggr9   rJ   rK   r-   s                   r   approx_hess2r\     s9   $ 	AAQ7A&&A	B	
aT$Y	"6	"	"B
A	!B1XX 3 3qAbAAAhJ=%1&11!Qr!QQQ$xZM$&262218Aq>>D1XX $ $q! 	$ 	$A!q2ad8|bAAAh684?KFKKA$!"1&(*+!q2ad8|bAAAh684?KFKKL Q%  #%Q%( +-- 0141:~?DAJ adDAJJ	$  BzTzr   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                    t          |           }t          | d||          }t          j        |          }t          j        ||          }t          |          D ]}	t          |	|          D ]}
t          j         || ||	d d f         z   ||
d d f         z   f|z   i | || ||	d d f         z   ||
d d f         z
  f|z   i |z
   || ||	d d f         z
  ||
d d f         z   f|z   i | || ||	d d f         z
  ||
d d f         z
  f|z   i |z
  z
  d||	|
f         z  z            ||	|
f<   ||	|
f         ||
|	f<   Ҍ|S )N   g      @)r   r   r   rF   rG   r$   r&   rH   s              r   approx_hess3rb     s    	AAQ7A&&A	B8Aq>>D1XX 	$ 	$q! 	$ 	$Aa"QT(lR111X-/$6B6BB1Bq!!!tHr!QQQ$x/1D8DVDDEAR111X1aaa402T9EfEEa1r!QQQ$x<"QT(24t;GGGHI tAqDzM	# DAJ adDAJJ	$ Kr   z&
    This is an alias for approx_hess3)__doc__numpyr   statsmodels.compat.pandasr   r   finfor"   r2   r   _hessian_docsr   r0   r3   rA   rD   rL   rX   r\   rb   approx_hessr   r   r   <module>ri      sX   Z     < < < < < < < < bhuoo&R   !%2b5 7  7  7  7 t )-2b#(+ + + +\ $(b )  )  )  ) X ,0b , , , ,^ "&Br * * * *Z 
    
-#"RU     2 
    
-#"RU      < 
F	 	 	 
-#"R    	 	&    @ @    r   