
    _-PhzH                         d Z ddlmZ ddlZddlmZ ddlmZ ddl	m
Z
mZmZmZ ddlmZ dd
Zd ZddZddZ	 	 	 ddZddZd Zd dZd!dZdS )"zLinear Algebra Helper Routines.    )warnN)sparse)aslinearoperator)lapackget_blas_funcseigsvd   )set_tol2c                 (   t          j        |           } |dk    r>t          j        t          j        |                                 |           j                  S |dk    r&t          j        t          j        |                     S t          d          )ai  2-norm of a vector.

    Parameters
    ----------
    x : array_like
        Vector of complex or real values

    pnorm : string
        '2' calculates the 2-norm
        'inf' calculates the infinity-norm

    Returns
    -------
    n : float
        2-norm of a vector

    Notes
    -----
    - currently 1+ order of magnitude faster than scipy.linalg.norm(x), which
      calls sqrt(numpy.sum(real((conjugate(x)*x)),axis=0)) resulting in an
      extra copy
    - only handles the 2-norm and infinity-norm for vectors

    See Also
    --------
    scipy.linalg.norm : scipy general matrix or vector norm

    r   infz/Only the 2-norm and infinity-norm are supported)	npravelsqrtinnerconjrealmaxabs
ValueError)xpnorms     Q/var/www/html/test/jupyter/venv/lib/python3.11/site-packages/pyamg/util/linalg.pynormr      sq    : 	A||wrx!,,1222~~vbfQii   
F
G
GG    c                    t          j        |           st          j        |           r{|                     t	          j        | j                  | j        | j        f| j	                  }|t	          j
        | j	        d         | j                  z                                  S t          j        |           rHt          |           t	          j
        | j	        d         | j                  z                                  S t	          j        t	          j        |           t	          j
        | j	        d         f| j                                                            S )a  Infinity norm of a matrix (maximum absolute row sum).

    Parameters
    ----------
    A : csr_matrix, csc_matrix, sparse, or numpy matrix
        Sparse or dense matrix

    Returns
    -------
    n : float
        Infinity norm of the matrix

    Notes
    -----
    - This serves as an upper bound on spectral radius.
    - csr and csc avoid a deep copy
    - dense calls scipy.linalg.norm

    See Also
    --------
    scipy.linalg.norm : dense matrix norms

    Examples
    --------
    >>> import numpy as np
    >>> from scipy.sparse import spdiags
    >>> from pyamg.util.linalg import infinity_norm
    >>> n=10
    >>> e = np.ones((n,1)).ravel()
    >>> data = [ -1*e, 2*e, -1*e ]
    >>> A = spdiags(data,[-1,0,1],n,n)
    >>> print(infinity_norm(A))
    4.0

    )shaper
   dtype)r   isspmatrix_csrisspmatrix_csc	__class__r   r   dataindicesindptrr   onesr    r   
isspmatrixdot)Aabs_As     r   infinity_normr,   5   s   H Q D6#8#;#; DRVAF^^QYA"#'  + +AG<<<<AACCC EA!'!*QW====BBDDD6"&))RWagaj]!'BBBCCGGIIIr         ?c                 R    t          dg| |g          d         } || ||           dS )a  Quick level-1 call to BLAS y = a*x+y.

    Parameters
    ----------
    x : array_like
        nx1 real or complex vector
    y : array_like
        nx1 real or complex vector
    a : float
        real or complex scalar

    Returns
    -------
    y : array_like
        Input variable y is rewritten

    Notes
    -----
    The call to get_blas_funcs automatically determines the prefix for the blas
    call.

    axpyr   N)r   )r   yafns       r   r/   r/   e   s3    . 
1a&	)	)!	,BBq!QKKKKKr   c                    t          |           } t          | j                  }d}| j        d         | j        d         k    rt	          d          t          | j        d         |          }|mt          j                            | j        d         d          }| j        t          k    r1|dt          j                            | j        d         d          z  z   }n|}|t          |          z  }t          j        |dz   |ft          j        |j        | j                            }|g}d}	t          |          D ]}
| |d	         z  }|r|
dk    r|	||
dz
  |
f<   ||	|d
         z  z  }t          j        t          j        |                                          |d	                                                   }|||
|
f<   |||d	         z  z  }t          |          }	|	||
dz   |
f<   ||
dz   |
f         |k     rd} n#||	z  }|                    |           |d
d         }t%          |          D ]e\  }}t          j        t          j        |                                          |                                          |||
f<   ||||
f         |z  z
  }ft          |          ||
