class_docstr: Performs constrained coordinate descent on the architecture.
  
  This algorithm searches convolutions then inserts reduction blocks after
  every phoenix_spec.num_blocks_in_cell blocks. If phoenix_spec.replicate_cell
  is True, then only the first phoenix_spec.num_blocks_in_cell will be search
  via mutation and the whole architecture will be replicated with reduction
  blocks between each cell.
docstr: See the base class for details.
docstr_tok: ["See","the","base","class","for","details","."]
code: def get_suggestion(
      self, trials, hparams, my_trial_id=None, model_dir=None
  ):
      """See the base class for details."""
      del my_trial_id  # Unused.
  
      new_block = block_builder.BlockType[
          common.get_random_block(self._phoenix_spec.blocks_to_use)
      ]
      if self._is_reduction_block(new_block):
          raise ValueError(
              "ConstrainedDescent should not have reduction blocks in "
              "its search space."
          )
  
      if self._phoenix_spec.beam_size < 1:
          raise ValueError("phoenix_spec.beam_size must be >= 1.")
      sorted_trials = (
          self._metadata.get_best_k(
              trials, k=int(1e10), valid_only=True
          )
          or []
      )
      num_completed_trials = len(sorted_trials)
      best_trials = sorted_trials[: self._phoenix_spec.beam_size]
  
      # No feasible trials yet, use initial architecture passed in from hparams.
      if not best_trials:
          best_architecture = common.encode_architecture(
              common.get_random_architecture(
                  self._phoenix_spec.blocks_to_use,
                  self._phoenix_spec.minimum_depth,
              ),
              self._phoenix_spec.problem_type,
          )
          best_trial = None
      else:
          (
              best_architecture,
              best_trial,
          ) = common.choose_random_trial_and_get_architecture(
              best_trials
          )
  
      # Get the architecture without reductions or replications which will be
      # grown or mutated.
      if self._phoenix_spec.replicate_cell:
          output_architecture = best_architecture[
              : self._phoenix_spec.num_blocks_in_cell
          ]
          grow_mode = False
      else:
          output_architecture = self._remove_reduction_blocks(
              best_architecture
          )
          grow_mode = common.random(
              self._phoenix_spec.increase_complexity_probability
          )
  
      # Grow, mutate, and/or replicate architecture then add reductions & flatten.
      allowed_depth = self._get_allowed_depth(num_completed_trials)
      logging.info("Maximum depth allowed: %d", allowed_depth)
      if output_architecture.size < allowed_depth and grow_mode:
          logging.info("Growing the architecture.")
          output_architecture = (
              architecture_utils.increase_structure_depth(
                  output_architecture,
                  new_block,
                  self._phoenix_spec.problem_type,
              )
          )
      else:
          logging.info("Mutating the architecture.")
          output_architecture = common.mutate_replace(
              output_architecture, new_block
          )
  
      if self._phoenix_spec.replicate_cell:
          replication_times = (
              allowed_depth // self._phoenix_spec.num_blocks_in_cell
          )
          output_architecture = np.concatenate(
              [output_architecture for _ in range(replication_times)]
          )
  
      output_architecture = self._add_reduction_blocks(
          output_architecture,
          self._phoenix_spec.num_blocks_in_cell,
          self._phoenix_spec.reduction_block_type,
      )
      output_architecture = [
          block_builder.BlockType(x) for x in output_architecture
      ]
      output_architecture = np.array(
          architecture_utils.fix_architecture_order(
              output_architecture, self._phoenix_spec.problem_type
          )
      )
      return output_architecture, best_trial
  
file_path: model_search/model_search/search/constrained_descent.py
imports: from absl import logging
  from model_search import block_builder
  from model_search.architecture import architecture_utils
  from model_search.search import common
  from model_search.search import search_algorithm
  import numpy
label_desc: Use image node_id 6 for calling the ConstrainedDescent obj's underlying member method code with example usage: obj.get_suggestion(trials, hparams, my_trial_id, model_dir) and returns: output_architecture,  best_trial