class_docstr: Base class for GenerationNode, capable of fitting one or more model specs under
  the hood and generating candidates from them.
  
  Args:
      model_specs: A list of ModelSpecs to be selected from for generation in this
          GenerationNode
      should_deduplicate: Whether to deduplicate the parameters of proposed arms
          against those of previous arms via rejection sampling. If this is True,
          the GenerationStrategy will discard generator runs produced from the
          GenerationNode that has `should_deduplicate=True` if they contain arms
          already present on the experiment and replace them with new generator runs.
          If no generator run with entirely unique arms could be produced in 5
          attempts, a `GenerationStrategyRepeatedPoints` error will be raised, as we
          assume that the optimization converged when the model can no longer suggest
          unique arms.
      node_name: A unique name for the GenerationNode. Used for storage purposes.
      transition_criteria: List of TransitionCriterion, each of which describes a
          condition that must be met before completing a GenerationNode. All `is_met`
          must evaluateTrue for the GenerationStrategy to move on to the next
          GenerationNode.
      gen_unlimited_trials: If True the number of trials that can be generated from
          this GenerationNode is unlimited.
  
  Note for developers: by "model" here we really mean an Ax ModelBridge object, which
  contains an Ax Model under the hood. We call it "model" here to simplify and focus
  on explaining the logic of GenerationStep and GenerationStrategy.
class_docstr_tok: ["Base","class","for","GenerationNode",",","capable","of","fitting","one","or","more","model","specs","under","the","hood","and","generating","candidates","from","them",".","Args",":","model_specs",":","A","list","of","ModelSpecs","to","be","selected","from","for","generation","in","this","GenerationNode","should_deduplicate",":","Whether","to","deduplicate","the","parameters","of","proposed","arms","against","those","of","previous","arms","via","rejection","sampling",".","If","this","is","True",",","the","GenerationStrategy","will","discard","generator","runs","produced","from","the","GenerationNode","that","has","`","should_deduplicate=True","`","if","they","contain","arms","already","present","on","the","experiment","and","replace","them","with","new","generator","runs",".","If","no","generator","run","with","entirely","unique","arms","could","be","produced","in","5","attempts",",","a","`","GenerationStrategyRepeatedPoints","`","error","will","be","raised",",","as","we","assume","that","the","optimization","converged","when","the","model","can","no","longer","suggest","unique","arms",".","node_name",":","A","unique","name","for","the","GenerationNode",".","Used","for","storage","purposes",".","transition_criteria",":","List","of","TransitionCriterion",",","each","of","which","describes","a","condition","that","must","be","met","before","completing","a","GenerationNode",".","All","`","is_met","`","must","evaluateTrue","for","the","GenerationStrategy","to","move","on","to","the","next","GenerationNode",".","gen_unlimited_trials",":","If","True","the","number","of","trials","that","can","be","generated","from","this","GenerationNode","is","unlimited",".","Note","for","developers",":","by","``","model","''","here","we","really","mean","an","Ax","ModelBridge","object",",","which","contains","an","Ax","Model","under","the","hood",".","We","call","it","``","model","''","here","to","simplify","and","focus","on","explaining","the","logic","of","GenerationStep","and","GenerationStrategy","."]
docstr: Returns the cached `_model_spec_to_gen_from` or gets it from
  `_pick_fitted_model_to_gen_from` and then caches and returns it
code: def model_spec_to_gen_from(self) -> ModelSpec:
      """Returns the cached `_model_spec_to_gen_from` or gets it from
      `_pick_fitted_model_to_gen_from` and then caches and returns it
      """
      if self._model_spec_to_gen_from is not None:
          return self._model_spec_to_gen_from
  
      self._model_spec_to_gen_from = (
          self._pick_fitted_model_to_gen_from()
      )
      return self._model_spec_to_gen_from
  
imports: from __future__ import annotations
  from dataclasses import dataclass, field
  from logging import Logger
  from typing import Any, Callable, Dict, List, Optional, Sequence, Set, Tuple, Union
  from ax import modelbridge
  from ax.core.arm import Arm
  from ax.core.base_trial import TrialStatus
  from ax.core.data import Data
  from ax.core.experiment import Experiment
  from ax.core.generator_run import GeneratorRun
  from ax.core.observation import ObservationFeatures
  from ax.core.optimization_config import OptimizationConfig
  from ax.core.search_space import SearchSpace
  from ax.exceptions.core import UserInputError
  from ax.exceptions.generation_strategy import GenerationStrategyRepeatedPoints
  from ax.modelbridge.base import ModelBridge
  from ax.modelbridge.cross_validation import BestModelSelector, CVDiagnostics, CVResult
  from ax.modelbridge.model_spec import FactoryFunctionModelSpec, ModelSpec
  from ax.modelbridge.registry import ModelRegistryBase
  from ax.modelbridge.transition_criterion import MaxGenerationParallelism, MaxTrials, MinTrials, TransitionCriterion, TrialBasedCriterion
  from ax.utils.common.base import Base, SortableBase
  from ax.utils.common.logger import get_logger
  from ax.utils.common.serialization import SerializationMixin
  from ax.utils.common.typeutils import not_none
label_desc: Use image node_id 3 for calling the GenerationNode obj's underlying member method code with example usage: obj.model_spec_to_gen_from() and returns: self, self