class_docstr: Implementation of the Local Lipschitz Estimate (or Stability) test by Alvarez-Melis et al., 2018a, 2018b.
  
  This tests asks how consistent are the explanations for similar/neighboring examples.
  The test denotes a (weaker) empirical notion of stability based on discrete,
  finite-sample neighborhoods i.e., argmax_(||f(x) - f(x')||_2 / ||x - x'||_2)
  where f(x) is the explanation for input x and x' is the perturbed input.
  
  References:
      1) David Alvarez-Melis and Tommi S. Jaakkola. "On the robustness of interpretability methods."
      arXiv preprint arXiv:1806.08049 (2018).
  
      2) David Alvarez-Melis and Tommi S. Jaakkola. "Towards robust interpretability with self-explaining
      neural networks." NeurIPS (2018): 7786-7795.
  
  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: Evaluates model and attributes on a single data batch and returns the batched evaluation result.
  
  Parameters
  ----------
  model: ModelInterface
      A ModelInteface that is subject to explanation.
  x_batch: np.ndarray
      The input to be evaluated on a batch-basis.
  y_batch: np.ndarray
      The output to be evaluated on a batch-basis.
  a_batch: np.ndarray
      The explanation to be evaluated on a batch-basis.
  kwargs:
      Unused.
  
  Returns
  -------
  scores_batch: np.ndarray
      The batched evaluation results.
docstr_tok: ["Evaluates","model","and","attributes","on","a","single","data","batch","and","returns","the","batched","evaluation","result",".","Parameters","--","--","--","--","--","model",":","ModelInterface","A","ModelInteface","that","is","subject","to","explanation",".","x_batch",":","np.ndarray","The","input","to","be","evaluated","on","a","batch-basis",".","y_batch",":","np.ndarray","The","output","to","be","evaluated","on","a","batch-basis",".","a_batch",":","np.ndarray","The","explanation","to","be","evaluated","on","a","batch-basis",".","kwargs",":","Unused",".","Returns","--","--","--","-","scores_batch",":","np.ndarray","The","batched","evaluation","results","."]
code: def evaluate_batch(
      self,
      model: ModelInterface,
      x_batch: np.ndarray,
      y_batch: np.ndarray,
      a_batch: np.ndarray,
      **kwargs,
  ) -> np.ndarray:
      """
      Evaluates model and attributes on a single data batch and returns the batched evaluation result.
  
      Parameters
      ----------
      model: ModelInterface
          A ModelInteface that is subject to explanation.
      x_batch: np.ndarray
          The input to be evaluated on a batch-basis.
      y_batch: np.ndarray
          The output to be evaluated on a batch-basis.
      a_batch: np.ndarray
          The explanation to be evaluated on a batch-basis.
      kwargs:
          Unused.
  
      Returns
      -------
      scores_batch: np.ndarray
          The batched evaluation results.
      """
  
      batch_size = x_batch.shape[0]
      similarities = np.zeros((batch_size, self.nr_samples)) * np.nan
  
      for step_id in range(self.nr_samples):
          # Perturb input.
          x_perturbed = perturb_batch(
              perturb_func=self.perturb_func,
              indices=np.tile(
                  np.arange(0, x_batch[0].size), (batch_size, 1)
              ),
              indexed_axes=np.arange(0, x_batch[0].ndim),
              arr=x_batch,
          )
  
          changed_prediction_indices = (
              self.changed_prediction_indices_func(
                  model, x_batch, x_perturbed
              )
          )
  
          for x_instance, x_instance_perturbed in zip(
              x_batch, x_perturbed
          ):
              warn.warn_perturbation_caused_no_change(
                  x=x_instance,
                  x_perturbed=x_instance_perturbed,
              )
  
          # Generate explanation based on perturbed input x.
          a_perturbed = self.explain_batch(model, x_perturbed, y_batch)
          # Measure similarity for each instance separately.
          for instance_id in range(batch_size):
              if instance_id in changed_prediction_indices:
                  similarities[instance_id, step_id] = np.nan
                  continue
  
              similarity = self.similarity_func(
                  a=a_batch[instance_id].flatten(),
                  b=a_perturbed[instance_id].flatten(),
                  c=x_batch[instance_id].flatten(),
                  d=x_perturbed[instance_id].flatten(),
                  norm_numerator=self.norm_numerator,
                  norm_denominator=self.norm_denominator,
              )
              similarities[instance_id, step_id] = similarity
  
      return self.max_func(similarities, axis=1)
  
file_path: Quantus/quantus/metrics/robustness/local_lipschitz_estimate.py
imports: import sys
  from typing import Any, Callable, Dict, List, Optional
  import numpy
  from quantus.functions.perturb_func import gaussian_noise, perturb_batch
  from quantus.functions.similarity_func import distance_euclidean, lipschitz_constant
  from quantus.helpers import asserts, 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_changed_prediction_indices_func, make_perturb_func
  from quantus.metrics.base import Metric
label_desc: Use image node_id 3 for calling the LocalLipschitzEstimate obj's underlying member method code with example usage: obj.evaluate_batch(model, x_batch, y_batch, a_batch) and returns: self