B
    &]\nG                 @   sv  d dl mZmZmZ dddddddd	d
dddddgZd dlmZmZmZm	Z	m
Z
mZmZmZmZmZmZmZmZ d dlZddlmZ ddlmZmZ ddlmZ ddlmZ ddlmZmZ ddl m!Z!m"Z" ddl#m$Z$ e%e&j'Z'e%ej'Z(ddd dd ddZ)dd Z*d+ddZ+dd Z,d,d!d	Z-d"d Z.d#d Z/d$d Z0d%d Z1d&d Z2d'd Z3d(d Z4d-d)d
Z5d.d*dZ6dS )/    )divisionprint_functionabsolute_importexpmcosmsinmtanmcoshmsinhmtanhmlogmfunmsignmsqrtmexpm_frechet	expm_condfractional_matrix_power)Infdotdiagproductlogical_notravel	transpose	conjugateabsoluteamaxsignisfinitesingleN   )norm)solveinv)triu)svd)schurrsf2csf)r   r   )r   )ilfdFDc             C   s8   t | } t| jdks,| jd | jd kr4td| S )a  
    Wraps asarray with the extra requirement that the input be a square matrix.

    The motivation is that the matfuncs module has real functions that have
    been lifted to square matrix functions.

    Parameters
    ----------
    A : array_like
        A square matrix.

    Returns
    -------
    out : ndarray
        An ndarray copy or view or other representation of A.

       r   r    z expected square array_like input)npZasarraylenshape
ValueError)A r4   4lib/python3.7/site-packages/scipy/linalg/matfuncs.py_asarray_square"   s    
"r6   c             C   sV   t | rRt |rR|dkr:td td dt|jj  }t j|j	d|drR|j
}|S )a(  
    Return either B or the real part of B, depending on properties of A and B.

    The motivation is that B has been computed as a complicated function of A,
    and B may be perturbed by negligible imaginary components.
    If A is real and B is complex with small imaginary components,
    then return a real copy of B.  The assumption in that case would be that
    the imaginary components of B are numerical artifacts.

    Parameters
    ----------
    A : ndarray
        Input array whose type is to be checked as real vs. complex.
    B : ndarray
        Array to be returned, possibly without its imaginary part.
    tol : float
        Absolute tolerance.

    Returns
    -------
    out : real or complex array
        Either the input array B or only the real part of the input array B.

    Ng     @@g    .A)r   r    g        )Zatol)r/   Z	isrealobjiscomplexobjfepseps_array_precisiondtypecharZallcloseimagreal)r3   Btolr4   r4   r5   _maybe_real:   s    rA   c             C   s    t | } ddl}|jj| |S )a  
    Compute the fractional power of a matrix.

    Proceeds according to the discussion in section (6) of [1]_.

    Parameters
    ----------
    A : (N, N) array_like
        Matrix whose fractional power to evaluate.
    t : float
        Fractional power.

    Returns
    -------
    X : (N, N) array_like
        The fractional power of the matrix.

    References
    ----------
    .. [1] Nicholas J. Higham and Lijing lin (2011)
           "A Schur-Pade Algorithm for Fractional Powers of a Matrix."
           SIAM Journal on Matrix Analysis and Applications,
           32 (3). pp. 1056-1078. ISSN 0895-4798

    Examples
    --------
    >>> from scipy.linalg import fractional_matrix_power
    >>> a = np.array([[1.0, 3.0], [1.0, 4.0]])
    >>> b = fractional_matrix_power(a, 0.5)
    >>> b
    array([[ 0.75592895,  1.13389342],
           [ 0.37796447,  1.88982237]])
    >>> np.dot(b, b)      # Verify square root
    array([[ 1.,  3.],
           [ 1.,  4.]])

    r   N)r6   scipy.linalg._matfuncs_inv_ssqlinalg_matfuncs_inv_ssqZ_fractional_matrix_power)r3   tscipyr4   r4   r5   r   `   s    (Tc             C   sz   t | } ddl}|jj| }t| |}dt }tt||  dt| d }|rnt	|r`||krjt
