class_docstr: Graph Convolutional Encoder
  GcEncoder take as input an :math:`N \times D` feature matrix :math:`X` and a graph adjacency matrix :math:`A`,
  and produce an :math:`N \times E` node embedding matrix;
  Note that :math:`N` denotes the number of nodes, :math:`D` the number of input features,
  and :math:`E` the embedding size.
class_docstr_tok: ["Graph","Convolutional","Encoder","GcEncoder","take","as","input","an",":","math",":","`","N","\\times","D","`","feature","matrix",":","math",":","`","X","`","and","a","graph","adjacency","matrix",":","math",":","`","A","`",",","and","produce","an",":","math",":","`","N","\\times","E","`","node","embedding","matrix",";","Note","that",":","math",":","`","N","`","denotes","the","number","of","nodes",",",":","math",":","`","D","`","the","number","of","input","features",",","and",":","math",":","`","E","`","the","embedding","size","."]
code: def forward(self, user_X, item_X):
      # ----------------------------------------GCN layer----------------------------------------
  
      user_X = self.sparse_dropout(user_X)
      item_X = self.sparse_dropout(item_X)
  
      embeddings = []
      if self.accum == "sum":
          wu = 0.0
          wv = 0.0
          for i in range(self.num_support):
              # weight sharing
              wu = self.weights_u[i] + wu
              wv = self.weights_v[i] + wv
  
              # multiply feature matrices with weights
              if self.sparse_feature:
                  temp_u = torch.sparse.mm(user_X, wu)
                  temp_v = torch.sparse.mm(item_X, wv)
              else:
                  temp_u = torch.mm(user_X, wu)
                  temp_v = torch.mm(item_X, wv)
              all_embedding = torch.cat([temp_u, temp_v])
  
              # then multiply with adj matrices
              graph_A = self.support[i]
              all_emb = torch.sparse.mm(graph_A, all_embedding)
              embeddings.append(all_emb)
  
          embeddings = torch.stack(embeddings, dim=1)
          embeddings = torch.sum(embeddings, dim=1)
      else:
          for i in range(self.num_support):
              # multiply feature matrices with weights
              if self.sparse_feature:
                  temp_u = torch.sparse.mm(user_X, self.weights_u[i])
                  temp_v = torch.sparse.mm(item_X, self.weights_v[i])
              else:
                  temp_u = torch.mm(user_X, self.weights_u[i])
                  temp_v = torch.mm(item_X, self.weights_v[i])
              all_embedding = torch.cat([temp_u, temp_v])
  
              # then multiply with adj matrices
              graph_A = self.support[i]
              all_emb = torch.sparse.mm(graph_A, all_embedding)
              embeddings.append(all_emb)
  
          embeddings = torch.cat(embeddings, dim=1)
  
      users, items = torch.split(
          embeddings, [self.num_users, self.num_items]
      )
  
      u_hidden = self.activate(users)
      v_hidden = self.activate(items)
  
      # ----------------------------------------Dense Layer----------------------------------------
  
      u_hidden = self.dropout(u_hidden)
      v_hidden = self.dropout(v_hidden)
  
      u_hidden = self.dense_layer_u(u_hidden)
      v_hidden = self.dense_layer_v(v_hidden)
  
      u_outputs = self.dense_activate(u_hidden)
      v_outputs = self.dense_activate(v_hidden)
  
      return u_outputs, v_outputs
  
imports: import math
  import numpy
  import scipy.sparse
  import torch
  import torch.nn
  from recbole.model.abstract_recommender import GeneralRecommender
  from recbole.model.layers import SparseDropout
  from recbole.utils import InputType
label_desc: Use image node_id 3 for calling the GcEncoder obj's underlying member method code with example usage: obj.forward(user_X, item_X) and returns: u_outputs,  v_outputs