'Tries to match each column of the similarity matrix to a row.
Args:
similarity_matrix: tensor of shape [N, M] representing any similarity
metric.
Returns:
Match object with corresponding matches for each of M columns.'

def _match(self, similarity_matrix):

    def _match_when_rows_are_empty():
        "Performs    matching    when    the    rows    of    similarity    matrix    are    empty.\n\n                        When    the    rows    are    empty,    all    detections    are    false    positives.    So    we    return\n                        a    tensor    of    -1's    to    indicate    that    the    columns    do    not    match    to    any    rows.\n\n                        Returns:\n                                matches:        int32    tensor    indicating    the    row    each    column    matches    to.\n                        "
        return ((-1) * tf.ones([tf.shape(similarity_matrix)[1]], dtype=tf.int32))
    def _match_when_rows_are_non_empty():
        'Performs    matching    when    the    rows    of    similarity    matrix    are    non    empty.\n\n                        Returns:\n                                matches:        int32    tensor    indicating    the    row    each    column    matches    to.\n                        '
        matches = tf.argmax(similarity_matrix, 0)
        if (self._matched_threshold is not None):
            matched_vals = tf.reduce_max(similarity_matrix, 0)
            below_unmatched_threshold = tf.greater(self._unmatched_threshold, matched_vals)
            between_thresholds = tf.logical_and(tf.greater_equal(matched_vals, self._unmatched_threshold), tf.greater(self._matched_threshold, matched_vals))
            if self._negatives_lower_than_unmatched:
                matches = self._set_values_using_indicator(matches, below_unmatched_threshold, (-1))
                matches = self._set_values_using_indicator(matches, between_thresholds, (-2))
            else:
                matches = self._set_values_using_indicator(matches, below_unmatched_threshold, (-2))
                matches = self._set_values_using_indicator(matches, between_thresholds, (-1))
        if self._force_match_for_each_row:
            forced_matches_ids = tf.cast(tf.argmax(similarity_matrix, 1), tf.int32)
            row_range = tf.range(tf.shape(similarity_matrix)[0])
            col_range = tf.range(tf.shape(similarity_matrix)[1])
            forced_matches_values = tf.cast(row_range, matches.dtype)
            (keep_matches_ids, _) = tf.setdiff1d(col_range, forced_matches_ids)
            keep_matches_values = tf.gather(matches, keep_matches_ids)
            matches = tf.dynamic_stitch([forced_matches_ids, keep_matches_ids], [forced_matches_values, keep_matches_values])
        return tf.cast(matches, tf.int32)
    return tf.cond(tf.greater(tf.shape(similarity_matrix)[0], 0), _match_when_rows_are_non_empty, _match_when_rows_are_empty)
