class_docstr: Implementation of Region Perturbation by Samek et al., 2015.
  
  Consider a greedy iterative procedure that consists of measuring how the class
  encoded in the image (e.g. as measured by the function f) disappears when we
  progressively remove information from the image x, a process referred to as
  region perturbation, at the specified locations.
  
  Assumptions:
      - The original metric definition relies on image-patch functionality. Therefore, only apply the
      metric to 3-dimensional (image) data. To extend the applicablity to other data domains,
      adjustments to the current implementation might be necessary.
  
  References:
      1) Wojciech Samek et al.: "Evaluating the visualization of what a deep
      neural network has learned." IEEE transactions on neural networks and
      learning systems 28.11 (2016): 2660-2673.
  
  Attributes:
      -  _name: The name of the metric.
      - _data_applicability: The data types that the metric implementation currently supports.
      - _models: The model types that this metric can work with.
      - score_direction: How to interpret the scores, whether higher/ lower values are considered better.
      - evaluation_category: What property/ explanation quality that this metric measures.
class_docstr_tok: ["Implementation","of","Region","Perturbation","by","Samek","et","al.",",","2015",".","Consider","a","greedy","iterative","procedure","that","consists","of","measuring","how","the","class","encoded","in","the","image","(","e.g",".","as","measured","by","the","function","f",")","disappears","when","we","progressively","remove","information","from","the","image","x",",","a","process","referred","to","as","region","perturbation",",","at","the","specified","locations",".","Assumptions",":","-","The","original","metric","definition","relies","on","image-patch","functionality",".","Therefore",",","only","apply","the","metric","to","3-dimensional","(","image",")","data",".","To","extend","the","applicablity","to","other","data","domains",",","adjustments","to","the","current","implementation","might","be","necessary",".","References",":","1",")","Wojciech","Samek","et","al",".",":","``","Evaluating","the","visualization","of","what","a","deep","neural","network","has","learned",".","''","IEEE","transactions","on","neural","networks","and","learning","systems","28.11","(","2016",")",":","2660-2673",".","Attributes",":","-","_name",":","The","name","of","the","metric",".","-","_data_applicability",":","The","data","types","that","the","metric","implementation","currently","supports",".","-","_models",":","The","model","types","that","this","metric","can","work","with",".","-","score_direction",":","How","to","interpret","the","scores",",","whether","higher\/","lower","values","are","considered","better",".","-","evaluation_category",":","What","property\/","explanation","quality","that","this","metric","measures","."]
docstr: Evaluate instance gets model and data for a single instance as input and returns the evaluation result.
  
  Parameters
  ----------
  model: ModelInterface
      A ModelInteface that is subject to explanation.
  x: np.ndarray
      The input to be evaluated on an instance-basis.
  y: np.ndarray
      The output to be evaluated on an instance-basis.
  a: np.ndarray
      The explanation to be evaluated on an instance-basis.
  s: np.ndarray
      The segmentation to be evaluated on an instance-basis.
  
  Returns
  -------
     : list
      The evaluation results.
