class_docstr: Computes an epsilon-greedy distribution over actions.
  
  This policy does the following:
  - With probability 1 - epsilon, take the action corresponding to the highest
  action value, breaking ties uniformly at random.
  - With probability epsilon, take an action uniformly at random.
code: def __call__(self, action_values: tf.Tensor) -> tfd.Categorical:
      legal_actions_mask = tf.where(
          tf.math.less_equal(action_values, self._threshold),
          tf.fill(tf.shape(action_values), 0.0),
          tf.fill(tf.shape(action_values), 1.0),
      )
  
      # Dithering action distribution.
      dither_probs = (
          1
          / tf.reduce_sum(legal_actions_mask, axis=-1, keepdims=True)
          * legal_actions_mask
      )
      masked_action_values = tf.where(
          tf.equal(legal_actions_mask, 1),
          action_values,
          tf.fill(tf.shape(action_values), -np.inf),
      )
      # Greedy action distribution, breaking ties uniformly at random.
      max_value = tf.reduce_max(
          masked_action_values, axis=-1, keepdims=True
      )
      greedy_probs = tf.cast(
          tf.equal(action_values * legal_actions_mask, max_value),
          action_values.dtype,
      )
  
      greedy_probs /= tf.reduce_sum(
          greedy_probs, axis=-1, keepdims=True
      )
  
      # Epsilon-greedy action distribution.
      probs = (
          self._epsilon * dither_probs
          + (1 - self._epsilon) * greedy_probs
      )
  
      # Make the policy object.
      policy = tfd.Categorical(probs=probs)
  
      return policy
  
file_path: acme/acme/tf/networks/legal_actions.py
imports: from typing import Any, Callable, Iterable, Optional, Union
  from acme.wrappers import open_spiel_wrapper
  import numpy
  import sonnet
  import tensorflow
  import tensorflow_probability
label_desc: Use image node_id 2 for calling the EpsilonGreedy obj's underlying member method code with example usage: obj.__call__(action_values) and returns: policy