parameters: (self, source_padded: torch.Tensor, source_lengths: List[int])
return_statement: return enc_hiddens, dec_init_state
docstring: Apply the encoder to source sentences to obtain encoder hidden states.
              Additionally, take the final states of the encoder and project them to obtain initial states for decoder.
  
          @param source_padded (Tensor): Tensor of padded source sentences with shape (src_len, b), where
                                          b = batch_size, src_len = maximum source sentence length. Note that 
                                         these have already been sorted in order of longest to shortest sentence.
          @param source_lengths (List[int]): List of actual lengths for each of the source sentences in the batch
          @returns enc_hiddens (Tensor): Tensor of hidden units with shape (b, src_len, h*2), where
                                          b = batch size, src_len = maximum source sentence length, h = hidden size.
          @returns dec_init_state (tuple(Tensor, Tensor)): Tuple of tensors representing the decoder's initial
                                                  hidden state and cell.
docstring_summary: Apply the encoder to source sentences to obtain encoder hidden states.
              Additionally, take the final states of the encoder and project them to obtain initial states for decoder.
docstring_tokens: Apply the encoder to source sentences to obtain encoder hidden states . Additionally take the final states of the encoder and project them to obtain initial states for decoder .
function: def encode(self, source_padded: torch.Tensor, source_lengths: List[int]) -> Tuple[torch.Tensor, Tuple[torch.Tensor, torch.Tensor]]:
          """ Apply the encoder to source sentences to obtain encoder hidden states.
              Additionally, take the final states of the encoder and project them to obtain initial states for decoder.
  
          @param source_padded (Tensor): Tensor of padded source sentences with shape (src_len, b), where
                                          b = batch_size, src_len = maximum source sentence length. Note that 
                                         these have already been sorted in order of longest to shortest sentence.
          @param source_lengths (List[int]): List of actual lengths for each of the source sentences in the batch
          @returns enc_hiddens (Tensor): Tensor of hidden units with shape (b, src_len, h*2), where
                                          b = batch size, src_len = maximum source sentence length, h = hidden size.
          @returns dec_init_state (tuple(Tensor, Tensor)): Tuple of tensors representing the decoder's initial
                                                  hidden state and cell.
          """
          enc_hiddens, dec_init_state = None, None
  
          ### YOUR CODE HERE (~ 8 Lines)
          ### TODO:
          ###     1. Construct Tensor `X` of source sentences with shape (src_len, b, e) using the source model embeddings.
          ###         src_len = maximum source sentence length, b = batch size, e = embedding size. Note
          ###         that there is no initial hidden state or cell for the decoder.
          ###     2. Compute `enc_hiddens`, `last_hidden`, `last_cell` by applying the encoder to `X`.
          ###         - Before you can apply the encoder, you need to apply the `pack_padded_sequence` function to X.
          ###         - After you apply the encoder, you need to apply the `pad_packed_sequence` function to enc_hiddens.
          ###         - Note that the shape of the tensor returned by the encoder is (src_len, b, h*2) and we want to
          ###           return a tensor of shape (b, src_len, h*2) as `enc_hiddens`.
          ###     3. Compute `dec_init_state` = (init_decoder_hidden, init_decoder_cell):
          ###         - `init_decoder_hidden`:
          ###             `last_hidden` is a tensor shape (2, b, h). The first dimension corresponds to forwards and backwards.
          ###             Concatenate the forwards and backwards tensors to obtain a tensor shape (b, 2*h).
          ###             Apply the h_projection layer to this in order to compute init_decoder_hidden.
          ###             This is h_0^{dec} in the PDF. Here b = batch size, h = hidden size
          ###         - `init_decoder_cell`:
          ###             `last_cell` is a tensor shape (2, b, h). The first dimension corresponds to forwards and backwards.
          ###             Concatenate the forwards and backwards tensors to obtain a tensor shape (b, 2*h).
          ###             Apply the c_projection layer to this in order to compute init_decoder_cell.
          ###             This is c_0^{dec} in the PDF. Here b = batch size, h = hidden size
          ###
          ### See the following docs, as you may need to use some of the following functions in your implementation:
          ###     Pack the padded sequence X before passing to the encoder:
          ###         https://pytorch.org/docs/stable/nn.html#torch.nn.utils.rnn.pack_padded_sequence
          ###     Pad the packed sequence, enc_hiddens, returned by the encoder:
          ###         https://pytorch.org/docs/stable/nn.html#torch.nn.utils.rnn.pad_packed_sequence
          ###     Tensor Concatenation:
          ###         https://pytorch.org/docs/stable/torch.html#torch.cat
          ###     Tensor Permute:
          ###         https://pytorch.org/docs/stable/tensors.html#torch.Tensor.permute
          X = self.model_embeddings.source(source_padded)
          X = pack_padded_sequence(X, torch.tensor(source_lengths))
          enc_hiddens, (last_hidden, last_cell) = self.encoder(X)
          enc_hiddens, _ = pad_packed_sequence(enc_hiddens, batch_first=True)
          init_dec_hidden = self.h_projection(torch.cat((last_hidden[0], last_hidden[1]), 1))
          init_dec_cell = self.c_projection(torch.cat((last_cell[0], last_cell[1]), 1))
          dec_init_state = (init_dec_hidden, init_dec_cell)
  
          ### END YOUR CODE
  
          return enc_hiddens, dec_init_state
