def copy_u(g, x_node, etype=None):
    """Compute new edge data by fetching from source node data.

    Given an input graph :math:`G(V, E)` (or a unidirectional bipartite graph
    :math:`G(V_{src}, V_{dst}, E)`) and an input tensor :math:`X`,
    the operator computes a tensor :math:`Y` storing the new edge data.
    For each edge :math:`e=(u,v) \\in E`, it computes:

    .. math:

        Y_e = X_u

    Parameters
    ----------
    g : DGLGraph
        The input graph.
    x_node : Tensor
        The tensor storing the source node data. Shape :math:`(|V_{src}|, *)`.
    etype : str or (str, str, str), optional
        Edge type. If not specified, the input graph must have only one type of
        edges.

    Returns
    -------
    Tensor
        The tensor storing the new edge data. Shape :math:`(|E|, *)`.

    Examples
    --------

    **Homogeneous graph**

    >>> import torch, dgl
    >>> g = dgl.rand_graph(100, 500)  # a random graph of 100 nodes, 500 edges
    >>> x = torch.randn(g.num_nodes(), 5)  # 5 features
    >>> y = dgl.copy_u(g, x)
    >>> print(y.shape)
    (500, 5)

    **Heterogeneous graph**

    >>> hg = dgl.heterograph({
    ...     ('user', 'follow', 'user'): ([0, 1, 2], [2, 3, 4]),
    ...     ('user', 'like', 'movie'): ([3, 3, 1, 2], [0, 0, 1, 1])
    ... })
    >>> x = torch.randn(hg.num_nodes('user'), 5)
    >>> y = dgl.copy_u(hg, x, etype='like')
    >>> print(y.shape)
    (4, 5)
    """
    etype_subg = g if etype is None else g[etype]
    return ops.gsddmm(etype_subg, "copy_lhs", x_node, None)
Compute new edge data by fetching from source node data.

    Given an input graph :math:`G(V, E)` (or a unidirectional bipartite graph
    :math:`G(V_{src}, V_{dst}, E)`) and an input tensor :math:`X`,
    the operator computes a tensor :math:`Y` storing the new edge data.
    For each edge :math:`e=(u,v) \in E`, it computes:

    .. math:

        Y_e = X_u

    Parameters
    ----------
    g : DGLGraph
        The input graph.
    x_node : Tensor
        The tensor storing the source node data. Shape :math:`(|V_{src}|, *)`.
    etype : str or (str, str, str), optional
        Edge type. If not specified, the input graph must have only one type of
        edges.

    Returns
    -------
    Tensor
        The tensor storing the new edge data. Shape :math:`(|E|, *)`.

    Examples
    --------

    **Homogeneous graph**

    >>> import torch, dgl
    >>> g = dgl.rand_graph(100, 500)  # a random graph of 100 nodes, 500 edges
    >>> x = torch.randn(g.num_nodes(), 5)  # 5 features
    >>> y = dgl.copy_u(g, x)
    >>> print(y.shape)
    (500, 5)

    **Heterogeneous graph**

    >>> hg = dgl.heterograph({
    ...     ('user', 'follow', 'user'): ([0, 1, 2], [2, 3, 4]),
    ...     ('user', 'like', 'movie'): ([3, 3, 1, 2], [0, 0, 1, 1])
    ... })
    >>> x = torch.randn(hg.num_nodes('user'), 5)
    >>> y = dgl.copy_u(hg, x, etype='like')
    >>> print(y.shape)
    (4, 5)
    
python/dgl/mpops/edgewise.py