class_docstr: Implementation of the 'Auto Conjugate Gradient' attack.
  The original implementation is https://github.com/yamamura-k/ACG.
  
  | Paper link: https://arxiv.org/abs/2206.09628
class_docstr_tok: ["Implementation","of","the","'Auto","Conjugate","Gradient","'","attack",".","The","original","implementation","is","https",":","\/\/github.com\/yamamura-k\/ACG",".","|","Paper","link",":","https",":","\/\/arxiv.org\/abs\/2206.09628"]
docstr: Generate adversarial samples and return them in an array.
  
  :param x: An array with the original inputs.
  :param y: Target values (class labels) one-hot-encoded of shape `(nb_samples, nb_classes)` or indices of shape
            (nb_samples,). Only provide this parameter if you'd like to use true labels when crafting adversarial
            samples. Otherwise, model predictions are used as labels to avoid the "label leaking" effect
            (explained in this paper: https://arxiv.org/abs/1611.01236). Default is `None`.
  :param mask: An array with a mask broadcastable to input `x` defining where to apply adversarial perturbations.
               Shape needs to be broadcastable to the shape of x and can also be of the same shape as `x`. Any
               features for which the mask is zero will not be adversarially perturbed.
  :type mask: `np.ndarray`
  :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",":","Target","values","(","class","labels",")","one-hot-encoded","of","shape","`","(","nb_samples",",","nb_classes",")","`","or","indices","of","shape","(","nb_samples",",",")",".","Only","provide","this","parameter","if","you","'d","like","to","use","true","labels","when","crafting","adversarial","samples",".","Otherwise",",","model","predictions","are","used","as","labels","to","avoid","the","``","label","leaking","''","effect","(","explained","in","this","paper",":","https",":","\/\/arxiv.org\/abs\/1611.01236",")",".","Default","is","`","None","`",".",":","param","mask",":","An","array","with","a","mask","broadcastable","to","input","`","x","`","defining","where","to","apply","adversarial","perturbations",".","Shape","needs","to","be","broadcastable","to","the","shape","of","x","and","can","also","be","of","the","same","shape","as","`","x","`",".","Any","features","for","which","the","mask","is","zero","will","not","be","adversarially","perturbed",".",":","type","mask",":","`","np.ndarray","`",":","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: Target values (class labels) one-hot-encoded of shape `(nb_samples, nb_classes)` or indices of shape
                (nb_samples,). Only provide this parameter if you'd like to use true labels when crafting adversarial
                samples. Otherwise, model predictions are used as labels to avoid the "label leaking" effect
                (explained in this paper: https://arxiv.org/abs/1611.01236). Default is `None`.
      :param mask: An array with a mask broadcastable to input `x` defining where to apply adversarial perturbations.
                   Shape needs to be broadcastable to the shape of x and can also be of the same shape as `x`. Any
                   features for which the mask is zero will not be adversarially perturbed.
      :type mask: `np.ndarray`
      :return: An array holding the adversarial examples.
      """
      mask = kwargs.get("mask")
  
      if y is not None:
          y = check_and_transform_label_format(
              y, nb_classes=self.estimator.nb_classes
          )
  
      if y is None:
          if self.targeted:
              raise ValueError(
                  "Target labels `y` need to be provided for a targeted attack."
              )
          y = get_labels_np_array(
              self.estimator.predict(x, batch_size=self.batch_size)
          ).astype(int)
  
      if self.estimator.nb_classes == 2 and y.shape[1] == 1:
          raise ValueError(
              "This attack has not yet been tested for binary classification with a single output classifier."
          )
  
      x_adv = x.astype(ART_NUMPY_DTYPE)
  
      for _ in trange(
          max(1, self.nb_random_init),
          desc="ACG - restart",
          disable=not self.verbose,
      ):
          # Determine correctly predicted samples
          y_pred = self.estimator.predict(x_adv)
          if self.targeted:
              sample_is_robust = np.argmax(y_pred, axis=1) != np.argmax(
                  y, axis=1
              )
          elif not self.targeted:
              sample_is_robust = np.argmax(y_pred, axis=1) == np.argmax(
                  y, axis=1
              )
  
          if np.sum(sample_is_robust) == 0:
              break
  
          x_robust = x_adv[sample_is_robust]
          y_robust = y[sample_is_robust]
          x_init = x[sample_is_robust]
  
          n = x_robust.shape[0]
          m = np.prod(x_robust.shape[1:]).item()
          random_perturbation = (
              random_sphere(n, m, self.eps, self.norm)
              .reshape(x_robust.shape)
              .astype(ART_NUMPY_DTYPE)
          )
  
          x_robust = x_robust + random_perturbation
  
          if self.estimator.clip_values is not None:
              clip_min, clip_max = self.estimator.clip_values
              x_robust = np.clip(x_robust, clip_min, clip_max)
  
          perturbation = projection(
              x_robust - x_init, self.eps, self.norm
          )
          x_robust = x_init + perturbation
  
          # Compute perturbation with implicit batching
          for batch_id in trange(
              int(np.ceil(x_robust.shape[0] / float(self.batch_size))),
              desc="ACG - batch",
              leave=False,
              disable=not self.verbose,
          ):
              batch_index_1, batch_index_2 = (
                  batch_id * self.batch_size,
                  (batch_id + 1) * self.batch_size,
              )
              x_k = x_robust[batch_index_1:batch_index_2].astype(
                  ART_NUMPY_DTYPE
              )
              x_init_batch = x_init[batch_index_1:batch_index_2].astype(
                  ART_NUMPY_DTYPE
              )
              y_batch = y_robust[batch_index_1:batch_index_2]
  
              p_0 = 0
              p_1 = 0.22
              var_w = [p_0, p_1]
  
              while True:
                  p_j_p_1 = var_w[-1] + max(
                      var_w[-1] - var_w[-2] - 0.03, 0.06
                  )
                  if p_j_p_1 > 1:
                      break
                  var_w.append(p_j_p_1)
  
              var_w = [math.ceil(p * self.max_iter) for p in var_w]
  
              # self.eta = np.full((self.batch_size, 1, 1, 1), 2 * self.eps_step).astype(ART_NUMPY_DTYPE)
              _batch_size = x_k.shape[0]
              eta = np.full(
                  (_batch_size,)
                  + (1,) * len(self.estimator.input_shape),
                  self.eps_step,
              ).astype(ART_NUMPY_DTYPE)
              self.count_condition_1 = np.zeros(shape=(_batch_size,))
              gradk_1 = np.zeros_like(x_k)
              cgradk_1 = np.zeros_like(x_k)
              cgradk = np.zeros_like(x_k)
              gradk_1_best = np.zeros_like(x_k)
              cgradk_1_best = np.zeros_like(x_k)
              gradk_1_tmp = np.zeros_like(x_k)
              cgradk_1_tmp = np.zeros_like(x_k)
  
              for k_iter in trange(
                  self.max_iter,
                  desc="ACG - iteration",
                  leave=False,
                  disable=not self.verbose,
              ):
                  # Get perturbation, use small scalar to avoid division by 0
                  tol = 10e-8
  
                  # Get gradient wrt loss; invert it if attack is targeted
                  grad = self.estimator.loss_gradient(x_k, y_batch) * (
                      1 - 2 * int(self.targeted)
                  )
                  if k_iter == 0:
                      gradk_1 = grad.copy()
                      cgradk_1 = grad.copy()
                      cgradk = grad.copy()
                  else:
                      beta = get_beta(grad, gradk_1, cgradk_1)
                      cgradk = grad + beta * cgradk_1
  
                  # Apply norm bound
                  if self.norm in [np.inf, "inf"]:
                      grad = np.sign(cgradk)
                  elif self.norm == 1:
                      ind = tuple(range(1, len(x_k.shape)))
                      cgradk = cgradk / (
                          np.sum(
                              np.abs(cgradk), axis=ind, keepdims=True
                          )
                          + tol
                      )
                  elif self.norm == 2:
                      ind = tuple(range(1, len(x_k.shape)))
                      cgradk = cgradk / (
                          np.sqrt(
                              np.sum(
                                  np.square(cgradk),
                                  axis=ind,
                                  keepdims=True,
                              )
                          )
                          + tol
                      )
                  assert x_k.shape == cgradk.shape
  
                  perturbation = cgradk
  
                  if mask is not None:
                      perturbation = perturbation * (
                          mask.astype(ART_NUMPY_DTYPE)
                      )
  
                  # Apply perturbation and clip
                  x_k_p_1 = x_k + eta * perturbation
  
                  if self.estimator.clip_values is not None:
                      clip_min, clip_max = self.estimator.clip_values
                      x_k_p_1 = np.clip(x_k_p_1, clip_min, clip_max)
  
                  if k_iter == 0:
                      x_1 = x_k_p_1
                      perturbation = projection(
                          x_1 - x_init_batch, self.eps, self.norm
                      )
                      x_1 = x_init_batch + perturbation
  
                      f_0 = self.estimator.compute_loss(
                          x=x_k, y=y_batch, reduction="none"
                      )
                      f_1 = self.estimator.compute_loss(
                          x=x_1, y=y_batch, reduction="none"
                      )
  
                      self.eta_w_j_m_1 = eta.copy()
                      self.f_max_w_j_m_1 = f_0.copy()
  
                      self.f_max = f_0.copy()
                      self.x_max = x_k.copy()
  
                      f1_ge_f0 = f_1 >= f_0
                      f_1_tmp = f_1[f1_ge_f0].copy()
                      self.f_max[f1_ge_f0] = f_1_tmp.copy()
                      x_1_tmp = x_1[f1_ge_f0].copy()
                      self.x_max[f1_ge_f0] = x_1_tmp.copy()
                      self.count_condition_1[f1_ge_f0] += 1
  
                      # Settings for next iteration k
                      x_k = x_1
                      gradk_1_best = gradk_1.copy()
                      cgradk_1_best = cgradk_1.copy()
  
                  else:
                      perturbation = projection(
                          x_k_p_1 - x_init_batch, self.eps, self.norm
                      )
                      x_k_p_1 = x_init_batch + perturbation
  
                      if self.estimator.clip_values is not None:
                          (
                              clip_min,
                              clip_max,
                          ) = self.estimator.clip_values
                          x_k_p_1 = np.clip(x_k_p_1, clip_min, clip_max)
  
                      perturbation = projection(
                          x_k_p_1 - x_init_batch, self.eps, self.norm
                      )
                      x_k_p_1 = x_init_batch + perturbation
  
                      f_k_p_1 = self.estimator.compute_loss(
                          x=x_k_p_1, y=y_batch, reduction="none"
                      )
  
                      if (f_k_p_1 == 0.0).all():
                          x_k = x_k_p_1.copy()
                          break
  
                      if self.targeted:
                          fk_ge_fm = (
                              f_k_p_1 < self.f_max
                          )  # assume the loss function is cross-entropy
                      else:
                          fk_ge_fm = f_k_p_1 > self.f_max
  
                      self.count_condition_1[fk_ge_fm] += 1
                      # update the best points
                      x_k_p_1_tmp = x_k_p_1[fk_ge_fm].copy()
                      self.x_max[fk_ge_fm] = x_k_p_1_tmp.copy()
                      f_k_p_1_tmp = f_k_p_1[fk_ge_fm].copy()
                      self.f_max[fk_ge_fm] = f_k_p_1_tmp.copy()
                      gradk_1_tmp = gradk_1[fk_ge_fm].copy()
                      gradk_1_best[fk_ge_fm] = gradk_1_tmp.copy()
                      cgradk_1_tmp = cgradk_1[fk_ge_fm].copy()
                      cgradk_1_best[fk_ge_fm] = cgradk_1_tmp.copy()
  
                      # update the search points
                      x_k = x_k_p_1.copy()
                      gradk_1 = grad.copy()
                      cgradk_1 = cgradk.copy()
  
                      if k_iter in var_w:
                          rho = 0.75
  
                          condition_1 = self.count_condition_1 < rho * (
                              k_iter - var_w[var_w.index(k_iter) - 1]
                          )
                          condition_2 = np.logical_and(
                              (self.eta_w_j_m_1 == eta).squeeze(),
                              self.f_max_w_j_m_1 == self.f_max,
                          )
                          condition = np.logical_or(
                              condition_1, condition_2
                          )
  
                          # halve the stepsize if the condition is satisfied
                          eta[condition] /= 2
                          # move to the best point
                          x_max_tmp = self.x_max[condition].copy()
                          x_k[condition] = x_max_tmp.copy()
                          gradk_1_tmp = gradk_1_best[condition].copy()
                          gradk_1[condition] = gradk_1_tmp.copy()
                          cgradk_1_tmp = cgradk_1_best[condition].copy()
                          cgradk_1[condition] = cgradk_1_tmp.copy()
  
                          self.count_condition_1[:] = 0
                          self.eta_w_j_m_1 = eta.copy()
                          self.f_max_w_j_m_1 = self.f_max.copy()
  
              y_pred_adv_k = self.estimator.predict(x_k)
              if self.targeted:
                  sample_is_not_robust_k = np.invert(
                      np.argmax(y_pred_adv_k, axis=1)
                      != np.argmax(y_batch, axis=1)
                  )
              elif not self.targeted:
                  sample_is_not_robust_k = np.invert(
                      np.argmax(y_pred_adv_k, axis=1)
                      == np.argmax(y_batch, axis=1)
                  )
  
              x_robust[batch_index_1:batch_index_2][
                  sample_is_not_robust_k
              ] = x_k[sample_is_not_robust_k]
  
          x_adv[sample_is_robust] = x_robust
  
      return x_adv
  
file_path: adversarial-robustness-toolbox/art/attacks/evasion/auto_conjugate_gradient.py
imports: import abc
  import logging
  import math
  from typing import Optional, Union, TYPE_CHECKING
  import numpy
  from tqdm.auto import trange
  from art.config import ART_NUMPY_DTYPE
  from art.attacks.attack import EvasionAttack
  from art.estimators.estimator import BaseEstimator, LossGradientsMixin
  from art.estimators.classification.classifier import ClassifierMixin
  from art.utils import check_and_transform_label_format, projection, random_sphere, is_probability, get_labels_np_array
label_desc: Use image node_id 2 for calling the AutoConjugateGradient obj's underlying member method code with example usage: obj.generate(x, y) and returns: x_adv