function_tokens: def encode ( self , source_padded : torch . Tensor , source_lengths : List [ int ] ) -> Tuple [ torch . Tensor , Tuple [ torch . Tensor , torch . Tensor ] ] : enc_hiddens , dec_init_state = None , None ### YOUR CODE HERE (~ 8 Lines) ### TODO: ###     1. Construct Tensor `X` of source sentences with shape (src_len, b, e) using the source model embeddings. ###         src_len = maximum source sentence length, b = batch size, e = embedding size. Note ###         that there is no initial hidden state or cell for the decoder. ###     2. Compute `enc_hiddens`, `last_hidden`, `last_cell` by applying the encoder to `X`. ###         - Before you can apply the encoder, you need to apply the `pack_padded_sequence` function to X. ###         - After you apply the encoder, you need to apply the `pad_packed_sequence` function to enc_hiddens. ###         - Note that the shape of the tensor returned by the encoder is (src_len, b, h*2) and we want to ###           return a tensor of shape (b, src_len, h*2) as `enc_hiddens`. ###     3. Compute `dec_init_state` = (init_decoder_hidden, init_decoder_cell): ###         - `init_decoder_hidden`: ###             `last_hidden` is a tensor shape (2, b, h). The first dimension corresponds to forwards and backwards. ###             Concatenate the forwards and backwards tensors to obtain a tensor shape (b, 2*h). ###             Apply the h_projection layer to this in order to compute init_decoder_hidden. ###             This is h_0^{dec} in the PDF. Here b = batch size, h = hidden size ###         - `init_decoder_cell`: ###             `last_cell` is a tensor shape (2, b, h). The first dimension corresponds to forwards and backwards. ###             Concatenate the forwards and backwards tensors to obtain a tensor shape (b, 2*h). ###             Apply the c_projection layer to this in order to compute init_decoder_cell. ###             This is c_0^{dec} in the PDF. Here b = batch size, h = hidden size ### ### See the following docs, as you may need to use some of the following functions in your implementation: ###     Pack the padded sequence X before passing to the encoder: ###         https://pytorch.org/docs/stable/nn.html#torch.nn.utils.rnn.pack_padded_sequence ###     Pad the packed sequence, enc_hiddens, returned by the encoder: ###         https://pytorch.org/docs/stable/nn.html#torch.nn.utils.rnn.pad_packed_sequence ###     Tensor Concatenation: ###         https://pytorch.org/docs/stable/torch.html#torch.cat ###     Tensor Permute: ###         https://pytorch.org/docs/stable/tensors.html#torch.Tensor.permute X = self . model_embeddings . source ( source_padded ) X = pack_padded_sequence ( X , torch . tensor ( source_lengths ) ) enc_hiddens , ( last_hidden , last_cell ) = self . encoder ( X ) enc_hiddens , _ = pad_packed_sequence ( enc_hiddens , batch_first = True ) init_dec_hidden = self . h_projection ( torch . cat ( ( last_hidden [ 0 ] , last_hidden [ 1 ] ) , 1 ) ) init_dec_cell = self . c_projection ( torch . cat ( ( last_cell [ 0 ] , last_cell [ 1 ] ) , 1 ) ) dec_init_state = ( init_dec_hidden , init_dec_cell ) ### END YOUR CODE return enc_hiddens , dec_init_state