o
    sit                     @   s   d Z ddlZddlZddlZddlmZ ddlZd@ddZdAdd	ZdBddZ	dCddZ
dCddZdDddZdEddZdd Z					dFddZdGddZd d! Zd"d# Zd$d% ZdHd'd(ZdCd)d*Zd+d, Zd-d. ZdId0d1Zd@d2d3Zd4d5 Zd6d7 Zd8d9 Zd:d; Zd<d= Zd>d? ZdS )Jzw
Useful functionality required across the task submodules,
such as preprocessing, validation, and common computations.
    N	decoratorFc                    s^   i  i }|sdd | D } t tt| D ]\}}| |< |||< q fdd| D }||fS )aO  Convert a list of string identifiers into numerical indices.

    Parameters
    ----------
    labels : list of strings, shape=(n,)
        A list of annotations, e.g., segment or chord labels from an
        annotation file.
    case_sensitive : bool
        Set to True to enable case-sensitive label indexing
        (Default value = False)

    Returns
    -------
    indices : list, shape=(n,)
        Numerical representation of ``labels``
    index_to_label : dict
        Mapping to convert numerical indices back to labels.
        ``labels[i] == index_to_label[indices[i]]``
    c                 S   s   g | ]}t | qS  )strlower.0sr   r   A/home/ubuntu/.local/lib/python3.10/site-packages/mir_eval/util.py
<listcomp>'       z index_labels.<locals>.<listcomp>c                       g | ]} | qS r   r   r   label_to_indexr   r
   r   /       )	enumeratesortedset)labelscase_sensitiveindex_to_labelindexr	   indicesr   r   r
   index_labels   s   
r   __c                    s    fddt t| D S )a  Given an array of items (e.g. events, intervals), create a synthetic label
    for each event of the form '(label prefix)(item number)'

    Parameters
    ----------
    items : list-like
        A list or array of events or intervals
    prefix : str
        This prefix will be prepended to all synthetically generated labels
        (Default value = '__')

    Returns
    -------
    labels : list of str
        Synthetically generated labels

    c                    s   g | ]}  | qS r   r   )r   nprefixr   r
   r   G   r   z#generate_labels.<locals>.<listcomp>)rangelen)itemsr   r   r   r
   generate_labels5   s   r!   皙?c           	      C   sL   t t|  | }tj|tjd}|| |  }t| |||}||fS )a;  Convert an array of labeled time intervals to annotated samples.

    Parameters
    ----------
    intervals : np.ndarray, shape=(n, d)
        An array of time intervals, as returned by
        :func:`mir_eval.io.load_intervals()` or
        :func:`mir_eval.io.load_labeled_intervals()`.
        The ``i`` th interval spans time ``intervals[i, 0]`` to
        ``intervals[i, 1]``.
    labels : list, shape=(n,)
        The annotation for each interval
    offset : float > 0
        Phase offset of the sampled time grid (in seconds)
        (Default value = 0)
    sample_size : float > 0
        duration of each sample to be generated (in seconds)
        (Default value = 0.1)
    fill_value : type(labels[0])
        Object to use for the label with out-of-range time points.
        (Default value = None)

    Returns
    -------
    sample_times : list
        list of sample times
    sample_labels : list
        array of labels for each generated sample

    Notes
    -----
        Intervals will be rounded down to the nearest multiple
        of ``sample_size``.
    )dtype)intnpfloormaxarangefloat32tolistinterpolate_intervals)		intervalsr   offsetsample_size
