U
    3dړ                  
   @   s   d Z ddlZddlZddlZddlmZmZmZm	Z	m
Z
mZ ddlmZ ddlmZ ddlmZ dgZdd	 Zd
d Zdd Zdd ZdddZdd Zdd ZdddZdS )a\  
scikit-learn copy of scipy/sparse/linalg/_eigen/lobpcg/lobpcg.py v1.10
to be deleted after scipy 1.4 becomes a dependency in scikit-lean
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Locally Optimal Block Preconditioned Conjugate Gradient Method (LOBPCG).

References
----------
.. [1] A. V. Knyazev (2001),
       Toward the Optimal Preconditioned Eigensolver: Locally Optimal
       Block Preconditioned Conjugate Gradient Method.
       SIAM Journal on Scientific Computing 23, no. 2,
       pp. 517-541. :doi:`10.1137/S1064827500366124`

.. [2] A. V. Knyazev, I. Lashuk, M. E. Argentati, and E. Ovchinnikov (2007),
       Block Locally Optimal Preconditioned Eigenvalue Xolvers (BLOPEX)
       in hypre and PETSc.  :arxiv:`0705.2626`

.. [3] A. V. Knyazev's C and MATLAB implementations:
       https://github.com/lobpcg/blopex
    N)inveigh
cho_factor	cho_solvecholeskyLinAlgError)LinearOperator)
isspmatrix)blocklobpcgc              
   C   s   ddl m} | | j  }||d}dt| jj }t|||| d }||kr~t	j
d| d| j d| d| d		td
d dS )zA
    Report if `M` is not a Hermitian matrix given its type.
    r   )norm   
   zMatrix z of the type z is not Hermitian: condition: z < z fails.   
stacklevelN)scipy.linalgr   TconjnpfinfodtypeepsmaxwarningswarnUserWarning)Mnamer   ZmdZnmdtol r    =/tmp/pip-unpacked-wheel-zrfo1fqw/sklearn/externals/_lobpcg.py_report_nonhermitian"   s    
 r"   c                 C   s4   | j dkr| S tj| dd}| jd df|_|S dS )zm
    If the input array is 2D return it, if it is 1D, append a dimension,
    making it a column vector.
       F)copyr   r   N)ndimr   arrayshape)arauxr    r    r!   _as2d3   s
    
r*   c                    s0    d krd S t  r  fddS  fddS d S )Nc                    s    | S Nr    vmr    r!   <lambda>D       z_makeMatMat.<locals>.<lambda>c                    s    |  S r+   r    r,   r.   r    r!   r0   F   r1   )callabler.   r    r.   r!   _makeMatMat@   s
    r3   c                 C   s0   t |j | }t||}| t ||8 } dS )zChanges blockVectorV in place.N)r   dotr   r   r   )blockVectorVZfactYBYblockVectorBYblockVectorYZYBVtmpr    r    r!   _applyConstraintsI   s    
r9   c              
   C   sT  |j ddt|jj }|| }|dkr| dk	rz| |}W nR tk
r } z4|rtjd| dtdd ddd|f W Y S W 5 d}~X Y nX |j	|j	krt
d|j	 d	|j	 d
q|}n|| }|j | }z@t|dd}t|dd}|| }| dk	r
|| }||||fW S  tk
rN   |r>tjdtdd ddd|f Y S X dS )z@in-place B-orthonormalize the given block vector using Cholesky.r   )ZaxisN(Secondary MatMul call failed with error

   r   
The shape z; of the orthogonalized matrix not preserved
and changed to , after multiplying by the secondary matrix.
T)Zoverwrite_azCholesky has failed.)r   r   r   r   r   	Exceptionr   r   r   r'   
ValueErrorr   r   r   r   r   )Br5   ZblockVectorBVverbosityLevelZnormalizationeZVBVr    r    r!   _b_orthonormalizeP   sH    
 &
 rD   c                 C   s4   t | }|r$|d| d d }n|d| }|S )z?Get `num` indices into `_lambda` depending on `largest` option.Nr   )r   Zargsort)_lambdanumlargestiir    r    r!   	_get_indx   s
    
