class_docstr: This class is used to automatically find problematic nodes in a model. It takes a FX
  graphmodule and generate some submodules while traverse the graph. Then two functions
  `run_a` and `run_b` will be used to run the same submodule and a function `compare_fn`
  will be used to compare the results.
  
  Currently we provides two ways to traverse the graph and generate submodules.
      1. Sequential traversal: this will traverse the graph node by node and generate
         one submodule with one sigle node.
      2. Binary searching: this will do a binary search style traversal on the graph.
  
  For internal Users, a guide can be found here https://fb.quip.com/HDtuAgiKGfkP.
docstr: Recursive binary search implementation.
code: def _binary_search_impl(
      self, all_nodes: NodeList, start_idx: int, end_idx: int
  ) -> NodeSet:
      """
      Recursive binary search implementation.
      """
      nodes: NodeList = all_nodes[start_idx:end_idx]
  
      report: List[str] = []
      self.reports.append(report)
      self.iteration += 1
      report.append(f"Binary search iteration {self.iteration}.")
      report.append(
          f"From node index {start_idx} to {end_idx-1}. "
          f"Size of the interested node list is {len(nodes)}"
      )
  
      cur_nodes: NodeSet = set(nodes)
  
      for node in nodes:
          if node in self.fusions:
              cur_nodes.update(self.fusions[node])
  
      try:
          split_module, submod_name = self._build_submodule(cur_nodes)
          self._run_and_compare(split_module, submod_name, [])
      except (
          FxNetMinimizerRunFuncError,
          FxNetMinimizerResultMismatchError,
      ):
          if len(nodes) == 1:
              report.append(
                  f"This is the last node in the sub-module. "
                  f"Search in the current branch is successful with culprit = {cur_nodes}."
              )
              self.print_report(report)
              return cur_nodes
  
          report.append(
              "Proceed to split and lower the halves of the current "
              "sub-module individually."
          )
          self.print_report(report)
  
          mid = len(nodes) // 2
          culprits = self._binary_search_impl(
              all_nodes, start_idx, start_idx + mid
          )
  
          if len(culprits) != 0 and not self.settings.find_all:
              return culprits
  
          culprits = self._binary_search_impl(
              all_nodes, start_idx + mid, end_idx
          )
  
          if len(culprits) == 0:
              report.append(
                  f"Further split and lowering found no errors. "
                  f"Unable to minimize the submodule with list of nodes: {nodes}"
              )
              self.print_report(report)
  
          return culprits
      else:
          report.append("No discrepancy found.")
          self.print_report(report)
          return set()
  
imports: import logging
  from dataclasses import dataclass
  from typing import Any, Callable, Dict, List, Optional, Tuple
  import torch
  import torch.fx
  from torch.fx._compatibility import compatibility
  from torch.fx.node import map_arg
  from .shape_prop import ShapeProp
  from .split_utils import split_by_tags
  from .tools_common import CALLABLE_NODE_OPS, FxNetAccFusionsFinder, Names, NodeList, NodeSet, TensorOrTensors, Tensors
label_desc: Use image node_id 9 for calling the _MinimizerBase obj's underlying member method code with example usage: obj._binary_search_impl(all_nodes, start_idx, end_idx) and returns: set, culprits, cur_nodes, culprits