def exact_match(answer_ids, prediction_ids, vocab):
  """Compute exact match score between answer tokens and prediction tokens.

  Args:
    answer_ids: <int32> [batch_size, answer_length]
    prediction_ids: <int32> [batch_size, prediction_length]
    vocab: Instance of text_utils.Vocab.

  Returns:
    score: <float32> [batch_size] tensor of {0.0, 1.0}.
  """
  batch_size = tensor_utils.shape(answer_ids, 0)

  # Get cleanable words.
  remove_ids = list(_get_normalized_set(vocab))
  remove_ids = tf.reshape(remove_ids, [1, 1, -1])
  remove_ids = tf.tile(remove_ids, [batch_size, 1, 1])

  # Clean answer: remove tokens that are in the normalized set.
  should_keep = tf.reduce_all(
      tf.not_equal(tf.expand_dims(answer_ids, -1), remove_ids), axis=-1)
  answer_ids = tensor_utils.boolean_mask(answer_ids, should_keep)

  # Clean context: remove tokens that are in the normalized set.
  should_keep = tf.reduce_all(
      tf.not_equal(tf.expand_dims(prediction_ids, -1), remove_ids), axis=-1)
  prediction_ids = tensor_utils.boolean_mask(prediction_ids, should_keep)

  # Cleaned lengths.
  answer_len = tensor_utils.shape(answer_ids, 1)
  prediction_len = tensor_utils.shape(prediction_ids, 1)

  # Pad the shorter one to the length of the longer.
  padding = tf.maximum(0, prediction_len - answer_len)
  answer_ids = tf.pad(answer_ids, [[0, 0], [0, padding]])
  padding = tf.maximum(0, answer_len - prediction_len)
  prediction_ids = tf.pad(prediction_ids, [[0, 0], [0, padding]])

  # Check for equality: Padded A == Padded B?
  is_equal = tf.reduce_all(tf.equal(answer_ids, prediction_ids), axis=1)
  score = tf.cast(is_equal, tf.float32)

  return score
Compute exact match score between answer tokens and prediction tokens.

  Args:
    answer_ids: <int32> [batch_size, answer_length]
    prediction_ids: <int32> [batch_size, prediction_length]
    vocab: Instance of text_utils.Vocab.

  Returns:
    score: <float32> [batch_size] tensor of {0.0, 1.0}.
  
language/capwap/utils/reward_utils.py