rJ   c                 C   s   |rt | d t |d d S )NgramAgramB)r"   )rK   rL   rB   r    r    r!   _handle_gramA_gramB_verbosity   s    
rM   TF   c           O      C   sT  |}|}|}|}|dkrd}|}d}|dk	rht |jdkr^tjdt |j dtdd d}n
|jd }|dkrxtd	t |jdkrtd
|j\}}t|jtj	stjd|j dtdd tj
|tjd}|	rtj|d |f|jd}|
rtj|d |f|jd}|rd}|dkr*|d7 }n|d7 }|d7 }|dkrL|d7 }|d7 }|d| 7 }|d| 7 }|dkr|d7 }n$|dkr|d| 7 }n|d| 7 }t| || d| k rDtjd| d| d| dtdd t||}|dk	rtd|r|| |d f}nd|d f}zt| trD| tj|td} n^t| r| tj|td} | j||fkrtd | j d!nt| r|  } n
t
| } W n4 tk
r } ztd"| d#W 5 d}~X Y nX |dk	rzt|tr|tj|td}n^t|rF|tj|td}|j||fkrdtd |j d$nt|rZ| }n
t
|}W n4 tk
r } ztd%| d#W 5 d}~X Y nX zrd&ttjkrd&|i}nd'|i}t| |fd(d)i|\}}|r|ddd* }|ddddd*f }||fW S  tk
rB } ztd+| d#W 5 d}~X Y nX |dksX|d,krptt|jj| }t| } t|}t|}|dk	r.|dk	r||}|j|jkrtd |j d-|j d.n|}t |j!" |}zt#|}W n. t$k
r } ztd/|W 5 d}~X Y nX t%|||| t&|||d0\}}}}|dkrVtd1| |} | j|jkrtd |j d2| j d3t |j!" | }!t|!d)d4\}"}#t'|"||}$|"|$ }"|	r|"|dddf< t
|#dd|$f }#t ||#}t | |#} |dk	rt ||#}tj(|ft)d}%d}&d}'d}(t*t|jj+})d*}*d5}+d)},d)}-|*|k r|*d7 }*|dk	r||"tj,ddf  }n||"tj,ddf  }| | }.t-|." |. d}tt*|}/|
r|/||*ddf< t-t*|/| }0|0|)k r|0})|*}|}n|0d| |) krd5},| |} | j|jkrTtd |j d6| j d3|dk	r||}|j|jkrtd |j d6|j d.t.|/|kd5d)}$|%|$@ }%|%- }1|rtd7|*  td8|1  td9|"  td:|/  |1dkrqt/|.dd|%f }2|*dkr`t/|&dd|%f }3t/|'dd|%f }4|dk	r`t/|(dd|%f }5|dk	rr||2}2|dk	rt%|2||| |dk	r|2||j!" |2   }2n|2||j!" |2   }2t&||2|d0}|\}2}6}}|2dk	rtjd;|* d<|/ d=| d>tdd q| |2}7|*dk	r|dk		rHt&||3|5|d0}|\}3}5}8}9nt&||3|d0}|\}3}}8}9|3dk		r|4|9 }4t |4|8}4|,}+nd5}+|7jd?k	rd}:ntt|2jj}:|/+ |:k	r|-	sd)}-nd5}-|dk	r|}|2}6|+	s|3}5t |j!" |7};t |2j!" |7}<|7j}=|-
r|<|<j!"  d }<t |j!" | }!|!|!j!"  d }!t |j!" |}>t |2j!" |6}?t |j!" |6}@n>t0|"1|=}!tj||=d}>tj|1|=d}?tj||1f|=d}@|+s4t |j!" |4}At |2j!" |4}Bt |3j!" |4}Ct |j!" |5}Dt |2j!" |5}E|-rR|C|Cj!"  d }Ct |3j!" |5}Fntj|1|=d}Ft2|!|;|Ag|;j!" |<|Bg|Aj!" |Bj!" |Cgg}Gt2|>|@|Dg|@j!" |?|Eg|Dj!" |Ej!" |Fgg}Ht3|G|H| zt|G|Hd)d4\}"}#W nL t$k
r2 } z,|rtjd@|* dA| dBtdd d5}+W 5 d}~X Y nX |+rt2|!|;g|;j!" |<gg}Gt2|>|@g|@j!" |?gg}Ht3|G|H| zt|G|Hd)d4\}"}#W nL t$k
r } z,tjd@|* dC| d#tdd W Y qW 5 d}~X Y nX t'|"||}$|"|$ }"|#dd|$f }#|	r|"||*d ddf< |dk	r,|+s|#d| }I|#|||1  }J|#||1 d }Kt |2|J}L|Lt |3|K7 }Lt |7|J}M|Mt |4|K7 }Mt |6|J}N|Nt |5|K7 }Nn<|#d| }I|#|d }Jt |2|J}Lt |7|J}Mt |6|J}Nt ||I|L }t | |I|M } t ||I|N }|L|M|N  }&}'}(n|+s|#d| }I|#|||1  }J|#||1 d }Kt |2|J}L|Lt |3|K7 }Lt |7|J}M|Mt |4|K7 }Mn0|#d| }I|#|d }Jt |2|J}Lt |7|J}Mt ||I|L }t | |I|M } |L|M }&}'qV|dk	r||"tj,ddf  }n||"tj,ddf  }| | }.t-|." |. d}tt*|}/|	rt|"||*d ddf< |
r|/||*d ddf< t-t*|/| }0|0|)k r|0})|*d }|}t+t*|/|krtjdD|* dE|/ dF| dG| dH|) dItdd |r$tdJ|"  tdK|/  |}|dk	r@t%|||| | |} | j|jkrptd |j dL| j d3t |j!" | }!|}|dk	r||}|j|jkrtd |j dL|j d.t |j!" |}>t3|!|>| |!|!j!"  d }!|>|>j!"  d }>zt|!|>d)d4\}"}#W n. t$k
rF } ztdM|W 5 d}~X Y nX t'|"||}$|"|$ }"t
|#dd|$f }#t ||#}t | |#} |dk	rt ||#}||"tj,ddf  }n||"tj,ddf  }| | }.t-|." |. d}tt*|}/|	r|"||d ddf< |
r.|/||d ddf< |	rL|d|d ddf }|
rj|d|d ddf }t+t*|/|krtjdN|/ dF| d>tdd |rtdO|"  tdP|/  |	rt4|t|d }dQdR |D }|
rt4|t|d }dSdR |D }|	r8|
r,|"|||fS |"||fS n|
rH|"||fS |"|fS dS )Ta  Locally Optimal Block Preconditioned Conjugate Gradient Method (LOBPCG).

    LOBPCG is a preconditioned eigensolver for large symmetric positive
    definite (SPD) generalized eigenproblems.

    Parameters
    ----------
    A : {sparse matrix, dense matrix, LinearOperator, callable object}
        The symmetric linear operator of the problem, usually a
        sparse matrix.  Often called the "stiffness matrix".
    X : ndarray, float32 or float64
        Initial approximation to the ``k`` eigenvectors (non-sparse). If `A`
        has ``shape=(n,n)`` then `X` should have shape ``shape=(n,k)``.
    B : {dense matrix, sparse matrix, LinearOperator, callable object}
        Optional.
        The right hand side operator in a generalized eigenproblem.
        By default, ``B = Identity``.  Often called the "mass matrix".
    M : {dense matrix, sparse matrix, LinearOperator, callable object}
        Optional.
        Preconditioner to `A`; by default ``M = Identity``.
        `M` should approximate the inverse of `A`.
    Y : ndarray, float32 or float64, optional.
        An n-by-sizeY matrix of constraints (non-sparse), sizeY < n.
        The iterations will be performed in the B-orthogonal complement
        of the column-space of Y. Y must be full rank.
    tol : scalar, optional.
        Solver tolerance (stopping criterion).
        The default is ``tol=n*sqrt(eps)``.
    maxiter : int, optional.
        Maximum number of iterations.  The default is ``maxiter=20``.
    largest : bool, optional.
        When True, solve for the largest eigenvalues, otherwise the smallest.
    verbosityLevel : int, optional
        Controls solver output.  The default is ``verbosityLevel=0``.
    retLambdaHistory : bool, optional.
        Whether to return eigenvalue history.  Default is False.
    retResidualNormsHistory : bool, optional.
        Whether to return history of residual norms.  Default is False.
    restartControl : int, optional.
        Iterations restart if the residuals jump up 2**restartControl times
        compared to the smallest ones recorded in retResidualNormsHistory.
        The default is ``restartControl=20``, making the restarts rare for
        backward compatibility.

    Returns
    -------
    w : ndarray
        Array of ``k`` eigenvalues.
    v : ndarray
        An array of ``k`` eigenvectors.  `v` has the same shape as `X`.
    lambdas : ndarray, optional
        The eigenvalue history, if `retLambdaHistory` is True.
    rnorms : ndarray, optional
        The history of residual norms, if `retResidualNormsHistory` is True.

    Notes
    -----
    The iterative loop in lobpcg runs maxit=maxiter (or 20 if maxit=None)
    iterations at most and finishes earler if the tolerance is met.
    Breaking backward compatibility with the previous version, lobpcg
    now returns the block of iterative vectors with the best accuracy rather
    than the last one iterated, as a cure for possible divergence.

    The size of the iteration history output equals to the number of the best
    (limited by maxit) iterations plus 3 (initial, final, and postprocessing).

    If both ``retLambdaHistory`` and ``retResidualNormsHistory`` are True,
    the return tuple has the following format
    ``(lambda, V, lambda history, residual norms history)``.

    In the following ``n`` denotes the matrix size and ``k`` the number
    of required eigenvalues (smallest or largest).

    The LOBPCG code internally solves eigenproblems of the size ``3k`` on every
    iteration by calling the dense eigensolver `eigh`, so if ``k`` is not
    small enough compared to ``n``, it makes no sense to call the LOBPCG code.
    Moreover, if one calls the LOBPCG algorithm for ``5k > n``, it would likely
    break internally, so the code calls the standard function `eigh` instead.
    It is not that ``n`` should be large for the LOBPCG to work, but rather the
    ratio ``n / k`` should be large. It you call LOBPCG with ``k=1``
    and ``n=10``, it works though ``n`` is small. The method is intended
    for extremely large ``n / k``.

    The convergence speed depends basically on two factors:

    1. Relative separation of the seeking eigenvalues from the rest
       of the eigenvalues. One can vary ``k`` to improve the absolute
       separation and use proper preconditioning to shrink the spectral spread.
       For example, a rod vibration test problem (under tests
       directory) is ill-conditioned for large ``n``, so convergence will be
       slow, unless efficient preconditioning is used. For this specific
       problem, a good simple preconditioner function would be a linear solve
       for `A`, which is easy to code since `A` is tridiagonal.

    2. Quality of the initial approximations `X` to the seeking eigenvectors.
       Randomly distributed around the origin vectors work well if no better
       choice is known.

    References
    ----------
    .. [1] A. V. Knyazev (2001),
           Toward the Optimal Preconditioned Eigensolver: Locally Optimal
           Block Preconditioned Conjugate Gradient Method.
           SIAM Journal on Scientific Computing 23, no. 2,
           pp. 517-541. :doi:`10.1137/S1064827500366124`

    .. [2] A. V. Knyazev, I. Lashuk, M. E. Argentati, and E. Ovchinnikov
           (2007), Block Locally Optimal Preconditioned Eigenvalue Xolvers
           (BLOPEX) in hypre and PETSc. :arxiv:`0705.2626`

    .. [3] A. V. Knyazev's C and MATLAB implementations:
           https://github.com/lobpcg/blopex

    Examples
    --------
    Solve ``A x = lambda x`` with constraints and preconditioning.

    >>> import numpy as np
    >>> from scipy.sparse import spdiags, issparse
    >>> from scipy.sparse.linalg import lobpcg, LinearOperator

    The square matrix size:

    >>> n = 100
    >>> vals = np.arange(1, n + 1)

    The first mandatory input parameter, in this test
    a sparse 2D array representing the square matrix
    of the eigenvalue problem to solve:

    >>> A = spdiags(vals, 0, n, n)
    >>> A.toarray()
    array([[  1,   0,   0, ...,   0,   0,   0],
           [  0,   2,   0, ...,   0,   0,   0],
           [  0,   0,   3, ...,   0,   0,   0],
           ...,
           [  0,   0,   0, ...,  98,   0,   0],
           [  0,   0,   0, ...,   0,  99,   0],
           [  0,   0,   0, ...,   0,   0, 100]])

    Initial guess for eigenvectors, should have linearly independent
    columns. The second mandatory input parameter, a 2D array with the
    row dimension determining the number of requested eigenvalues.
    If no initial approximations available, randomly oriented vectors
    commonly work best, e.g., with components normally disrtibuted
    around zero or uniformly distributed on the interval [-1 1].

    >>> rng = np.random.default_rng()
    >>> X = rng.normal(size=(n, 3))

    Constraints - an optional input parameter is a 2D array comprising
    of column vectors that the eigenvectors must be orthogonal to:

    >>> Y = np.eye(n, 3)

    Preconditioner in the inverse of A in this example:

    >>> invA = spdiags([1./vals], 0, n, n)

    The preconditiner must be defined by a function:

    >>> def precond( x ):
    ...     return invA @ x

    The argument x of the preconditioner function is a matrix inside `lobpcg`,
    thus the use of matrix-matrix product ``@``.

    The preconditioner function is passed to lobpcg as a `LinearOperator`:

    >>> M = LinearOperator(matvec=precond, matmat=precond,
    ...                    shape=(n, n), dtype=np.float64)

    Let us now solve the eigenvalue problem for the matrix A:

    >>> eigenvalues, _ = lobpcg(A, X, Y=Y, M=M, largest=False)
    >>> eigenvalues
    array([4., 5., 6.])

    Note that the vectors passed in Y are the eigenvectors of the 3 smallest
    eigenvalues. The results returned are orthogonal to those.
    NrN   r   r#   z2Expected rank-2 array for argument Y, instead got z&, so ignore it and use no constraints.r   r   z-The mandatory initial matrix X cannot be Nonez$expected rank-2 array for argument XzData type for argument X is z0, which is not inexact, so casted to np.float32.)r   r<   zSolving standardZgeneralizedz eigenvalue problem withoutz preconditioning

