.. DO NOT EDIT.
.. THIS FILE WAS AUTOMATICALLY GENERATED BY SPHINX-GALLERY.
.. TO MAKE CHANGES, EDIT THE SOURCE PYTHON FILE:
.. "tutorials/blitz/2_dglgraph.py"
.. LINE NUMBERS ARE GIVEN BELOW.

.. only:: html

    .. note::
        :class: sphx-glr-download-link-note

        :ref:`Go to the end <sphx_glr_download_tutorials_blitz_2_dglgraph.py>`
        to download the full example code.

.. rst-class:: sphx-glr-example-title

.. _sphx_glr_tutorials_blitz_2_dglgraph.py:


How Does DGL Represent A Graph?
===============================

By the end of this tutorial you will be able to:

-  Construct a graph in DGL from scratch.
-  Assign node and edge features to a graph.
-  Query properties of a DGL graph such as node degrees and
   connectivity.
-  Transform a DGL graph into another graph.
-  Load and save DGL graphs.

(Time estimate: 16 minutes)

.. GENERATED FROM PYTHON SOURCE LINES 20-32

DGL Graph Construction
----------------------

DGL represents a directed graph as a ``DGLGraph`` object. You can
construct a graph by specifying the number of nodes in the graph as well
as the list of source and destination nodes.  Nodes in the graph have
consecutive IDs starting from 0.

For instance, the following code constructs a directed star graph with 5
leaves. The center node's ID is 0. The edges go from the
center node to the leaves.


.. GENERATED FROM PYTHON SOURCE LINES 32-51

.. code-block:: Python


    import os

    os.environ["DGLBACKEND"] = "pytorch"
    import dgl
    import numpy as np
    import torch

    g = dgl.graph(([0, 0, 0, 0, 0], [1, 2, 3, 4, 5]), num_nodes=6)
    # Equivalently, PyTorch LongTensors also work.
    g = dgl.graph(
        (torch.LongTensor([0, 0, 0, 0, 0]), torch.LongTensor([1, 2, 3, 4, 5])),
        num_nodes=6,
    )

    # You can omit the number of nodes argument if you can tell the number of nodes from the edge list alone.
    g = dgl.graph(([0, 0, 0, 0, 0], [1, 2, 3, 4, 5]))









.. GENERATED FROM PYTHON SOURCE LINES 52-56

Edges in the graph have consecutive IDs starting from 0, and are
in the same order as the list of source and destination nodes during
creation.


.. GENERATED FROM PYTHON SOURCE LINES 56-61

.. code-block:: Python


    # Print the source and destination nodes of every edge.
    print(g.edges())






.. rst-class:: sphx-glr-script-out

 .. code-block:: none

    (tensor([0, 0, 0, 0, 0]), tensor([1, 2, 3, 4, 5]))




.. GENERATED FROM PYTHON SOURCE LINES 62-72

.. note::

   ``DGLGraph``'s are always directed to best fit the computation
   pattern of graph neural networks, where the messages sent
   from one node to the other are often different between both
   directions. If you want to handle undirected graphs, you may consider
   treating it as a bidirectional graph. See `Graph
   Transformations`_ for an example of making
   a bidirectional graph.


.. GENERATED FROM PYTHON SOURCE LINES 75-88

Assigning Node and Edge Features to Graph
-----------------------------------------

Many graph data contain attributes on nodes and edges.
Although the types of node and edge attributes can be arbitrary in real
world, ``DGLGraph`` only accepts attributes stored in tensors (with
numerical contents). Consequently, an attribute of all the nodes or
edges must have the same shape. In the context of deep learning, those
attributes are often called *features*.

You can assign and retrieve node and edge features via ``ndata`` and
``edata`` interface.


.. GENERATED FROM PYTHON SOURCE LINES 88-99

.. code-block:: Python


    # Assign a 3-dimensional node feature vector for each node.
    g.ndata["x"] = torch.randn(6, 3)
    # Assign a 4-dimensional edge feature vector for each edge.
    g.edata["a"] = torch.randn(5, 4)
    # Assign a 5x4 node feature matrix for each node.  Node and edge features in DGL can be multi-dimensional.
    g.ndata["y"] = torch.randn(6, 5, 4)

    print(g.edata["a"])






.. rst-class:: sphx-glr-script-out

 .. code-block:: none

    tensor([[ 1.9536,  0.1854,  0.0914,  1.8699],
            [ 0.3899, -0.4047, -0.9593,  0.5322],
            [ 0.2731,  0.0393,  0.4219, -1.5069],
            [-1.0900,  1.9680,  1.1952, -0.1310],
            [ 0.1610, -2.6382,  0.4905,  0.2794]])




