def _binary_classification_curve(scores: np.ndarray, gts: np.ndarray, thresholds: np.ndarray) -> np.ndarray:
    """Compute binary classification matrices at multiple thresholds.

    This implementation is optimized for CPU performance compared to torchmetrics
    alternatives when using pre-defined thresholds.

    Note:
        Arguments must be validated before calling this function.

    Args:
        scores: Anomaly scores of shape ``(D,)``
        gts: Binary ground truth of shape ``(D,)``
        thresholds: Sequence of thresholds in ascending order ``(K,)``

    Returns:
        Binary classification matrix curve of shape ``(K, 2, 2)``
        containing TP, FP, FN, TN counts at each threshold
    """
    num_th = len(thresholds)

    # POSITIVES
    scores_positives = scores[gts]
    # the sorting is very important for the algorithm to work and the speedup
    scores_positives = np.sort(scores_positives)
    # variable updated in the loop; start counting with lowest thresh ==>
    # everything is predicted as positive
    num_pos = current_count_tp = scores_positives.size
    tps = np.empty((num_th,), dtype=np.int64)

    # NEGATIVES
    # same thing but for the negative samples
    scores_negatives = scores[~gts]
    scores_negatives = np.sort(scores_negatives)
    num_neg = current_count_fp = scores_negatives.size
    fps = np.empty((num_th,), dtype=np.int64)

    def score_less_than_thresh(score: float, thresh: float) -> bool:
        return score < thresh

    # it will progressively drop the scores that are below the current thresh
    for thresh_idx, thresh in enumerate(thresholds):
        # UPDATE POSITIVES
        # < becasue it is the same as ~(>=)
        num_drop = sum(1 for _ in itertools.takewhile(partial(score_less_than_thresh, thresh=thresh), scores_positives))
        scores_positives = scores_positives[num_drop:]
        current_count_tp -= num_drop
        tps[thresh_idx] = current_count_tp

        # UPDATE NEGATIVES
        # same with the negatives
        num_drop = sum(1 for _ in itertools.takewhile(partial(score_less_than_thresh, thresh=thresh), scores_negatives))
        scores_negatives = scores_negatives[num_drop:]
        current_count_fp -= num_drop
        fps[thresh_idx] = current_count_fp

    # deduce the rest of the matrix counts
    fns = num_pos * np.ones((num_th,), dtype=np.int64) - tps
    tns = num_neg * np.ones((num_th,), dtype=np.int64) - fps

    # sequence of dimensions is (thresholds, true class, predicted class)
    return np.stack(
        [
            np.stack([tns, fps], axis=-1),
            np.stack([fns, tps], axis=-1),
        ],
        axis=-1,
    ).transpose(0, 2, 1)
Compute binary classification matrices at multiple thresholds.

    This implementation is optimized for CPU performance compared to torchmetrics
    alternatives when using pre-defined thresholds.

    Note:
        Arguments must be validated before calling this function.

    Args:
        scores: Anomaly scores of shape ``(D,)``
        gts: Binary ground truth of shape ``(D,)``
        thresholds: Sequence of thresholds in ascending order ``(K,)``

    Returns:
        Binary classification matrix curve of shape ``(K, 2, 2)``
        containing TP, FP, FN, TN counts at each threshold
    
src/anomalib/metrics/pimo/binary_classification_curve.py