class_docstr: A gated graph neural network configured as an encoder.
     Based on github.com/JamesChuanggg/ggnn.pytorch.git,
     which is based on the paper "Gated Graph Sequence Neural Networks"
     by Y. Li, D. Tarlow, M. Brockschmidt, and R. Zemel.
  
  Args:
     rnn_type (str):
        style of recurrent unit to use, one of [LSTM]
     src_ggnn_size (int) : Size of token-to-node embedding input
     src_word_vec_size (int) : Size of token-to-node embedding output
     state_dim (int) : Number of state dimensions in nodes
     n_edge_types (int) : Number of edge types
     bidir_edges (bool): True if reverse edges should be autocreated
     n_node (int) : Max nodes in graph
     bridge_extra_node (bool): True indicates only 1st extra node
        (after token listing) should be used for decoder init.
     n_steps (int): Steps to advance graph encoder for stabilization
     src_vocab (int): Path to source vocabulary.(The ggnn uses src_vocab
          during training because the graph is built using edge information
          which requires parsing the input sequence.)
class_docstr_tok: ["A","gated","graph","neural","network","configured","as","an","encoder",".","Based","on","github.com\/JamesChuanggg\/ggnn.pytorch.git",",","which","is","based","on","the","paper","``","Gated","Graph","Sequence","Neural","Networks","''","by","Y.","Li",",","D.","Tarlow",",","M.","Brockschmidt",",","and","R.","Zemel",".","Args",":","rnn_type","(","str",")",":","style","of","recurrent","unit","to","use",",","one","of","[","LSTM","]","src_ggnn_size","(","int",")",":","Size","of","token-to-node","embedding","input","src_word_vec_size","(","int",")",":","Size","of","token-to-node","embedding","output","state_dim","(","int",")",":","Number","of","state","dimensions","in","nodes","n_edge_types","(","int",")",":","Number","of","edge","types","bidir_edges","(","bool",")",":","True","if","reverse","edges","should","be","autocreated","n_node","(","int",")",":","Max","nodes","in","graph","bridge_extra_node","(","bool",")",":","True","indicates","only","1st","extra","node","(","after","token","listing",")","should","be","used","for","decoder","init",".","n_steps","(","int",")",":","Steps","to","advance","graph","encoder","for","stabilization","src_vocab","(","int",")",":","Path","to","source","vocabulary",".","(","The","ggnn","uses","src_vocab","during","training","because","the","graph","is","built","using","edge","information","which","requires","parsing","the","input","sequence",".",")"]
docstr: See :func:`EncoderBase.forward()`
docstr_tok: ["See",":","func",":","`","EncoderBase.forward","(",")","`"]
code: def forward(self, src, src_len=None):
      """See :func:`EncoderBase.forward()`"""
  
      nodes = self.n_node
      batch_size = src.size()[0]
      first_extra = np.zeros(batch_size, dtype=np.int32)
      token_onehot = np.zeros(
          (
              batch_size,
              nodes,
              self.src_ggnn_size
              if self.src_ggnn_size > 0
              else self.state_dim,
          ),
          dtype=np.int32,
      )
      edges = np.zeros(
          (batch_size, nodes, nodes * self.n_edge_types * 2),
          dtype=np.int32,
      )
      npsrc = src[:, :, 0].cpu().data.numpy().astype(np.int32)
  
      # Initialize graph using formatted input sequence
      for i in range(batch_size):
          tokens_done = False
          # Number of flagged nodes defines node count for this sample
          # (Nodes can have no flags on them, but must be in 'flags' list).
          flag_node = 0
          flags_done = False
          edge = 0
          source_node = -1
          for j in range(len(npsrc)):
              token = npsrc[i][j]
              if not tokens_done:
                  if token == self.DELIMITER:
                      tokens_done = True
                      first_extra[i] = j
                  else:
                      token_onehot[i][j][token] = 1
              elif token == self.DELIMITER:
                  flag_node += 1
                  flags_done = True
                  assert flag_node <= nodes, "Too many nodes with flags"
              elif not flags_done:
                  # The total number of integers in the vocab should allow
                  # for all features and edges to be defined.
                  if token == self.COMMA:
                      flag_node = 0
                  else:
                      num = self.idx2num[token]
                      if num >= 0:
                          token_onehot[i][flag_node][
                              num + self.DELIMITER
                          ] = 1
                      flag_node += 1
              elif token == self.COMMA:
                  edge += 1
                  assert (
                      source_node == -1
                  ), f"Error in graph edge input: {source_node} unpaired"
                  assert (
                      edge < self.n_edge_types
                  ), "Too many edge types in input"
              else:
                  num = self.idx2num[token]
                  if source_node < 0:
                      source_node = num
                  else:
                      edges[i][source_node][num + nodes * edge] = 1
                      if self.bidir_edges:
                          edges[i][num][
                              nodes * (edge + self.n_edge_types)
                              + source_node
                          ] = 1
                      source_node = -1
  
      token_onehot = (
          torch.from_numpy(token_onehot).float().to(src.device)
      )
      if self.src_ggnn_size > 0:
          token_embed = self.embed(token_onehot)
          prop_state = torch.cat(
              (
                  token_embed,
                  torch.zeros(
                      (
                          batch_size,
                          nodes,
                          self.state_dim - self.src_word_vec_size,
                      )
                  )
                  .float()
                  .to(src.device),
              ),
              2,
          )
      else:
          prop_state = token_onehot
      edges = torch.from_numpy(edges).float().to(src.device)
  
      for i_step in range(self.n_steps):
          in_states = []
          out_states = []
          for i in range(self.n_edge_types):
              in_states.append(self.in_fcs[i](prop_state))
              out_states.append(self.out_fcs[i](prop_state))
          in_states = (
              torch.stack(in_states).transpose(0, 1).contiguous()
          )
          in_states = in_states.view(
              -1, nodes * self.n_edge_types, self.state_dim
          )
          out_states = (
              torch.stack(out_states).transpose(0, 1).contiguous()
          )
          out_states = out_states.view(
              -1, nodes * self.n_edge_types, self.state_dim
          )
  
          prop_state = self.propogator(
              in_states, out_states, prop_state, edges, nodes
          )
  
      if self.bridge_extra_node:
          # Use first extra node as only source for decoder init
          join_state = prop_state[first_extra, torch.arange(batch_size)]
      else:
          # Average all nodes to get bridge input
          join_state = prop_state.mean(0)
      join_state = torch.stack(
          (join_state, join_state, join_state, join_state)
      )
      join_state = (join_state, join_state)
  
      enc_final_hs = self._bridge(join_state)
  
      return prop_state, enc_final_hs, src_len
  
imports: import numpy
  import torch
  import torch.nn
  import torch.nn.functional
  from onmt.encoders.encoder import EncoderBase
label_desc: Use image node_id 4 for calling the GGNNEncoder obj's underlying member method code with example usage: obj.forward(src, src_len) and returns: prop_state,  enc_final_hs,  src_len