
    bi$                         d dl Zd dlmZ d dlmZ d dlmc mZ	 d dlm
Z
 d dlmZ ddZd Zd Zd Zd Z G d d	      Zej&                  d
fdZy)    N)	csc_arrayc                    t        j                  | dd      \  }}}t        j                  t        j                  t        j
                  |      |kD  d            }|ddd|f   j                  | j                  d   |f      }|S )zCReturn a matrix whose columns are an orthonormal basis for range(V)economicT)modepivoting   axisNr   )laqrnpcount_nonzerosumabsreshapeshape)VtolQRpranks         Q/home/cdr/jupyterlab/.venv/lib/python3.12/site-packages/cvxpy/utilities/linalg.pyorthr   
   so    eeAJ6GAq!BFF266!9s?;<D	!UdU(QWWQZ./AH    c                 X   | j                   d   }t        |       }|j                   d   }||kD  sJ t        j                  |       r4t        j                  |      ||j                         j                  z  z
  }n%t        j                  |      ||j                  z  z
  }t        |      }|S )z
    Let U = the orthogonal complement of range(V).

    This function returns an array Q whose columns are
    an orthonormal basis for U. It requires that dim(U) > 0.
    r   r   )r   r   r   iscomplexobjeyeconjT)r   nQ1r   PQ2s         r   onb_for_orthogonal_complementr%      s     	

A	aB88A;Dt8O8	qFF1IRWWY[[((FF1IRTT	!	aBIr   c                 h   t        j                  |       r7| t        j                  | j                               z
  }|j	                         }nQt        | t        j                        r,| t        j                  t        j                  |             z
  }nt        d      t        j                  |d      S )NzUnsupported matrix type.r   )sparissparsediags_arraydiagonaltoarray
isinstancer   ndarraydiag
ValueErrorallclose)Aoff_diagonal_elementss     r   is_diagonalr3   &   s    }}Q !D$4$4QZZ\$B B 5 = = ?	Arzz	" !BGGBGGAJ$7 7344;;,a00r   c                     t         |      ryt               rat         t              r#t	        j
                   j                  | k\        S t	        j                  t	        j                               }|| k\  S  fd}	  ||       }t	        j                  |      j                         r5|t	        j                    j"                        j$                  z
  } ||       }t	        j
                  || k\        S # t        j                  $ rB}d}t        |       d| }t        j                  ||j                  |j                        d}~ww xY w)a  
    Return True if we can certify that A is PSD (up to tolerance "tol").

    First we check if A is PSD according to the Gershgorin Circle Theorem.

    If Gershgorin is inconclusive, then we use an iterative method (from ARPACK,
    as called through SciPy) to estimate extremal eigenvalues of certain shifted
    versions of A. The shifts are chosen so that the signs of those eigenvalues
    tell us the signs of the eigenvalues of A.

    If there are numerical issues then it's possible that this function returns
    False even when A is PSD. If you know that you're in that situation, then
    you should replace A by

        A = cvxpy.atoms.affine.wraps.psd_wrap(A).

    Parameters
    ----------
    A : Union[np.ndarray, spar.sparray]
        Symmetric (or Hermitian) NumPy ndarray or SciPy sparse array.

    tol : float
        Nonnegative. Something very small, like 1e-10.
    Tc                 2   t        t        j                  d      r t        j                  j                  d      }nt        j                  j	                  d      }j
                  d   }|j                  dd|      }t        j                  d| d|d	
      S )Ndefault_rng{   r   g              ?)locscalesizer   SAF)ksigmawhichv0return_eigenvectors)	hasattrr   randomr6   RandomStater   normalsparlaeigsh)r>   gr!   r@   r1   s       r   SA_eigshz#is_psd_within_tol.<locals>.SA_eigshV   sz     299m,		%%c*A		%%c*AGGAJXX#SqX1||A%t057 	7r   a  
        CVXPY note: This failure was encountered while trying to certify
        that a matrix is positive semi-definite (see [1] for a definition).
        In rare cases, this method fails for numerical reasons even when the matrix is
        positive semi-definite. If you know that you're in that situation, you can
        replace the matrix A by cvxpy.psd_wrap(A).

        [1] https://en.wikipedia.org/wiki/Definite_matrix
        z

