o
    iN]                     @   sl  d dl Z d dl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mZmZmZ ddlmZmZ 						d2d
ejdejdee dee dee dee deejdf fddZ			d3dejdejdee dee deejejf f
ddZ	d4dejdejdee deejejf fddZ						d5dejd
ejdee dee dee dee dee dee dejfdd Z					d6dejd
ejdee dee dee dee dee dejfd!d"Z					d6dejd
ejdee dee dee dee dee dejfd#d$Z							d7d
ejdejdee dee dee dee dee d%ee d&ee dejfd'd(Z						d8d
ejdejdee dee dee dee dee deejejf fd)d*Z	d4d+ejd,ejdee deejejejf fd-d.Z							d9d
ejdejdee dee dee dee d/ee dee dejfd0d1Z dS ):    N)OptionalTuple)fft   )!block_toeplitz_conjugate_gradienttoeplitz_conjugate_gradient)_coherence_to_neg_sdr
_normalize_remove_mean_solve_permutation)toeplitzblock_toeplitzFTrefest	zero_meanpairwise	load_diagwith_coh_sarreturn.c                 C   s   |rt | dd} t |dd}t| dd} t|dd}|s|r%td| |}|r*|}ntd| |}t|}|rrtd| | }|durO|t|jd |  }tj||}	td||	}
|rnt	||
ddddf \}}
||
fS |S )zJ
    Special case of computing cosine metrics with filter length of 1
    axisz...cn,...dn->...cdz...n,...n->...N...lc,...lc->...c.)
r
   r	   npeinsumsquareeyeshapelinalgsolvebroadcast_arrays)r   r   r   r   r   r   xcorrcoh_sdracmsolcoh_sar r&   O/home/ubuntu/.local/lib/python3.10/site-packages/fast_bss_eval/numpy/metrics.py'square_cosine_metrics_length_one_filter%   s*   
r(   xylengthc                 C   s  |du r	| j d }t| j d |j d }dtt| j d | d  }tj| |dd}tj||dd}tj|jd |j	d  |d}|rjt
d| |}	tj|	|dd}
|d	d|f |
d	d|ddf fS | | }	tj|	|dd}
|d	d|f |
d	d|f fS )
a  
    Compute the auto correlation function of x and its cross-correlation with y.
    This function is specialized for when only the SDR is needed.
    In this case, only the auto-correlation of each source is required.

    Parameters
    ----------
    x: numpy.ndarray, (..., n_chan_x, n_samples)
        Usually the reference signals
    y: numpy.ndarray, (..., n_chan_y, n_samples)
        Usually the estimated signals
    length: int, optional
        The length at which to truncate the statistics
    pairwise: bool, optional
        When this flag is true, statistics are computed for all
        pairs of source/estimate. This only affects the cross-correlation.

    Returns
    -------
    acf: numpy.ndarray, (..., n_chan_x, length)
        The auto-correlation functions of x
    xcorr: numpy.ndarray
        The cross-correlation functions of x and y.
        The shape is (..., n_chan_x, length, n_chan_y) when pairwise is True, and
        (..., n_chan_x, length) when pairwise is False.
    Nr      r   nr   )r.   z...cn,...dn->...cnd.)r   maxmathceillog2r   rfftirfftrealimagr   r   conj)r)   r*   r+   r   max_lenn_fftXYacfXYr!   r&   r&   r'   compute_statsQ   s    
"& r?   c                 C   s  |du r	| j d }t| j d |j d }dtt| j d | d  }tj| |dd}tj||dd}td||	 }tj
||dd}tj|dd|ddddf |d| dddddf gdd	}td|	 |}	tj
|	|dd}
|
dd|ddddf }
||
fS )
a  
    Compute the auto correlation function of x and its cross-correlation with y.
    This function computes the full auto-correlation matrix for all reference signals.
    This is only needed when both the SDR and the SIR have to be computed.

    Parameters
    ----------
    x: np.ndarray, (..., n_chan_x, n_samples)
        Usually the reference signals
    y: np.ndarray, (..., n_chan_y, n_samples)
        Usually the estimated signals
    length: int, optional
        The length at which to truncate the statistics

    Returns
    -------
    acf: (..., length, n_chan_x, n_chan_y)
        The auto-correlation functions of x
    xcorr: np.ndarray, (..., length, n_chan_x, n_chan_y)
        The cross-correlation functions of y
    Nr   r,   r   r-   z...cn,...dn->...ncd.r   )r   r0   r1   r2   r3   r   r4   r   r   r8   r5   concatenate)r)   r*   r+   r9   r:   r;   r<   prodr=   r>   r!   r&   r&   r'   compute_stats_2   s   
