class_docstr: Parametric action model that handles the dot product and masking.
  
  This assumes the outputs are logits for a single Categorical action dist.
  Getting this to work with a more complex output (e.g., if the action space
  is a tuple of several distributions) is also possible but left as an
  exercise to the reader.
code: def forward(self, input_dict, state, seq_lens):
      # Extract the available actions tensor from the observation.
      avail_actions = input_dict["obs"]["avail_actions"]
      action_mask = input_dict["obs"]["action_mask"]
  
      # Compute the predicted action embedding
      action_embed, _ = self.action_embed_model(
          {"obs": input_dict["obs"]["cart"]}
      )
  
      # Expand the model output to [BATCH, 1, EMBED_SIZE]. Note that the
      # avail actions tensor is of shape [BATCH, MAX_ACTIONS, EMBED_SIZE].
      intent_vector = tf.expand_dims(action_embed, 1)
  
      # Batch dot product => shape of logits is [BATCH, MAX_ACTIONS].
      action_logits = tf.reduce_sum(
          avail_actions * intent_vector, axis=2
      )
  
      # Mask out invalid actions (use tf.float32.min for stability)
      inf_mask = tf.maximum(tf.math.log(action_mask), tf.float32.min)
      return action_logits + inf_mask, state
  
imports: from gymnasium.spaces import Box
  from ray.rllib.algorithms.dqn.distributional_q_tf_model import DistributionalQTFModel
  from ray.rllib.algorithms.dqn.dqn_torch_model import DQNTorchModel
  from ray.rllib.models.tf.fcnet import FullyConnectedNetwork
  from ray.rllib.models.torch.fcnet import FullyConnectedNetwork
  from ray.rllib.utils.framework import try_import_tf, try_import_torch
  from ray.rllib.utils.torch_utils import FLOAT_MAX, FLOAT_MIN
label_desc: Use image node_id 2 for calling the ParametricActionsModel obj's underlying member method code with example usage: obj.forward(input_dict, state, seq_lens) and returns: unknown,  state