class_docstr: Description
  -----------
  Pytorch Auto-Grad Function for edge sparsemax.
  
  We define this auto-grad function here since
  sparsemax involves sort and select, which are
  not derivative.
class_docstr_tok: ["Description","--","--","--","--","--","-","Pytorch","Auto-Grad","Function","for","edge","sparsemax",".","We","define","this","auto-grad","function","here","since","sparsemax","involves","sort","and","select",",","which","are","not","derivative","."]
code: def forward(
      ctx,
      gidx: HeteroGraphIndex,
      scores: Tensor,
      eids: Tensor,
      end_n_ids: Tensor,
      norm_by: str,
  ):
      if not is_all(eids):
          gidx = gidx.edge_subgraph([eids], True).graph
      if norm_by == "src":
          gidx = gidx.reverse()
  
      # use feat - max(feat) for numerical stability.
      scores = scores.float()
      scores_max = _gspmm(gidx, "copy_rhs", "max", None, scores)[0]
      scores = _gsddmm(gidx, "sub", scores, scores_max, "e", "v")
  
      # find threshold for each node and perform ReLU(u-t(u)) operation.
      tau, supp_size = _threshold_and_support_graph(
          gidx, scores, end_n_ids
      )
      out = torch.clamp(
          _gsddmm(gidx, "sub", scores, tau, "e", "v"), min=0
      )
      ctx.backward_cache = gidx
      ctx.save_for_backward(supp_size, out)
      torch.cuda.empty_cache()
      return out
  
file_path: dgl/examples/pytorch/hgp_sl/functions.py
imports: import dgl
  import torch
  from dgl.backend import astype
  from dgl.base import ALL, is_all
  from dgl.heterograph_index import HeteroGraphIndex
  from dgl.sparse import _gsddmm, _gspmm
  from torch import Tensor
  from torch.autograd import Function
label_desc: Use image node_id 1 for calling the EdgeSparsemaxFunction obj's underlying member method code with example usage: obj.forward(ctx, gidx, scores, eids, end_n_ids, norm_by) and returns: out