"DrC      filter_lengthuse_cg_iterclamp_dbc                 C   s   |dkrt || |d|dd}nT|rt| } t|}t| dd} t|dd}t|| ||d\}	}
|dur;|	d  |7  < |du rKt|	}tj||
}nt|	|
|d	}|r\t	d
|
|}nt	d|
|}t
||d}|S )a  
    Compute the negative signal-to-distortion ratio (SDR).

    The order of est/ref follows the convention of pytorch loss functions
    (i.e., est first).

    Parameters
    ----------
    est: np.ndarray (..., n_channels_est, n_samples)
        The estimated signals
    ref: np.ndarray (..., n_channels_ref, n_samples)
        The groundtruth reference signals
    filter_length: int, optional
        The length of the distortion filter allowed (default: ``512``)
    use_cg_iter: int, optional
        If provided, an iterative method is used to solve for the distortion
        filter coefficients instead of direct Gaussian elimination.
        This can speed up the computation of the metrics in case the filters
        are long. Using a value of 10 here has been shown to provide
        good accuracy in most cases and is sufficient when using this
        loss to train neural separation networks.
    zero_mean: bool, optional
        When set to True, the mean of all signals is subtracted prior
        to computation of the metrics (default: ``False``)
    clamp_db: bool, optional
        If provided, the resulting metrics are clamped to be in the range ``[-clamp_db, clamp_db]``
    pairwise: bool, optional
        If set to True, the metrics are computed for every est/ref signals pair (default: False).
        When set to False, it is expected that ``n_channels_ref == n_channels_est``.
    load_diag: float, optional
        If provided, this small value is added to the diagonal coefficients of
        the system metrics when solving for the filter coefficients.
        This can help stabilize the metric in the case where some of the reference
        signals may sometimes be zero

    Returns
    -------
    neg_cisdr: np.ndarray
        The negative SDR of the input signal. The returned tensor has shape
        (..., n_channels_est) if ``pairwise == False`` and
        (..., n_channels_ref, n_channels_est) if ``pairwise == True``.
    r   NF)r   r   r   r   r   r   )r+   r   ).r   n_iterr   ...l,...l->...rG   )r(   r
   r	   r?   r   r   r   r   r   r   r   )r   r   rE   rF   r   rG   r   r   cohr=   r!   R_matr$   	neg_cisdrr&   r&   r'   sdr_loss   s4   5rO   c                 C   s   t || |||||ddd	S )NTF)rE   rF   r   rG   r   change_signreturn_perm)sdrr   r   rE   rF   r   rG   r   r&   r&   r'   sdr_pit_loss  s   	rT   c              
   C   s   t | ||||||ddS )a  
    Compute the negative signal-to-distortion ratio (SDR).

    This function computes the SDR for all pairs of est/ref signals.

    The order of est/ref follows the convention of pytorch loss functions
    (i.e., est first).

    Parameters
    ----------
    est: np.ndarray (..., n_channels_est, n_samples)
        The estimated signals
    ref: np.ndarray (..., n_channels_ref, n_samples)
        The groundtruth reference signals
    filter_length: int, optional
        The length of the distortion filter allowed (default: ``512``)
    use_cg_iter: int, optional
        If provided, an iterative method is used to solve for the distortion
        filter coefficients instead of direct Gaussian elimination.
        This can speed up the computation of the metrics in case the filters
        are long. Using a value of 10 here has been shown to provide
        good accuracy in most cases and is sufficient when using this
        loss to train neural separation networks.
    zero_mean: bool, optional
        When set to True, the mean of all signals is subtracted prior
        to computation of the metrics (default: ``False``)
    clamp_db: bool, optional
        If provided, the resulting metrics are clamped to be in the range ``[-clamp_db, clamp_db]``
    load_diag: float, optional
        If provided, this small value is added to the diagonal coefficients of
        the system metrics when solving for the filter coefficients.
        This can help stabilize the metric in the case where some of the reference
        signals may sometimes be zero

    Returns
    -------
    neg_cisdr: np.ndarray, (..., n_channels_ref, n_channels_est)
        The negative SDR of the input signal
    T)rE   rF   r   rG   r   r   )rO   rS   r&   r&   r'   pairwise_sdr_loss5  s   0rU   rQ   rP   c	              
   C   sF   t || ||d|||d}	t|	dd\}	}
