class_docstr: Implements the Sign-OPT attack `SignOPTAttack`. This is a query-efficient
  hard-label adversarial attack.
  
  Paper link: https://arxiv.org/pdf/1909.10773.pdf
docstr: Perform the line search in a local region plus binary search.
  Details in paper (Chen and Zhang, 2019), paper link: https://openreview.net/pdf?id=rJlk6iRqKX
  
  :param x_0: An array with the original input to be attacked.
  :param y_0: Target value.
  :param theta: Initial query direction.
  :param target: Target value. If `self.targeted` is true, it presents the targeted label. Defaults to None.
  :param initial_lbd: Previous solution. Defaults to 1.0.
  :param tol: Maximum tolerance of computed error. Stop computing if tol is reached.
  Defaults to 1e-5.
  :return: optimal solution in local; the number of query performed
docstr_tok: ["Perform","the","line","search","in","a","local","region","plus","binary","search",".","Details","in","paper","(","Chen","and","Zhang",",","2019",")",",","paper","link",":","https",":","\/\/openreview.net\/pdf","?","id=rJlk6iRqKX",":","param","x_0",":","An","array","with","the","original","input","to","be","attacked",".",":","param","y_0",":","Target","value",".",":","param","theta",":","Initial","query","direction",".",":","param","target",":","Target","value",".","If","`","self.targeted","`","is","true",",","it","presents","the","targeted","label",".","Defaults","to","None",".",":","param","initial_lbd",":","Previous","solution",".","Defaults","to","1.0.",":","param","tol",":","Maximum","tolerance","of","computed","error",".","Stop","computing","if","tol","is","reached",".","Defaults","to","1e-5",".",":","return",":","optimal","solution","in","local",";","the","number","of","query","performed"]
code: def _fine_grained_binary_search_local(
      self,
      x_0: np.ndarray,
      y_0: int,
      theta: np.ndarray,
      target: Optional[int] = None,
      initial_lbd: float = 1.0,
      tol: float = 1e-5,
  ) -> Tuple[float, int]:
      """
      Perform the line search in a local region plus binary search.
      Details in paper (Chen and Zhang, 2019), paper link: https://openreview.net/pdf?id=rJlk6iRqKX
  
      :param x_0: An array with the original input to be attacked.
      :param y_0: Target value.
      :param theta: Initial query direction.
      :param target: Target value. If `self.targeted` is true, it presents the targeted label. Defaults to None.
      :param initial_lbd: Previous solution. Defaults to 1.0.
      :param tol: Maximum tolerance of computed error. Stop computing if tol is reached.
      Defaults to 1e-5.
      :return: optimal solution in local; the number of query performed
      """
      nquery = 0
      lbd = initial_lbd
      # For targeted: we want to expand(x1.01) boundary away from targeted dataset
      # For untargeted, we want to slim(x0.99) the boundary toward the original dataset
      if (
          self.targeted
          and not self._is_label(x_0 + lbd * theta, target)
      ) or (
          not self.targeted and self._is_label(x_0 + lbd * theta, y_0)
      ):
          lbd_lo = lbd
          lbd_hi = lbd * 1.01
          nquery += 1
          while (
              self.targeted
              and not self._is_label(x_0 + lbd_hi * theta, target)
          ) or (
              not self.targeted
              and self._is_label(x_0 + lbd_hi * theta, y_0)
          ):
              lbd_hi = lbd_hi * 1.01
              nquery += 1
              if lbd_hi > 20:
                  return float("inf"), nquery
      else:
          lbd_hi = lbd
          lbd_lo = lbd * 0.99
          nquery += 1
          while (
              self.targeted
              and self._is_label(x_0 + lbd_lo * theta, target)
          ) or (
              not self.targeted
              and not self._is_label(x_0 + lbd_lo * theta, y_0)
          ):
              lbd_lo = lbd_lo * 0.99
              nquery += 1
  
      while (lbd_hi - lbd_lo) > tol:
          lbd_mid = (lbd_lo + lbd_hi) / 2.0
          nquery += 1
          if (
              self.targeted
              and self._is_label(x_0 + lbd_mid * theta, target)
          ) or (
              not self.targeted
              and not self._is_label(x_0 + lbd_mid * theta, y_0)
          ):
              lbd_hi = lbd_mid
          else:
              lbd_lo = lbd_mid
      return lbd_hi, nquery
  
imports: import logging
  from typing import Optional, TYPE_CHECKING, Tuple
  import time
  import numpy
  from tqdm.auto import tqdm
  from art.attacks.attack import EvasionAttack
  from art.config import ART_NUMPY_DTYPE
  from art.estimators.estimator import BaseEstimator
  from art.estimators.classification.classifier import ClassifierMixin
  from art.utils import compute_success, check_and_transform_label_format, get_labels_np_array
label_desc: Use image node_id 4 for calling the SignOPTAttack obj's underlying member method code with example usage: obj._fine_grained_binary_search_local(x_0, y_0, theta, target, initial_lbd, tol) and returns: lbd_hi,  nquery, float,  nquery