dz   |
f<   ||
dz   |
f         |k     r:d}||
dz   |
f         dk    r|||
dz   |
f         z  }|                    |            n'|||
dz   |
f         z  }|                    |           t'          |d|
dz   d|
dz   f         dd          \  }}|||||fS )a  Apprixmate eigenvalues.

    Used by approximate_spectral_radius and condest.

    Returns [W, E, H, V, breakdown_flag], where W and E are the eigenvectors
    and eigenvalues of the Hessenberg matrix H, respectively, and V is the
    Krylov space.  breakdown_flag denotes whether Lanczos/Arnoldi suffered
    breakdown.  E is therefore the approximate eigenvalues of A.

    To obtain approximate eigenvectors of A, compute V*W.

    Fr   r
   expected square matrixN              ?r           T)leftright)r   r   r    r   r   minr   randomrandcomplexr   zerosresult_typeranger)   	conjugater   append	enumerater   )r*   maxiter	symmetricinitial_guess	breakdownbreakdown_flagv0HVbetajwalphaivEigsVectss                    r   _approximate_eigenvaluesrU      sW    	A   INwqzQWQZ1222!'!*g&&GY^^AGAJ**7gdRY^^AGAJ::::B$r((NB 	'!)W%~bh88	: 	: 	:A 
AD7^^ ( ("I %	Avv !A#q&	TAbE\!F2<		22AbEKKMMBBEAadG2A77DAac1fI!A#q&	I%%!%IAHHQKKK"##AA "! " "1&aggii!8!8!''))DD!Q$!Q$	MQAac1fI!A#q&	I%%!%QqS!V9##!AaCF)A!AaCF)AHHQKKKK a1dqsd
m%t<<<KD%4A~..r   {Gz?      Fc                    t          | d          r|rd}|dk     rt          d          |dk     rt          d          | j        t          k    rt          d          | j        d         | j        d         k    rt          d          |mt
          j                            | j        d         d          }| j        t          k    r1|d
t
          j                            | j        d         d          z  z   }n|j        d         | j        d         k    rt          d          t          |j                  dk    r |j        d         dk    rt          d          |
                    dd          }t          j        || j                  }t          |dz             D ]}t          | |||          \  }	}
}}}|
j        d         }t          j        |
                                          }|||dz
  f         |	d|f         z  }t          j        t          j        |d	d                   |	d	d	|f         
                    dd                    }t          j        |          t          j        |
|                   z  |k     r n|rt%          d|             nt          j        |
|                   }t'          j        |           r|| _        |r||fS |S | j        S )ac	  Approximate the spectral radius of a matrix.

    Parameters
    ----------
    A : {dense or sparse matrix}
        E.g. csr_matrix, csc_matrix, ndarray, etc.
    tol : {scalar}
        Relative tolerance of approximation, i.e., the error divided
        by the approximate spectral radius is compared to tol.
    maxiter : {integer}
        Maximum number of iterations to perform
    restart : {integer}
        Number of restarted Arnoldi processes.  For example, a value of 0 will
        run Arnoldi once, for maxiter iterations, and a value of 1 will restart
        Arnoldi once, using the maximal eigenvector from the first Arnoldi
        process as the initial guess.
    symmetric : {boolean}
        True  - if A is symmetric Lanczos iteration is used (more efficient)
        False - if A is non-symmetric Arnoldi iteration is used (less efficient)
    initial_guess : {array|None}
        If n x 1 array, then use as initial guess for Arnoldi/Lanczos.
        If None, then use a random initial guess.
    return_vector : {boolean}
        True - return an approximate dominant eigenvector and the spectral radius.
        False - Do not return the approximate dominant eigenvector

    Returns
    -------
    An approximation to the spectral radius of A, and
    if return_vector=True, then also return the approximate dominant
    eigenvector

    Notes
    -----
    The spectral radius is approximated by looking at the Ritz eigenvalues.
    Arnoldi iteration (or Lanczos) is used to project the matrix A onto a
    Krylov subspace: H = Q* A Q.  The eigenvalues of H (i.e. the Ritz
    eigenvalues) should represent the eigenvalues of A in the sense that the
    minimum and maximum values are usually well matched (for the symmetric case
    it is true since the eigenvalues are real).

    References
    ----------
    .. [1] Z. Bai, J. Demmel, J. Dongarra, A. Ruhe, and H. van der Vorst,
       editors.  "Templates for the Solution of Algebraic Eigenvalue Problems:
       A Practical Guide", SIAM, Philadelphia, 2000.

    Examples
    --------
    >>> from pyamg.util.linalg import approximate_spectral_radius
    >>> import numpy as np
    >>> from scipy.linalg import eigvals, norm
    >>> A = np.array([[1.,0.],[0.,1.]])
    >>> sr = approximate_spectral_radius(A,maxiter=3)
    >>> print(f'{sr:2.6}')
    1.0
    >>> print(max([norm(x) for x in eigvals(A)]))
    1.0

    rhoFr
   zexpected maxiter > 0r   zexpected restart >= 0z(expected A to be float (complex or real)zexpected square ANr5   z(initial_guess and A must have same shapezNinitial_guess must be an (n,1) or                                  (n,) vectorr7   r   )rG   zBreakdown occurred in step )hasattrr   r    intr   r   r<   r=   r>   lenreshapearrayrA   rU   r   argmaxr)   hstackr   r   r(   rZ   )r*   tolrE   restartrF   rG   return_vectorrJ   rN   evectevrK   rL   rI   nvecs	max_indexerrorrZ   s                     r   approximate_spectral_radiusrj     s   ~ 1e ? ? 	Q;;3444Q;;45557c>>GHHH71:##0111 
