code: def assert_valid_inputs_multiannotator(
      labels_multiannotator: np.ndarray,
      pred_probs: Optional[np.ndarray] = None,
      ensemble: bool = False,
      allow_single_label: bool = False,
      annotator_ids: Optional[pd.Index] = None,
  ) -> None:
      """Validate format of multi-annotator labels"""
      # Check that labels_multiannotator is a 2D array
      if labels_multiannotator.ndim != 2:
          raise ValueError(
              "labels_multiannotator must be a 2D array or dataframe, "
              "each row represents an example and each column represents an annotator."
          )
  
      # Raise error if labels are not formatted properly
      if any(
          [
              isinstance(label, str)
              for label in labels_multiannotator.ravel()
          ]
      ):
          raise ValueError(
              "Labels cannot be strings, they must be zero-indexed integers corresponding to class indices."
          )
  
      # Raise error if labels_multiannotator has NaN rows
      nan_row_mask = np.isnan(labels_multiannotator).all(axis=1)
      if nan_row_mask.any():
          nan_rows = list(np.where(nan_row_mask)[0])
          raise ValueError(
              "labels_multiannotator cannot have rows with all NaN, each example must have at least one label.\n"
              f"Examples {nan_rows} do not have any labels."
          )
  
      # Raise error if labels_multiannotator has NaN columns
      nan_col_mask = np.isnan(labels_multiannotator).all(axis=0)
      if nan_col_mask.any():
          if annotator_ids is not None:
              nan_columns = list(
                  annotator_ids[np.where(nan_col_mask)[0]]
              )
          else:
              nan_columns = list(np.where(nan_col_mask)[0])
          raise ValueError(
              "labels_multiannotator cannot have columns with all NaN, each annotator must annotator at least one example.\n"
              f"Annotators {nan_columns} did not label any examples."
          )
  
      if not allow_single_label:
          # Raise error if labels_multiannotator has <= 1 column
          if labels_multiannotator.shape[1] <= 1:
              raise ValueError(
                  "labels_multiannotator must have more than one column.\n"
                  "If there is only one annotator, use cleanlab.rank.get_label_quality_scores instead"
              )
  
          # Raise error if labels_multiannotator only has 1 label per example
          if (
              np.sum(~np.isnan(labels_multiannotator), axis=1) == 1
          ).all():
              raise ValueError(
                  "Each example only has one label, collapse the labels into a 1-D array and use "
                  "cleanlab.rank.get_label_quality_scores instead"
              )
  
          # Raise warning if no examples with 2 or more annotators agree
          # TODO: might shift this later in the code to avoid extra compute
          if np.apply_along_axis(
              lambda s: np.array_equal(
                  np.unique(s[~np.isnan(s)]), s[~np.isnan(s)]
              ),
              axis=1,
              arr=labels_multiannotator,
          ).all():
              warnings.warn(
                  "Annotators do not agree on any example. Check input data."
              )
  
      # Check labels
      all_labels_flatten = labels_multiannotator.ravel()
      all_labels_flatten = all_labels_flatten[
          ~np.isnan(all_labels_flatten)
      ]
      assert_valid_class_labels(
          all_labels_flatten, allow_one_class=True
      )
  
      # Raise error if number of classes in labels_multiannoator does not match number of classes in pred_probs
      if pred_probs is not None:
          if not isinstance(pred_probs, np.ndarray):
              raise TypeError("pred_probs must be a numpy array.")
  
          if ensemble:
              if pred_probs.ndim != 3:
                  error_message = "pred_probs must be a 3d array."
                  if pred_probs.ndim == 2:
                      error_message += " If you have a 2d pred_probs array, use the non-ensemble version of this function."
                  raise ValueError(error_message)
  
              if pred_probs.shape[1] != len(labels_multiannotator):
                  raise ValueError(
                      "each pred_probs and labels_multiannotator must have same length."
                  )
  
              num_classes = pred_probs.shape[2]
          else:
              if pred_probs.ndim != 2:
                  error_message = "pred_probs must be a 2d array."
                  if pred_probs.ndim == 3:
                      error_message += " If you have a 3d pred_probs array, use the ensemble version of this function."
                  raise ValueError(error_message)
  
              if len(pred_probs) != len(labels_multiannotator):
                  raise ValueError(
                      "pred_probs and labels_multiannotator must have same length."
                  )
  
              num_classes = pred_probs.shape[1]
  
          highest_class = np.nanmax(labels_multiannotator) + 1
  
          # this allows for missing labels, but not missing columns in pred_probs
          if num_classes < highest_class:
              raise ValueError(
                  f"pred_probs must have at least {int(highest_class)} columns based on the largest class label "
                  "which appears in labels_multiannotator. Perhaps some rarely-annotated classes were lost while "
                  "establishing consensus labels used to train your classifier."
              )
  
file_path: cleanlab/cleanlab/internal/multiannotator_utils.py
imports: from cleanlab.typing import LabelLike
  from typing import Optional, Tuple
  import warnings
  import numpy
  import pandas
  from cleanlab.internal.validation import assert_valid_class_labels
  from cleanlab.internal.numerics import softmax
  from cleanlab.internal.util import get_num_classes, value_counts
label_desc: Use image node_id 1 for calling a global function with example usage: assert_valid_inputs_multiannotator(labels_multiannotator, pred_probs, ensemble, allow_single_label, annotator_ids) without return types