U
    !?h@*                     @   s   d dl Zd dlZd dlmZ edddddd Zeddddd	d
 Zedddddd ZG dd de	Z
dddddddddddddgedddfddZdS )    N)njitzDi8(i8, f8[:], i8[:], i8[:], f8[:], i8[:], i8[:], f8, f8, i8, f8, b1)T)cacheZnogilc           !      C   s  d}d}t | t j}t | t j}t | t jd }t | t j}t | t j}t | t j}t | t j}t | |t j}t| D ]p}t|| ||d  D ]T}|| }||kr||  || 7  < |d ||< ||kr||  t|| 7  < qqt| D ]}t|| ||d  D ]\}|| }|| }|dkr||kr||  |7  < || sd||< |||< |d7 }q|| }|dkrF|| }||d  }|| }|| }|d7 }||k r>|||< || }|| ||< |||< t||D ]L}|| }|| }||  || 8  < || sd||< |||< |d7 }q|}q|| dkrZ dS |d | |	krr dS t 	|| ||< || ||< |||< |d7 }|||< t 
|d| D ]}|| ||  }|r||  || 8  < |
||  } t||krFt|| | krF|s.||  || 8  < |||< |||< |d7 }d||< d||< qd}|||d < || d ||d  k r ||| d  }|| ||< |||< q |S )	z
    :cite:`jones1995improved` might be slightly interesting for the general idea
    to use linked list to keep track of the sparse matrix values. But instead of
    pointers, we have to use indices here, since this is Python and not C.
    r              TNF)npzerosint64float64Zbool_emptyfullrangeabssqrtsort)!nZAvZArZApLvLrLpdiscard_thresholdshiftmax_nnzrelative_discard_thresholddiag_keep_discardednnzZc_nstlarbcdjidxiL_ijkZk0Zk1Zk2ZL_jkZL_ikrel r*   P/var/www/html/venv/lib/python3.8/site-packages/pymatting/preconditioner/ichol.py_ichol   s    






r,   z$void(f8[:], i8[:], i8[:], f8[:], i8)c                 C   sz   t |D ]l}|| }| | }|| | }|||< t || d ||d  D ](}|| }	| | }
||	  |
| 8  < qJqd S )Nr   r   )dataindicesindptrxr   r$   r(   ZL_jjtempr&   r'   r*   r*   r+   _backsub_L_csc_inplacet   s    r3   c                 C   s~   t |d ddD ]h}|| }t || d ||d  D ]$}|| }| | }	||	||  8 }q6|| }| | }
||
 ||< qd S )Nr   r   r-   )r.   r/   r0   r1   r   r&   r   r(   r$   ZL_jiZL_iir*   r*   r+   _backsub_LT_csc_inplace   s    r4   c                   @   s,   e Zd ZdZdd Zedd Zdd ZdS )	CholeskyDecompositionaH  Cholesky Decomposition

    Calling this object applies the preconditioner to a vector by forward and back substitution.

    Parameters
    ----------
    Ltuple: tuple of numpy.ndarrays
        Tuple of array describing values, row indices and row pointers for Cholesky factor in the compressed sparse column format (csc)
    c                 C   s
   || _ d S N)Ltuple)selfr7   r*   r*   r+   __init__   s    zCholeskyDecomposition.__init__c                 C   s,   | j \}}}t|d }tj| j ||fS )zReturns the Cholesky factor

        Returns
        -------
        L: scipy.sparse.csc_matrix
            Cholesky factor
        r   )r7   lenscipysparse
csc_matrix)r8   r   r   r   r   r*   r*   r+   L   s    	zCholeskyDecomposition.Lc                 C   s@   | j \}}}t|}| }t||||| t||||| |S r6   )r7   r:   copyr3   r4   )r8   r!   r   r   r   r   r1   r*   r*   r+   __call__   s    zCholeskyDecomposition.__call__N)__name__
__module____qualname____doc__r9   propertyr>   r@   r*   r*   r*   r+   r5      s
   

r5   g-C6?r   gMbP?g{Gz?g?g      ?g      ?g      $@d   g     @@g     @g     j@g    eͭAc                 C   sX  t | tjjr| j} t | tjjs*td| js8|   | j	\}}||ksNt
tj|tjd}tj|tjd}	tj|d tjd}
|D ]}t|| j| jtj| jtj||	|
|||||}|dkr q |dkrtd td td|  td	|  td
 td |dkrtdq|dk r2td|d| }|	d| }	t||	|
fS )aQ  Implements the thresholded incomplete Cholesky decomposition.
    For reference, a dense ichol implementation with relative threshold would look like this:

        L = np.tril(A)
        for j in range(n):
            col = L[j:, j]
            col -= np.sum(L[j, :j] * L[j:, :j], axis=1)
            discard_mask = abs(col[1:]) < relative_discard_threshold * np.sum(np.abs(A[j:, j]))
            col[1:][discard_mask] = 0
            col[0] **= 0.5
            col[1:] /= col[0]

    Parameters
    ----------
    A: scipy.sparse.csc_matrix
        Matrix for which the preconditioner should be calculated
    discard_threshold: float
        Values having an absolute value smaller than this threshold will be discarded while calculating the Cholesky decompositions
    shifts: array of floats
        Values to try for regularizing the matrix of interest in case it is not positive definite after discarding the small values
    max_nnz: int
        Maximum number of non-zero entries in the Cholesky decomposition. Defaults to 250 million, which should usually be around 4 GB.
    relative_discard_threshold: float
        Values with an absolute value of less than :code:`relative_discard_threshold * sum(abs(A[j:, j]))` will be discarded.
    diag_keep_discarded: bool
        Whether to update the diagonal with the discarded values. Usually better if :code:`True`.

    Returns
    -------
    chol: CholeskyDecomposition
        Preconditioner or solver object.

    Raises
    ------
    ValueError:
        If inappropriate parameter values were passed

    Example
    -------
    >>> from pymatting import *
    >>> import numpy as np
    >>> from scipy.sparse import csc_matrix
    >>> A = np.array([[2.0, 3.0], [3.0, 5.0]])
    >>> cholesky_decomposition = ichol(csc_matrix(A))
    >>> cholesky_decomposition(np.array([1.0, 2.0]))
    array([-1.,  1.])
    z*Matrix A must be a scipy.sparse.csc_matrix)Zdtyper   r   r   zPERFORMANCE WARNING:z{Thresholded incomplete Cholesky decomposition failed due to insufficient positive-definiteness of matrix A with parameters:z    discard_threshold = %ez    shift = %ez=Try decreasing discard_threshold or start with a larger shift r   zThresholded incomplete Cholesky decomposition failed because more than max_nnz non-zero elements were created. Try increasing max_nnz or discard_threshold.zThresholded incomplete Cholesky decomposition failed due to insufficient positive-definiteness of matrix A and diagonal shifts did not help.N)
isinstancer;   r<   Z
csr_matrixTr=   
ValueErrorZhas_canonical_formatZsum_duplicatesshapeAssertionErrorr   r   r   r
   r	   r,   r.   r/   Zastyper0   printr5   )Ar   Zshiftsr   r   r   mr   r   r   r   r   r   r*   r*   r+   ichol   sf    8
 

rP   )numpyr   Zscipy.sparser;   Znumbar   r,   r3   r4   objectr5   intrP   r*   r*   r*   r+   <module>   s&   
i

&