fill_valuenum_samplessample_indicessample_timessampled_labelsr   r   r
   intervals_to_samplesJ   s
   $r4   c           
      C   s   t |}t |dd |dd k rtd|gt| }t j|| dddf dd}t j|| dddf dd}t|||D ]\}}}	|	g||  |||< qA|S )	a  Assign labels to a set of points in time given a set of intervals.

    Time points that do not lie within an interval are mapped to `fill_value`.

    Parameters
    ----------
    intervals : np.ndarray, shape=(n, 2)
        An array of time intervals, as returned by
        :func:`mir_eval.io.load_intervals()`.
        The ``i`` th interval spans time ``intervals[i, 0]`` to
        ``intervals[i, 1]``.

        Intervals are assumed to be disjoint.

    labels : list, shape=(n,)
        The annotation for each interval

    time_points : array_like, shape=(m,)
        Points in time to assign labels.  These must be in
        non-decreasing order.

    fill_value : type(labels[0])
        Object to use for the label with out-of-range time points.
        (Default value = None)

    Returns
    -------
    aligned_labels : list
        Labels corresponding to the given time points.

    Raises
    ------
    ValueError
        If `time_points` is not in non-decreasing order.
       Nz+time_points must be in non-decreasing orderr   leftsideright)r%   asarrayany
ValueErrorr   searchsortedzip)
r,   r   time_pointsr/   aligned_labelsstartsendsstartendlabr   r   r
   r+   v   s   
%r+   c                    s@   t | dddf }| | } du r|S | fdd|D fS )a  Sort intervals, and optionally, their corresponding labels
    according to start time.

    Parameters
    ----------
    intervals : np.ndarray, shape=(n, 2)
        The input intervals
    labels : list, optional
        Labels for each interval

    Returns
    -------
    intervals_sorted or (intervals_sorted, labels_sorted)
        Labels are only returned if provided as input
    Nr   c                    r   r   r   )r   _r   r   r
   r      r   z*sort_labeled_intervals.<locals>.<listcomp>)r%   argsort)r,   r   idxintervals_sortedr   rH   r
   sort_labeled_intervals   s
   rL         ?c                 C   s8   | dkr
|dkr
dS d|d  |  | |d |  |  S )aa  Compute the f-measure from precision and recall scores.

    Parameters
    ----------
    precision : float in (0, 1]
        Precision
    recall : float in (0, 1]
        Recall
    beta : float > 0
        Weighting factor for f-measure
        (Default value = 1.0)

    Returns
    -------
    f_measure : float
        The weighted f-measure
    r           r5      r   )	precisionrecallbetar   r   r
   	f_measure   s   $rS      c                 C   s   t t t j| |dS )ao  Convert interval times into boundaries.

    Parameters
    ----------
    intervals : np.ndarray, shape=(n_events, 2)
        Array of interval start and end-times
    q : int
        Number of decimals to round to. (Default value = 5)

    Returns
    -------
    boundaries : np.ndarray
        Interval boundary times, including the end of the final interval
    )decimals)r%   uniqueravelround)r,   qr   r   r
   intervals_to_boundaries   s   rZ   c                 C   sB   t | t | stdt tt| dd | dd }|S )aO  Convert an array of event times into intervals

    Parameters
    ----------
    boundaries : list-like
        List-like of event times.  These are assumed to be unique
        timestamps in ascending order.

    Returns
    -------
    intervals : np.ndarray, shape=(n_intervals, 2)
        Start and end time for each interval
    z/Boundary times are not unique or not ascending.Nr6   r5   )r%   allcloserV   r=   r;   listr?   )
boundariesr,   r   r   r
   boundaries_to_intervals   s   $r^   rN   __T_MIN__T_MAXc                 C   s  |dur|dur| j dkrt||gg|gfS |du s |du r)| j dkr)td|durut| dddf |k}t|dkrT|durL||d d }| |d d } t|| } |  |krut||  g| f} |duru|	d| |durt| dddf |k}t|dkr|dur|d|d  }| d|d  } t
