class_docstr: Area under per region overlap (AUPRO) Metric.
class_docstr_tok: ["Area","under","per","region","overlap","(","AUPRO",")","Metric","."]
docstr: Compute the pro/fpr value-pairs until the fpr specified by self.fpr_limit.
  
  It leverages the fact that the overlap corresponds to the tpr, and thus computes the overall
  PRO curve by aggregating per-region tpr/fpr values produced by ROC-construction.
  
  Returns:
      tuple[Tensor, Tensor]: tuple containing final fpr and tpr values.
docstr_tok: ["Compute","the","pro\/fpr","value-pairs","until","the","fpr","specified","by","self.fpr_limit",".","It","leverages","the","fact","that","the","overlap","corresponds","to","the","tpr",",","and","thus","computes","the","overall","PRO","curve","by","aggregating","per-region","tpr\/fpr","values","produced","by","ROC-construction",".","Returns",":","tuple","[","Tensor",",","Tensor","]",":","tuple","containing","final","fpr","and","tpr","values","."]
code: def compute_pro(
      self, cca: Tensor, target: Tensor, preds: Tensor
  ) -> tuple[Tensor, Tensor]:
      """Compute the pro/fpr value-pairs until the fpr specified by self.fpr_limit.
  
      It leverages the fact that the overlap corresponds to the tpr, and thus computes the overall
      PRO curve by aggregating per-region tpr/fpr values produced by ROC-construction.
  
      Returns:
          tuple[Tensor, Tensor]: tuple containing final fpr and tpr values.
      """
      if self.num_thresholds is not None:
          # binary_roc is applying a sigmoid on the predictions before computing the roc curve
          # when some predictions are out of [0, 1], the binning between min and max predictions
          # cannot be applied in that case. This can be removed when
          #  https://github.com/Lightning-AI/torchmetrics/issues/1526 is fixed and
          #  the roc curve is computed with deactivated formatting.
  
          if torch.all((0 <= preds) * (preds <= 1)):
              thresholds = thresholds_between_min_and_max(
                  preds, self.num_thresholds, self.device
              )
          else:
              thresholds = thresholds_between_0_and_1(
                  self.num_thresholds, self.device
              )
  
      else:
          thresholds = None
  
      # compute the global fpr-size
      fpr: Tensor = binary_roc(
          preds=preds,
          target=target,
          thresholds=thresholds,
      )[
          0
      ]  # only need fpr
      output_size = torch.where(fpr <= self.fpr_limit)[0].size(0)
  
      # compute the PRO curve by aggregating per-region tpr/fpr curves/values.
      tpr = torch.zeros(
          output_size, device=preds.device, dtype=torch.float
      )
      fpr = torch.zeros(
          output_size, device=preds.device, dtype=torch.float
      )
      new_idx = torch.arange(
          0, output_size, device=preds.device, dtype=torch.float
      )
  
      # Loop over the labels, computing per-region tpr/fpr curves, and aggregating them.
      # Note that, since the groundtruth is different for every all to `roc`, we also get
      # different/unique tpr/fpr curves (i.e. len(_fpr_idx) is different for every call).
      # We therefore need to resample per-region curves to a fixed sampling ratio (defined above).
      labels = cca.unique()[1:]  # 0 is background
      background = cca == 0
      _fpr: Tensor
      _tpr: Tensor
      for label in labels:
          interp: bool = False
          new_idx[-1] = output_size - 1
          mask = cca == label
          # Need to calculate label-wise roc on union of background & mask, as otherwise we wrongly consider other
          # label in labels as FPs. We also don't need to return the thresholds
          _fpr, _tpr = binary_roc(
              preds=preds[background | mask],
              target=mask[background | mask],
              thresholds=thresholds,
          )[:-1]
  
          # catch edge-case where ROC only has fpr vals > self.fpr_limit
          if _fpr[_fpr <= self.fpr_limit].max() == 0:
              _fpr_limit = _fpr[_fpr > self.fpr_limit].min()
          else:
              _fpr_limit = self.fpr_limit
  
          _fpr_idx = torch.where(_fpr <= _fpr_limit)[0]
          # if computed roc curve is not specified sufficiently close to self.fpr_limit,
          # we include the closest higher tpr/fpr pair and linearly interpolate the tpr/fpr point at self.fpr_limit
          if not torch.allclose(_fpr[_fpr_idx].max(), self.fpr_limit):
              _tmp_idx = torch.searchsorted(_fpr, self.fpr_limit)
              _fpr_idx = torch.cat([_fpr_idx, _tmp_idx.unsqueeze_(0)])
              _slope = 1 - (
                  (_fpr[_tmp_idx] - self.fpr_limit)
                  / (_fpr[_tmp_idx] - _fpr[_tmp_idx - 1])
              )
              interp = True
  
          _fpr = _fpr[_fpr_idx]
          _tpr = _tpr[_fpr_idx]
  
          _fpr_idx = _fpr_idx.float()
          _fpr_idx /= _fpr_idx.max()
          _fpr_idx *= new_idx.max()
  
          if interp:
              # last point will be sampled at self.fpr_limit
              new_idx[-1] = _fpr_idx[-2] + (
                  (_fpr_idx[-1] - _fpr_idx[-2]) * _slope
              )
  
          _tpr = self.interp1d(_fpr_idx, _tpr, new_idx)
          _fpr = self.interp1d(_fpr_idx, _fpr, new_idx)
          tpr += _tpr
          fpr += _fpr
  
      # Actually perform the averaging
      tpr /= labels.size(0)
      fpr /= labels.size(0)
      return fpr, tpr
  
imports: from __future__ import annotations
  from typing import Any, Callable
  import torch
  from matplotlib.figure import Figure
  from torch import Tensor
  from torchmetrics import Metric
  from torchmetrics.functional import auc
  from torchmetrics.functional.classification import binary_roc
  from torchmetrics.utilities.data import dim_zero_cat
  from anomalib.utils.metrics.pro import connected_components_cpu, connected_components_gpu
  from .binning import thresholds_between_0_and_1, thresholds_between_min_and_max
  from .plotting_utils import plot_figure
label_desc: Use image node_id 4 for calling the AUPRO obj's underlying member method code with example usage: obj.compute_pro(cca, target, preds) and returns: fpr,  tpr