code: def substitute_parameters(
      config: ModelConfigDict,
      parameters: Dict[str, Any],
  ):
      """Update Ludwig config with parameters sampled from the Hyperopt sampler."""
  
      # Collect the sets of names for each feature grouping so we can map feature names to
      # groups
      input_feature_names = {
          feature[NAME] for feature in config[INPUT_FEATURES]
      }
      output_feature_names = {
          feature[NAME] for feature in config[OUTPUT_FEATURES]
      }
  
      # Features in the user config are provided as a list, but in hyperopt we reference
      # features by name, so convert temporarily to a dict to simplify the mergep process.
      config = feature_list_to_dict(config)
  
      # Merge parameters into the user configuration in order. As such, if there are conflicting
      # params, the later params will take precedence.
      for name, value in parameters.items():
          # User params are provided as <feature_name>.<param>, but we group input / output features
          # together during the merge to make it easier and unambiguous to convert back and forth
          # TODO(travis): we should revisit the user format here, as it silently breaks situations
          # where the user has a feature named "trainer", "combiner", etc.
          prefix = name.split(".")[0]
          if prefix in input_feature_names:
              name = f"{INPUT_FEATURES}.{name}"
          elif prefix in output_feature_names:
              name = f"{OUTPUT_FEATURES}.{name}"
  
          param_dict = parameter_to_dict(name, value)
          config = merge_dict(config, param_dict)
  
      # Now that all features have been merged, convert back to the original list format.
      config = feature_dict_to_list(config)
  
      return config
  
imports: import copy
  import dataclasses
  import json
  import logging
  import os
  import warnings
  from typing import Any, Dict
  from ludwig.api_annotations import DeveloperAPI
  from ludwig.constants import AUTO, COMBINED, EXECUTOR, GOAL, GRID_SEARCH, HYPEROPT, INPUT_FEATURES, LOSS, MAX_CONCURRENT_TRIALS, METRIC, MINIMIZE, NAME, NUM_SAMPLES, OUTPUT_FEATURES, PARAMETERS, PREPROCESSING, RAY, SPACE, SPLIT, TYPE, VALIDATION
  from ludwig.globals import HYPEROPT_STATISTICS_FILE_NAME
  from ludwig.hyperopt.results import HyperoptResults, TrialResults
  from ludwig.types import HyperoptConfigDict, ModelConfigDict
  from ludwig.utils.data_utils import save_json
  from ludwig.utils.misc_utils import get_class_attributes, get_from_registry, merge_dict, set_default_value, set_default_values
  from ludwig.utils.print_utils import print_boxed
label_desc: Use image node_id 9 for calling a global function with example usage: substitute_parameters(config, parameters) and returns: config