zmatrix size %d
zblock size %d

zNo constraints

z%d constraints

z%d constraint

   zThe problem size z minus the constraints size z) is too small relative to the block size zd. Using a dense eigensolver instead of LOBPCG iterations.No output of the history of the iterations.z3The dense eigensolver does not support constraints.r=   z> of the primary matrix
defined by a callable object is wrong.
z&Primary MatMul call failed with error
r;   z@ of the secondary matrix
defined by a callable object is wrong.
r:   Zsubset_by_indexeigvalscheck_finiteFrE   z$Dense eigensolver failed with error
g        z0 of the constraint not preserved
and changed to r>   zLinearly dependent constraints)rB   z)Linearly dependent initial approximationsz< of the initial approximations not preserved
and changed to z* after multiplying by the primary matrix.
)rS   Tz7 of the restarted iterate not preserved
and changed to z
iteration zcurrent block size: zeigenvalue(s):
zresidual norm(s):
zFailed at iteration z with accuracies z'
 not reaching the requested tolerance .float32zeigh failed at iteration z 
with error z causing a restart.
z with error
zExited at iteration z with accuracies 
z&
not reaching the requested tolerance z.
Use iteration z instead with accuracy 
z.
zFinal iterative eigenvalue(s):
z"Final iterative residual norm(s):
z< of the postprocessing iterate not preserved
and changed to z(eigh has failed in lobpcg postprocessingz'Exited postprocessing with accuracies 
z$Final postprocessing eigenvalue(s):
zFinal residual norm(s):
c                 S   s   g | ]}t |qS r    r   Zsqueeze.0ir    r    r!   
<listcomp>  s     zlobpcg.<locals>.<listcomp>c                 S   s   g | ]}t |qS r    rV   rW   r    r    r!   rZ     s     )5lenr'   r   r   r   r@   r   Z
issubdtyper   ZinexactZasarrayrU   zerosprintminNotImplementedError
isinstancer   Zeyeintr2   r	   Ztoarrayr?   inspect	signaturer   
parameterssqrtr   r   r3   r4   r   r   r   r   r9   rD   rJ   Zonesboolabsr   Znewaxissumwherer*   ZdiagZastypebmatrM   Zvsplit)OAXrA   r   Yr   maxiterrH   rB   ZretLambdaHistoryZretResidualNormsHistoryZrestartControlZblockVectorXZbestblockVectorXr7   ZresidualToleranceZbestIterationNumberZsizeYnZsizeXZlambdaHistoryZresidualNormsHistoryr)   rR   rC   Zadditional_paramsvalsZvecsr6   ZgramYBYZblockVectorBX_ZblockVectorAXZgramXAXrF   ZeigBlockVectorrI   Z
activeMaskZblockVectorPZblockVectorAPZblockVectorBPZsmallestResidualNormZiterationNumberZrestartZforcedRestartZexplicitGramFlagZblockVectorRZresidualNormsZresidualNormZcurrentBlockSizeZactiveBlockVectorRZactiveBlockVectorPZactiveBlockVectorAPZactiveBlockVectorBPZactiveBlockVectorBRZactiveBlockVectorARZinvRnormalZmyepsZgramXARZgramRARZ	gramDtypeZgramXBXZgramRBRZgramXBRZgramXAPZgramRAPZgramPAPZgramXBPZgramRBPZgramPBPrK   rL   ZeigBlockVectorXZeigBlockVectorRZeigBlockVectorPppZappZbppr    r    r!   r      s    D 

 





 
















  











  
 

  

  


" 	


 
)Nr   )
NNNNNTr   FFrN   )__doc__rb   r   Znumpyr   r   r   r   r   r   r   r   Zscipy.sparse.linalgr   Zscipy.sparser	   r
   rj   __all__r"   r*   r3   r9   rD   rJ   rM   r   r    r    r    r!   <module>   s8    	  
0	          