.. DO NOT EDIT. .. THIS FILE WAS AUTOMATICALLY GENERATED BY SPHINX-GALLERY. .. TO MAKE CHANGES, EDIT THE SOURCE PYTHON FILE: .. "getting-started/tutorials/02_construct_simple_pc.py" .. LINE NUMBERS ARE GIVEN BELOW. .. only:: html .. note:: :class: sphx-glr-download-link-note :ref:`Go to the end ` to download the full example code. .. rst-class:: sphx-glr-example-title .. _sphx_glr_getting-started_tutorials_02_construct_simple_pc.py: Construct Simple PCs ==================== In this tutorial, you will learn about the basic APIs to construct PCs. .. GENERATED FROM PYTHON SOURCE LINES 7-10 .. code-block:: Python # sphinx_gallery_thumbnail_path = 'imgs/juice.png' .. GENERATED FROM PYTHON SOURCE LINES 11-12 Let's start by importing the necessary packages. .. GENERATED FROM PYTHON SOURCE LINES 12-17 .. code-block:: Python import torch import pyjuice as juice import pyjuice.nodes.distributions as dists .. GENERATED FROM PYTHON SOURCE LINES 18-20 A PC can be created using :code:`pyjuice.inputs`, :code:`pyjuice.multiply`, and :code:`pyjuice.summate`, which create input node vectors, product node vectors, and sum node vectors, respectively. The goal of this tutorial is to get you familiar with these functions. .. GENERATED FROM PYTHON SOURCE LINES 22-24 Input nodes ----------- .. GENERATED FROM PYTHON SOURCE LINES 26-27 Let us start with :code:`pyjuice.inputs`. .. GENERATED FROM PYTHON SOURCE LINES 27-30 .. code-block:: Python ni0 = juice.inputs(var = 0, num_node_blocks = 4, block_size = 2, dist = dists.Categorical(num_cats = 4)) .. GENERATED FROM PYTHON SOURCE LINES 31-38 The above line defines :code:`num_node_blocks * block_size = 8` input nodes on variable ID :code:`var = 0` featuring Categorical distributions with 4 categories (i.e., :code:`dists.Categorical(num_cats = 4)`). The set of input distributions are defined under :code:`pyjuice.nodes.distributions`. A seemingly redundant pair of parameters are :code:`num_node_blocks` and :code:`block_size`, since we can alternatively only specify the number of nodes in the node vector :code:`ni0`. In fact, ensuring large :code:`block_size` is crucial to the efficiency of the PC. So always try to use large block sizes when defining PCs. Although using larger block sizes when defining input node vectors do not have any negative effects, it poses restrictions on the edge connection pattern as we shall proceed to show. Note that :code:`block_size` has to be a power of 2. .. GENERATED FROM PYTHON SOURCE LINES 40-42 Product nodes ------------- .. GENERATED FROM PYTHON SOURCE LINES 44-45 Let us define another input node vector and a product node vector that take the input nodes as children. .. GENERATED FROM PYTHON SOURCE LINES 45-51 .. code-block:: Python ni1 = juice.inputs(var = 1, num_node_blocks = 4, block_size = 2, dist = dists.Categorical(num_cats = 4)) edge_ids = torch.tensor([[0, 0], [1, 1], [2, 2], [3, 3]]) ms = juice.multiply(ni0, ni1, edge_ids = edge_ids) .. GENERATED FROM PYTHON SOURCE LINES 52-62 :code:`ms` defines a product node vector where every node have two children: the first child is a node in :code:`ni0` and the second child is a node in :code:`ni1`. :code:`edge_ids` specifies which child nodes do every node in :code:`ms` connects to. Specifically, :code:`edge_ids` has size :code:`[# product node blocks, # child node vectors]`, so in this case, it should has size :code:`[4, 2]`. Specifically, :code:`edge_ids[i,j]` suggests that the :code:`i` th product node block connects to the :code:`edge_ids[i,j]` th node block in the :code:`j` th child node vector (assume we always count from 0). For example, :code:`edge_ids[1,0] = 1` means that the 1th product node block connects to the 1th node block in :code:`ni0`. We require the node vectors fed to :code:`pyjuice.multiply` have the same :code:`block_size`. And the block size of the output product node vector is also the same with that of the inputs. We do not need to specify the number of node blocks (e.g., using :code:`num_node_blocks`) since it is equal to :code:`edge_ids.size(0)`. For :code:`pyjuice.multiply`, if two node blocks are connected (as defined by :code:`edge_ids`), we assume the :math:`i`th node in the (parent) product node block is connected to the :math:`i`th node in the child node block. When we do not provide the :code:`edge_ids`, PyJuice assumes it to be the following (we can only use this shortcut when the child node vectors have the same :code:`num_node_blocks` and :code:`block_size`): .. GENERATED FROM PYTHON SOURCE LINES 62-67 .. code-block:: Python num_node_blocks = 4 num_child_node_vectors = 2 edge_ids = torch.arange(0, num_node_blocks)[:,None].repeat(1, num_child_node_vectors) .. GENERATED FROM PYTHON SOURCE LINES 68-70 Sum nodes --------- .. GENERATED FROM PYTHON SOURCE LINES 72-73 Finally, we introduce :code:`pyjuice.summate`, which is used to define sum node vectors. .. GENERATED FROM PYTHON SOURCE LINES 73-77 .. code-block:: Python edge_ids = torch.tensor([[0, 0, 1, 1, 2, 2, 3, 3, 4, 5], [0, 1, 0, 2, 1, 2, 2, 3, 2, 0]]) ns = juice.summate(ms, num_node_blocks = 6, block_size = 2, edge_ids = edge_ids) .. GENERATED FROM PYTHON SOURCE LINES 78-88 Similar to :code:`pyjuice.multiply`, the positional arguments to :code:`pyjuice.summate` are the list of input node vectors (here we only provide :code:`ms`). :code:`num_node_blocks` and :code:`block_size` are the number of node blocks and the size of each node block, respectively. Therefore, :code:`ns` defines a vector of :code:`num_node_blocks * block_size = 12` sum nodes that are (partially) connected to the nodes in :code:`ms`. If there are multiple child node vectors, :code:`pyjuice.summate` assumes they have the same block size. However, the sum node vector can have a different block size compared to its children. The connection pattern is specified by the keyword argument :code:`edge_ids`, which have shape :code:`[2, # edge blocks]`. Every size-2 column vector :math:`[m, n]^T` in :code:`edge_ids` indicates the existance of fully-connected edges between the :code:`m` th sum node block and the :code:`n` th product node block. That is, in the case where both :code:`ns` and :code:`ms` have block size 2, every column in :code:`edge_ids` specifies :math:`2 \times 2 = 4` edges. If :code:`edge_ids` is not provided, we assume that all nodes in the sum node vector are connected to all child nodes: .. GENERATED FROM PYTHON SOURCE LINES 88-89 .. code-block:: Python ns = juice.summate(ms, num_node_blocks = 6, block_size = 2) .. _sphx_glr_download_getting-started_tutorials_02_construct_simple_pc.py: .. only:: html .. container:: sphx-glr-footer sphx-glr-footer-example .. container:: sphx-glr-download sphx-glr-download-jupyter :download:`Download Jupyter notebook: 02_construct_simple_pc.ipynb <02_construct_simple_pc.ipynb>` .. container:: sphx-glr-download sphx-glr-download-python :download:`Download Python source code: 02_construct_simple_pc.py <02_construct_simple_pc.py>` .. container:: sphx-glr-download sphx-glr-download-zip :download:`Download zipped: 02_construct_simple_pc.zip <02_construct_simple_pc.zip>` .. only:: html .. rst-class:: sphx-glr-signature `Gallery generated by Sphinx-Gallery `_