class_docstr: A powerful adversarial attack that requires neither gradients
  nor probabilities [#Chen19].
  
  Args:
      init_attack : Attack to use to find a starting points. Defaults to
          LinearSearchBlendedUniformNoiseAttack. Only used if starting_points is None.
      steps : Number of optimization steps within each binary search step.
      initial_gradient_eval_steps: Initial number of evaluations for gradient estimation.
          Larger initial_num_evals increases time efficiency, but
          may decrease query efficiency.
      max_gradient_eval_steps : Maximum number of evaluations for gradient estimation.
      stepsize_search : How to search for stepsize; choices are 'geometric_progression',
          'grid_search'. 'geometric progression' initializes the stepsize
          by ||x_t - x||_p / sqrt(iteration), and keep decreasing by half
          until reaching the target side of the boundary. 'grid_search'
          chooses the optimal epsilon over a grid, in the scale of
          ||x_t - x||_p.
      gamma : The binary search threshold theta is gamma / d^1.5 for
                 l2 attack and gamma / d^2 for linf attack.
      tensorboard : The log directory for TensorBoard summaries. If False, TensorBoard
          summaries will be disabled (default). If None, the logdir will be
          runs/CURRENT_DATETIME_HOSTNAME.
      constraint : Norm to minimize, either "l2" or "linf"
  
  References:
      .. [#Chen19] Jianbo Chen, Michael I. Jordan, Martin J. Wainwright,
      "HopSkipJumpAttack: A Query-Efficient Decision-Based Attack",
      https://arxiv.org/abs/1904.02144
class_docstr_tok: ["A","powerful","adversarial","attack","that","requires","neither","gradients","nor","probabilities","[","#","Chen19","]",".","Args",":","init_attack",":","Attack","to","use","to","find","a","starting","points",".","Defaults","to","LinearSearchBlendedUniformNoiseAttack",".","Only","used","if","starting_points","is","None",".","steps",":","Number","of","optimization","steps","within","each","binary","search","step",".","initial_gradient_eval_steps",":","Initial","number","of","evaluations","for","gradient","estimation",".","Larger","initial_num_evals","increases","time","efficiency",",","but","may","decrease","query","efficiency",".","max_gradient_eval_steps",":","Maximum","number","of","evaluations","for","gradient","estimation",".","stepsize_search",":","How","to","search","for","stepsize",";","choices","are","'geometric_progression","'",",","'grid_search","'",".","'geometric","progression","'","initializes","the","stepsize","by","||x_t","-","x||_p","\/","sqrt","(","iteration",")",",","and","keep","decreasing","by","half","until","reaching","the","target","side","of","the","boundary",".","'grid_search'","chooses","the","optimal","epsilon","over","a","grid",",","in","the","scale","of","||x_t","-","x||_p",".","gamma",":","The","binary","search","threshold","theta","is","gamma","\/","d^1.5","for","l2","attack","and","gamma","\/","d^2","for","linf","attack",".","tensorboard",":","The","log","directory","for","TensorBoard","summaries",".","If","False",",","TensorBoard","summaries","will","be","disabled","(","default",")",".","If","None",",","the","logdir","will","be","runs\/CURRENT_DATETIME_HOSTNAME",".","constraint",":","Norm","to","minimize",",","either","``","l2","''","or","``","linf","''","References",":","..","[","#","Chen19","]","Jianbo","Chen",",","Michael","I.","Jordan",",","Martin","J.","Wainwright",",","``","HopSkipJumpAttack",":","A","Query-Efficient","Decision-Based","Attack","''",",","https",":","\/\/arxiv.org\/abs\/1904.02144"]
code: def approximate_gradients(
      self,
      is_adversarial: Callable[[ep.Tensor], ep.Tensor],
      x_advs: ep.Tensor,
      steps: int,
      delta: ep.Tensor,
  ) -> ep.Tensor:
      # (steps, bs, ...)
      noise_shape = tuple([steps] + list(x_advs.shape))
      if self.constraint == "l2":
          rv = ep.normal(x_advs, noise_shape)
      elif self.constraint == "linf":
          rv = ep.uniform(x_advs, low=-1, high=1, shape=noise_shape)
      rv /= (
          atleast_kd(ep.norms.l2(flatten(rv, keep=1), -1), rv.ndim)
          + 1e-12
      )
  
      scaled_rv = atleast_kd(ep.expand_dims(delta, 0), rv.ndim) * rv
  
      perturbed = ep.expand_dims(x_advs, 0) + scaled_rv
      perturbed = ep.clip(perturbed, 0, 1)
  
      rv = (perturbed - x_advs) / atleast_kd(
          ep.expand_dims(delta + 1e-8, 0), rv.ndim
      )
  
      multipliers_list: List[ep.Tensor] = []
      for step in range(steps):
          decision = is_adversarial(perturbed[step])
          multipliers_list.append(
              ep.where(
                  decision,
                  ep.ones(
                      x_advs,
                      (
                          len(
                              x_advs,
                          )
                      ),
                  ),
                  -ep.ones(
                      x_advs,
                      (
                          len(
                              decision,
                          )
                      ),
                  ),
              )
          )
      # (steps, bs, ...)
      multipliers = ep.stack(multipliers_list, 0)
  
      vals = ep.where(
          ep.abs(ep.mean(multipliers, axis=0, keepdims=True)) == 1,
          multipliers,
          multipliers - ep.mean(multipliers, axis=0, keepdims=True),
      )
      grad = ep.mean(atleast_kd(vals, rv.ndim) * rv, axis=0)
  
      grad /= ep.norms.l2(atleast_kd(flatten(grad), grad.ndim)) + 1e-12
  
      return grad
  
imports: import logging
  from typing import Union, Any, Optional, Callable, List
  from typing_extensions import Literal
  import math
  import eagerpy
  import numpy
  from foolbox.attacks import LinearSearchBlendedUniformNoiseAttack
  from foolbox.tensorboard import TensorBoard
  from ..models import Model
  from ..criteria import Criterion
  from ..distances import l1
  from ..devutils import atleast_kd, flatten
  from .base import MinimizationAttack, get_is_adversarial
  from .base import get_criterion
  from .base import T
  from .base import raise_if_kwargs
  from .base import verify_input_bounds
  from ..distances import l2, linf
label_desc: Use image node_id 3 for calling the HopSkipJumpAttack obj's underlying member method code with example usage: obj.approximate_gradients(is_adversarial, x_advs, steps, delta) and returns: grad