o
    9wi                     @   sp   d dl mZ d dlmZmZ d dlmZmZ d dlZ	d dl
Z
d dlmZ d dlm  mZ G dd dejZdS )    )cached_property)combinationspermutations)DictTupleNc                       s   e Zd ZdZdedef fddZedefddZdej	fd	d
Z
dej	fddZddej	dedej	fddZddej	dedej	fddZdej	dej	fddZdeedf deedf fddZedeeedf eedf f fddZ  ZS )PowersetzPowerset to multilabel conversion, and back.

    Parameters
    ----------
    num_classes : int
        Number of regular classes.
    max_set_size : int
        Maximum number of classes in each set.
    num_classesmax_set_sizec                    sB   t    || _|| _| jd|  dd | jd|  dd d S )NmappingF)
persistentcardinality)super__init__r   r	   register_bufferbuild_mappingbuild_cardinality)selfr   r	   	__class__ Z/home/ubuntu/sommelier/.venv/lib/python3.10/site-packages/pyannote/audio/utils/powerset.pyr   0   s
   
zPowerset.__init__returnc                    s&   t t fddtd jd D S )Nc                 3   s     | ]}t j j|V  qd S )N)scipyspecialbinomr   ).0ir   r   r   	<genexpr>>   s
    
z0Powerset.num_powerset_classes.<locals>.<genexpr>r      )intsumranger	   r   r   r   r   num_powerset_classes8   s
   zPowerset.num_powerset_classesc                 C   sX   t | j| j}d}td| jd D ]}tt| j|D ]}d|||f< |d7 }qq|S )at  Compute powerset to regular mapping

        Returns
        -------
        mapping : (num_powerset_classes, num_classes) torch.Tensor
            mapping[i, j] == 1 if jth regular class is a member of ith powerset class
            mapping[i, j] == 0 otherwise

        Example
        -------
        With num_classes == 3 and max_set_size == 2, returns

            [0, 0, 0]  # none
            [1, 0, 0]  # class #1
            [0, 1, 0]  # class #2
            [0, 0, 1]  # class #3
            [1, 1, 0]  # classes #1 and #2
            [1, 0, 1]  # classes #1 and #3
            [0, 1, 1]  # classes #2 and #3

        r   r   )torchzerosr#   r   r"   r	   r   )r   r
   
powerset_kset_sizecurrent_setr   r   r   r   D   s   
zPowerset.build_mappingc                 C   s   t j| jddS )z#Compute size of each powerset classr   dim)r$   r!   r
   r   r   r   r   r   c   s   zPowerset.build_cardinalityFpowersetsoftc                 C   s>   |rt |}nt jjt j|dd| j }t || j	S )a/  Convert predictions from powerset to multi-label

        Parameter
        ---------
        powerset : (batch_size, num_frames, num_powerset_classes) torch.Tensor
            Soft predictions in "powerset" space.
        soft : bool, optional
            Return soft multi-label predictions. Defaults to False (i.e. hard predictions)
            Assumes that `powerset` are "log probabilities".

        Returns
        -------
        multi_label : (batch_size, num_frames, num_classes) torch.Tensor
            Predictions in "multi-label" space.
        r)   )
r$   expnn
functionalone_hotargmaxr#   floatmatmulr
   )r   r+   r,   powerset_probsr   r   r   to_multilabelg   s   zPowerset.to_multilabelc                 C   s   | j ||dS )zAlias for `to_multilabel`)r,   )r6   )r   r+   r,   r   r   r   forward   s   zPowerset.forward
multilabelc                 C   s&   t jtjt|| jjdd| jdS )a  Convert (hard) predictions from multi-label to powerset

        Parameter
        ---------
        multi_label : (batch_size, num_frames, num_classes) torch.Tensor
            Prediction in "multi-label" space.

        Returns
        -------
        powerset : (batch_size, num_frames, num_powerset_classes) torch.Tensor
            Hard, one-hot prediction in "powerset" space.

        Note
        ----
        This method will not complain if `multilabel` is provided a soft predictions
        (e.g. the output of a sigmoid-ed classifier). However, in that particular
        case, the resulting powerset output will most likely not make much sense.
        r-   r)   )r   )Fr1   r$   r2   r4   r
   Tr#   )r   r8   r   r   r   to_powerset   s   zPowerset.to_powersetmultilabel_permutation.c                 C   s   | j dd|f }tj| j| j jtjd}d| | jdf}tj| j | dd}tj|| dd}|d |dddf k j	dd}t
| S )a  Helper function for `permutation_mapping` property

        Takes a (num_classes,)-shaped permutation in multilabel space and returns
        the corresponding (num_powerset_classes,)-shaped permutation in powerset space.
        This does not cache anything and only works on one single permutation at a time.

        Parameters
        ----------
        multilabel_permutation : tuple of int
            Permutation in multilabel space.

        Returns
        -------
        powerset_permutation : tuple of int
            Permutation in powerset space.

        Example
        -------
        >>> powerset = Powerset(3, 2)
        >>> powerset._permutation_powerset((1, 0, 2))
        # (0, 2, 1, 3, 4, 6, 5)

        N)devicedtype   r   r-   r)   r   )r
   r$   aranger   r=   r    tiler#   r!   r2   tupletolist)r   r<   permutated_mappingr@   powers_of_twobeforeafterpowerset_permutationr   r   r   _permutation_powerset   s   $zPowerset._permutation_powersetc                 C   s2   i }t t| j| jD ]}| ||t|< q|S )a  Mapping between multilabel and powerset permutations

        Example
        -------
        With num_classes == 3 and max_set_size == 2, returns

        {
            (0, 1, 2): (0, 1, 2, 3, 4, 5, 6),
            (0, 2, 1): (0, 1, 3, 2, 5, 4, 6),
            (1, 0, 2): (0, 2, 1, 3, 4, 6, 5),
            (1, 2, 0): (0, 2, 3, 1, 6, 4, 5),
            (2, 0, 1): (0, 3, 1, 2, 5, 6, 4),
            (2, 1, 0): (0, 3, 2, 1, 6, 5, 4)
        }
        )r   r"   r   rI   rB   )r   permutation_mappingr<   r   r   r   rJ      s   zPowerset.permutation_mapping)F)__name__
__module____qualname____doc__r    r   r   r#   r$   Tensorr   r   boolr6   r7   r;   r   rI   r   rJ   __classcell__r   r   r   r   r   %   s"    



-0r   )	functoolsr   	itertoolsr   r   typingr   r   scipy.specialr   r$   torch.nnr/   torch.nn.functionalr0   r9   Moduler   r   r   r   r   <module>   s   