class_docstr: Implementation of Infidelity by Yeh et al., 2019.
  
  Explanation infidelity represents the expected mean square error
  between 1) a dot product of an attribution and input perturbation and
  2) difference in model output after significant perturbation.
  
  Assumptions:
      - The original implementation (https://github.com/chihkuanyeh/saliency_evaluation/
      blob/master/infid_sen_utils.py) supports perturbation of Gaussian noise and squared patches.
      In this implementation, we use squared patches as the default option.
      - Since we use squared patches in this implementation, the metric is only applicable
      to 3-dimensional (image) data. To extend the applicability to other data domains, adjustments
      to the current implementation might be necessary.
  
  References:
      1) Chih-Kuan Yeh et al.:
      "On the (In)fidelity and Sensitivity of Explanations."
      33rd Conference on Neural Information Processing Systems (NeurIPS 2019), Vancouver, Canada.
  
  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","Infidelity","by","Yeh","et","al.",",","2019",".","Explanation","infidelity","represents","the","expected","mean","square","error","between","1",")","a","dot","product","of","an","attribution","and","input","perturbation","and","2",")","difference","in","model","output","after","significant","perturbation",".","Assumptions",":","-","The","original","implementation","(","https",":","\/\/github.com\/chihkuanyeh\/saliency_evaluation\/","blob\/master\/infid_sen_utils.py",")","supports","perturbation","of","Gaussian","noise","and","squared","patches",".","In","this","implementation",",","we","use","squared","patches","as","the","default","option",".","-","Since","we","use","squared","patches","in","this","implementation",",","the","metric","is","only","applicable","to","3-dimensional","(","image",")","data",".","To","extend","the","applicability","to","other","data","domains",",","adjustments","to","the","current","implementation","might","be","necessary",".","References",":","1",")","Chih-Kuan","Yeh","et","al",".",":","``","On","the","(","In",")","fidelity","and","Sensitivity","of","Explanations",".","''","33rd","Conference","on","Neural","Information","Processing","Systems","(","NeurIPS","2019",")",",","Vancouver",",","Canada",".","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 ModelInterface 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.
  
  Returns
  -------
  float
      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","ModelInterface","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",".","Returns","--","--","--","-","float","The","evaluation","results","."]
code: def evaluate_instance(
      self,
      model: ModelInterface,
      x: np.ndarray,
      y: np.ndarray,
      a: np.ndarray,
  ) -> float:
      """
      Evaluate instance gets model and data for a single instance as input and returns the evaluation result.
  
      Parameters
      ----------
      model: ModelInterface
          A ModelInterface 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.
  
      Returns
      -------
      float
          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])
  
      results = []
  
      for _ in range(self.n_perturb_samples):
          sub_results = []
  
          for patch_size in self.perturb_patch_sizes:
              pred_deltas = np.zeros(
                  (
                      int(a.shape[1] / patch_size),
                      int(a.shape[2] / patch_size),
                  )
              )
              a_sums = np.zeros(
                  (
                      int(a.shape[1] / patch_size),
                      int(a.shape[2] / patch_size),
                  )
              )
              x_perturbed = x.copy()
              pad_width = patch_size - 1
  
              for i_x, top_left_x in enumerate(
                  range(0, x.shape[1], patch_size)
              ):
                  for i_y, top_left_y in enumerate(
                      range(0, x.shape[2], patch_size)
                  ):
                      # Perturb input patch-wise.
                      x_perturbed_pad = utils._pad_array(
                          x_perturbed,
                          pad_width,
                          mode="edge",
                          padded_axes=self.a_axes,
                      )
                      patch_slice = utils.create_patch_slice(
                          patch_size=patch_size,
                          coords=[top_left_x, top_left_y],
                      )
  
                      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,
                      )
  
                      # Predict on perturbed input x_perturbed.
                      x_input = model.shape_input(
                          x_perturbed, x.shape, channel_first=True
                      )
                      warn.warn_perturbation_caused_no_change(
                          x=x, x_perturbed=x_input
                      )
                      y_pred_perturb = float(
                          model.predict(x_input)[:, y]
                      )
  
                      x_diff = x - x_perturbed
                      a_diff = np.dot(
                          np.repeat(
                              a, repeats=self.nr_channels, axis=0
                          ),
                          x_diff,
                      )
  
                      pred_deltas[i_x][i_y] = y_pred - y_pred_perturb
                      a_sums[i_x][i_y] = np.sum(a_diff)
  
              assert callable(self.loss_func)
              sub_results.append(
                  self.loss_func(
                      a=pred_deltas.flatten(), b=a_sums.flatten()
                  )
              )
  
          results.append(np.mean(sub_results))
  
      return np.mean(results)
  
file_path: Quantus/quantus/metrics/faithfulness/infidelity.py
imports: import sys
  from typing import Any, Callable, Dict, List, Optional, Union
  import numpy
  from quantus.functions.loss_func import mse
  from quantus.functions.perturb_func import baseline_replacement_by_indices
  from quantus.helpers import 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 Infidelity obj's underlying member method code with example usage: obj.evaluate_instance(model, x, y, a) and returns: np