d| |S ||fS dS )a  
    Compute matrix logarithm.

    The matrix logarithm is the inverse of
    expm: expm(logm(`A`)) == `A`

    Parameters
    ----------
    A : (N, N) array_like
        Matrix whose logarithm to evaluate
    disp : bool, optional
        Print warning if error in the result is estimated large
        instead of returning estimated error. (Default: True)

    Returns
    -------
    logm : (N, N) ndarray
        Matrix logarithm of `A`
    errest : float
        (if disp == False)

        1-norm of the estimated error, ||err||_1 / ||A||_1

    References
    ----------
    .. [1] Awad H. Al-Mohy and Nicholas J. Higham (2012)
           "Improved Inverse Scaling and Squaring Algorithms
           for the Matrix Logarithm."
           SIAM Journal on Scientific Computing, 34 (4). C152-C169.
           ISSN 1095-7197

    .. [2] Nicholas J. Higham (2008)
           "Functions of Matrices: Theory and Computation"
           ISBN 978-0-898716-46-7

    .. [3] Nicholas J. Higham and Lijing lin (2011)
           "A Schur-Pade Algorithm for Fractional Powers of a Matrix."
           SIAM Journal on Matrix Analysis and Applications,
           32 (3). pp. 1056-1078. ISSN 0895-4798

    Examples
    --------
    >>> from scipy.linalg import logm, expm
    >>> a = np.array([[1.0, 3.0], [1.0, 4.0]])
    >>> b = logm(a)
    >>> b
    array([[-1.02571087,  2.05142174],
           [ 0.68380725,  1.02571087]])
    >>> expm(b)         # Verify expm(logm(a)) returns a
    array([[ 1.,  3.],
           [ 1.,  4.]])

    r   Ni  r    z0logm result may be inaccurate, approximate err =)r6   rB   rC   rD   Z_logmrA   r9   r!   r   r   print)r3   disprF   r,   errtolerrestr4   r4   r5   r      s    6

c             C   s   ddl }|jj| S )a  
    Compute the matrix exponential using Pade approximation.

    Parameters
    ----------
    A : (N, N) array_like or sparse matrix
        Matrix to be exponentiated.

    Returns
    -------
    expm : (N, N) ndarray
        Matrix exponential of `A`.

    References
    ----------
    .. [1] Awad H. Al-Mohy and Nicholas J. Higham (2009)
           "A New Scaling and Squaring Algorithm for the Matrix Exponential."
           SIAM Journal on Matrix Analysis and Applications.
           31 (3). pp. 970-989. ISSN 1095-7162

    Examples
    --------
    >>> from scipy.linalg import expm, sinm, cosm

    Matrix version of the formula exp(0) = 1:

    >>> expm(np.zeros((2,2)))
    array([[ 1.,  0.],
           [ 0.,  1.]])

    Euler's identity (exp(i*theta) = cos(theta) + i*sin(theta))
    applied to a matrix:

    >>> a = np.array([[1.0, 2.0], [-1.0, 3.0]])
    >>> expm(1j*a)
    array([[ 0.42645930+1.89217551j, -2.13721484-0.97811252j],
           [ 1.06860742+0.48905626j, -1.71075555+0.91406299j]])
    >>> cosm(a) + 1j*sinm(a)
    array([[ 0.42645930+1.89217551j, -2.13721484-0.97811252j],
           [ 1.06860742+0.48905626j, -1.71075555+0.91406299j]])

    r   N)Zscipy.sparse.linalgZsparserC   r   )r3   rF   r4   r4   r5   r      s    ,c             C   s@   t | } t| r.dtd|  td|    S td|  jS dS )a  
    Compute the matrix cosine.

    This routine uses expm to compute the matrix exponentials.

    Parameters
    ----------
    A : (N, N) array_like
        Input array

    Returns
    -------
    cosm : (N, N) ndarray
        Matrix cosine of A

    Examples
    --------
    >>> from scipy.linalg import expm, sinm, cosm

    Euler's identity (exp(i*theta) = cos(theta) + i*sin(theta))
    applied to a matrix:

    >>> a = np.array([[1.0, 2.0], [-1.0, 3.0]])
    >>> expm(1j*a)
    array([[ 0.42645930+1.89217551j, -2.13721484-0.97811252j],
           [ 1.06860742+0.48905626j, -1.71075555+0.91406299j]])
    >>> cosm(a) + 1j*sinm(a)
    array([[ 0.42645930+1.89217551j, -2.13721484-0.97811252j],
           [ 1.06860742+0.48905626j, -1.71075555+0.91406299j]])

    g      ?y              ?y             N)r6   r/   r7   r   r>   )r3   r4   r4   r5   r     s     
