class_docstr: Describes the sub-module-architectures to be used in RLModules.
  
  RLlib's native RLModules get their Models from a Catalog object.
  By default, that Catalog builds the configs it has as attributes.
  This component was build to be hackable and extensible. You can inject custom
  components into RL Modules by overriding the `build_xxx` methods of this class.
  Note that it is recommended to write a custom RL Module for a single use-case.
  Modifications to Catalogs mostly make sense if you want to reuse the same
  Catalog for different RL Modules. For example if you have written a custom
  encoder and want to inject it into different RL Modules (e.g. for PPO, DQN, etc.).
  You can influence the decision tree that determines the sub-components by modifying
  `Catalog._determine_components_hook`.
  
  Usage example:
  
  # Define a custom catalog
  
  .. testcode::
  
      import torch
      import gymnasium as gym
      from ray.rllib.core.models.configs import MLPHeadConfig
      from ray.rllib.core.models.catalog import Catalog
  
      class MyCatalog(Catalog):
          def __init__(
              self,
              observation_space: gym.Space,
              action_space: gym.Space,
              model_config_dict: dict,
          ):
              super().__init__(observation_space, action_space, model_config_dict)
              self.my_model_config = MLPHeadConfig(
                  hidden_layer_dims=[64, 32],
                  input_dims=[self.observation_space.shape[0]],
              )
  
          def build_my_head(self, framework: str):
              return self.my_model_config.build(framework=framework)
  
      # With that, RLlib can build and use models from this catalog like this:
      catalog = MyCatalog(gym.spaces.Box(0, 1), gym.spaces.Box(0, 1), {})
      my_head = catalog.build_my_head(framework="torch")
  
      # Make a call to the built model.
      out = my_head(torch.Tensor([[1]]))
class_docstr_tok: ["Describes","the","sub-module-architectures","to","be","used","in","RLModules",".","RLlib","'s","native","RLModules","get","their","Models","from","a","Catalog","object",".","By","default",",","that","Catalog","builds","the","configs","it","has","as","attributes",".","This","component","was","build","to","be","hackable","and","extensible",".","You","can","inject","custom","components","into","RL","Modules","by","overriding","the","`","build_xxx","`","methods","of","this","class",".","Note","that","it","is","recommended","to","write","a","custom","RL","Module","for","a","single","use-case",".","Modifications","to","Catalogs","mostly","make","sense","if","you","want","to","reuse","the","same","Catalog","for","different","RL","Modules",".","For","example","if","you","have","written","a","custom","encoder","and","want","to","inject","it","into","different","RL","Modules","(","e.g",".","for","PPO",",","DQN",",","etc.",")",".","You","can","influence","the","decision","tree","that","determines","the","sub-components","by","modifying","`","Catalog._determine_components_hook","`",".","Usage","example",":","#","Define","a","custom","catalog","..","testcode",":",":","import","torch","import","gymnasium","as","gym","from","ray.rllib.core.models.configs","import","MLPHeadConfig","from","ray.rllib.core.models.catalog","import","Catalog","class","MyCatalog","(","Catalog",")",":","def","__init__","(","self",",","observation_space",":","gym.Space",",","action_space",":","gym.Space",",","model_config_dict",":","dict",",",")",":","super","(",")",".__init__","(","observation_space",",","action_space",",","model_config_dict",")","self.my_model_config","=","MLPHeadConfig","(","hidden_layer_dims=","[","64",",","32","]",",","input_dims=","[","self.observation_space.shape","[","0","]","]",",",")","def","build_my_head","(","self",",","framework",":","str",")",":","return","self.my_model_config.build","(","framework=framework",")","#","With","that",",","RLlib","can","build","and","use","models","from","this","catalog","like","this",":","catalog","=","MyCatalog","(","gym.spaces.Box","(","0",",","1",")",",","gym.spaces.Box","(","0",",","1",")",",","{","}",")","my_head","=","catalog.build_my_head","(","framework=","''","torch","''",")","#","Make","a","call","to","the","built","model",".","out","=","my_head","(","torch.Tensor","(","[","[","1","]","]",")",")"]
docstr: Returns an EncoderConfig for the given input_space and model_config_dict.
  
  Encoders are usually used in RLModules to transform the input space into a
  latent space that is then fed to the heads. The returned EncoderConfig
  objects correspond to the built-in Encoder classes in RLlib.
  For example, for a simple 1D-Box input_space, RLlib offers an
  MLPEncoder, hence this method returns the MLPEncoderConfig. You can overwrite
  this method to produce specific EncoderConfigs for your custom Models.
  
  The following input spaces lead to the following configs:
  - 1D-Box: MLPEncoderConfig
  - 3D-Box: CNNEncoderConfig
  # TODO (Artur): Support more spaces here
  # ...
  
  Args:
      observation_space: The observation space to use.
      model_config_dict: The model config to use.
      action_space: The action space to use if actions are to be encoded. This
          is commonly the case for LSTM models.
      view_requirements: The view requirements to use if anything else than
          observation_space or action_space is to be encoded. This signifies an
          advanced use case.
  
  Returns:
      The encoder config.