A..Bw'!!$
A!>!>>>"1%33 !KLLLM'((1,,=3Fq3IA3M3M  "/ 0 0 0&&r1--B"AG,,,Bwqy!! 	 	A(GYbQQQ .UB1n HQKEr

))++IeU1Wn%b)m(<<E 	!CRC&))5I+>+F+Fr1+M+MNNBve}}RVByM222S88 6166777
 fR	]##Q 	AE 	9
5Lr      c                    
 t          |           
d}|s
fd}|
_        d}t          
||          \  }}}}}	~~~~	t          j        d |D                       t          d |D                       z  |z  S )aK  Estimates the condition number of A.

    Parameters
    ----------
    A   : {dense or sparse matrix}
        e.g. array, matrix, csr_matrix, ...
    maxiter: {int}
        Max number of Arnoldi/Lanczos iterations
    symmetric : {bool}
        If symmetric use the far more efficient Lanczos algorithm,
        Else use Arnoldi.
        If hermitian, use symmetric=True.
        If complex symmetric, use symmetric=False.

    Returns
    -------
    Estimate of cond(A) with \|lambda_max\| / \|lambda_min\| or simga_max / sigma_min
    through the use of Arnoldi or Lanczos iterations, depending on
    the symmetric flag

    Notes
    -----
    The condition number measures how large of a change in the
    the problems solution is caused by a change in problem's input.
    Large condition numbers indicate that small perturbations
    and numerical errors are magnified greatly when solving the system.

    Examples
    --------
    >>> import numpy as np
    >>> from pyamg.util.linalg import condest
    >>> c = condest(np.array([[1.,0.],[0.,2.]]))
    >>> print(f'{c:2.6}')
    2.0

    r
   c                 >                         j        | z            S N)rmatvecr*   )rR   Cs    r   matveczcondest.<locals>.matvec  s    99QS1W%%%r   g      ?c                 ,    g | ]}t          |          S  r   .0r   s     r   