c             C   s@   t | } t| r.dtd|  td|    S td|  jS dS )a  
    Compute the matrix sine.

    This routine uses expm to compute the matrix exponentials.

    Parameters
    ----------
    A : (N, N) array_like
        Input array.

    Returns
    -------
    sinm : (N, N) ndarray
        Matrix sine of `A`

    Examples
    --------
    >>> from scipy.linalg import expm, sinm, cosm

    Euler's identity (exp(i*theta) = cos(theta) + i*sin(theta))
    applied to a matrix:

    >>> a = np.array([[1.0, 2.0], [-1.0, 3.0]])
    >>> expm(1j*a)
    array([[ 0.42645930+1.89217551j, -2.13721484-0.97811252j],
           [ 1.06860742+0.48905626j, -1.71075555+0.91406299j]])
    >>> cosm(a) + 1j*sinm(a)
    array([[ 0.42645930+1.89217551j, -2.13721484-0.97811252j],
           [ 1.06860742+0.48905626j, -1.71075555+0.91406299j]])

    y             y              ?y             N)r6   r/   r7   r   r=   )r3   r4   r4   r5   r   *  s     
c             C   s    t | } t| tt| t| S )a  
    Compute the matrix tangent.

    This routine uses expm to compute the matrix exponentials.

    Parameters
    ----------
    A : (N, N) array_like
        Input array.

    Returns
    -------
    tanm : (N, N) ndarray
        Matrix tangent of `A`

    Examples
    --------
    >>> from scipy.linalg import tanm, sinm, cosm
    >>> a = np.array([[1.0, 3.0], [1.0, 4.0]])
    >>> t = tanm(a)
    >>> t
    array([[ -2.00876993,  -8.41880636],
           [ -2.80626879, -10.42757629]])

    Verify tanm(a) = sinm(a).dot(inv(cosm(a)))

    >>> s = sinm(a)
    >>> c = cosm(a)
    >>> s.dot(np.linalg.inv(c))
    array([[ -2.00876993,  -8.41880636],
           [ -2.80626879, -10.42757629]])

    )r6   rA   r"   r   r   )r3   r4   r4   r5   r   Q  s    "c             C   s$   t | } t| dt| t|    S )a  
    Compute the hyperbolic matrix cosine.

    This routine uses expm to compute the matrix exponentials.

    Parameters
    ----------
    A : (N, N) array_like
        Input array.

    Returns
    -------
    coshm : (N, N) ndarray
        Hyperbolic matrix cosine of `A`

    Examples
    --------
    >>> from scipy.linalg import tanhm, sinhm, coshm
    >>> a = np.array([[1.0, 3.0], [1.0, 4.0]])
    >>> c = coshm(a)
    >>> c
    array([[ 11.24592233,  38.76236492],
           [ 12.92078831,  50.00828725]])

    Verify tanhm(a) = sinhm(a).dot(inv(coshm(a)))

    >>> t = tanhm(a)
    >>> s = sinhm(a)
    >>> t - s.dot(np.linalg.inv(c))
    array([[  2.72004641e-15,   4.55191440e-15],
           [  0.00000000e+00,  -5.55111512e-16]])

    g      ?)r6   rA   r   )r3   r4   r4   r5   r	   w  s    "c             C   s$   t | } t| dt| t|    S )a  
    Compute the hyperbolic matrix sine.

    This routine uses expm to compute the matrix exponentials.

    Parameters
    ----------
    A : (N, N) array_like
        Input array.

    Returns
    -------
    sinhm : (N, N) ndarray
        Hyperbolic matrix sine of `A`

    Examples
    --------
    >>> from scipy.linalg import tanhm, sinhm, coshm
    >>> a = np.array([[1.0, 3.0], [1.0, 4.0]])
    >>> s = sinhm(a)
    >>> s
    array([[ 10.57300653,  39.28826594],
           [ 13.09608865,  49.86127247]])

    Verify tanhm(a) = sinhm(a).dot(inv(coshm(a)))

    >>> t = tanhm(a)
    >>> c = coshm(a)
    >>> t - s.dot(np.linalg.inv(c))
    array([[  2.72004641e-15,   4.55191440e-15],
           [  0.00000000e+00,  -5.55111512e-16]])

    g      ?)r6   rA   r   )r3   r4   r4   r5   r
     s    "c             C   s    t | } t| tt| t| S )a  
    Compute the hyperbolic matrix tangent.

    This routine uses expm to compute the matrix exponentials.

    Parameters
    ----------
    A : (N, N) array_like
        Input array

    Returns
    -------
    tanhm : (N, N) ndarray
        Hyperbolic matrix tangent of `A`

    Examples
    --------
    >>> from scipy.linalg import tanhm, sinhm, coshm
    >>> a = np.array([[1.0, 3.0], [1.0, 4.0]])
    >>> t = tanhm(a)
    >>> t
    array([[ 0.3428582 ,  0.51987926],
           [ 0.17329309,  0.86273746]])

    Verify tanhm(a) = sinhm(a).dot(inv(coshm(a)))

    >>> s = sinhm(a)
    >>> c = coshm(a)
    >>> t - s.dot(np.linalg.inv(c))
    array([[  2.72004641e-15,   4.55191440e-15],
           [  0.00000000e+00,  -5.55111512e-16]])

    )r6   rA   r"   r	   r
   )r3   r4   r4   r5   r     s    "c          	   C   s<  t | } t| \}}t||\}}|j\}}t|t|}||jj}t|d }x,t	d|D ]}xt	d|| d D ]}	|	| }
