Repository: roboflow/supervision
File: supervision/metrics/mean_average_precision.py (Python)

Code before:
        Add new predictions and targets to the metric, but do not compute the result.

        Args:
            predictions (Union[Detections, List[Detections]]): The predicted detections.
            targets (Union[Detections, List[Detections]]): The ground-truth detections.

        Returns:
            (MeanAveragePrecision): The updated metric instance.
        """
        if not isinstance(predictions, list):
            predictions = [predictions]
        if not isinstance(targets, list):
            targets = [targets]

        if len(predictions) != len(targets):
            raise ValueError(
                f"The number of predictions ({len(predictions)}) and"
                f" targets ({len(targets)}) during the update must be the same."
            )
        # class-agnostic
        if self._class_agnostic:
            # Set all class_ids to 0 to ignore class distinction
            for prediction in predictions:
                prediction.class_id[:] = 0
            for target in targets:
                target.class_id[:] = 0

        self._predictions_list.extend(predictions)
        self._targets_list.extend(targets)

        return self

    def compute(
        self,
    ) -> MeanAveragePrecisionResult:
        """
        Calculate Mean Average Precision based on predicted and ground-truth
            detections at different thresholds.

        Returns:
            (MeanAveragePrecisionResult): New instance of MeanAveragePrecision.

        Example:
            ```python
            import supervision as sv
            from supervision.metrics import MeanAveragePrecision

            predictions = sv.Detections(...)
            targets = sv.Detections(...)

            map_metric = MeanAveragePrecision()

Review comment (performance):
The downside of this approach is that original `detections` are affected - their values are modified.

At the cost of performance, I reckon we should `copy.deepcopy` the data first, if class_agnostic is set.

Code after:
        Add new predictions and targets to the metric, but do not compute the result.

        Args:
            predictions (Union[Detections, List[Detections]]): The predicted detections.
            targets (Union[Detections, List[Detections]]): The ground-truth detections.

        Returns:
            (MeanAveragePrecision): The updated metric instance.
        """
        if not isinstance(predictions, list):
            predictions = [predictions]
        if not isinstance(targets, list):
            targets = [targets]

        if len(predictions) != len(targets):
            raise ValueError(
                f"The number of predictions ({len(predictions)}) and"
                f" targets ({len(targets)}) during the update must be the same."
            )

        if self._class_agnostic:
            predictions = deepcopy(predictions)
            targets = deepcopy(targets)

            for prediction in predictions:
                prediction.class_id[:] = -1
            for target in targets:
                target.class_id[:] = -1

        self._predictions_list.extend(predictions)
        self._targets_list.extend(targets)

        return self

    def compute(
        self,
    ) -> MeanAveragePrecisionResult:
        """
        Calculate Mean Average Precision based on predicted and ground-truth
            detections at different thresholds.

        Returns:
            (MeanAveragePrecisionResult): New instance of MeanAveragePrecision.

        Example:
            ```python
            import supervision as sv
            from supervision.metrics import MeanAveragePrecision

            predictions = sv.Detections(...)
            targets = sv.Detections(...)