This function requires that at least one positive example is provided for each pair -- a property that is assured by these functions.

The input has a specific format, which is a list of two-element tuples.

Each of the tuples contains the negative :math:`\\{S_p^-\\}` and the positive :math:`\\{S_p^+\\}` scores for one probe item :math:`p`, or ``None`` in case of open set recognition.

To read the lists from score files in 4 or 5 column format, please use the :py:func:`bob.measure.load.cmc_four_column` or :py:func:`bob.measure.load.cmc_five_column` function.

If **threshold** is set to ``None``, the rank 1 recognition rate is defined as the number of test items, for which the highest positive :math:`\\max\\{S_p^+\\}` score is greater than or equal to all negative scores, divided by the number of all probe items :math:`P`:

If **threshold** is set to `None`, the recognition rate is defined as the number of test items, for which the

positive score is greater than or equal to all negative scores, divided by

the number of all test items. If several positive scores for one test item exist, the **highest** score is taken.

For a given rank :math:`r>1`, up to :math:`r` negative scores that are higher than the highest positive score are allowed to still count as correctly classified in the top :math:`r` rank.

If **threshold** is given, the recognition rate is defined as the number of test items, for which the

positive score is greater than or equal to all negative scores and the threshold divided by

the number of all test items. If several positive scores for one test item exist, the **highest** score is taken.

If ``threshold`` :math:`\\theta` is given, **all** scores below threshold will be filtered out.

Hence, if all positive scores are below threshold :math:`\\max\\{S_p^+\\} < \\theta`, the probe will be misclassified **at any rank**.

For open set recognition, i.e., when there exist a tuple including negative scores without corresponding positive scores (``None``), and **all** negative scores are below ``threshold`` :math:`\\max\\{S_p^+\\} < \\theta`, the probe item is correctly rejected, **and it does not count into the denominator** :math:`P`.

When no ``threshold`` is provided, the open set probes will **always** count as misclassified, regardless of the ``rank``.

CMC scores loaded with one of the functions (:py:func:`bob.measure.load.cmc_four_column` or :py:func:`bob.measure.load.cmc_five_column`)

CMC scores loaded with one of the functions (:py:func:`bob.measure.load.cmc_four_column` or :py:func:`bob.measure.load.cmc_five_column`).

Each pair contains the ``negative`` and the ``positive`` scores for **one probe item**.

Each pair can contain up to one empty array (or ``None``), i.e., in case of open set recognition.

``rank`` : int

The ranks for which the recognition rate should be computed.

``rank`` : int or ``None``

The rank for which the recognition rate should be computed, 1 by default.

``threshold`` : float or ``None``

Decision threshold. If ``None``, the decision threshold will be the **highest** positive score.

Decision threshold. If not ``None``, **all** scores will be filtered by the threshold.

In an open set recognition problem, all open set scores (negatives with no corresponding positive) for which all scores are below threshold, will be counted as correctly rejected and **removed** from the probe list (i.e., the denominator).

**Returns:**

``RR`` : float

The rank 1 recognition rate, i.e., the relative number of correctly identified identities

The (open set) recognition rate for the given rank, a value between 0 and 1.

"""

# If no scores are given, the recognition rate is exactly 0.

ifnotcmc_scores:

return0.

ifrankisNone:

rank=1

correct=0

counter=0

forneg,posincmc_scores:

# set all values that are empty before to None

ifposisnotNoneandnotnumpy.array(pos).size:

pos=None

ifnegisnotNoneandnotnumpy.array(neg).size:

neg=None

ifposisNoneandnegisNone:

raiseValueError("One pair of the CMC scores has neither positive nor negative values")

# filter out any negative or positive scores below threshold

ifthresholdisnotNoneandnegisnotNone:

neg=numpy.array(neg[neg>=threshold])

# filter out any negative or positive scores below threshold; scores with exactly the threshold are also filtered out

# now, None and an empty array have different meanings.

ifthresholdisnotNone:

ifnegisnotNone:

neg=numpy.array(neg)[neg>threshold]

ifposisnotNone:

pos=numpy.array(pos)[pos>threshold]

ifposisNone:

# no positives, so we definitely do not have a match;

# check if we have negatives above threshold

ifnotneg.ndim:

ifnotneg.size:

# we have no negative scores over the threshold, so we have correctly rejected the probe