o
    pi!                     @   sh   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	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ee  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__ Q/home/ubuntu/.local/lib/python3.10/site-packages/pyannote/audio/utils/powerset.pyr   0   s
   
zPowerset.__init__returnc                 C   sB   g }t d| jd D ]}tt | j|D ]	}|t| qq
|S )a3  List of powerset classes

        e.g. with num_classes = 3 and max_set_size = 2:
        {}, {0}, {1}, {2}, {0, 1}, {0, 2}, {1, 2}

        Returns
        -------
        powerset_classes : list of set[int]
            List of powerset classes, each represented as a set of regular class indices.
        r      )ranger	   r   r   appendset)r   powerset_classesset_sizecurrent_setr   r   r   r   9   s   zPowerset.powerset_classesc                 C   s
   t | jS )zNumber of powerset classes)lenr   r   r   r   r   num_powerset_classesK   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_kr   r   r   r   r   r   P   s   
zPowerset.build_mappingc                 C   s   t j| jddS )z#Compute size of each powerset classr   dim)r"   sumr
   r    r   r   r   r   o   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_multilabels   s   zPowerset.to_multilabelc                 C   s   | j ||dS )zAlias for `to_multilabel`)r)   )r3   )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   )Fr.   r"   r/   r1   r
   Tr!   )r   r5   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:   inttiler!   r'   r/   tupletolist)r   r9   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   rG   r@   )r   permutation_mappingr9   r   r   r   rH      s   zPowerset.permutation_mapping)F)__name__
__module____qualname____doc__r>   r   r   listr   r   r!   r"   Tensorr   r   boolr3   r4   r8   r   rG   r   rH   __classcell__r   r   r   r   r   %   s&    
	


-0r   )	functoolsr   	itertoolsr   r   typingr   r   r"   torch.nnr,   torch.nn.functionalr-   r6   Moduler   r   r   r   r   <module>   s   