code: def construct_mask_from_multiple_sources(
      observation: types.NestedTensor,
      observation_and_action_constraint_splitter: types.Splitter,
      constraints: Iterable[BaseConstraint],
      max_num_actions: int,
  ) -> Optional[types.Tensor]:
      """Constructs an action mask from multiple sources.
  
      The sources include:
      -- The action mask encoded in the observation,
      -- the `num_actions` feature restricting the number of actions per sample,
      -- the feasibility mask implied by constraints.
  
      The resulting mask disables all actions that are masked out in any of the
      three sources.
  
      Args:
        observation: A nest of Tensors containing the observation.
        observation_and_action_constraint_splitter: The observation action mask
          splitter function if the observation has action mask.
        constraints: Iterable of constraints objects that are instances of
          `tf_agents.bandits.agents.NeuralConstraint`.
        max_num_actions: The maximum number of actions per sample.
  
      Returns:
        An action mask in the form of a `[batch_size, max_num_actions]` 0-1 tensor.
      """
      mask = None
      if observation_and_action_constraint_splitter is not None:
          (
              observation,
              mask,
          ) = observation_and_action_constraint_splitter(observation)
      elif (
          isinstance(observation, dict)
          and bandit_spec_utils.NUM_ACTIONS_FEATURE_KEY in observation
      ):
          number_of_actions = observation[
              bandit_spec_utils.NUM_ACTIONS_FEATURE_KEY
          ]
          mask = tf.sequence_mask(
              lengths=number_of_actions,
              maxlen=max_num_actions,
              dtype=tf.int32,
          )
  
      first_observation = tf.nest.flatten(observation)[0]
      batch_size = tf.shape(first_observation)[0]
      if constraints:
          feasibility_prob = compute_feasibility_probability(
              observation,
              constraints,
              batch_size,
              max_num_actions,
              mask,
          )
          # Probabilistic masking.
          mask = tfp.distributions.Bernoulli(
              probs=feasibility_prob
          ).sample()
      return mask
  
imports: from __future__ import absolute_import
  from __future__ import division
  from __future__ import print_function
  import abc
  import functools
  from typing import Callable, Iterable, Optional, Text
  import six
  import tensorflow
  import tensorflow_probability
  from tf_agents.bandits.policies import loss_utils
  from tf_agents.bandits.specs import utils
  from tf_agents.policies import utils
  from tf_agents.trajectories import time_step
  from tf_agents.typing import types
  from tf_agents.utils import common
  from tf_agents.utils import nest_utils
label_desc: Use image node_id 2 for calling a global function with example usage: construct_mask_from_multiple_sources(observation, observation_and_action_constraint_splitter, constraints, max_num_actions) and returns: mask