.. GENERATED FROM PYTHON SOURCE LINES 100-116

.. note::

   The vast development of deep learning has provided us many
   ways to encode various types of attributes into numerical features.
   Here are some general suggestions:

   -  For categorical attributes (e.g. gender, occupation), consider
      converting them to integers or one-hot encoding.
   -  For variable length string contents (e.g. news article, quote),
      consider applying a language model.
   -  For images, consider applying a vision model such as CNNs.

   You can find plenty of materials on how to encode such attributes
   into a tensor in the `PyTorch Deep Learning
   Tutorials <https://pytorch.org/tutorials/>`__.


.. GENERATED FROM PYTHON SOURCE LINES 119-124

Querying Graph Structures
-------------------------

``DGLGraph`` object provides various methods to query a graph structure.


.. GENERATED FROM PYTHON SOURCE LINES 124-133

.. code-block:: Python


    print(g.num_nodes())
    print(g.num_edges())
    # Out degrees of the center node
    print(g.out_degrees(0))
    # In degrees of the center node - note that the graph is directed so the in degree should be 0.
    print(g.in_degrees(0))






.. rst-class:: sphx-glr-script-out

 .. code-block:: none

    6
    5
    5
    0




.. GENERATED FROM PYTHON SOURCE LINES 134-137

Graph Transformations
---------------------


.. GENERATED FROM PYTHON SOURCE LINES 140-143

DGL provides many APIs to transform a graph to another such as
extracting a subgraph:


.. GENERATED FROM PYTHON SOURCE LINES 143-150

.. code-block:: Python


    # Induce a subgraph from node 0, node 1 and node 3 from the original graph.
    sg1 = g.subgraph([0, 1, 3])
    # Induce a subgraph from edge 0, edge 1 and edge 3 from the original graph.
    sg2 = g.edge_subgraph([0, 1, 3])









.. GENERATED FROM PYTHON SOURCE LINES 151-155

You can obtain the node/edge mapping from the subgraph to the original
graph by looking into the node feature ``dgl.NID`` or edge feature
``dgl.EID`` in the new graph.


.. GENERATED FROM PYTHON SOURCE LINES 155-166

.. code-block:: Python


    # The original IDs of each node in sg1
    print(sg1.ndata[dgl.NID])
    # The original IDs of each edge in sg1
    print(sg1.edata[dgl.EID])
    # The original IDs of each node in sg2
    print(sg2.ndata[dgl.NID])
    # The original IDs of each edge in sg2
    print(sg2.edata[dgl.EID])






.. rst-class:: sphx-glr-script-out

 .. code-block:: none

    tensor([0, 1, 3])
    tensor([0, 2])
    tensor([0, 1, 2, 4])
    tensor([0, 1, 3])




.. GENERATED FROM PYTHON SOURCE LINES 167-170

``subgraph`` and ``edge_subgraph`` also copies the original features
to the subgraph:


.. GENERATED FROM PYTHON SOURCE LINES 170-181

.. code-block:: Python


    # The original node feature of each node in sg1
    print(sg1.ndata["x"])
    # The original edge feature of each node in sg1
    print(sg1.edata["a"])
    # The original node feature of each node in sg2
    print(sg2.ndata["x"])
    # The original edge feature of each node in sg2
    print(sg2.edata["a"])






.. rst-class:: sphx-glr-script-out

 .. code-block:: none

    tensor([[-1.8605, -0.2270,  0.0280],
            [-0.1693,  1.1287,  2.0127],
            [ 0.6646,  0.5802, -1.4393]])
    tensor([[ 1.9536,  0.1854,  0.0914,  1.8699],
            [ 0.2731,  0.0393,  0.4219, -1.5069]])
    tensor([[-1.8605, -0.2270,  0.0280],
            [-0.1693,  1.1287,  2.0127],
            [ 1.4013, -0.4476,  1.5255],
            [ 0.0036,  0.8280, -0.5049]])
    tensor([[ 1.9536,  0.1854,  0.0914,  1.8699],
            [ 0.3899, -0.4047, -0.9593,  0.5322],
            [-1.0900,  1.9680,  1.1952, -0.1310]])




.. GENERATED FROM PYTHON SOURCE LINES 182-190

Another common transformation is to add a reverse edge for each edge in
the original graph with ``dgl.add_reverse_edges``.

