U
    Gvf=                     @   s|   d Z ddlZddlmZ ddlmZ ddlmZ dddgZ	G d	d dZ
G d
d de
ZG dd deZG dd deZdS )z@Hessian update strategies for quasi-Newton optimization methods.    N)norm)get_blas_funcs)warnHessianUpdateStrategyBFGSSR1c                   @   s0   e Zd ZdZdd Zdd Zdd Zdd	 Zd
S )r   a]  Interface for implementing Hessian update strategies.

    Many optimization methods make use of Hessian (or inverse Hessian)
    approximations, such as the quasi-Newton methods BFGS, SR1, L-BFGS.
    Some of these  approximations, however, do not actually need to store
    the entire matrix or can compute the internal matrix product with a
    given vector in a very efficiently manner. This class serves as an
    abstract interface between the optimization algorithm and the
    quasi-Newton update strategies, giving freedom of implementation
    to store and update the internal matrix as efficiently as possible.
    Different choices of initialization and update procedure will result
    in different quasi-Newton strategies.

    Four methods should be implemented in derived classes: ``initialize``,
    ``update``, ``dot`` and ``get_matrix``.

    Notes
    -----
    Any instance of a class that implements this interface,
    can be accepted by the method ``minimize`` and used by
    the compatible solvers to approximate the Hessian (or
    inverse Hessian) used by the optimization algorithms.
    c                 C   s   t ddS )  Initialize internal matrix.

        Allocate internal memory for storing and updating
        the Hessian or its inverse.

        Parameters
        ----------
        n : int
            Problem dimension.
        approx_type : {'hess', 'inv_hess'}
            Selects either the Hessian or the inverse Hessian.
            When set to 'hess' the Hessian will be stored and updated.
            When set to 'inv_hess' its inverse will be used instead.
        z=The method ``initialize(n, approx_type)`` is not implemented.NNotImplementedErrorselfnapprox_type r   K/tmp/pip-unpacked-wheel-96ln3f52/scipy/optimize/_hessian_update_strategy.py
initialize$   s    z HessianUpdateStrategy.initializec                 C   s   t ddS )  Update internal matrix.

        Update Hessian matrix or its inverse (depending on how 'approx_type'
        is defined) using information about the last evaluated points.

        Parameters
        ----------
        delta_x : ndarray
            The difference between two points the gradient
            function have been evaluated at: ``delta_x = x2 - x1``.
        delta_grad : ndarray
            The difference between the gradients:
            ``delta_grad = grad(x2) - grad(x1)``.
        z>The method ``update(delta_x, delta_grad)`` is not implemented.Nr	   r   delta_x
delta_gradr   r   r   update6   s    zHessianUpdateStrategy.updatec                 C   s   t ddS )P  Compute the product of the internal matrix with the given vector.

        Parameters
        ----------
        p : array_like
            1-D array representing a vector.

        Returns
        -------
        Hp : array
            1-D represents the result of multiplying the approximation matrix
            by vector p.
        z)The method ``dot(p)`` is not implemented.Nr	   r   pr   r   r   dotH   s    zHessianUpdateStrategy.dotc                 C   s   t ddS )zReturn current internal matrix.

        Returns
        -------
        H : ndarray, shape (n, n)
            Dense matrix containing either the Hessian
            or its inverse (depending on how 'approx_type'
            is defined).
        z0The method ``get_matrix(p)`` is not implemented.Nr	   )r   r   r   r   
get_matrixY   s    
z HessianUpdateStrategy.get_matrixN)__name__
__module____qualname____doc__r   r   r   r   r   r   r   r   r      s
   c                   @   sn   e Zd ZdZedddZedddZedddZddd	Zd
d Z	dd Z
dd Zdd Zdd Zdd ZdS )FullHessianUpdateStrategyzKHessian update strategy with full dimensional internal representation.
    ZsyrdZdtypeZsyr2Zsymvautoc                 C   s"   || _ d | _d | _d | _d | _d S N)
