U
    5d/                     @   s   d Z ddlZddlZddlmZ ddlmZ ddgZej	ddd	d
d Z
ej	ddd	dd Zej	ddd	dddZdddZdddZej	ddd	dddZdS )zMatching functions    N   )ParameterError)valid_intervalsmatch_intervalsmatch_eventsT)Znopythoncachec                 C   s   | d |d g}|d |d k r(|   | d |d g}|d |d k rP|   |d |d  }|dk rld}|d |d  }|dkr|| S dS )zJaccard similarity between two intervals

    Parameters
    ----------
    int_a, int_b : np.ndarrays, shape=(2,)

    Returns
    -------
    Jaccard similarity between intervals
    r   r   g        )reverse)Zint_aZint_bZendsZstartsintersectionunion r   9/tmp/pip-unpacked-wheel-8l90aumz/librosa/util/matching.py	__jaccard   s    r   c                 C   s6   d}d}|D ]$}t | || }||kr|| }}q|S )z4Find the best Jaccard match from query to candidates)r   )queryintervals_to
candidatesZ
best_scoreZbest_idxidxZscorer   r   r   __match_interval_overlaps.   s    r   c                 C   s  t |dddf }t |dddf }||df }||df }t j|| dddf dd}t j|| dddf dd}t jt| tjd}	tt| D ]}
| |
 }||
 }||
 }t|d| t||d @ }t|dkrt	||||	|
< q|rt
qt j}t j}||
 dkr4|d |||
 d   }||
 d t|k rb|||
 d  |d  }||k r|||
 d  |	|
< q|||
 d  |	|
< q|	S )z.Numba-accelerated interval matching algorithm.Nr   r   right)ZsideleftZdtype)npargsortsearchsortedemptylennumbaZuint32rangesetr   r   inf)intervals_fromr   strictstart_indexZ	end_indexZstart_sortedZ
end_sortedZsearch_endsZsearch_startsoutputir   Zafter_queryZbefore_queryr   Zdist_beforeZ
dist_afterr   r   r   __match_intervals<   s4     
r%   c              
   C   sx   t | dkst |dkr tdt|  t| zt| ||dW S  tk
