class_docstr: Class to evaluate the performance of the poison detection method.
docstr: For each training sample, determine whether the activation clustering method was correct.
  
  :param assigned_clean_by_class: Result of clustering.
  :param is_clean_by_class: is clean separated by class.
  :return: Two variables are returned:
           1) all_errors_by_class[i]: an array indicating the correctness of each assignment
           in the ith class. Such that:
           all_errors_by_class[i] = 0 if marked poison, is poison
           all_errors_by_class[i] = 1 if marked clean, is clean
           all_errors_by_class[i] = 2 if marked poison, is clean
           all_errors_by_class[i] = 3 marked clean, is poison
           2) Json object with confusion matrix per-class.
code: def analyze_correctness(
      self,
      assigned_clean_by_class: Union[
          np.ndarray, List[int], List[np.ndarray]
      ],
      is_clean_by_class: list,
  ) -> Tuple[np.ndarray, str]:
      """
      For each training sample, determine whether the activation clustering method was correct.
  
      :param assigned_clean_by_class: Result of clustering.
      :param is_clean_by_class: is clean separated by class.
      :return: Two variables are returned:
               1) all_errors_by_class[i]: an array indicating the correctness of each assignment
               in the ith class. Such that:
               all_errors_by_class[i] = 0 if marked poison, is poison
               all_errors_by_class[i] = 1 if marked clean, is clean
               all_errors_by_class[i] = 2 if marked poison, is clean
               all_errors_by_class[i] = 3 marked clean, is poison
               2) Json object with confusion matrix per-class.
      """
      all_errors_by_class = []
      poison = 0
      clean = 1
      dic_json = {}
  
      logger.debug("Error rates per class:")
      for class_i, (assigned_clean, is_clean) in enumerate(
          zip(assigned_clean_by_class, is_clean_by_class)
      ):
          errors = []
          for assignment, bl_var in zip(assigned_clean, is_clean):
              bl_var = int(bl_var)
              # marked poison, is poison = 0
              # true positive
              if assignment == poison and bl_var == poison:
                  errors.append(0)
  
              # marked clean, is clean = 1
              # true negative
              elif assignment == clean and bl_var == clean:
                  errors.append(1)
  
              # marked poison, is clean = 2
              # false positive
              elif assignment == poison and bl_var == clean:
                  errors.append(2)
  
              # marked clean, is poison = 3
              # false negative
              elif assignment == clean and bl_var == poison:
                  errors.append(3)
              else:
                  raise Exception(
                      "Analyze_correctness entered wrong class"
                  )
  
          errors_array = np.asarray(errors)
          logger.debug("-------------------%d---------------", class_i)
          key_i = "class_" + str(class_i)
          matrix_i = self.get_confusion_matrix(errors_array)
          dic_json.update({key_i: matrix_i})
          all_errors_by_class.append(errors_array)
  
      all_errors_by_class_array = np.asarray(
          all_errors_by_class, dtype=object
      )
      conf_matrix_json = json.dumps(dic_json)
  
      return all_errors_by_class_array, conf_matrix_json
  
file_path: adversarial-robustness-toolbox/art/defences/detector/poison/ground_truth_evaluator.py
imports: from __future__ import absolute_import, division, print_function, unicode_literals
  import json
  import logging
  from typing import Tuple, Union, List
  import numpy
label_desc: Use image node_id 2 for calling the GroundTruthEvaluator obj's underlying member method code with example usage: obj.analyze_correctness(assigned_clean_by_class, is_clean_by_class) and returns: all_errors_by_class_array,  conf_matrix_json