docstr_tok: ["Returns","an","EncoderConfig","for","the","given","input_space","and","model_config_dict",".","Encoders","are","usually","used","in","RLModules","to","transform","the","input","space","into","a","latent","space","that","is","then","fed","to","the","heads",".","The","returned","EncoderConfig","objects","correspond","to","the","built-in","Encoder","classes","in","RLlib",".","For","example",",","for","a","simple","1D-Box","input_space",",","RLlib","offers","an","MLPEncoder",",","hence","this","method","returns","the","MLPEncoderConfig",".","You","can","overwrite","this","method","to","produce","specific","EncoderConfigs","for","your","custom","Models",".","The","following","input","spaces","lead","to","the","following","configs",":","-","1D-Box",":","MLPEncoderConfig","-","3D-Box",":","CNNEncoderConfig","#","TODO","(","Artur",")",":","Support","more","spaces","here","#","...","Args",":","observation_space",":","The","observation","space","to","use",".","model_config_dict",":","The","model","config","to","use",".","action_space",":","The","action","space","to","use","if","actions","are","to","be","encoded",".","This","is","commonly","the","case","for","LSTM","models",".","view_requirements",":","The","view","requirements","to","use","if","anything","else","than","observation_space","or","action_space","is","to","be","encoded",".","This","signifies","an","advanced","use","case",".","Returns",":","The","encoder","config","."]
code: def _get_encoder_config(
      cls,
      observation_space: gym.Space,
      model_config_dict: dict,
      action_space: gym.Space = None,
      view_requirements=None,
  ) -> ModelConfig:
      """Returns an EncoderConfig for the given input_space and model_config_dict.
  
      Encoders are usually used in RLModules to transform the input space into a
      latent space that is then fed to the heads. The returned EncoderConfig
      objects correspond to the built-in Encoder classes in RLlib.
      For example, for a simple 1D-Box input_space, RLlib offers an
      MLPEncoder, hence this method returns the MLPEncoderConfig. You can overwrite
      this method to produce specific EncoderConfigs for your custom Models.
  
      The following input spaces lead to the following configs:
      - 1D-Box: MLPEncoderConfig
      - 3D-Box: CNNEncoderConfig
      # TODO (Artur): Support more spaces here
      # ...
  
      Args:
          observation_space: The observation space to use.
          model_config_dict: The model config to use.
          action_space: The action space to use if actions are to be encoded. This
              is commonly the case for LSTM models.
          view_requirements: The view requirements to use if anything else than
              observation_space or action_space is to be encoded. This signifies an
              advanced use case.
  
      Returns:
          The encoder config.
      """
      # TODO (Artur): Make it so that we don't work with complete MODEL_DEFAULTS
      model_config_dict = {**MODEL_DEFAULTS, **model_config_dict}
  
      activation = model_config_dict["fcnet_activation"]
      output_activation = model_config_dict["fcnet_activation"]
      fcnet_hiddens = model_config_dict["fcnet_hiddens"]
      # TODO (sven): Move to a new ModelConfig object (dataclass) asap, instead of
      #  "linking" into the old ModelConfig (dict)! This just causes confusion as to
      #  which old keys now mean what for the new RLModules-based default models.
      encoder_latent_dim = (
          model_config_dict["encoder_latent_dim"] or fcnet_hiddens[-1]
      )
      use_lstm = model_config_dict["use_lstm"]
      use_attention = model_config_dict["use_attention"]
  
      if use_lstm:
          encoder_config = RecurrentEncoderConfig(
              input_dims=observation_space.shape,
              recurrent_layer_type="lstm",
              hidden_dim=model_config_dict["lstm_cell_size"],
              hidden_weights_initializer=model_config_dict[
                  "lstm_weights_initializer"
              ],
              hidden_weights_initializer_config=model_config_dict[
                  "lstm_weights_initializer_config"
              ],
              hidden_bias_initializer=model_config_dict[
                  "lstm_bias_initializer"
              ],
              hidden_bias_initializer_config=model_config_dict[
                  "lstm_bias_initializer_config"
              ],
              batch_major=not model_config_dict["_time_major"],
              num_layers=1,
              tokenizer_config=cls.get_tokenizer_config(
                  observation_space,
                  model_config_dict,
                  view_requirements,
              ),
          )
      elif use_attention:
          raise NotImplementedError
      else:
          # TODO (Artur): Maybe check for original spaces here
          # input_space is a 1D Box
          if (
              isinstance(observation_space, Box)
              and len(observation_space.shape) == 1
          ):
              # In order to guarantee backward compatability with old configs,
              # we need to check if no latent dim was set and simply reuse the last
              # fcnet hidden dim for that purpose.
              if model_config_dict["encoder_latent_dim"]:
                  hidden_layer_dims = model_config_dict["fcnet_hiddens"]
              else:
                  hidden_layer_dims = model_config_dict[
                      "fcnet_hiddens"
                  ][:-1]
              encoder_config = MLPEncoderConfig(
                  input_dims=observation_space.shape,
                  hidden_layer_dims=hidden_layer_dims,
                  hidden_layer_activation=activation,
                  hidden_layer_weights_initializer=model_config_dict[
                      "fcnet_weights_initializer"
                  ],
                  hidden_layer_weights_initializer_config=model_config_dict[
                      "fcnet_weights_initializer_config"
                  ],
                  hidden_layer_bias_initializer=model_config_dict[
                      "fcnet_bias_initializer"
                  ],
                  hidden_layer_bias_initializer_config=model_config_dict[
                      "fcnet_bias_initializer_config"
                  ],
                  output_layer_dim=encoder_latent_dim,
                  output_layer_activation=output_activation,
                  output_layer_weights_initializer=model_config_dict[
                      "post_fcnet_weights_initializer"
                  ],
                  output_layer_weights_initializer_config=model_config_dict[
                      "post_fcnet_weights_initializer_config"
                  ],
                  output_layer_bias_initializer=model_config_dict[
                      "post_fcnet_bias_initializer"
                  ],
                  output_layer_bias_initializer_config=model_config_dict[
                      "post_fcnet_bias_initializer_config"
                  ],
              )
  
          # input_space is a 3D Box
          elif (
              isinstance(observation_space, Box)
              and len(observation_space.shape) == 3
          ):
              if not model_config_dict.get("conv_filters"):
                  model_config_dict["conv_filters"] = get_filter_config(
                      observation_space.shape
                  )
  
              encoder_config = CNNEncoderConfig(
                  input_dims=observation_space.shape,
                  cnn_filter_specifiers=model_config_dict[
                      "conv_filters"
                  ],
                  cnn_activation=model_config_dict["conv_activation"],
                  cnn_use_layernorm=model_config_dict.get(
                      "conv_use_layernorm", False
                  ),
                  cnn_kernel_initializer=model_config_dict[
                      "conv_kernel_initializer"
                  ],
                  cnn_kernel_initializer_config=model_config_dict[
                      "conv_kernel_initializer_config"
                  ],
                  cnn_bias_initializer=model_config_dict[
                      "conv_bias_initializer"
                  ],
                  cnn_bias_initializer_config=model_config_dict[
                      "conv_bias_initializer_config"
                  ],
              )
          # input_space is a 2D Box
          elif (
              isinstance(observation_space, Box)
              and len(observation_space.shape) == 2
          ):
              # RLlib used to support 2D Box spaces by silently flattening them
              raise ValueError(
                  f"No default encoder config for obs space={observation_space},"
                  f" lstm={use_lstm} and attention={use_attention} found. 2D Box "
                  f"spaces are not supported. They should be either flattened to a "
                  f"1D Box space or enhanced to be a 3D box space."
              )
          # input_space is a possibly nested structure of spaces.
          else:
              # NestedModelConfig
              raise ValueError(
                  f"No default encoder config for obs space={observation_space},"
                  f" lstm={use_lstm} and attention={use_attention} found."
              )
  
      return encoder_config
  