|r|	n|	 }|r!||
fS |S )ah  
    Compute the signal-to-distortion ratio (SDR).

    This function computes the SDR for all pairs of est/ref signals and finds the
    permutation maximizing the SDR.

    The order of ref/est follows the convention of bss_eval (i.e., ref first).

    Parameters
    ----------
    ref: np.ndarray (..., n_channels_est, n_samples)
        The estimated signals
    est: np.ndarray (..., n_channels_ref, n_samples)
        The groundtruth reference signals
    filter_length: int, optional
        The length of the distortion filter allowed (default: ``512``)
    use_cg_iter: int, optional
        If provided, an iterative method is used to solve for the distortion
        filter coefficients instead of direct Gaussian elimination.
        This can speed up the computation of the metrics in case the filters
        are long. Using a value of 10 here has been shown to provide
        good accuracy in most cases and is sufficient when using this
        loss to train neural separation networks.
    zero_mean: bool, optional
        When set to True, the mean of all signals is subtracted prior
        to computation of the metrics (default: ``False``)
    clamp_db: bool, optional
        If provided, the resulting metrics are clamped to be in the range ``[-clamp_db, clamp_db]``
    load_diag: float, optional
        If provided, this small value is added to the diagonal coefficients of
        the system metrics when solving for the filter coefficients.
        This can help stabilize the metric in the case where some of the reference
        signals may sometimes be zero
    return_perm: bool, optional
        If set to True, the optimal permutation of the estimated signals is
        also returned (default: ``False``)
    change_sign: bool, optional
        If set to True, the sign is flipped and the negative SDR is returned
        (default: ``False``)

    Returns
    -------
    cisdr: np.ndarray, (..., n_channels_est)
        The SDR of the input signal
    perm: np.ndarray, (..., n_channels_est), optional
        The index of the corresponding reference signal.
        Only returned if ``return_perm == True``
    T)rE   rF   r   r   rG   r   rQ   )rO   r   )r   r   rE   rF   r   rG   r   rQ   rP   neg_sdrpermrR   r&   r&   r'   rR   q  s   <rR   c                 C   s  |dkrt | ||||ddS |rt|}t| } t|dd}t| dd} t| ||d\}}tt| jd }	|durF|d	d
|	|	f  |7  < |d	|	|	f }
|
dd}
|
d	d|f }
|rd|dd}n|d	dd|	|	f dd}|du rt|
}t	j
||}nt|
||d}|rt	d||}nt	d||}||jdd d |jdd  }|du rt|}t	j
||}n(|r|}|dd}||jdd d |jdd  }nd}t||||d}t	d||}|rt	||d	dddf \}}||fS )a   
    This function computes the square cosines of the angles between

    1. the estimate and the subspaces of shifts of each of the reference signals
    2. the estimate and the subspace of shifts of all reference signals

    The order of ref/est follows the convention of bss_eval (i.e., ref first).

    Parameters
    ----------
    ref: np.ndarray (..., n_channels_est, n_samples)
        The estimated signals
    est: np.ndarray (..., n_channels_ref, n_samples)
        The groundtruth reference signals
    filter_length: int, optional
        The length of the distortion filter allowed (default: ``512``)
    use_cg_iter: int, optional
        If provided, an iterative method is used to solve for the distortion
        filter coefficients instead of direct Gaussian elimination.
        This can speed up the computation of the metrics in case the filters
        are long. Using a value of 10 here has been shown to provide
        good accuracy in most cases and is sufficient when using this
        loss to train neural separation networks.
    zero_mean: bool, optional
        When set to True, the mean of all signals is subtracted prior
        to computation of the metrics (default: ``False``)
    pairwise: bool, optional
        When this flag is true, statistics are computed for all
        pairs of source/estimate. This only affects the cross-correlation.
    load_diag: float, optional
        If provided, this small value is added to the diagonal coefficients of
        the system metrics when solving for the filter coefficients.
        This can help stabilize the metric in the case where some of the reference
        signals may sometimes be zero

    Returns
    -------
    neg_cisdr: np.ndarray, (..., n_channels_ref, n_channels_est)
        The negative SDR of the input signal
    r   T)r   r   r   r   r   r   )r+   r/   N.r   r@   rH   r   rJ   )r   )rI   r)   )r(   r
   r	   rC   listranger   swapaxesr   r   r   r   r   r   reshaper   r   r    )r   r   rE   rF   r   r   r   r=   r!   diag_indicesacf_sdr	xcorr_sdrrM   r$   r"   x0r%   r&   r&   r'   square_cosine_metrics  sZ   3	&(ra   r"   r%   c                 C   s6   | | }t | |d}t ||d}t ||d}|||fS )zP
    Helper function that converts the square cosine metrics to SDR/SIR/SAR
    rK   )r   )r"   r%   rG   coh_sirrW   neg_sirneg_sarr&   r&   r'   _base_metrics_bss_evalA  s
   
