def forward(ctx, gidx, eids, norm_by, *score):
        """Forward function.

        Pseudo-code:

        .. code:: python

            score = dgl.EData(g, score)
            score_max = score.dst_max()  # of type dgl.NData
            score = score - score_max  # edge_sub_dst, ret dgl.EData
            score_sum = score.dst_sum()  # of type dgl.NData
            out = score / score_sum    # edge_div_dst, ret dgl.EData
            return out.data
        """
        # remember to save the graph to backward cache before making it
        # a local variable
        if not is_all(eids):
            gidx = gidx.edge_subgraph([eids], True).graph
        if norm_by == "src":
            gidx = gidx.reverse()
        u_len = gidx.number_of_ntypes()
        e_len = gidx.number_of_etypes()
        lhs = [None] * u_len
        feats = tuple(lhs + list(score))
        score_max = _gspmm_hetero(gidx, "copy_rhs", "max", u_len, feats)[0]
        out_tmp = _gsddmm_hetero(
            gidx, "sub", e_len, "e", "v", tuple(list(score) + list(score_max))
        )
        score = tuple(
            [
                th.exp(out_tmp[i]) if out_tmp[i] is not None else None
                for i in range(len(out_tmp))
            ]
        )
        score_sum = _gspmm_hetero(
            gidx, "copy_rhs", "sum", u_len, tuple(lhs + list(score))
        )[0]
        out = _gsddmm_hetero(
            gidx, "div", e_len, "e", "v", tuple(list(score) + list(score_sum))
        )
        ctx.backward_cache = gidx
        ctx.save_for_backward(*out)
        return out
Forward function.

        Pseudo-code:

        .. code:: python

            score = dgl.EData(g, score)
            score_max = score.dst_max()  # of type dgl.NData
            score = score - score_max  # edge_sub_dst, ret dgl.EData
            score_sum = score.dst_sum()  # of type dgl.NData
            out = score / score_sum    # edge_div_dst, ret dgl.EData
            return out.data
        
python/dgl/backend/pytorch/sparse.py