<listcomp>zcondest.<locals>.<listcomp>  s    (((DGG(((r   c              3   4   K   | ]}t          |          V  d S rn   rt   ru   s     r   	<genexpr>zcondest.<locals>.<genexpr>  s(      -B-B!d1gg-B-B-B-B-B-Br   )r   rq   rU   r   r   r;   )r*   rE   rF   powerrq   re   rf   rK   rL   rI   rp   s             @r   condestr{     s    J 	AE 	& 	& 	& 	& 	& 	!GY77 &UB1nq!^F((R((())#-B-Br-B-B-B*B*BBUJJr   c                    | j         d         | j         d         k    rt          d          t          j        |           r|                                 } t          |           \  }}}~~t          j        |          t          |          z  S )a  Return condition number of A.

    Parameters
    ----------
    A   : {dense or sparse matrix}
        e.g. array, matrix, csr_matrix, ...

    Returns
    -------
    2-norm condition number through use of the SVD
    Use for small to moderate sized dense matrices.
    For large sparse matrices, use condest.

    Notes
    -----
    The condition number measures how large of a change in
    the problems solution is caused by a change in problem's input.
    Large condition numbers indicate that small perturbations
    and numerical errors are magnified greatly when solving the system.

    Examples
    --------
    >>> import numpy as np
    >>> from pyamg.util.linalg import condest
    >>> c = condest(np.array([[1.0,0.],[0.,2.0]]))
    >>> print(f'{c:2.6}')
    2.0

    r   r
   r4   )	r   r   r   r(   toarrayr	   r   r   r;   )r*   USigmaVhs       r   condr     s{    < 	wqzQWQZ1222 IIKKq66LAub	2 6%==U##r   Tư>c           	      ,   t          j        |           st          j        |           } |rt          j                            | j        d                   }t          j                            | j        d                   }| j        t          k    r`|dt          j                            | j        d                   z  z   }|dt          j                            | j        d                   z  z   }t          j	        | 	                    |          
                                j        |          }t          j	        |
                                j        | 	                    |                    }t          t          j        ||z
            t          j        t          j        ||z                      z            }nt          j        |           r4t          j        | |                                 j        z
  j                  }n.t          j        | |                                 j        z
            }t          j        |j                  dk    rd}n&t          j        t          j        |                    }||k     rd}dS |rt'          |           dS )a)  Return True if A is Hermitian to within tol.

    Parameters
    ----------
    A   : {dense or sparse matrix}
        e.g. array, matrix, csr_matrix, ...
    fast_check : {bool}
        If True, use the heuristic < Ax, y> = < x, Ay>
        for random vectors x and y to check for conjugate symmetry.
        If False, compute A - A.conj().T.
    tol : {float}
        Symmetry tolerance

    verbose: {bool}
        prints
        max( \|A - A.conj().T\| ) if nonhermitian and fast_check=False..
        \| <Ax, y> - <x, Ay> ) \| / sqrt( \| <Ax, y> * <x, Ay> \| )
        if nonhermitian and fast_check=True

    Returns
    -------
    True                        if hermitian
    False                       if nonhermitian

    Notes
    -----
    This function applies a simple test of conjugate symmetry

    Examples
    --------
    >>> import numpy as np
    >>> from pyamg.util.linalg import ishermitian
    >>> ishermitian(np.array([[1,2],[1,1]]))
    False

    >>> from pyamg.gallery import poisson
    >>> ishermitian(poisson((10,10)))
    True

    r   r5   TF)r   r(   r   asarrayr<   r=   r   r    r>   r)   rB   Tfloatr   r   r   r   r$   r   print)	r*   
fast_checkrb   verboser   r0   xAyxAtydiffs	            r   ishermitianr     s   T Q JqMM (INN171:&&INN171:&&7gD
3333AD
3333AfaeeAhh))++-q11vakkmmoquuQxx00RVC$J''"'"&T2B2B*C*CCDD Q 	,8Q^122DD8A
N++D6$*""DD6"&,,''Dczzt d5r   c           	      
   | j         d         }| j         d         }|dk    r5| dk                                    d         }d| |<   d| z  | dd<   d| |<   ~dS t          j        dt	          j        d| j                            \  }}t	          j        || j                  }t          j        ||||          }|t          | j                  }t          |          D ]$}	 || |	         |||d	d
          }
|
d         | |	<   %dS )a+  Calculate the Moore-Penrose pseudo inverse of each block of the 3D array a.

    Parameters
    ----------
    a   : {dense array}
        Is of size (n, m, m)
    tol : {float}
        Used by gelss to filter numerically zeros singular values.
        If None, a suitable value is chosen for you.

    Returns
    -------
    Nothing, a is modified in place so that a[k] holds the pseudoinverse
    of that block.

    Notes
    -----
    By using lapack wrappers, this can be much faster for large n, than
    directly calling a pseudoinverse (SVD)

    Examples
    --------
    >>> import numpy as np
    >>> from pyamg.util.linalg import pinv_array
    >>> a = np.array([[[1.,2.],[1.,1.]], [[1.,1.],[3.,3.]]])
    >>> ac = a.copy()
    >>> # each block of a is inverted in-place
    >>> pinv_array(a)

    r   r
   r6   r-   N)gelssgelss_lwork)r
   r   TF)r   lworkoverwrite_aoverwrite_b)r   nonzeror   get_lapack_funcsr   r'   r    eye_compute_lworkr   rA   )r1   rb   nmzero_entriesr   r   RHSr   kkgelssoutputs              r   
pinv_arrayr   0  s5   > 	

A	
AAvvS))++A.,1u!!!,LL $45M68gd!'6R6R6RU U{fQag&&&%k1a;; ;!'""C (( 	# 	#B%"sE,0eE E EKNAbEE	# 	#r   )r   )r-   )NN)rV   rW   rX   NNF)rk   F)Tr   Frn   )__doc__warningsr   numpyr   scipyr   scipy.sparse.linalgr   scipy.linalgr   r   r   r	   paramsr   r   r,   r/   rU   rj   r{   r   r   r   rs   r   r   <module>r      se   % %                 0 0 0 0 0 0 9 9 9 9 9 9 9 9 9 9 9 9      %H %H %H %HP-J -J -J`   nb/ b/ b/ b/J BC>B.3@ @ @ @F1K 1K 1K 1Kh($ ($ ($VJ J J JZ=# =# =# =# =# =#r   