init_scalefirst_iterationr   BH)r   r%   r   r   r   __init__o   s
    z"FullHessianUpdateStrategy.__init__c                 C   sR   d| _ || _|| _|dkr"td| jdkr>tj|td| _ntj|td| _dS )r   T)hessZinv_hessz+`approx_type` must be 'hess' or 'inv_hess'.r*   r"   N)	r&   r   r   
ValueErrornpeyefloatr'   r(   r   r   r   r   r   x   s    
z$FullHessianUpdateStrategy.initializec                 C   sd   t ||}t ||}t t ||}|dksB|dksB|dkrFdS | jdkrX|| S || S d S )N        r      r*   )r,   r   absr   )r   r   r   Zs_norm2Zy_norm2ysr   r   r   _auto_scale   s    
z%FullHessianUpdateStrategy._auto_scalec                 C   s   t dd S )Nz9The method ``_update_implementation`` is not implemented.r	   r   r   r   r   _update_implementation   s    z0FullHessianUpdateStrategy._update_implementationc                 C   s   t |dkrdS t |dkr.tdt dS | jr| jdkrL| ||}n
t| j}| jdkrp|  j	|9  _	n|  j
|9  _
d| _| || dS )r   r/   Nzdelta_grad == 0.0. Check if the approximated function is linear. If the function is linear better results can be obtained by defining the Hessian as zero instead of using quasi-Newton approximations.r#   r*   F)r,   allr   UserWarningr&   r%   r3   r.   r   r'   r(   r4   )r   r   r   scaler   r   r   r      s     


z FullHessianUpdateStrategy.updatec                 C   s.   | j dkr| d| j|S | d| j|S dS )r   r*   r0   N)r   _symvr'   r(   r   r   r   r   r      s    
zFullHessianUpdateStrategy.dotc                 C   sD   | j dkrt| j}nt| j}tj|dd}|j| ||< |S )zReturn the current internal matrix.

        Returns
        -------
        M : ndarray, shape (n, n)
            Dense matrix containing either the Hessian or its inverse
            (depending on how `approx_type` was defined).
        r*   )k)r   r,   copyr'   r(   Ztril_indices_fromT)r   Mlir   r   r   r      s    	
z$FullHessianUpdateStrategy.get_matrixN)r#   )r   r   r   r   r   _syr_syr2r8   r)   r   r3   r4   r   r   r   r   r   r   r   r    g   s   
	&r    c                       s:   e Zd ZdZd fdd	Zdd Zd	d
 Zdd Z  ZS )r   a  Broyden-Fletcher-Goldfarb-Shanno (BFGS) Hessian update strategy.

    Parameters
    ----------
    exception_strategy : {'skip_update', 'damp_update'}, optional
        Define how to proceed when the curvature condition is violated.
        Set it to 'skip_update' to just skip the update. Or, alternatively,
        set it to 'damp_update' to interpolate between the actual BFGS
        result and the unmodified matrix. Both exceptions strategies
        are explained  in [1]_, p.536-537.
    min_curvature : float
        This number, scaled by a normalization factor, defines the
        minimum curvature ``dot(delta_grad, delta_x)`` allowed to go
        unaffected by the exception strategy. By default is equal to
        1e-8 when ``exception_strategy = 'skip_update'`` and equal
        to 0.2 when ``exception_strategy = 'damp_update'``.
    init_scale : {float, 'auto'}
        Matrix scale at first iteration. At the first
        iteration the Hessian matrix or its inverse will be initialized
        with ``init_scale*np.eye(n)``, where ``n`` is the problem dimension.
        Set it to 'auto' in order to use an automatic heuristic for choosing
        the initial scale. The heuristic is described in [1]_, p.143.
        By default uses 'auto'.

    Notes
    -----
    The update is based on the description in [1]_, p.140.

    References
    ----------
    .. [1] Nocedal, Jorge, and Stephen J. Wright. "Numerical optimization"
           Second Edition (2006).
    skip_updateNr#   c                    s^   |dkr |d k	r|| _ qHd| _ n(|dkr@|d k	r8|| _ qHd| _ ntdt | || _d S )NrA   :0yE>damp_updateg?z<`exception_strategy` must be 'skip_update' or 'damp_update'.)min_curvaturer+   superr)   exception_strategy)r   rF   rD   r%   	__class__r   r   r)     s    zBFGS.__init__c                 C   s>   | j d| ||| jd| _| j|| |d  || jd| _dS )a  Update the inverse Hessian matrix.

        BFGS update using the formula:

            ``H <- H + ((H*y).T*y + s.T*y)/(s.T*y)^2 * (s*s.T)
                     - 1/(s.T*y) * ((H*y)*s.T + s*(H*y).T)``

        where ``s = delta_x`` and ``y = delta_grad``. This formula is
        equivalent to (6.17) in [1]_ written in a more efficient way
        for implementation.

        References
        ----------
        .. [1] Nocedal, Jorge, and Stephen J. Wright. "Numerical optimization"
               Second Edition (2006).
              a   N)r@   r(   r?   )r   r2   ZHyZyHysr   r   r   _update_inverse_hessian%  s    zBFGS._update_inverse_hessianc                 C   s4   | j d| || jd| _| j d| || jd| _dS )a  Update the Hessian matrix.

        BFGS update using the formula:

            ``B <- B - (B*s)*(B*s).T/s.T*(B*s) + y*y^T/s.T*y``

        where ``s`` is short for ``delta_x`` and ``y`` is short
        for ``delta_grad``. Formula (6.19) in [1]_.

        References
        ----------
        .. [1] Nocedal, Jorge, and Stephen J. Wright. "Numerical optimization"
               Second Edition (2006).
        g      ?rJ   rI   N)r?   r'   )r   r2   ZBsZsBsyr   r   r   _update_hessian9  s    zBFGS._update_hessianc           
      C   s*  | j dkr|}|}n|}|}t||}| |}||}|dkr| ||}| j dkrr|tj| jtd | _n|tj| jtd | _| |}||}|| j	| kr| j