re   compute_permutationc              	   C   s   |s| j d |j d ksJ dt| ||||||d\}}	t||	|d\}
}}|r>t||
|dd\}}
}}|
 | | |fS |
 | | fS )av  
    This function computes the SDR, SIR, and SAR for the input reference and estimated
    signals.

    The order of ref/est follows the convention of bss_eval (i.e., ref first).

    Parameters
    ----------
    ref: np.ndarray (..., n_channels_est, n_samples)
        The estimated signals
    est: np.ndarray (..., n_channels_ref, n_samples)
        The groundtruth reference signals
    filter_length: int, optional
        The length of the distortion filter allowed (default: ``512``)
    use_cg_iter: int, optional
        If provided, an iterative method is used to solve for the distortion
        filter coefficients instead of direct Gaussian elimination.
        This can speed up the computation of the metrics in case the filters
        are long. Using a value of 10 here has been shown to provide
        good accuracy in most cases and is sufficient when using this
        loss to train neural separation networks.
    zero_mean: bool, optional
        When set to True, the mean of all signals is subtracted prior
        to computation of the metrics (default: ``False``)
    clamp_db: bool, optional
        If provided, the resulting metrics are clamped to be in the range ``[-clamp_db, clamp_db]``
    compute_permutation: bool, optional
        When this flag is true, the optimal permutation of the estimated signals
        to maximize the SIR is computed (default: ``True``)
    load_diag: float, optional
        If provided, this small value is added to the diagonal coefficients of
        the system metrics when solving for the filter coefficients.
        This can help stabilize the metric in the case where some of the reference
        signals may sometimes be zero

    Returns
    -------
    sdr: numpy.ndarray, (..., n_channels_est)
        The signal-to-distortion-ratio (SDR)
    sir: numpy.ndarray, (..., n_channels_est)
        The signal-to-interference-ratio (SIR)
    sar: numpy.ndarray, (..., n_channels_est)
        The signal-to-interference-ratio (SIR)
    perm: numpy.ndarray, (..., n_channels_est)
        The index of the corresponding reference signal (only when
        ``compute_permutation == True``)
    r/   z\For non-pairwise computation, the number of reference and estimated signals must be the same)rE   rF   r   r   r   rK   TrV   )r   ra   re   r   )r   r   rE   rF   r   rG   rf   r   r"   r%   rW   rc   rd   rX   r&   r&   r'   bss_eval_sourcesQ  s,   :

rg   )FTNT)NT)N)rD   NFNNF)rD   NFNN)rD   NFNNFF)rD   NFTN)rD   NFNTN)!r1   typingr   r   numpyr   scipyr   cgdr   r   helpersr   r	   r
   r   r   r   r   ndarrayboolfloatr(   intr?   rC   rO   rT   rU   rR   ra   re   rg   r&   r&   r&   r'   <module>   s  
/
;
3	
i

?	

T
 
	