code: def single_restart(
      pvalues: np.ndarray,
      a_max: float,
      indices_of_seeds: np.ndarray,
      image_to_node: bool,
      score_function: Callable[
          [np.ndarray, np.ndarray, np.ndarray], np.ndarray
      ],
  ) -> Tuple[float, np.ndarray, np.ndarray, float]:
      """
      Here we control the iteration between images->nodes and nodes->images. It starts with a fixed subset of nodes by
      default.
  
      :param pvalues: pvalue ranges.
      :param a_max: Determines the significance level threshold.
      :param indices_of_seeds: Indices of initial sets of images or nodes to perform optimization.
      :param image_to_node: Informs the direction for optimization.
      :param score_function: Scoring function.
      :return: (best_score_so_far, best_sub_of_images, best_sub_of_nodes, best_alpha).
      """
      best_score_so_far = -100000.0
      count = 0
  
      while True:
          # These can be moved outside the while loop as only executed first time through??
          if (
              count == 0
          ):  # first time through, we need something initialized depending on direction.
              if image_to_node:
                  sub_of_images = indices_of_seeds
              else:
                  sub_of_nodes = indices_of_seeds
  
          if (
              image_to_node
          ):  # passed pvalues are only those belonging to fixed images, update nodes in return
              # only sending sub of images
              (
                  score_from_optimization,
                  sub_of_nodes,
                  optimal_alpha,
              ) = ScanningOps.optimize_in_single_dimension(
                  pvalues[sub_of_images, :, :],
                  a_max,
                  image_to_node,
                  score_function,
              )
          else:  # passed pvalues are only those belonging to fixed nodes, update images in return
              # only sending sub of nodes
              (
                  score_from_optimization,
                  sub_of_images,
                  optimal_alpha,
              ) = ScanningOps.optimize_in_single_dimension(
                  pvalues[:, sub_of_nodes, :],
                  a_max,
                  image_to_node,
                  score_function,
              )
  
          if (
              score_from_optimization > best_score_so_far
          ):  # haven't converged yet
              # update
              best_score_so_far = score_from_optimization
              best_sub_of_nodes = sub_of_nodes
              best_sub_of_images = sub_of_images
              best_alpha = optimal_alpha
  
              image_to_node = not image_to_node  # switch direction!
              count = count + 1  # for printing and
          else:  # converged!  Don't update from most recent optimization, return current best
              return (
                  best_score_so_far,
                  best_sub_of_images,
                  best_sub_of_nodes,
                  best_alpha,
              )
  
imports: from typing import Callable, Tuple
  import numpy
label_desc: Use image node_id 2 for calling the ScanningOps obj's underlying member method code with example usage: obj.single_restart(pvalues, a_max, indices_of_seeds, image_to_node, score_function) and returns: best_score_so_far,  best_sub_of_images,  best_sub_of_nodes,  best_alpha