imports: import enum
  import functools
  from typing import Optional
  import gymnasium
  import numpy
  import tree
  from gymnasium.spaces import Box, Dict, Discrete, MultiDiscrete, Tuple
  from ray.rllib.core.models.base import Encoder
  from ray.rllib.core.models.configs import CNNEncoderConfig, MLPEncoderConfig, RecurrentEncoderConfig
  from ray.rllib.core.models.configs import ModelConfig
  from ray.rllib.models import MODEL_DEFAULTS
  from ray.rllib.models.distributions import Distribution
  from ray.rllib.models.preprocessors import get_preprocessor, Preprocessor
  from ray.rllib.models.utils import get_filter_config
  from ray.rllib.utils.deprecation import deprecation_warning
  from ray.rllib.utils.error import UnsupportedSpaceException
  from ray.rllib.utils.spaces.simplex import Simplex
  from ray.rllib.utils.spaces.space_utils import flatten_space
  from ray.rllib.utils.spaces.space_utils import get_base_struct_from_space
  from ray.rllib.utils.typing import ViewRequirementsDict
  from ray.rllib.utils.annotations import OverrideToImplementCustomLogic, OverrideToImplementCustomLogic_CallToSuperRecommended
label_desc: Use image node_id 7 for calling the Catalog obj's underlying member method code with example usage: obj._get_encoder_config(cls, observation_space, model_config_dict, action_space, view_requirements) and returns: encoder_config