||	d |
d f ||
d |
d f ||	d |	d f   }t
|	|
d }t||	d |f |||
d f t||	d |f |||
d f  }|| }||
d |
d f ||	d |	d f  }|dkr\|| }|||	d |
d f< t|t|}qW qdW tt||tt|}t| |}ttdt|jj  }|dkr|}tdt||| tt|dd }tttt|ddrt}|r0|d| kr,td| |S ||fS d	S )
a{  
    Evaluate a matrix function specified by a callable.

    Returns the value of matrix-valued function ``f`` at `A`. The
    function ``f`` is an extension of the scalar-valued function `func`
    to matrices.

    Parameters
    ----------
    A : (N, N) array_like
        Matrix at which to evaluate the function
    func : callable
        Callable object that evaluates a scalar function f.
        Must be vectorized (eg. using vectorize).
    disp : bool, optional
        Print warning if error in the result is estimated large
        instead of returning estimated error. (Default: True)

    Returns
    -------
    funm : (N, N) ndarray
        Value of the matrix function specified by func evaluated at `A`
    errest : float
        (if disp == False)

        1-norm of the estimated error, ||err||_1 / ||A||_1

    Examples
    --------
    >>> from scipy.linalg import funm
    >>> a = np.array([[1.0, 3.0], [1.0, 4.0]])
    >>> funm(a, lambda x: x*x)
    array([[  4.,  15.],
           [  5.,  19.]])
    >>> a.dot(a)
    array([[  4.,  15.],
           [  5.,  19.]])

    Notes
    -----
    This function implements the general algorithm based on Schur decomposition
    (Algorithm 9.1.1. in [1]_).

    If the input matrix is known to be diagonalizable, then relying on the
    eigendecomposition is likely to be faster. For example, if your matrix is
    Hermitian, you can do

    >>> from scipy.linalg import eigh
    >>> def funm_herm(a, func, check_finite=False):
    ...     w, v = eigh(a, check_finite=check_finite)
    ...     ## if you further know that your matrix is positive semidefinite,
    ...     ## you can optionally guard against precision errors by doing
    ...     # w = np.maximum(w, 0)
    ...     w = func(w)
    ...     return (v * w).dot(v.conj().T)

    References
    ----------
    .. [1] Gene H. Golub, Charles F. van Loan, Matrix Computations 4th ed.

    )r   r   r    g        )r   r    r   )Zaxisi  z0funm result may be inaccurate, approximate err =N)r6   r&   r'   r1   r   Zastyper;   r<   absrangeslicer   minr   r   rA   r8   r9   r:   maxr!   r$   r   r   r   r   r   rG   )r3   funcrH   TZnr,   Zmindenpr(   jsZkslvalZdenr@   errr4   r4   r5   r     s@    >