docstr_tok: ["Evaluate","instance","gets","model","and","data","for","a","single","instance","as","input","and","returns","the","evaluation","result",".","Parameters","--","--","--","--","--","model",":","ModelInterface","A","ModelInteface","that","is","subject","to","explanation",".","x",":","np.ndarray","The","input","to","be","evaluated","on","an","instance-basis",".","y",":","np.ndarray","The","output","to","be","evaluated","on","an","instance-basis",".","a",":","np.ndarray","The","explanation","to","be","evaluated","on","an","instance-basis",".","s",":","np.ndarray","The","segmentation","to","be","evaluated","on","an","instance-basis",".","Returns","--","--","--","-",":","list","The","evaluation","results","."]
code: def evaluate_instance(
      self,
      model: ModelInterface,
      x: np.ndarray,
      y: np.ndarray,
      a: np.ndarray,
  ) -> List[float]:
      """
      Evaluate instance gets model and data for a single instance as input and returns the evaluation result.
  
      Parameters
      ----------
      model: ModelInterface
          A ModelInteface that is subject to explanation.
      x: np.ndarray
          The input to be evaluated on an instance-basis.
      y: np.ndarray
          The output to be evaluated on an instance-basis.
      a: np.ndarray
          The explanation to be evaluated on an instance-basis.
      s: np.ndarray
          The segmentation to be evaluated on an instance-basis.
  
      Returns
      -------
         : list
          The evaluation results.
      """
  
      # Predict on input.
      x_input = model.shape_input(x, x.shape, channel_first=True)
      y_pred = float(model.predict(x_input)[:, y])
  
      patches = []
      x_perturbed = x.copy()
  
      # Pad input and attributions. This is needed to allow for any patch_size.
      pad_width = self.patch_size - 1
      x_pad = utils._pad_array(
          x, pad_width, mode="constant", padded_axes=self.a_axes
      )
      a_pad = utils._pad_array(
          a, pad_width, mode="constant", padded_axes=self.a_axes
      )
  
      # Create patches across whole input shape and aggregate attributions.
      att_sums = []
      axis_iterators = [
          range(pad_width, x_pad.shape[axis] - pad_width)
          for axis in self.a_axes
      ]
      for top_left_coords in itertools.product(*axis_iterators):
          # Create slice for patch.
          patch_slice = utils.create_patch_slice(
              patch_size=self.patch_size,
              coords=top_left_coords,
          )
  
          # Sum attributions for patch.
          att_sums.append(
              a_pad[
                  utils.expand_indices(a_pad, patch_slice, self.a_axes)
              ].sum()
          )
          patches.append(patch_slice)
  
      if self.order == "random":
          # Order attributions randomly.
          order = np.arange(len(patches))
          np.random.shuffle(order)
  
      elif self.order == "morf":
          # Order attributions according to the most relevant first.
          order = np.argsort(att_sums)[::-1]
  
      elif self.order == "lerf":
          # Order attributions according to the least relevant first.
          order = np.argsort(att_sums)
  
      else:
          raise ValueError(
              "Chosen order must be in ['random', 'morf', 'lerf'] but is: {self.order}."
          )
  
      # Create ordered list of patches.
      ordered_patches = [patches[p] for p in order]
  
      # Remove overlapping patches
      blocked_mask = np.zeros(x_pad.shape, dtype=bool)
      ordered_patches_no_overlap = []
      for patch_slice in ordered_patches:
          patch_mask = np.zeros(x_pad.shape, dtype=bool)
          patch_mask[
              utils.expand_indices(patch_mask, patch_slice, self.a_axes)
          ] = True
          # patch_mask_exp = utils.expand_indices(patch_mask, patch_slice, self.a_axes)
          # patch_mask[patch_mask_exp] = True
          intersected = blocked_mask & patch_mask
  
          if not intersected.any():
              ordered_patches_no_overlap.append(patch_slice)
              blocked_mask = blocked_mask | patch_mask
  
          if len(ordered_patches_no_overlap) >= self.regions_evaluation:
              break
  
      # Warn
      warn.warn_iterations_exceed_patch_number(
          self.regions_evaluation, len(ordered_patches_no_overlap)
      )
  
      # Increasingly perturb the input and store the decrease in function value.
      results = [None for _ in range(len(ordered_patches_no_overlap))]
      for patch_id, patch_slice in enumerate(
          ordered_patches_no_overlap
      ):
          # Pad x_perturbed. The mode should probably depend on the used perturb_func?
          x_perturbed_pad = utils._pad_array(
              x_perturbed,
              pad_width,
              mode="edge",
              padded_axes=self.a_axes,
          )
  
          # Perturb.
          x_perturbed_pad = self.perturb_func(
              arr=x_perturbed_pad,
              indices=patch_slice,
              indexed_axes=self.a_axes,
          )
  
          # Remove padding.
          x_perturbed = utils._unpad_array(
              x_perturbed_pad, pad_width, padded_axes=self.a_axes
          )
  
          warn.warn_perturbation_caused_no_change(
              x=x, x_perturbed=x_perturbed
          )
  
          # Predict on perturbed input x and store the difference from predicting on unperturbed input.
          x_input = model.shape_input(
              x_perturbed, x.shape, channel_first=True
          )
          y_pred_perturb = float(model.predict(x_input)[:, y])
  
          results[patch_id] = y_pred - y_pred_perturb
  
      return results
  
file_path: Quantus/quantus/metrics/faithfulness/region_perturbation.py
imports: import itertools
  import sys
  from typing import Any, Callable, Dict, List, Optional
  import numpy
  from quantus.functions.perturb_func import baseline_replacement_by_indices
  from quantus.helpers import asserts, plotting, utils, warn
  from quantus.helpers.enums import DataType, EvaluationCategory, ModelType, ScoreDirection
  from quantus.helpers.model.model_interface import ModelInterface
  from quantus.helpers.perturbation_utils import make_perturb_func
  from quantus.metrics.base import Metric
label_desc: Use image node_id 3 for calling the RegionPerturbation obj's underlying member method code with example usage: obj.evaluate_instance(model, x, y, a) and returns: results