|| } |  |k rt| |  |gf} |dur|| | |fS )af  Adjust a list of time intervals to span the range ``[t_min, t_max]``.

    Any intervals lying completely outside the specified range will be removed.

    Any intervals lying partially outside the specified range will be cropped.

    If the specified range exceeds the span of the provided data in either
    direction, additional intervals will be appended.  If an interval is
    appended at the beginning, it will be given the label ``start_label``; if
    an interval is appended at the end, it will be given the label
    ``end_label``.

    Parameters
    ----------
    intervals : np.ndarray, shape=(n_events, 2)
        Array of interval start and end-times
    labels : list, len=n_events or None
        List of labels
        (Default value = None)
    t_min : float or None
        Minimum interval start time.
        (Default value = 0.0)
    t_max : float or None
        Maximum interval end time.
        (Default value = None)
    start_label : str or float or int
        Label to give any intervals appended at the beginning
        (Default value = '__T_MIN')
    end_label : str or float or int
        Label to give any intervals appended at the end
        (Default value = '__T_MAX')

    Returns
    -------
    new_intervals : np.ndarray
        Intervals spanning ``[t_min, t_max]``
    new_labels : list
        List of labels for ``new_labels``
    Nr   z8Supplied intervals are empty, can't append new intervalsr5   r   r   )sizer%   arrayr=   argwherer   maximumminvstackinsertminimumr'   append)r,   r   t_mint_maxstart_label	end_label	first_idxlast_idxr   r   r
   adjust_intervals  s6   1
rq   c                 C   s  |dur?t | |k}t|dkr%|dur||d d }| |d d } | d |kr?t |g| f} |dur?|dd|  |dur}t | |k}t|dkrd|dur\|d|d  }| d|d  } | d |k r}t | |gf} |dur}|d|  | |fS )aB  Adjust the given list of event times to span the range
    ``[t_min, t_max]``.

    Any event times outside of the specified range will be removed.

    If the times do not span ``[t_min, t_max]``, additional events will be
    added with the prefix ``label_prefix``.

    Parameters
    ----------
    events : np.ndarray
        Array of event times (seconds)
    labels : list or None
        List of labels
        (Default value = None)
    t_min : float or None
        Minimum valid event time.
        (Default value = 0.0)
    t_max : float or None
        Maximum valid event time.
        (Default value = None)
    label_prefix : str
        Prefix string to use for synthetic labels
        (Default value = '__')

    Returns
    -------
    new_times : np.ndarray
        Event times corrected to the given range.

    Nr   ra   z%sT_MINr6   z%sT_MAX)r%   rd   r   concatenaterh   rj   )eventsr   rk   rl   label_prefixro   rp   r   r   r
   adjust_eventsg  s*    ru   c                    sd   dd   fdd| D }t  t  g}|D ]} ||v r/|d | |  |d | q|S )a'  Return the intersection of two sets of filepaths, based on the file name
    (after the final '/') and ignoring the file extension.

    Examples
    --------
     >>> flist1 = ['/a/b/abc.lab', '/c/d/123.lab', '/e/f/xyz.lab']
     >>> flist2 = ['/g/h/xyz.npy', '/i/j/123.txt', '/k/l/456.lab']
     >>> sublist1, sublist2 = mir_eval.util.intersect_files(flist1, flist2)
     >>> print sublist1
     ['/e/f/xyz.lab', '/c/d/123.lab']
     >>> print sublist2
     ['/g/h/xyz.npy', '/i/j/123.txt']

    Parameters
    ----------
    flist1 : list
        first list of filepaths
    flist2 : list
        second list of filepaths

    Returns
    -------
    sublist1 : list
        subset of filepaths with matching stems from ``flist1``
    sublist2 : list
        corresponding filepaths from ``flist2``

    c                 S   s   t jt j| d d S )zReturn the filename given an absolute path.

        Parameters
        ----------
        abs_path

        Returns
        -------
        filename

        r6   r   )ospathsplitextsplit)abs_pathr   r   r
   fname  s   zintersect_files.<locals>.fnamec                    s   i | ]} ||qS r   r   )r   fr{   r   r
   
<dictcomp>  s    z#intersect_files.<locals>.<dictcomp>r   r5   )r\   rj   )flist1flist2fmappairsr|   r   r}   r
   intersect_files  s   r   c                 C   s   | d |d k| d |d kg}d|v rt dttj| |gdd}t|dd |d	d gj}g g }}tt|}	tt|}