rr } ztd||W 5 d}~X Y nX dS )a
  Match one set of time intervals to another.

    This can be useful for tasks such as mapping beat timings
    to segments.

    Each element ``[a, b]`` of ``intervals_from`` is matched to the
    element ``[c, d]`` of ``intervals_to`` which maximizes the
    Jaccard similarity between the intervals::

        max(0, |min(b, d) - max(a, c)|) / |max(d, b) - min(a, c)|

    In ``strict=True`` mode, if there is no interval with positive
    intersection with ``[a,b]``, an exception is thrown.

    In ``strict=False`` mode, any interval ``[a, b]`` that has no
    intersection with any element of ``intervals_to`` is instead
    matched to the interval ``[c, d]`` which minimizes::

        min(|b - c|, |a - d|)

    that is, the disjoint interval [c, d] with a boundary closest
    to [a, b].

    .. note:: An element of ``intervals_to`` may be matched to multiple
       entries of ``intervals_from``.

    Parameters
    ----------
    intervals_from : np.ndarray [shape=(n, 2)]
        The time range for source intervals.
        The ``i`` th interval spans time ``intervals_from[i, 0]``
        to ``intervals_from[i, 1]``.
        ``intervals_from[0, 0]`` should be 0, ``intervals_from[-1, 1]``
        should be the track duration.
    intervals_to : np.ndarray [shape=(m, 2)]
        Analogous to ``intervals_from``.
    strict : bool
        If ``True``, intervals can only match if they intersect.
        If ``False``, disjoint intervals can match.

    Returns
    -------
    interval_mapping : np.ndarray [shape=(n,)]
        For each interval in ``intervals_from``, the
        corresponding interval in ``intervals_to``.

    See Also
    --------
    match_events

    Raises
    ------
    ParameterError
        If either array of input intervals is not the correct shape

        If ``strict=True`` and some element of ``intervals_from`` is disjoint from
        every element of ``intervals_to``.

    Examples
    --------
    >>> ints_from = np.array([[3, 5], [1, 4], [4, 5]])
    >>> ints_to = np.array([[0, 2], [1, 3], [4, 5], [6, 7]])
    >>> librosa.util.match_intervals(ints_from, ints_to)
    array([2, 1, 2], dtype=uint32)
    >>> # [3, 5] => [4, 5]  (ints_to[2])
    >>> # [1, 4] => [1, 3]  (ints_to[1])
    >>> # [4, 5] => [4, 5]  (ints_to[2])

    The reverse matching of the above is not possible in ``strict`` mode
    because ``[6, 7]`` is disjoint from all intervals in ``ints_from``.
    With ``strict=False``, we get the following:

    >>> librosa.util.match_intervals(ints_to, ints_from, strict=False)
    array([1, 1, 2, 2], dtype=uint32)
    >>> # [0, 2] => [1, 4]  (ints_from[1])
    >>> # [1, 3] => [1, 4]  (ints_from[1])
    >>> # [4, 5] => [4, 5]  (ints_from[2])
    >>> # [6, 7] => [4, 5]  (ints_from[2])
    r   z'Attempting to match empty interval list)r!   z(Unable to match intervals with strict={}N)r   r   r   r%   format)r    r   r!   excr   r   r   r   p   s    Qc                 C   s   t | dkst |dkr td|sB|sBtt| |sBtd|s^t|t| k r^td|szt|t| krztdtj| tjd}t	|| |||S )a  Match one set of events to another.

    This is useful for tasks such as matching beats to the nearest
    detected onsets, or frame-aligned events to the nearest zero-crossing.

    .. note:: A target event may be matched to multiple source events.

    Examples
    --------
    >>> # Sources are multiples of 7
    >>> s_from = np.arange(0, 100, 7)
    >>> s_from
    array([ 0,  7, 14, 21, 28, 35, 42, 49, 56, 63, 70, 77, 84, 91,
           98])
    >>> # Targets are multiples of 10
    >>> s_to = np.arange(0, 100, 10)
    >>> s_to
    array([ 0, 10, 20, 30, 40, 50, 60, 70, 80, 90])
    >>> # Find the matching
    >>> idx = librosa.util.match_events(s_from, s_to)
    >>> idx
    array([0, 1, 1, 2, 3, 3, 4, 5, 6, 6, 7, 8, 8, 9, 9])
    >>> # Print each source value to its matching target
    >>> zip(s_from, s_to[idx])
    [(0, 0), (7, 10), (14, 10), (21, 20), (28, 30), (35, 30),
     (42, 40), (49, 50), (56, 60), (63, 60), (70, 70), (77, 80),
     (84, 80), (91, 90), (98, 90)]

    Parameters
    ----------
    events_from : ndarray [shape=(n,)]
        Array of events (eg, times, sample or frame indices) to match from.
    events_to : ndarray [shape=(m,)]
        Array of events (eg, times, sample or frame indices) to
        match against.
    left : bool
    right : bool
        If ``False``, then matched events cannot be to the left (or right)
        of source events.

    Returns
    -------
    event_mapping : np.ndarray [shape=(n,)]
        For each event in ``events_from``, the corresponding event
        index in ``events_to``::

            event_mapping[i] == arg min |events_from[i] - events_to[:]|

    See Also
    --------
    match_intervals

    Raises
    ------
    ParameterError
        If either array of input events is not the correct shape
    r   z$Attempting to match empty event listzWCannot match events with left=right=False and events_from is not contained in events_tozICannot match events with left=False and max(events_to) < max(events_from)zJCannot match events with right=False and min(events_to) > min(events_from)r   )
r   r   r   allZin1dmaxmin
empty_likeZint32__match_events_helper)events_from	events_tor   r   r#   r   r   r   r      s     :c                 C   s  t |}|| }t |}|| }t ||}	t|	D ]:\}
}d}d}d}t|	}d}d}d}|	|
 }||
 }|t|kr|d8 }|r|dkr|d }d}|r|t|d k r|d }d}t|| | }|r|rt|| | }|r|rt|| | }|rJ|s|| |ks<|s(||k s<||k rJ||k rJ|| | |
< q8|rh||k rh|| | |
< q8|| | |
< q8t | }| ||< |S )NFr   r   r   T)r   r   r   	enumerater   absr+   )r#   r-   r.   r   r   Zfrom_idxZsorted_fromZto_idxZ	sorted_toZmatching_indicesindZ
middle_indZ	left_flagZ
right_flagZleft_indZ	right_indZ	left_diffZ
right_diffZmid_diffZsorted_from_numZ	solutionsr   r   r   r,   ,  s`    



r,   )T)T)TT)TT)__doc__Znumpyr   r   
exceptionsr   utilsr   __all__Zjitr   r   r%   r   r   r,   r   r   r   r   <module>   s"   

3
`
\   