def METHOD_NAME(self, g, x, ntype, etype, *, presorted=False):
    """Forward computation.
    Parameters
    ----------
    g : DGLGraph
        The input graph.
    x : torch.Tensor
        A 2D tensor of node features. Shape: :math:`(|V|, D_{in})`.
    ntype : torch.Tensor
        An 1D integer tensor of node types. Shape: :math:`(|V|,)`.
    etype : torch.Tensor
        An 1D integer tensor of edge types. Shape: :math:`(|E|,)`.
    presorted : bool, optional
        Whether *both* the nodes and the edges of the input graph have been sorted by
        their types. Forward on pre-sorted graph may be faster. Graphs created by
        :func:`~dgl.to_homogeneous` automatically satisfy the condition.
        Also see :func:`~dgl.reorder_graph` for manually reordering the nodes and edges.
    Returns
    -------
    torch.Tensor
        New node features. Shape: :math:`(|V|, D_{head} * N_{head})`.
    """
    self.presorted = presorted
    if g.is_block:
        x_src = x
        x_dst = x[: g.num_dst_nodes()]
        srcntype = ntype
        dstntype = ntype[: g.num_dst_nodes()]
    else:
        x_src = x
        x_dst = x
        srcntype = ntype
        dstntype = ntype
    with g.local_scope():
        k = self.linear_k(x_src, srcntype, presorted).view(
            -1, self.num_heads, self.head_size
        )
        q = self.linear_q(x_dst, dstntype, presorted).view(
            -1, self.num_heads, self.head_size
        )
        v = self.linear_v(x_src, srcntype, presorted).view(
            -1, self.num_heads, self.head_size
        )
        g.srcdata["k"] = k
        g.dstdata["q"] = q
        g.srcdata["v"] = v
        g.edata["etype"] = etype
        g.apply_edges(self.message)
        g.edata["m"] = g.edata["m"] * edge_softmax(
            g, g.edata["a"]
        ).unsqueeze(-1)
        g.update_all(fn.copy_e("m", "m"), fn.sum("m", "h"))
        h = g.dstdata["h"].view(-1, self.num_heads * self.head_size)
        # target-specific aggregation
        h = self.drop(self.linear_a(h, dstntype, presorted))
        alpha = torch.sigmoid(self.skip[dstntype]).unsqueeze(-1)
        if x_dst.shape != h.shape:
            h = h * alpha + (x_dst @ self.residual_w) * (1 - alpha)
        else:
            h = h * alpha + x_dst * (1 - alpha)
        if self.use_norm:
            h = self.norm(h)
        return h