|D ].\}}|	|| dddf k }|||d   |
||dddf k }|||d   qI|||fS )
a3  Merge the time intervals of two sequences.

    Parameters
    ----------
    x_intervals : np.ndarray
        Array of interval times (seconds)
    x_labels : list or None
        List of labels
    y_intervals : np.ndarray
        Array of interval times (seconds)
    y_labels : list or None
        List of labels

    Returns
    -------
    new_intervals : np.ndarray
        New interval times of the merged sequences.
    new_x_labels : list
        New labels for the sequence ``x``
    new_y_labels : list
        New labels for the sequence ``y``

    ra   )r6   r5   FzMTime intervals do not align; did you mean to call 'adjust_intervals()' first?r   axisNr6   r5   )	r=   r%   rV   rr   rc   Tr(   r   rj   )x_intervalsx_labelsy_intervalsy_labelsalign_checktime_boundariesoutput_intervalsx_labels_outy_labels_outx_label_rangey_label_ranget0rG   x_idxy_idxr   r   r
   merge_labeled_intervals  s$    

r   c                    sR  i  | D ]}| | D ]}| vr| |<  nq
q	 i g fdd| D  D ]} | = q(t }|r{s{i }|D ]}| | D ]}|vrQ||g | qBq<g }|D ]}|| |< | v rq| |  | | < qW| qW|r{r8si }| D ]}| | D ]
}|vrd||< qq S  fddD ]}| qq)a  Find maximum cardinality matching of a bipartite graph (U,V,E).
    The input format is a dictionary mapping members of U to a list
    of their neighbors in V.

    The output is a dict M mapping members of V to their matches in U.

    Parameters
    ----------
    graph : dictionary : left-vertex -> list of right vertices
        The input bipartite graph.  Each edge need only be specified once.

    Returns
    -------
    matching : dictionary : right-vertex -> left vertex
        A maximal bipartite matching.

    Tc                    s   i | ]}| qS r   r   )r   u)	unmatchedr   r
   r~   8  s    z$_bipartite_match.<locals>.<dictcomp>Nc                    sX   | v r*|  }| = |D ]}|v r)| }|= |u s"|r)| | <  dS qdS )zRecursively search backward through layers to find alternating
            paths.  recursion returns true if found path, false otherwise
            TFr   )vLr   pumatchingpredpredsrecurser   r   r
   r   V  s   z!_bipartite_match.<locals>.recurse)r\   
setdefaultrj   )graphr   r   layer	new_layer	unlayeredr   r   r
   _bipartite_match  sX   
