# Path: duplicate_questions/util/rnn.py
# def last_relevant_output(output, sequence_length):
#     """
#     Given the outputs of a LSTM, get the last relevant output that
#     is not padding. We assume that the last 2 dimensions of the input
#     represent (sequence_length, hidden_size).
# 
#     Parameters
#     ----------
#     output: Tensor
#         A tensor, generally the output of a tensorflow RNN.
#         The tensor index sequence_lengths+1 is selected for each
#         instance in the output.
# 
#     sequence_length: Tensor
#         A tensor of dimension (batch_size, ) indicating the length
#         of the sequences before padding was applied.
# 
#     Returns
#     -------
#     last_relevant_output: Tensor
#         The last relevant output (last element of the sequence), as retrieved
#         by the output Tensor and indicated by the sequence_length Tensor.
#     """
#     with tf.name_scope("last_relevant_output"):
#         batch_size = tf.shape(output)[0]
#         max_length = tf.shape(output)[-2]
#         out_size = int(output.get_shape()[-1])
#         index = tf.range(0, batch_size) * max_length + (sequence_length - 1)
#         flat = tf.reshape(output, [-1, out_size])
#         relevant = tf.gather(flat, index)
#         return relevant


import tensorflow as tf
from ...util.rnn import last_relevant_output
    bw_similarity_matrix = calculate_cosine_similarity_matrix(sentence_b_bw,
                                                              sentence_a_bw)
    bw_similarity_matrix = mask_similarity_matrix(bw_similarity_matrix,
                                                  sentence_b_mask,
                                                  sentence_a_mask)
    # Apply the multiperspective matching functions.
    if multiperspective_dims > 0:
        # Apply forward and backward full matching
        if with_full_match:
            # Forward full matching: each timestep of sentence_a_fw vs last
            # output of sentence_b_fw.
            with tf.variable_scope("forward_full_matching"):
                # Shape: (batch_size, rnn_hidden_size)
                last_output_sentence_b_fw = last_relevant_output(
                    sentence_b_fw, sentence_b_len)
                # The weights for the matching function.
                fw_full_match_params = tf.get_variable(
                    "forward_full_matching_params",
                    shape=[multiperspective_dims, sentence_encoding_dim],
                    dtype="float")
                # Shape: (batch_size, num_passage_words, multiperspective_dims)
                fw_full_match_output = full_matching(
                    sentence_a_fw,
                    last_output_sentence_b_fw,
                    fw_full_match_params)
            matched_representations.append(fw_full_match_output)
            # Backward full matching: each timestep of sentence_a_bw vs last
            # output of sentence_b_bw.
            with tf.variable_scope("backward_full_matching"):
                # Shape: (batch_size, rnn_hidden_size)

# Path: duplicate_questions/util/rnn.py
# def last_relevant_output(output, sequence_length):
#     """
#     Given the outputs of a LSTM, get the last relevant output that
#     is not padding. We assume that the last 2 dimensions of the input
#     represent (sequence_length, hidden_size).
# 
#     Parameters
#     ----------
#     output: Tensor
#         A tensor, generally the output of a tensorflow RNN.
#         The tensor index sequence_lengths+1 is selected for each
#         instance in the output.
# 
#     sequence_length: Tensor
#         A tensor of dimension (batch_size, ) indicating the length
#         of the sequences before padding was applied.
# 
#     Returns
#     -------
#     last_relevant_output: Tensor
#         The last relevant output (last element of the sequence), as retrieved
#         by the output Tensor and indicated by the sequence_length Tensor.
#     """
#     with tf.name_scope("last_relevant_output"):
#         batch_size = tf.shape(output)[0]
#         max_length = tf.shape(output)[-2]
#         out_size = int(output.get_shape()[-1])
#         index = tf.range(0, batch_size) * max_length + (sequence_length - 1)
#         flat = tf.reshape(output, [-1, out_size])
#         relevant = tf.gather(flat, index)
#         return relevant


# Path: duplicate_questions/models/bimpm/matching.py
import tensorflow as tf
from ...util.rnn import last_relevant_output

    bw_similarity_matrix = calculate_cosine_similarity_matrix(sentence_b_bw,
                                                              sentence_a_bw)
    bw_similarity_matrix = mask_similarity_matrix(bw_similarity_matrix,
                                                  sentence_b_mask,
                                                  sentence_a_mask)
    # Apply the multiperspective matching functions.
    if multiperspective_dims > 0:
        # Apply forward and backward full matching
        if with_full_match:
            # Forward full matching: each timestep of sentence_a_fw vs last
            # output of sentence_b_fw.
            with tf.variable_scope("forward_full_matching"):
                # Shape: (batch_size, rnn_hidden_size)
                last_output_sentence_b_fw = last_relevant_output(
                    sentence_b_fw, sentence_b_len)
                # The weights for the matching function.
                fw_full_match_params = tf.get_variable(
                    "forward_full_matching_params",
                    shape=[multiperspective_dims, sentence_encoding_dim],
                    dtype="float")
                # Shape: (batch_size, num_passage_words, multiperspective_dims)
                fw_full_match_output = full_matching(
                    sentence_a_fw,
                    last_output_sentence_b_fw,
                    fw_full_match_params)
            matched_representations.append(fw_full_match_output)
            # Backward full matching: each timestep of sentence_a_bw vs last
            # output of sentence_b_bw.
            with tf.variable_scope("backward_full_matching"):
                # Shape: (batch_size, rnn_hidden_size)

                last_output_sentence_b_bw = last_relevant_output(