o
    pi1/                     @   sT   d Z ddlZdddZdd Zdd Zd	d
 Zdd Zdd ZdddZdd Z	dS )z
Generalized Eigenvalue Decomposition.

This library contains different methods to adjust the format of
complex Hermitian matrices and find their eigenvectors and
eigenvalues.

Authors
 * William Aris 2020
 * Francois Grondin 2020
    Nc                 C   sX  |   }| j|d  }ttdd|  d d d }t| }|du rAtj| j| j| jd}t	||}d|dd	|d	 |d kf< t|}tj
|}t|}	t|	|d |d }
t|	t||
}tj
j|d
d\}}tj| jtd	|d  d| d| f | j| jd}||dtd	d| td	d| f< t|
|}t|}t|}||fS )a4  This method computes the eigenvectors and the eigenvalues
    of complex Hermitian matrices. The method finds a solution to
    the problem AV = BVD where V are the eigenvectors and D are
    the eigenvalues.

    The eigenvectors returned by the method (vs) are stored in a tensor
    with the following format (*,C,C,2).

    The eigenvalues returned by the method (ds) are stored in a tensor
    with the following format (*,C,C,2).

    Arguments
    ---------
    a : torch.Tensor
        A first input matrix. It is equivalent to the matrix A in the
        equation in the description above. The tensor must have the
        following format: (*,2,C+P).

    b : torch.Tensor
        A second input matrix. It is equivalent tot the matrix B in the
        equation in the description above. The tensor must have the
        following format: (*,2,C+P).
        This argument is optional and its default value is None. If
        b == None, then b is replaced by the identity matrix in the
        computations.

    Returns
    -------
    vs : torch.Tensor
    ds : torch.Tensor

    Example
    -------

    Suppose we would like to compute eigenvalues/eigenvectors on the
    following complex Hermitian matrix:

    A = [ 52        34 + 37j  16 + j28 ;
          34 - 37j  125       41 + j3  ;
          16 - 28j  41 - j3   62       ]

    >>> a = torch.FloatTensor([[52,34,16,125,41,62],[0,37,28,0,3,0]])
    >>> vs, ds = gevd(a)

    This corresponds to:

    D = [ 20.9513  0        0        ;
          0        43.9420  0        ;
          0        0        174.1067 ]

    V = [ 0.085976 - 0.85184j  -0.24620 + 0.12244j  -0.24868 - 0.35991j  ;
          -0.16006 + 0.20244j   0.37084 + 0.40173j  -0.79175 - 0.087312j ;
          -0.43990 + 0.082884j  -0.36724 - 0.70045j -0.41728 + 0 j       ]

    where

    A = VDV^-1

                ?   Ndtypedeviceg      ?.r   UUPLO)dimshapeintroundftorchzerosr   r   triu_indiceslinalgcholeskyinverse	transposematmuleighslicerangeginv)abDPCashidsbshlshlsh_inv	lsh_inv_Tcshesyshdshvshvsds r/   b/home/ubuntu/SoloSpeech/.venv/lib/python3.10/site-packages/speechbrain/processing/decomposition.pygevd   s0   = 
""r1   c                 C   s   |   }| j|d  }ttdd|  d d d }t| }t|dd}t||}tjj	|dd\}}tj
|j|j|jd	}	t||	d
tdd| tdd| f< t|}
t|	}|
|fS )a  Singular Value Decomposition (Left Singular Vectors).

    This function finds the eigenvalues and eigenvectors of the
    input multiplied by its transpose (a x a.T).

    The function will return (in this order):
        1. The eigenvalues in a tensor with the format (*,C,C,2)
        2. The eigenvectors in a tensor with the format (*,C,C,2)

    Arguments:
    ----------
    a : torch.Tensor
        A complex input matrix to work with. The tensor must have
        the following format: (*,2,C+P).

    Example:
    --------
    >>> import torch

    >>> from speechbrain.processing.features import STFT
    >>> from speechbrain.processing.multi_mic import Covariance
    >>> from speechbrain.processing.decomposition import svdl
    >>> from speechbrain.dataio.dataio import read_audio_multichannel

    >>> xs_speech = read_audio_multichannel(
    ...    'tests/samples/multi-mic/speech_-0.82918_0.55279_-0.082918.flac'
    ... )
    >>> xs_noise = read_audio_multichannel('tests/samples/multi-mic/noise_diffuse.flac')
    >>> xs = xs_speech + 0.05 * xs_noise
    >>> xs = xs.unsqueeze(0).float()
    >>>
    >>> stft = STFT(sample_rate=16000)
    >>> cov = Covariance()
    >>>
    >>> Xs = stft(xs)
    >>> XXs = cov(Xs)
    >>> us, ds = svdl(XXs)
    r   r   r   r   r	   r
   r   .r   )r   r   r   r   r   r   r   r   r   r   r   r   r   sqrtr   r   )r   r   r    r!   r"   ash_Tash_mm_ash_Tr)   ushr+   usr.   r/   r/   r0   svdlz   s   ( (r9   c                 C   s  |   }| |d |d } | j|d  }ttdd|  d d d }tj| jd|d  d| d| f | j| jd}t	||}| d |d|d d |d d f< | d |d|d d |d d f< | d |d|d d d |d d d f< | d |d|d d d |d d d f< d	| d
  |d|d d |d d d f< d	| d
  |d|d d d |d d f< | d
 |d|d d d |d d f< | d
 |d|d d |d d d f< |S )a  Transform 1.

    This method takes a complex Hermitian matrix represented by its
    upper triangular part and converts it to a block matrix
    representing the full original matrix with real numbers.
    The output tensor will have the following format:
    (*,2C,2C)

    Arguments
    ---------
    ws : torch.Tensor
        An input matrix. The tensor must have the following format:
        (*,2,C+P)

    Returns
    -------
    wsh : torch.Tensor
    r   r   r   r   r   r   .r   .r3   .r   )