r      c                 C   s<   t | |}t ||}t t j||}t ||| S )a  Compute the absolute outer distance modulo n.
    Using this distance, d(11, 0) = 1 (modulo 12)

    Parameters
    ----------
    ref : np.ndarray, shape=(n,)
        Array of reference values.
    est : np.ndarray, shape=(m,)
        Array of estimated values.
    modulus : int
        The modulus.
        12 by default for octave equivalence.

    Returns
    -------
    outer_distance : np.ndarray, shape=(n, m)
        The outer circular distance modulo n.

    )r%   modabssubtractouterri   )refestmodulus	ref_mod_n	est_mod_nabs_diffr   r   r
   _outer_distance_mod_nj  s   r   c           	      C   sr   |durt || ||k}nt| ||}i }t| D ]\}}||vr'g ||< || | qtt| }|S )a  Compute a maximum matching between reference and estimated event times,
    subject to a window constraint.

    Given two lists of event times ``ref`` and ``est``, we seek the largest set
    of correspondences ``(ref[i], est[j])`` such that
    ``distance(ref[i], est[j]) <= window``, and each
    ``ref[i]`` and ``est[j]`` is matched at most once.

    This is useful for computing precision/recall metrics in beat tracking,
    onset detection, and segmentation.

    Parameters
    ----------
    ref : np.ndarray, shape=(n,)
        Array of reference values
    est : np.ndarray, shape=(m,)
        Array of estimated values
    window : float > 0
        Size of the window.
    distance : function
        function that computes the outer distance of ref and est.
        By default uses ``|ref[i] - est[j]|``

    Returns
    -------
    matching : list of tuples
        A list of matched reference and event numbers.
        ``matching[i] == (i, j)`` where ``ref[i]`` matches ``est[j]``.

    N)r%   where_fast_hit_windowsr?   rj   r   r   r    )	r   r   windowdistancehitsGref_iest_ir   r   r   r
   match_events  s   r   c                 C   s   t | } t |}t | }| | }t j||| dd}t j||| dd}g g }}tt||D ]\}	\}
}|||
|  ||	g||
   q3||fS )a  Fast calculation of windowed hits for time events.

    Given two lists of event times ``ref`` and ``est``, and a
    tolerance window, computes a list of pairings
    ``(i, j)`` where ``|ref[i] - est[j]| <= window``.

    This is equivalent to, but more efficient than the following:

    >>> hit_ref, hit_est = np.where(np.abs(np.subtract.outer(ref, est))
    ...                             <= window)

    Parameters
    ----------
    ref : np.ndarray, shape=(n,)
        Array of reference values
    est : np.ndarray, shape=(m,)
        Array of estimated values
    window : float >= 0
        Size of the tolerance window

    Returns
    -------
    hit_ref : np.ndarray
    hit_est : np.ndarray
        indices such that ``|hit_ref[i] - hit_est[i]| <= window``
    r7   r8   r:   )r%   r;   rI   r>   r   r?   extend)r   r   r   ref_idx
ref_sortedleft_idx	right_idxhit_refhit_estjrD   rE   r   r   r
   r     s   



r   c                 C   sl   | j dks| jd dkrtd| j| dk  rtd| dddf | dddf k r4tddS )zCheck that an (n, 2) interval ndarray is well-formed, and raises errors
    if not.

    Parameters
    ----------
    intervals : np.ndarray, shape=(n, 2)
        Array of interval start/end locations.
    rO   r5   z6Intervals should be n-by-2 numpy ndarray, but shape={}r   zNegative interval times foundNz0All interval durations must be strictly positive)ndimshaper=   formatr<   r,   r   r   r
   validate_intervals  s   
$r        L@c                 C   sX   | |k  rtd|  || jdkrtd| jt| dk   r*tddS )a;  Check that a 1-d event location ndarray is well-formed, and raises
    errors if not.

    Parameters
    ----------
    events : np.ndarray, shape=(n,)
        Array of event times
    max_time : float
        If an event is found above this time, a ValueError will be raised.
        (Default value = 30000.)
    zAn event at time {} was found which is greater than the maximum allowable time of max_time = {} (did you supply event times in seconds?)r5   z5Event times should be 1-d numpy ndarray, but shape={}r   z%Events should be in increasing order.N)r<   r=   r   r'   r   r   r%   diff)rs   max_timer   r   r
   validate_events  s   
r   c                 C   sx   |rt | } t | |k rtd|  |t | |k  r-td|  || jdkr:td| jdS )a  Check that a 1-d frequency ndarray is well-formed, and raises
    errors if not.

    Parameters
    ----------
    frequencies : np.ndarray, shape=(n,)
        Array of frequency values
    max_freq : float
        If a frequency is found above this pitch, a ValueError will be raised.
        (Default value = 5000.)
    min_freq : float
        If a frequency is found below this pitch, a ValueError will be raised.
        (Default value = 20.)
    allow_negatives : bool
        Whether or not to allow negative frequency values.
    zA frequency of {} was found which is greater than the maximum allowable value of max_freq = {} (did you supply frequency values in Hz?)zA frequency of {} was found which is less than the minimum allowable value of min_freq = {} (did you supply frequency values in Hz?)r5   z5Frequencies should be 1-d numpy ndarray, but shape={}N)	r%   r   r<   r=   r   r'   rf   r   r   )frequenciesmax_freqmin_freqallow_negativesr   r   r
   validate_frequencies  s$   