<D(


$
c             C   s  t | } dd }t| |dd\}}dt dt dt|jj  }||k rL|S t| dd}t	|}d| }| |t
| jd   }	|}
x`td	D ]T}t|	}d|	|  }	dt|	|	|	  }tt||| d
}||k s|
|krP |}
qW |rt|r||krtd| |	S |	|fS dS )a'  
    Matrix sign function.

    Extension of the scalar sign(x) to matrices.

    Parameters
    ----------
    A : (N, N) array_like
        Matrix at which to evaluate the sign function
    disp : bool, optional
        Print warning if error in the result is estimated large
        instead of returning estimated error. (Default: True)

    Returns
    -------
    signm : (N, N) ndarray
        Value of the sign function at `A`
    errest : float
        (if disp == False)

        1-norm of the estimated error, ||err||_1 / ||A||_1

    Examples
    --------
    >>> from scipy.linalg import signm, eigvals
    >>> a = [[1,2,3], [1,2,1], [1,1,1]]
    >>> eigvals(a)
    array([ 4.12488542+0.j, -0.76155718+0.j,  0.63667176+0.j])
    >>> eigvals(signm(a))
    array([-1.+0.j,  1.+0.j,  1.+0.j])

    c             S   sL   t | }|jjdkr(dt t|  }ndt t|  }tt||k| S )Nr*   g     @@)	r/   r>   r;   r<   r8   r   r9   r   r   )xZrxcr4   r4   r5   rounded_signt  s
    
zsignm.<locals>.rounded_signr   )rH   g     @@)r   r    )Z
compute_uvg      ?d   r    z1signm result may be inaccurate, approximate err =N)r6   r   r8   r9   r:   r;   r<   r%   r/   r   Zidentityr1   rL   r#   r   r!   r   rG   )r3   rH   r[   resultrJ   rI   ZvalsZmax_svrZ   ZS0Zprev_errestr(   ZiS0ZPpr4   r4   r5   r   Q  s0    !

)N)T)T)T)7Z
__future__r   r   r   __all__Znumpyr   r   r   r   r   r   r   r   r   r   r   r   r   r/   Zmiscr!   Zbasicr"   r#   Zspecial_matricesr$   Z
decomp_svdr%   Zdecomp_schurr&   r'   Z_expm_frechetr   r   Z_matfuncs_sqrtmr   Zfinfofloatr9   r8   r:   r6   rA   r   r   r   r   r   r   r	   r
   r   r   r   r4   r4   r4   r5   <module>   s8   

<
&-
F0''&&&&
h