N)gershgorin_psd_checkr3   r,   r   r   alldataminr.   rF   ArpackNoConvergencestreigenvalueseigenvectorsisnananyfinfodtypeeps)	r1   r   min_diag_entryrI   evemessageerror_with_notetemps	   `        r   is_psd_within_tolr]   2   s   4 As#1~a#66!&&SD.))VVBGGAJ/N!cT))74Ysd^$ 
xx| RXXagg&***te_66"*/ %% Y !VHD	2((!--XXYs   	C; ;E=EEc                    t        j                  |       r| j                         }t        j                  || k        ry| t        j
                  |      z
  }t        j                  |      }t        j                  |j                  d            j                         }t        j                  ||z
  | k\        S t        | t        j                        rt        j                  |       }t        j                  || k        ry| t        j                  |      z
  }t        j                  |      }|j                  d      }t        j                  ||z
  | k\        S t               )a>  
    Use the Gershgorin Circle Theorem

        https://en.wikipedia.org/wiki/Gershgorin_circle_theorem

    As a sufficient condition for A being PSD with tolerance "tol".

    The computational complexity of this function is O(nnz(A)).

    Parameters
    ----------
    A : Union[np.ndarray, spar.sparray]
        Symmetric (or Hermitian) NumPy ndarray or SciPy sparse array.

    tol : float
        Nonnegative. Something very small, like 1e-10.

    Returns
    -------
    True if A is PSD according to the Gershgorin Circle Theorem.
    Otherwise, return False.
    Fr   r	   )r'   r(   r*   r   rS   r)   r   arrayr   ravelrK   r,   r-   r.   r/   )r1   r   r.   A_shiftradiis        r   rJ   rJ      s   . }}Qzz|66$#+d&&t,,&&/!,-335vvdUlsd*++	Arzz	"wwqz66$#+bggdm#&&/#vvdUlsd*++lr   c                   $    e Zd ZdZdZdZdZdZdZy)SparseCholeskyMessagesz;Input matrix is not symmetric to within provided tolerance.z7Input matrix is neither positive nor negative definite.zCholesky decomposition failed.z8The only allowed Expression inputs are Constant objects.z4Non-Expression inputs must be SciPy sparse matrices.zInput matrix must be real.N)	__name__
__module____qualname__
ASYMMETRIC
INDEFINITE
EIGEN_FAIL	NOT_CONST
NOT_SPARSENOT_REAL r   r   rd   rd      s     NJJJ1JJIGJ+Hr   rd   Fc           
         ddl mc mc m} ddlmc m} t        | |j                               r?t        | |j                               st        t        j                        | j                  } t        j                  |       st        t        j                         t#        j$                  |       rt        t        j&                        |s| | j(                  z
  }|j*                  j,                  }|dkD  rAt/        j0                  |j*                        ||dz  z  kD  rt        t        j2                        | j5                         }t#        j6                  |dkD        }t#        j6                  |dk        }	|s|	st        t        j8                        |	rt;        |  |d      \  }
}}d||fS t        j<                  |       }| j>                  d   }|jA                  |jB                        }|jA                  |jD                        }|jG                  |j*                        }|jA                         }|jA                         }|jA                         }|jG                         }	 |jI                  ||||||||       t#        jP                  |      }t#        jP                  |      }t#        jP                  |      }t#        jP                  |      }t        jR                  |||ff||f      }d||fS # tJ        $ rO}|jL                  d   t        jN                  k(  rt        |jL                        tK        |jL                        d}~ww xY w)	a  
    The input matrix A must be real and symmetric. If A is positive definite then
    Eigen will be used to compute its sparse Cholesky decomposition with AMD-ordering.
    If A is negative definite, then the analogous operation will be applied to -A.

    If Cholesky succeeds, then we return a lower-triangular matrix L in
    CSR-format and a permutation vector p so (L[p, :]) @ (L[p, :]).T == A
    within numerical precision.

    We raise a ValueError if Eigen's Cholesky fails or if we certify indefiniteness
    before calling Eigen. While checking for indefiniteness, we also check that
     ||A - A'||_Fro / sqrt(n) <= sym_tol, where n is the order of the matrix.
    r   Ng      ?T)assume_posdefg      )r   r8   )*"cvxpy.utilities.cpp.sparsecholesky	utilitiescppsparsecholeskycvxpy.expressions.cvxtypesexpressionscvxtypesr,   
expressionconstantr/   rd   rk   valuer'   r(   rl   r   r   rm   r    rL   r;   r   normrh   r*   rK   ri   sparse_cholesky
coo_matrixr   	IntVectorrowcolDoubleVectorsparse_chol_from_vecsRuntimeErrorargsrj   r_   	csr_array)r1   sym_tolrp   spcholrw   symdiffszdmaybe_posdefmaybe_negdef_Lr   A_coor!   inrowsincolsinvalsoutpivsoutrowsoutcolsoutvalsrY   s                          r   r|   r|      s    8711!X((*+!X..013==>>GG==/::;;	q/8899acc'\\6bgggll+gS.AA3>>?? JJLvva!e}vva!e}3>>??%qb'FGAq!A:OOAE	
A eii(Feii(F  ,F G G G!!#G	'$$vvvWgw	
 hhwGhhwGhhwGhhwG'7!34QFCA7?  '66!9.999QVV$$qvv&&	's   %K3 3	M<A
MM)g-q=)numpyr   scipy.linalglinalgr   scipy.sparsesparser'   scipy.sparse.linalgrF   r   cvxpy.settingssettingsr   r%   r3   r]   rJ   rd   CHOL_SYM_TOLr|   rn   r   r   <module>r      sS       $ $ " !&	1Wt(V, ,  (44E Gr   