r   c                 C   s4   t | }t|j D ]}|j|jkr dS qdS )zDetermine whether a function has \*\*kwargs.

    Parameters
    ----------
    function : callable
        The function to test

    Returns
    -------
    True if function accepts arbitrary keyword arguments.
    False otherwise.
    TF)inspect	signaturer\   
parametersvalueskindVAR_KEYWORD)functionsigparamr   r   r
   
has_kwargsF  s   
r   c                 O   sd   t | r| |i |S | j}|jd|j }i }t| D ]\}}||v r*|||< q| |i |S )a(  Given a function and args and keyword args to pass to it, call the function
    but using only the keyword arguments which it accepts.  This is equivalent
    to redefining the function with an additional \*\*kwargs to accept slop
    keyword args.

    If the target function already accepts \*\*kwargs parameters, no filtering
    is performed.

    Parameters
    ----------
    _function : callable
        Function to call.  Can take in any number of args or kwargs
    *args
    **kwargs
        Arguments and keyword arguments to _function.
    N)r   __code__co_varnamesco_argcountr\   r    )	_functionargskwargs	func_codefunction_argsfiltered_kwargskwargvaluer   r   r
   filter_kwargs\  s   r   c                 C   s    t |  ttj| dd S )a  Convert an array of n intervals to their n durations.

    Parameters
    ----------
    intervals : np.ndarray, shape=(n, 2)
        An array of time intervals, as returned by
        :func:`mir_eval.io.load_intervals()`.
        The ``i`` th interval spans time ``intervals[i, 0]`` to
        ``intervals[i, 1]``.

    Returns
    -------
    durations : np.ndarray, shape=(n,)
        Array of the duration of each interval.

    r6   r   )r   r%   r   r   flattenr   r   r   r
   intervals_to_durations|  s   r   c                 C   s   dt | t d  d S )a  Convert Hz to MIDI numbers

    Parameters
    ----------
    freqs : number or ndarray
        Frequency/frequencies in Hz

    Returns
    -------
    midi : number or ndarray
        MIDI note numbers corresponding to input frequencies.
        Note that these may be fractional.
          (@     {@     @Q@)r%   log2)freqsr   r   r
   
hz_to_midi  s   r   c                 C   s   dd| d d   S )zConvert MIDI numbers to Hz

    Parameters
    ----------
    midi : number or ndarray
        MIDI notes

    Returns
    -------
    freqs : number or ndarray
        Frequency/frequencies in Hz corresponding to `midi`
    r   g       @r   r   r   )midir   r   r
   
midi_to_hz  s   r   c                    s    fdd}t |S )zeMark a function as deprecated.

    Using the decorated (old) function will result in a warning.
    c              	      s:   t j| j d| j d  d dtdd | |i |S )z Warn the user, and then proceed..z$
	Deprecated as of mir_eval version z*.
	It will be removed in mir_eval version    )category
stacklevel)warningswarn
__module____name__FutureWarning)funcr   r   versionversion_removedr   r
   	__wrapper  s   zdeprecated.<locals>.__wrapperr   )r   r   r   r   r   r
   
deprecated  s   
r   )F)r   )r   r"   N)N)rM   )rT   )NrN   Nr_   r`   )NrN   Nr   )r   )r   ) __doc__rv   r   r   r   numpyr%   r   r!   r4   r+   rL   rS   rZ   r^   rq   ru   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r
   <module>   sH    

'

,
5



bD6/
Z
2,

, 