code: def _validate_and_update_models_and_configs(
      eval_shared_models: types.MaybeMultipleEvalSharedModels,
      cf_configs: Mapping[str, CounterfactualConfig],
  ):
      """Validates and updates the EvalSharedModels and CF configs.
  
      Args:
        eval_shared_models: The set of EvalSharedModels to validate and update.
        cf_configs: The CF configs to validate and update.
  
      Returns:
        A tuple of updated eval_shared_models and cf_configs.
  
      Raises:
        ValueError if:
          - eval_shared_models is empty
          - eval_shared_models are not all _SUPPORTED_MODEL_TYPES
          - cf_configs is empty
          - The model names in cf_configs do not match eval_shared_models
      """
      eval_shared_models = (
          model_util.verify_and_update_eval_shared_models(
              eval_shared_models
          )
      )
      if not eval_shared_models:
          raise ValueError(
              "The CounterfactualPredictionsExtractor requires at least one "
              f"EvalSharedModel, but got normalized models: {eval_shared_models}."
          )
      model_types = {m.model_type for m in eval_shared_models}
      if not model_types.issubset(_SUPPORTED_MODEL_TYPES):
          raise ValueError(
              f"Only {_SUPPORTED_MODEL_TYPES} model types are supported, but found "
              f"model types: {model_types}."
          )
      if not cf_configs:
          raise ValueError(
              "The CounterfactualPredictionsExtractor requires at least "
              "one cf_configs, but got 0."
          )
  
      if len(eval_shared_models) == 1:
          if len(cf_configs) == 1:
              # Follow the normalization logic in verify_and_update_eval_shared_models
              # and rekey cf_config in single model case under the empty key, "".
              cf_configs = {"": next(iter(cf_configs.values()))}
          else:
              raise ValueError(
                  "The CounterfactualPredictionsExtractor was provided only one "
                  "EvalSharedModel, in which case exactly one config is expected, but "
                  f"got {len(cf_configs)}: {cf_configs}"
              )
  
      configured_model_names = set(cf_configs)
      eval_shared_model_names = {
          model.model_name for model in eval_shared_models
      }
      unmatched_config_names = (
          configured_model_names - eval_shared_model_names
      )
      if unmatched_config_names:
          raise ValueError(
              "model_name_to_config contains model names which do not match the "
              "eval_shared_model model_names. Configured names: "
              f"{configured_model_names}, eval_shared_models names: "
              f"{eval_shared_model_names}. Unmatched configured model names: "
              f"{unmatched_config_names}."
          )
      return eval_shared_models, cf_configs
  
file_path: model-analysis/tensorflow_model_analysis/extractors/counterfactual_predictions_extractor.py
imports: from typing import Dict, Iterable, Mapping, Optional
  import apache_beam
  import numpy
  import tensorflow
  from tensorflow_model_analysis import constants
  from tensorflow_model_analysis.api import types
  from tensorflow_model_analysis.extractors import extractor
  from tensorflow_model_analysis.extractors import predictions_extractor
  from tensorflow_model_analysis.proto import config_pb2
  from tensorflow_model_analysis.utils import model_util
label_desc: Use image node_id 2 for calling a global function with example usage: _validate_and_update_models_and_configs(eval_shared_models, cf_configs) and returns: eval_shared_models,  cf_configs