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 run(
      self,
      model: Model,
      inputs: T,
      criterion: Union[Criterion, T],
      *,
      early_stop: Optional[float] = None,
      starting_points: Optional[T] = None,
      **kwargs: Any,
  ) -> T:
      raise_if_kwargs(kwargs)
      originals, restore_type = ep.astensor_(inputs)
      del inputs, kwargs
  
      verify_input_bounds(originals, model)
  
      criterion = get_criterion(criterion)
      is_adversarial = get_is_adversarial(criterion, model)
  
      if starting_points is None:
          init_attack: MinimizationAttack
          if self.init_attack is None:
              init_attack = LinearSearchBlendedUniformNoiseAttack(
                  steps=50
              )
              logging.info(
                  f"Neither starting_points nor init_attack given. Falling"
                  f" back to {init_attack!r} for initialization."
              )
          else:
              init_attack = self.init_attack
          # TODO: use call and support all types of attacks (once early_stop is
          # possible in __call__)
          x_advs = init_attack.run(
              model, originals, criterion, early_stop=early_stop
          )
      else:
          x_advs = ep.astensor(starting_points)
  
      is_adv = is_adversarial(x_advs)
      if not is_adv.all():
          failed = is_adv.logical_not().float32().sum()
          if starting_points is None:
              raise ValueError(
                  f"init_attack failed for {failed} of {len(is_adv)} inputs"
              )
          else:
              raise ValueError(
                  f"{failed} of {len(is_adv)} starting_points are not adversarial"
              )
      del starting_points
  
      tb = TensorBoard(logdir=self.tensorboard)
  
      # Project the initialization to the boundary.
      x_advs = self._binary_search(is_adversarial, originals, x_advs)
  
      assert ep.all(is_adversarial(x_advs))
  
      distances = self.distance(originals, x_advs)
  
      for step in range(self.steps):
          delta = self.select_delta(originals, distances, step)
  
          # Choose number of gradient estimation steps.
          num_gradient_estimation_steps = int(
              min(
                  [
                      self.initial_num_evals * math.sqrt(step + 1),
                      self.max_num_evals,
                  ]
              )
          )
  
          gradients = self.approximate_gradients(
              is_adversarial,
              x_advs,
              num_gradient_estimation_steps,
              delta,
          )
  
          if self.constraint == "linf":
              update = ep.sign(gradients)
          else:
              update = gradients
  
          if self.stepsize_search == "geometric_progression":
              # find step size.
              epsilons = distances / math.sqrt(step + 1)
  
              while True:
                  x_advs_proposals = ep.clip(
                      x_advs
                      + atleast_kd(epsilons, x_advs.ndim) * update,
                      0,
                      1,
                  )
                  success = is_adversarial(x_advs_proposals)
                  epsilons = ep.where(success, epsilons, epsilons / 2.0)
  
                  if ep.all(success):
                      break
  
              # Update the sample.
              x_advs = ep.clip(
                  x_advs + atleast_kd(epsilons, update.ndim) * update,
                  0,
                  1,
              )
  
              assert ep.all(is_adversarial(x_advs))
  
              # Binary search to return to the boundary.
              x_advs = self._binary_search(
                  is_adversarial, originals, x_advs
              )
  
              assert ep.all(is_adversarial(x_advs))
  
          elif self.stepsize_search == "grid_search":
              # Grid search for stepsize.
              epsilons_grid = ep.expand_dims(
                  ep.from_numpy(
                      distances,
                      np.logspace(
                          -4, 0, num=20, endpoint=True, dtype=np.float32
                      ),
                  ),
                  1,
              ) * ep.expand_dims(distances, 0)
  
              proposals_list = []
  
              for epsilons in epsilons_grid:
                  x_advs_proposals = (
                      x_advs
                      + atleast_kd(epsilons, update.ndim) * update
                  )
                  x_advs_proposals = ep.clip(x_advs_proposals, 0, 1)
  
                  mask = is_adversarial(x_advs_proposals)
  
                  x_advs_proposals = self._binary_search(
                      is_adversarial, originals, x_advs_proposals
                  )
  
                  # only use new values where initial guess was already adversarial
                  x_advs_proposals = ep.where(
                      atleast_kd(mask, x_advs.ndim),
                      x_advs_proposals,
                      x_advs,
                  )
  
                  proposals_list.append(x_advs_proposals)
  
              proposals = ep.stack(proposals_list, 0)
              proposals_distances = self.distance(
                  ep.expand_dims(originals, 0), proposals
              )
              minimal_idx = ep.argmin(proposals_distances, 0)
  
              x_advs = proposals[minimal_idx]
  
          distances = self.distance(originals, x_advs)
  
          # log stats
          tb.histogram("norms", distances, step)
  
      return restore_type(x_advs)
  
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 2 for calling the HopSkipJumpAttack obj's underlying member method code with example usage: obj.run(model, inputs, criterion) and returns: restore_type