code: def _binary_search(
      self,
      inputs: Any,
      preproc_input: Any,
      attack_kwargs: Optional[Dict[str, Any]],
      additional_forward_args: Any,
      expanded_additional_args: Any,
      correct_fn_kwargs: Optional[Dict[str, Any]],
      target: TargetType,
      perturbations_per_eval: int,
  ) -> Tuple[Any, Optional[Union[int, float]]]:
      min_range = self.arg_min
      max_range = self.arg_max
      min_so_far = None
      min_input = None
      while max_range > min_range:
          mid_step = ((max_range - min_range) // self.arg_step) // 2
  
          if mid_step == 0 and min_range + self.arg_step < max_range:
              mid_step = 1
          mid = min_range + (mid_step * self.arg_step)
  
          input_list = []
          param_list = []
          attack_inp_list = []
          attack_success = False
  
          for i in range(self.num_attempts):
              preproc_attacked_inp, attacked_inp = self._apply_attack(
                  inputs, preproc_input, attack_kwargs, mid
              )
  
              input_list.append(preproc_attacked_inp)
              param_list.append(mid)
              attack_inp_list.append(attacked_inp)
  
              if len(input_list) == perturbations_per_eval or i == (
                  self.num_attempts - 1
              ):
                  additional_args = expanded_additional_args
                  if len(input_list) != perturbations_per_eval:
                      additional_args = _expand_additional_forward_args(
                          additional_forward_args, len(input_list)
                      )
  
                  successful_ind = self._evaluate_batch(
                      input_list,
                      additional_args,
                      correct_fn_kwargs,
                      target,
                  )
                  if successful_ind is not None:
                      attack_success = True
                      max_range = mid
                      if min_so_far is None or min_so_far > mid:
                          min_so_far = mid
                          min_input = attack_inp_list[successful_ind]
                      break
  
                  input_list = []
                  param_list = []
                  attack_inp_list = []
  
          if math.isclose(min_range, mid):
              break
  
          if not attack_success:
              min_range = mid
  
      return min_input, min_so_far
  
file_path: captum/captum/robust/_core/metrics/min_param_perturbation.py
imports: import math
  from enum import Enum
  from typing import Any, Callable, cast, Dict, Generator, List, Optional, Tuple, Union
  import torch
  from captum._utils.common import _expand_additional_forward_args, _format_additional_forward_args, _reduce_list
  from captum._utils.typing import TargetType
  from captum.log import log_usage
  from captum.robust._core.perturbation import Perturbation
  from torch import Tensor
label_desc: Use image node_id 5 for calling the MinParamPerturbation obj's underlying member method code with example usage: obj._binary_search(inputs, preproc_input, attack_kwargs, additional_forward_args, expanded_additional_args, correct_fn_kwargs, target, perturbations_per_eval) and returns: min_input,  min_so_far