class_docstr: Implementation of the spatial transformation attack using translation and rotation of inputs. The attack conducts
  black-box queries to the target model in a grid search over possible translations and rotations to find optimal
  attack parameters.
  
  | Paper link: https://arxiv.org/abs/1712.02779
docstr: Generate adversarial samples and return them in an array.
  
  :param x: An array with the original inputs.
  :param y: An array with the original labels to be predicted.
  :return: An array holding the adversarial examples.
docstr_tok: ["Generate","adversarial","samples","and","return","them","in","an","array",".",":","param","x",":","An","array","with","the","original","inputs",".",":","param","y",":","An","array","with","the","original","labels","to","be","predicted",".",":","return",":","An","array","holding","the","adversarial","examples","."]
code: def generate(
      self, x: np.ndarray, y: Optional[np.ndarray] = None, **kwargs
  ) -> np.ndarray:
      """
      Generate adversarial samples and return them in an array.
  
      :param x: An array with the original inputs.
      :param y: An array with the original labels to be predicted.
      :return: An array holding the adversarial examples.
      """
      logger.info(
          "Computing spatial transformation based on grid search."
      )
  
      if len(x.shape) == 2:
          raise ValueError(
              "Feature vectors detected. The attack can only be applied to data with spatial"
              "dimensions."
          )
  
      if (
          self.attack_trans_x is None
          or self.attack_trans_y is None
          or self.attack_rot is None
      ):
          y_pred = self.estimator.predict(x, batch_size=1)
          if self.estimator.nb_classes == 2 and y_pred.shape[1] == 1:
              raise ValueError(
                  "This attack has not yet been tested for binary classification with a single output classifier."
              )
  
          y_pred_max = np.argmax(y_pred, axis=1)
  
          nb_instances = len(x)
  
          # Determine grids
          max_num_pixel_trans_x = int(
              round((x.shape[1] * self.max_translation / 100.0))
          )
          max_num_pixel_trans_y = int(
              round((x.shape[2] * self.max_translation / 100.0))
          )
  
          grid_trans_x = [
              int(round(g))
              for g in list(
                  np.linspace(
                      -max_num_pixel_trans_x,
                      max_num_pixel_trans_x,
                      num=self.num_translations,
                  )
              )
          ]
          grid_trans_y = [
              int(round(g))
              for g in list(
                  np.linspace(
                      -max_num_pixel_trans_y,
                      max_num_pixel_trans_y,
                      num=self.num_translations,
                  )
              )
          ]
          grid_rot = list(
              np.linspace(
                  -self.max_rotation,
                  self.max_rotation,
                  num=self.num_rotations,
              )
          )
  
          # Remove duplicates
          grid_trans_x = list(set(grid_trans_x))
          grid_trans_y = list(set(grid_trans_y))
          grid_rot = list(set(grid_rot))
  
          grid_trans_x.sort()
          grid_trans_y.sort()
          grid_rot.sort()
  
          # Search for worst case
          fooling_rate = 0.0
          x_adv = np.copy(x)
          trans_x = 0
          trans_y = 0
          rot = 0.0
  
          # Initialize progress bar
          pbar = tqdm(
              total=len(grid_trans_x)
              * len(grid_trans_y)
              * len(grid_rot),
              desc="Spatial transformation",
              disable=not self.verbose,
          )
  
          for trans_x_i in grid_trans_x:
              for trans_y_i in grid_trans_y:
                  for rot_i in grid_rot:
                      # Generate the adversarial examples
                      x_adv_i = self._perturb(
                          x, trans_x_i, trans_y_i, rot_i
                      )
  
                      # Compute the error rate
                      y_adv_i = np.argmax(
                          self.estimator.predict(x_adv_i, batch_size=1),
                          axis=1,
                      )
                      fooling_rate_i = (
                          np.sum(y_pred_max != y_adv_i) / nb_instances
                      )
  
                      if fooling_rate_i > fooling_rate:
                          fooling_rate = fooling_rate_i
                          trans_x = trans_x_i
                          trans_y = trans_y_i
                          rot = rot_i
                          x_adv = np.copy(x_adv_i)
                      pbar.update(1)
          pbar.close()
  
          self.fooling_rate = fooling_rate
          self.attack_trans_x = trans_x
          self.attack_trans_y = trans_y
          self.attack_rot = rot
  
          logger.info(
              "Success rate of spatial transformation attack: %.2f%%",
              100 * self.fooling_rate,
          )
          logger.info(
              "Attack-translation in x: %.2f%%", self.attack_trans_x
          )
          logger.info(
              "Attack-translation in y: %.2f%%", self.attack_trans_y
          )
          logger.info("Attack-rotation: %.2f%%", self.attack_rot)
  
      else:
          x_adv = self._perturb(
              x,
              self.attack_trans_x,
              self.attack_trans_y,
              self.attack_rot,
          )
  
      return x_adv
  
file_path: adversarial-robustness-toolbox/art/attacks/evasion/spatial_transformation.py
imports: from __future__ import absolute_import, division, print_function, unicode_literals
  import logging
  from typing import Optional, TYPE_CHECKING
  import numpy
  from scipy.ndimage import rotate, shift
  from tqdm.auto import tqdm
  from art.attacks.attack import EvasionAttack
  from art.estimators.estimator import BaseEstimator, NeuralNetworkMixin
label_desc: Use image node_id 2 for calling the SpatialTransformation obj's underlying member method code with example usage: obj.generate(x, y) and returns: x_adv