class_docstr: Close implementation of poisoning attack on Support Vector Machines (SVM) by Biggio et al.
  
  | Paper link: https://arxiv.org/pdf/1206.6389.pdf
class_docstr_tok: ["Close","implementation","of","poisoning","attack","on","Support","Vector","Machines","(","SVM",")","by","Biggio","et","al",".","|","Paper","link",":","https",":","\/\/arxiv.org\/pdf\/1206.6389.pdf"]
docstr: Calculates the attack gradient, or dP for this attack.
  See equation 8 in Biggio et al. Ch. 14
  
  :param attack_point: The current attack point.
  :param tol: Tolerance level.
  :return: The attack gradient.
docstr_tok: ["Calculates","the","attack","gradient",",","or","dP","for","this","attack",".","See","equation","8","in","Biggio","et","al",".","Ch",".","14",":","param","attack_point",":","The","current","attack","point",".",":","param","tol",":","Tolerance","level",".",":","return",":","The","attack","gradient","."]
code: def attack_gradient(
      self, attack_point: np.ndarray, tol: float = 0.0001
  ) -> np.ndarray:
      """
      Calculates the attack gradient, or dP for this attack.
      See equation 8 in Biggio et al. Ch. 14
  
      :param attack_point: The current attack point.
      :param tol: Tolerance level.
      :return: The attack gradient.
      """
      # pylint: disable=W0212
      if self.x_val is None or self.y_val is None:  # pragma: no cover
          raise ValueError(
              "The values of `x_val` and `y_val` are required for computing the gradients."
          )
  
      art_model = self.estimator
      model = self.estimator.model
      grad = np.zeros((1, self.x_val.shape[1]))
      support_vectors = model.support_vectors_
      num_support = len(support_vectors)
      support_labels = np.expand_dims(
          self.predict_sign(support_vectors), axis=1
      )
      c_idx = np.isin(support_vectors, attack_point).all(axis=1)
  
      if not c_idx.any():  # pragma: no cover
          return grad
  
      c_idx = np.where(c_idx > 0)[0][0]
      alpha_c = model.dual_coef_[0, c_idx]
  
      assert support_labels.shape == (num_support, 1)
      qss = art_model.q_submatrix(support_vectors, support_vectors)
      qss_inv = np.linalg.inv(
          qss
          + np.random.uniform(
              0, 0.01 * np.min(qss) + tol, (num_support, num_support)
          )
      )
      zeta = np.matmul(qss_inv, support_labels)
      zeta = np.matmul(support_labels.T, zeta)
      nu_k = np.matmul(qss_inv, support_labels)
      for x_k, y_k in zip(self.x_val, self.y_val):
          y_k = 2 * np.expand_dims(np.argmax(y_k), axis=0) - 1
  
          q_ks = art_model.q_submatrix(np.array([x_k]), support_vectors)
          m_k = (1.0 / zeta) * np.matmul(
              q_ks, zeta * qss_inv - np.matmul(nu_k, nu_k.T)
          ) + np.matmul(y_k, nu_k.T)
          d_q_sc = np.fromfunction(
              lambda i: art_model._get_kernel_gradient_sv(
                  i, attack_point
              ),
              (len(support_vectors),),
              dtype=int,
          )
          d_q_kc = art_model._kernel_grad(x_k, attack_point)
          grad += (np.matmul(m_k, d_q_sc) + d_q_kc) * alpha_c
  
      return grad
  
file_path: adversarial-robustness-toolbox/art/attacks/poisoning/poisoning_attack_svm.py
imports: from __future__ import absolute_import, division, print_function, unicode_literals
  import logging
  from typing import Optional, Tuple
  import numpy
  from tqdm.auto import tqdm
  from art.attacks.attack import PoisoningAttackWhiteBox
  from art.estimators.classification.scikitlearn import ScikitlearnSVC
  from art.utils import compute_success
label_desc: Use image node_id 5 for calling the PoisoningAttackSVM obj's underlying member method code with example usage: obj.attack_gradient(attack_point, tol) and returns: grad, grad