class_docstr: Returns random samples of the given action_spec.
  
  Note: the values in the info_spec (except for the log_probability) are random
    values that have nothing to do with the emitted actions.
  
  Note: The returned info.log_probabiliy will be an object matching the
  structure of action_spec, where each value is a tensor of size [batch_size].
class_docstr_tok: ["Returns","random","samples","of","the","given","action_spec",".","Note",":","the","values","in","the","info_spec","(","except","for","the","log_probability",")","are","random","values","that","have","nothing","to","do","with","the","emitted","actions",".","Note",":","The","returned","info.log_probabiliy","will","be","an","object","matching","the","structure","of","action_spec",",","where","each","value","is","a","tensor","of","size","[","batch_size","]","."]
code: def _action(
      self, time_step, policy_state, seed
  ):  # pytype: disable=signature-mismatch  # overriding-parameter-count-checks
      observation_and_action_constraint_splitter = (
          self.observation_and_action_constraint_splitter
      )
  
      outer_dims = nest_utils.get_outer_shape(
          time_step, self._time_step_spec
      )
      if observation_and_action_constraint_splitter is not None:
          (
              observation,
              mask,
          ) = observation_and_action_constraint_splitter(
              time_step.observation
          )
  
          if self._stationary_mask is not None:
              mask = mask * self._stationary_mask
  
          action_spec = tensor_spec.from_spec(self.action_spec)
          action_spec = cast(tensor_spec.BoundedTensorSpec, action_spec)
          zero_logits = tf.cast(tf.zeros_like(mask), tf.float32)
          masked_categorical = masked.MaskedCategorical(
              zero_logits, mask
          )
          action_ = tf.cast(
              masked_categorical.sample() + action_spec.minimum,
              action_spec.dtype,
          )
  
          # If the action spec says each action should be shaped (1,), add another
          # dimension so the final shape is (B, 1) rather than (B,).
          if action_spec.shape.rank == 1:
              action_ = tf.expand_dims(action_, axis=-1)
          policy_info = tensor_spec.sample_spec_nest(
              self._info_spec, outer_dims=outer_dims
          )
      else:
          observation = time_step.observation
          action_spec = cast(
              tensor_spec.BoundedTensorSpec, self.action_spec
          )
  
          if self._accepts_per_arm_features:
              max_num_arms = (
                  action_spec.maximum - action_spec.minimum + 1
              )
              batch_size = tf.shape(time_step.step_type)[0]
              num_actions = observation.get(
                  bandit_spec_utils.NUM_ACTIONS_FEATURE_KEY,
                  tf.ones(shape=(batch_size,), dtype=tf.int32)
                  * max_num_arms,
              )
              mask = tf.sequence_mask(num_actions, max_num_arms)
              zero_logits = tf.cast(tf.zeros_like(mask), tf.float32)
              masked_categorical = masked.MaskedCategorical(
                  zero_logits, mask
              )
              action_ = tf.nest.map_structure(
                  lambda t: tf.cast(
                      masked_categorical.sample() + t.minimum, t.dtype
                  ),
                  action_spec,
              )
          elif self._stationary_mask is not None:
              batch_size = tf.shape(time_step.step_type)[0]
              mask = tf.tile(self._stationary_mask, [batch_size, 1])
              zero_logits = tf.cast(tf.zeros_like(mask), tf.float32)
              masked_categorical = masked.MaskedCategorical(
                  zero_logits, mask
              )
              action_ = tf.cast(
                  masked_categorical.sample() + action_spec.minimum,
                  action_spec.dtype,
              )
          else:
              action_ = tensor_spec.sample_spec_nest(
                  self._action_spec, seed=seed, outer_dims=outer_dims
              )
  
          policy_info = tensor_spec.sample_spec_nest(
              self._info_spec, outer_dims=outer_dims
          )
  
      # Update policy info with chosen arm features.
      if self._accepts_per_arm_features:
  
          def _gather_fn(t):
              return tf.gather(params=t, indices=action_, batch_dims=1)
  
          chosen_arm_features = tf.nest.map_structure(
              _gather_fn,
              observation[bandit_spec_utils.PER_ARM_FEATURE_KEY],
          )
  
          if policy_utilities.has_chosen_arm_features(self._info_spec):
              policy_info = policy_info._replace(
                  chosen_arm_features=chosen_arm_features
              )
  
      # TODO(b/78181147): Investigate why this control dependency is required.
      def _maybe_convert_sparse_tensor(t):
          if isinstance(t, tf.SparseTensor):
              return tf.sparse.to_dense(t)
          else:
              return t
  
      if time_step is not None:
          with tf.control_dependencies(
              tf.nest.flatten(
                  tf.nest.map_structure(
                      _maybe_convert_sparse_tensor, time_step
                  )
              )
          ):
              action_ = tf.nest.map_structure(tf.identity, action_)
  
      if self.emit_log_probability:
          if (
              self._accepts_per_arm_features
              or observation_and_action_constraint_splitter is not None
              or self._stationary_mask is not None
          ):
              action_spec = cast(
                  tensor_spec.BoundedTensorSpec, self.action_spec
              )
              log_probability = masked_categorical.log_prob(
                  action_ - action_spec.minimum
              )
          else:
              log_probability = tf.nest.map_structure(
                  lambda s: _calculate_log_probability(outer_dims, s),
                  self._action_spec,
              )
          policy_info = policy_step.set_log_probability(
              policy_info, log_probability
          )
  
      step = policy_step.PolicyStep(action_, policy_state, policy_info)
      return step
  
imports: from __future__ import absolute_import
  from __future__ import division
  from __future__ import print_function
  from typing import cast
  import tensorflow
  from tf_agents.distributions import masked
  from tf_agents.policies import tf_policy
  from tf_agents.policies import utils
  from tf_agents.specs import bandit_spec_utils
  from tf_agents.specs import tensor_spec
  from tf_agents.trajectories import policy_step
  from tf_agents.trajectories import time_step
  from tf_agents.typing import types
  from tf_agents.utils import nest_utils
label_desc: Use image node_id 3 for calling the RandomTFPolicy obj's underlying member method code with example usage: obj._action(time_step, policy_state, seed) and returns: step, tf, tf, t