.. note::

   If you have an undirected graph, it is better to convert it
   into a bidirectional graph first via adding reverse edges.


.. GENERATED FROM PYTHON SOURCE LINES 190-195

.. code-block:: Python


    newg = dgl.add_reverse_edges(g)
    print(newg.edges())






.. rst-class:: sphx-glr-script-out

 .. code-block:: none

    (tensor([0, 0, 0, 0, 0, 1, 2, 3, 4, 5]), tensor([1, 2, 3, 4, 5, 0, 0, 0, 0, 0]))




.. GENERATED FROM PYTHON SOURCE LINES 196-202

Loading and Saving Graphs
-------------------------

You can save a graph or a list of graphs via ``dgl.save_graphs`` and
load them back with ``dgl.load_graphs``.


.. GENERATED FROM PYTHON SOURCE LINES 202-216

.. code-block:: Python


    # Save graphs
    dgl.save_graphs("graph.dgl", g)
    dgl.save_graphs("graphs.dgl", [g, sg1, sg2])

    # Load graphs
    (g,), _ = dgl.load_graphs("graph.dgl")
    print(g)
    (g, sg1, sg2), _ = dgl.load_graphs("graphs.dgl")
    print(g)
    print(sg1)
    print(sg2)






.. rst-class:: sphx-glr-script-out

 .. code-block:: none

    Graph(num_nodes=6, num_edges=5,
          ndata_schemes={'y': Scheme(shape=(5, 4), dtype=torch.float32), 'x': Scheme(shape=(3,), dtype=torch.float32)}
          edata_schemes={'a': Scheme(shape=(4,), dtype=torch.float32)})
    Graph(num_nodes=6, num_edges=5,
          ndata_schemes={'y': Scheme(shape=(5, 4), dtype=torch.float32), 'x': Scheme(shape=(3,), dtype=torch.float32)}
          edata_schemes={'a': Scheme(shape=(4,), dtype=torch.float32)})
    Graph(num_nodes=3, num_edges=2,
          ndata_schemes={'_ID': Scheme(shape=(), dtype=torch.int64), 'y': Scheme(shape=(5, 4), dtype=torch.float32), 'x': Scheme(shape=(3,), dtype=torch.float32)}
          edata_schemes={'_ID': Scheme(shape=(), dtype=torch.int64), 'a': Scheme(shape=(4,), dtype=torch.float32)})
    Graph(num_nodes=4, num_edges=3,
          ndata_schemes={'_ID': Scheme(shape=(), dtype=torch.int64), 'y': Scheme(shape=(5, 4), dtype=torch.float32), 'x': Scheme(shape=(3,), dtype=torch.float32)}
          edata_schemes={'_ID': Scheme(shape=(), dtype=torch.int64), 'a': Scheme(shape=(4,), dtype=torch.float32)})




.. GENERATED FROM PYTHON SOURCE LINES 217-233

What’s next?
------------

-  See
   :ref:`here <apigraph-querying-graph-structure>`
   for a list of graph structure query APIs.
-  See
   :ref:`here <api-subgraph-extraction>`
   for a list of subgraph extraction routines.
-  See
   :ref:`here <api-transform>`
   for a list of graph transformation routines.
-  API reference of :func:`dgl.save_graphs`
   and
   :func:`dgl.load_graphs`


.. GENERATED FROM PYTHON SOURCE LINES 233-237

.. code-block:: Python



    # Thumbnail credits: Wikipedia
    # sphinx_gallery_thumbnail_path = '_static/blitz_2_dglgraph.png'








.. rst-class:: sphx-glr-timing

   **Total running time of the script:** (0 minutes 0.015 seconds)


.. _sphx_glr_download_tutorials_blitz_2_dglgraph.py:

.. only:: html

  .. container:: sphx-glr-footer sphx-glr-footer-example

    .. container:: sphx-glr-download sphx-glr-download-jupyter

      :download:`Download Jupyter notebook: 2_dglgraph.ipynb <2_dglgraph.ipynb>`

    .. container:: sphx-glr-download sphx-glr-download-python

      :download:`Download Python source code: 2_dglgraph.py <2_dglgraph.py>`

    .. container:: sphx-glr-download sphx-glr-download-zip

      :download:`Download zipped: 2_dglgraph.zip <2_dglgraph.zip>`


.. only:: html

 .. rst-class:: sphx-glr-signature

    `Gallery generated by Sphinx-Gallery <https://sphinx-gallery.github.io>`_