r   r   r   r   r   r   r   r   r   r   )wsr   r    r!   wshr#   r/   r/   r0   r      s&     ""****&&r   c                 C   s   |   }t| j|d  d }t||d  d }tj| jd|d  d|f | j| jd}t||}| d|d d |d d f |ddddf< d| d|d d |d d d f  |ddddf< |S )a  Inverse transform 1

    This method takes a block matrix representing a complex Hermitian
    matrix and converts it to a complex matrix represented by its
    upper triangular part. The result will have the following format:
    (*,2,C+P)

    Arguments
    ---------
    wsh : torch.Tensor
        An input matrix. The tensor must have the following format:
        (*,2C,2C)

    Returns
    -------
    ws : torch.Tensor
    r   r   r   r   .Nr3   )r   r   r   r   r   r   r   r   )r=   r   r!   r    r<   r#   r/   r/   r0   finv   s    ,4r>   c                 C   s   |   }| j|d  }tj| jd|d  d| d| f | j| jd}| d |dtdd| dtdd| df< | d |dtdd| dtdd| df< d| d	  |dtdd| dtdd| df< | d	 |dtdd| dtdd| df< |S )
aX  Transform 2.

    This method takes a full complex matrix and converts it to a block
    matrix. The result will have the following format:
    (*,2C,2C).

    Arguments
    ---------
    ws : torch.Tensor
        An input matrix. The tensor must have the following format:
        (*,C,C,2)

    Returns
    -------
    wsh : torch.Tensor
    r   r      r   r:   .r   r3   r;   )r   r   r   r   r   r   r   )r<   r   r!   r=   r/   r/   r0   g  s    **.*r@   c                 C   s   |   }t| j|d  d }tj| jd|d  ||df | j| jd}| dtdd| dtdd| df |d< | dtdd| dtdd| df |d< |S )a  Inverse transform 2.

    This method takes a complex Hermitian matrix represented by a block
    matrix and converts it to a full complex complex matrix. The
    result will have the following format:
    (*,C,C,2)

    Arguments
    ---------
    wsh : torch.Tensor
        An input matrix. The tensor must have the following format:
        (*,2C,2C)

    Returns
    -------
    ws : torch.Tensor
    r   r   r   r   .r:   r;   )r   r   r   r   r   r   r   r   )r=   r   r!   r<   r/   r/   r0   r   +  s   "**r   MbP?#B;c           
      C   s   |   }| j|d  }ttdd|  d d d }t||}t|dddf |dddf }t| dd|f |d }||jd }|	d|d  |f }| 
 }	|	dd|f  || | 7  < |	S )	a  Diagonal modification.

    This method takes a complex Hermitian matrix represented by its upper
    triangular part and adds the value of its trace multiplied by alpha
    to the real part of its diagonal. The output will have the format:
    (*,2,C+P)

    Arguments
    ---------
    ws : torch.Tensor
        An input matrix. The tensor must have the following format:
        (*,2,C+P)
    alpha : float
        A coefficient to multiply the trace. The default value is 0.001.
    eps : float
        A small value to increase the real part of the diagonal. The
        default value is 1e-20.

    Returns
    -------
    ws_pf : torch.Tensor
    r   r   r   r   r   N.)r   )r   r   r   r   r   r   eqsumviewrepeatclone)
r<   alphaepsr   r    r!   ids_triuids_diagtracews_pfr/   r/   r0   pos_defK  s    $rN   c           	      C   s*  |   }| jd }ttdd|  d d d }tt| }t|}t|}t	||}tj
| jtd|d  ||df | j| jd}|ddd	d	f |d|d |d df< d|ddd	d	f  |d|d |d df< |ddd	d	f |d|d |d df< |ddd	d	f |d|d |d df< |S )
az  Inverse Hermitian Matrix.

    This method finds the inverse of a complex Hermitian matrix
    represented by its upper triangular part. The result will have
    the following format: (*, C, C, 2).

    Arguments
    ---------
    x : torch.Tensor
        An input matrix to work with. The tensor must have the
        following format: (*, 2, C+P)

    Returns
    -------
    x_inv : torch.Tensor

    Example
    -------
    >>> import torch
    >>>
    >>> from speechbrain.dataio.dataio import read_audio
    >>> from speechbrain.processing.features import STFT
    >>> from speechbrain.processing.multi_mic import Covariance
    >>> from speechbrain.processing.decomposition import inv
    >>>
    >>> xs_speech = read_audio(
    ...    'tests/samples/multi-mic/speech_-0.82918_0.55279_-0.082918.flac'
    ... )
    >>> xs_noise = read_audio('tests/samples/multi-mic/noise_0.70225_-0.70225_0.11704.flac')
    >>> xs = xs_speech + 0.05 * xs_noise
    >>> xs = xs.unsqueeze(0).float()
    >>>
    >>> stft = STFT(sample_rate=16000)
    >>> cov = Covariance()
    >>>
    >>> Xs = stft(xs)
    >>> XXs = cov(Xs)
    >>> XXs_inv = inv(XXs)
    r3   r   r   r   r   r   r   .N)r   r   r   r   r   rN   r   r   r>   r   r   r   r   r   )	xdp
n_channelsr"   ash_invas_invindicesx_invr/   r/   r0   invw  s"   )
 
&*&&rW   )N)rA   rB   )
__doc__r   r1   r9   r   r>   r@   r   rN   rW   r/   r/   r/   r0   <module>   s    
j@,"#
 ,