
    'YHhh;                        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_         y)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                    |Jt         d|z  z  t        j                  t        j                  t        j                  |             d      z  }nut        j
                  |      r't        j                  |      }|j                  |       n9t        j                  |      }|j                  | j                  k7  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        R/var/www/html/planif/env/lib/python3.12/site-packages/statsmodels/tools/numdiff.py_get_epsilonr   ^   s    "q&MBJJrvvbjjm'<cBB;;wAFF7O

7#Aww!''!  "0 1 1::a=     Fc                    t        |       } || f|z   i |}t        j                  |      j                  }t        j                  |f|z   t        j
                  t        | j                              }	t        j                  |ft              }
|sKt        | d||      }t        |      D ].  }||   |
|<    || |
z   f|z   i ||z
  ||   z  |	|ddf<   d|
|<   0 n]t        | d||      dz  }t        |      D ]>  }||   |
|<    || |
z   f|z   i | || |
z
  f|z   i |z
  d||   z  z  |	|ddf<   d|
|<   @ |dk(  r|	j                  S |	j                         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88QD3J 0 0 @AD	1$	Bq!Wa0q 	AAJBqEqtgn882=wqzIDAJBqE	
 q!Wa025q 	AAJBqEqtgdl6v6qtgdl6v679:WQZIDAJBqE		 	Avvv||~r   c                    t        j                  |       } d} || f|z   i |}|s%t        | d||      } || |z   f|z   i ||z
  |z  }	|	S 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; K	 1a!,r1QsUHTM-f-QsUHTM-f-.23c'; Kr   c           	      (   t        |       }t        | d||      }t        j                  |      dz  |z  }t	        |      D cg c]$  \  }} || |z   g|i |j
                  ||   z  & }	}}t        j                  |	      j                  S c c}}w )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                 ?)r   r   r   identity	enumerateimagarrayr%   )
r   r'   r   r(   r)   r   
incrementsiihpartialss
             r   approx_fprime_csr>      s    B 	AA1a!,GQ"$w.J 'z24Ar !B$(((--
: 4H 4 88H4s   )Bc                     t        j                  |       } | j                  d   }t        | d||      }d|z  } || |z   g|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   r8   r9   )r   r'   r   r(   r)   r   r2   r=   s           r   _approx_fprime_cs_scalarrA     sj    J 	

1A	A1a!,G
w,CS*4*6*//'9H88H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&   r8   r   r'   r   r(   r)   r   r   eehessr;   js              r   approx_hess_csrI   0  s(   4 	AAQ7A&A	B88Aq>DAA1X $q! 	$Aa"R1X+o1a402T9EfER1a4[2ad8!; =d B ( &(()-b115ad<DAJ
 adDAJ	$$ 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           	         t        |       }t        | d||      }t        j                  |      } || f|z   i |}	t        j                  |      }
t        |      D ]  } || ||d d f   z   f|z   i ||
|<    t        j                  ||      }t        |      D ][  }t        ||      D ]J  } || ||d d f   z   ||d d f   z   f|z   i ||
|   z
  |
|   z
  |	z   |||f   z  |||f<   |||f   |||f<   L ] |r|
|	z
  |z  }||fS |S )Nr   r   r   r   rC   r    r$   rD   )r   r'   r   r(   r)   return_gradr   r   rF   r+   gr;   rG   rH   r-   s                  r   approx_hess1rU   ]  s\    	AAQ7A&A	B	
aT$Y	"6	"B
A1X 2AbAhJ=%1&1!2 88Aq>D1X $q! 	$Aq2ad8|bAh684?KFKA$!"1&(*+,0AJ7DAJadDAJ	$$
 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 ]4  } || ||d d f   z   f|z   i ||
|<    || ||d d f   z
  f|z   i |||<   6 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   rR   )r   r'   r   r(   r)   rS   r   r   rF   r+   rT   ggr;   rG   rH   r-   s                   r   approx_hess2rY     s   $ 	AAQ7A&A	B	
aT$Y	"6	"B
A	!B1X 3AbAhJ=%1&1!Qr!Q$xZM$&26213 88Aq>D1X $q! 	$Aq2ad8|bAh684?KFKA$!"1&(*+q2ad8|bAh684?KFKL Q%  #%Q%( +-- 0141:~?DAJ adDAJ	$$ 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                 4   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   rC   rD   r$   r&   rE   s              r   approx_hess3r_     su    	AAQ7A&A	B88Aq>D1X 	$q! 	$Aa"QT(lR1X-/$6B6BBq!tHr!Q$x/1D8DVDER1X1a402T9EfE1r!Q$x<"QT(24t;GGHI tAqDzM	#DAJ adDAJ	$	$ Kr   z&
    This is an alias for approx_hess3)__doc__numpyr   statsmodels.compat.pandasr   r   finfor"   r2   r   _hessian_docsr   r0   r3   r>   rA   rI   rU   rY   r_   approx_hessr   r   r   <module>rf      sq  Z  < bhhuo&R !%2b5 7 t )-2b#(+\ $(b ) X ,0b ,^ "&Br *Z 
  
-#"RU  2 
  
-#"RU   < 
F	 
-#"R  	&    @ @ r   