dkrd S | j
dkrd| j	 d||   }	|	| d|	 |  }t||}| j dkr| |||| n| |||| d S )Nr*   r/   r"   rA   rC   r0   )r   r,   r   r3   r-   r   r.   r'   r(   rD   rF   rP   rN   )
r   r   r   wzZwzMwZwMwr7   Zupdate_factorr   r   r   r4   K  s2    







zBFGS._update_implementation)rA   Nr#   )	r   r   r   r   r)   rN   rP   r4   __classcell__r   r   rG   r   r      s   "  c                       s*   e Zd ZdZd fdd	Zdd Z  ZS )	r   a  Symmetric-rank-1 Hessian update strategy.

    Parameters
    ----------
    min_denominator : float
        This number, scaled by a normalization factor,
        defines the minimum denominator magnitude allowed
        in the update. When the condition is violated we skip
        the update. By default uses ``1e-8``.
    init_scale : {float, 'auto'}, optional
        Matrix scale at first iteration. At the first
        iteration the Hessian matrix or its inverse will be initialized
        with ``init_scale*np.eye(n)``, where ``n`` is the problem dimension.
        Set it to 'auto' in order to use an automatic heuristic for choosing
        the initial scale. The heuristic is described in [1]_, p.143.
        By default uses 'auto'.

    Notes
    -----
    The update is based on the description in [1]_, p.144-146.

    References
    ----------
    .. [1] Nocedal, Jorge, and Stephen J. Wright. "Numerical optimization"
           Second Edition (2006).
    rB   r#   c                    s   || _ t | d S r$   )min_denominatorrE   r)   )r   rU   r%   rG   r   r   r)     s    zSR1.__init__c                 C   s   | j dkr|}|}n|}|}| |}|| }t||}t|| jt| t| kr^d S | j dkr| jd| || jd| _n| jd| || jd| _d S )Nr*   r0   rJ   )	r   r   r,   r1   rU   r   r?   r'   r(   )r   r   r   rQ   rR   rS   Z
z_minus_Mwdenominatorr   r   r   r4     s    

 
zSR1._update_implementation)rB   r#   )r   r   r   r   r)   r4   rT   r   r   rG   r   r   y  s   )r   Znumpyr,   Znumpy.linalgr   Zscipy.linalgr   warningsr   __all__r   r    r   r   r   r   r   r   <module>   s   
\ 	 