Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Python code examples #43

Merged
merged 15 commits into from
Jul 5, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .github/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,8 @@

### Documentation

* The "Using Jet" section of the Sphinx documentation now has Python code snippets. [(#43)](https://github.com/XanaduAI/jet/pull/43)

* The Sphinx documentation now includes API documentation for the `jet` Python package. [(#40)](https://github.com/XanaduAI/jet/pull/40)

* The "Using Jet" section of the Sphinx documentation website now compiles with the latest Jet headers. [(#26)](https://github.com/XanaduAI/jet/pull/26)
Expand Down
82 changes: 66 additions & 16 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -43,10 +43,13 @@ browse the full `API documentation
Installation
============

Jet requires `Taskflow <https://github.com/taskflow/taskflow>`_, a BLAS library
with a CBLAS interface, and a C++ compiler with C++17 support. To use Jet, add
``#include <Jet.hpp>`` to the top of your header file and link your program with
the CBLAS library.
C++
^^^

The Jet C++ library requires `Taskflow <https://github.com/taskflow/taskflow>`_,
a BLAS library with a CBLAS interface, and a C++ compiler with C++17 support.
To use Jet, add ``#include <Jet.hpp>`` to the top of your header file and link
your program with the CBLAS library.

For example, assuming that the Taskflow headers can be found in your ``g++``
include path and OpenBLAS is installed on your system, you can compile the
Expand All @@ -63,15 +66,15 @@ include path and OpenBLAS is installed on your system, you can compile the
int main(){
using Tensor = Jet::Tensor<std::complex<float>>;

std::array<Tensor, 3> tensors;
tensors[0] = Tensor({"i", "j", "k"}, {2, 2, 2});
tensors[1] = Tensor({"j", "k", "l"}, {2, 2, 2});
Tensor lhs({"i", "j", "k"}, {2, 2, 2});
Tensor rhs({"j", "k", "l"}, {2, 2, 2});

lhs.FillRandom();
rhs.FillRandom();

tensors[0].FillRandom();
tensors[1].FillRandom();
tensors[2] = Tensor::ContractTensors(tensors[0], tensors[1]);

for (const auto &datum : tensors[2].GetData()) {
Tensor res = Tensor::ContractTensors(lhs, rhs);

for (const auto &datum : res.GetData()) {
std::cout << datum << std::endl;
}

Expand All @@ -92,15 +95,62 @@ The output of this program should resemble
.. code-block:: text

$ ./hellojet
(0.804981,0)
(1.53207,0)
(0.414398,0)
(0.721263,0)
(-0.936549,0.0678852)
(-0.0786964,-0.771624)
(2.98721,-0.657124)
(-1.90032,1.58051)
You have successfully used Jet version 0.2.0

For more detailed instructions, see the `development guide
<https://quantum-jet.readthedocs.io/en/stable/dev/guide.html>`_.

Python
^^^^^^

The Jet Python package requires Python version 3.7 and above. Installation of Jet,
as well as all dependencies, can be done using pip:

.. code-block:: bash

pip install quantum-jet

To build the Jet Python distribution locally, a BLAS library with a CBLAS
interface and a C++ compiler with C++17 support is required. Simply run

.. code-block:: bash

make dist
pip install dist/*.whl

To verify that Jet is installed, you can run the ``hellojet.py`` program below

.. code-block:: python

import jet

lhs = jet.Tensor(["i", "j", "k"], [2, 2, 2])
rhs = jet.Tensor(["j", "k", "l"], [2, 2, 2])

lhs.fill_random()
rhs.fill_random()
res = jet.contract_tensors(lhs, rhs)

for datum in res.data:
print(f"{datum:.5f}")

print("You have successfully used Jet version", jet.version())

The output of this program should resemble

.. code-block:: text

$ python hellojet.py
1.96289+0.25257j
-0.16588-1.44652j
-1.43005+0.49516j
1.66881-1.67099j
You have successfully used Jet version 0.2.0
Mandrenkov marked this conversation as resolved.
Show resolved Hide resolved

Contributing to Jet
===================

Expand Down
1 change: 1 addition & 0 deletions docs/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@
"nbsphinx",
"sphinx_automodapi.automodapi",
"sphinx_copybutton",
"sphinx_tabs.tabs",
"sphinx.ext.autodoc",
"sphinx.ext.autosummary",
"sphinx.ext.inheritance_diagram",
Expand Down
1 change: 1 addition & 0 deletions docs/requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ repoze.lru>=0.7
scipy>=1.2.1
sphinx-automodapi
sphinx-copybutton
sphinx-tabs
sphinx==3.5.4
sphinxcontrib-bibtex
sympy>=1.5.1
Expand Down
150 changes: 99 additions & 51 deletions docs/use/tensor_network_files.rst
Original file line number Diff line number Diff line change
@@ -1,79 +1,119 @@
Tensor network files
====================

Jet defines and provides tools for saving and loading tensor
networks to/from JSON strings.
Jet defines and provides tools for saving (and loading) tensor networks to (and
from) JSON strings.

Tensor networks are represented as JSON objects with a 'tensors' key,
which contains a list of tensors with labeled indices, and an optional
'path' key describing a contraction path through those tensors.
Tensor networks are represented as JSON objects with a ``"tensors"`` key, which
contains a list of tensors with labeled indices, and an optional ``"path"`` key
describing a contraction path through those tensors.

Tensors are represented as a tuple of 4 elements:
Tensors are represented as a tuple of 4 elements:

* **tags**: a list of string tags
* **indices**: a list of string labels for each index
* **shape**: a list of integers containing the dimension of each index
* **data**: an array containing the unshaped complex data of the tensor, in row-major order. Complex numbers are represented using 2-element arrays ``[real, imaginary]``
* **Tags**: A list of string tags.
* **Indices**: A list of string labels for each index.
* **Shape**: A list of integers containing the dimension of each index.
* **Data**: An array containing the unshaped complex data of the tensor, in
row-major order. Complex numbers are represented using 2-element arrays
``[real, imaginary]``.

Saving and loading are both handled by the :doc:`TensorNetworkSerializer </api/classJet_1_1TensorNetworkSerializer>` class.
In the C++ API, saving and loading are both handled by the
:doc:`TensorNetworkSerializer </api/classJet_1_1TensorNetworkSerializer>` class.
Like the :doc:`TensorNetwork </api/classJet_1_1TensorNetwork>` class, the
``TensorNetworkSerializer`` class is templated by a ``Tensor`` type and
can serialize or deserialize any valid ``TensorNetwork<Tensor>`` instance.

An ``invalid_tensor_file`` exception will be thrown when a string cannot
be parsed as JSON, or does not encode a valid tensor network.
``TensorNetworkSerializer`` class is templated by a ``Tensor`` type and can
serialize or deserialize any valid ``TensorNetwork<Tensor>`` instance.

A :doc:`TensorFileException </api/classJet_1_1TensorFileException>` exception
is thrown when a string cannot be parsed as JSON or the string does not encode a
valid tensor network.

Example
-------

The following C++ program demonstrates creating a tensor network and dumping it
to a JSON string. First, create a simple network of three tensors with a
contraction path and initialize the serializer:
The following C++ and Python programs demonstrate creating a tensor network,
dumping it to a JSON string, and then reading the JSON string to populate a
``TensorNetworkFile`` data structure.

.. tabs::

.. code-tab:: c++

#include <complex>
#include <iostream>
#include <string>

#include <Jet.hpp>

int main()
{
using Tensor = Jet::Tensor<std::complex<float>>;

Tensor A({"i", "j"}, {2, 2}, {{1, 0}, {0, 1}, {0, -1}, {1, 0}});
Tensor B({"j", "k"}, {2, 2}, {{1, 0}, {0, 0}, {0, 0}, {1, 0}});
Tensor C({"k"}, {2}, {{1, 0}, {0, 0}});

.. code-block:: cpp
Jet::TensorNetwork<Tensor> tn;
tn.AddTensor(A, {"A", "hermitian"});
tn.AddTensor(B, {"B", "identity", "real"});
tn.AddTensor(C, {"C", "vec", "real"});

#include <complex>
#include <iostream>
#include <string>
Jet::PathInfo path(tn, {{0, 2}, {2, 1}});

#include <Jet.hpp>
Jet::TensorNetworkSerializer<Tensor> serializer;

int main()
{
using Tensor = Jet::Tensor<std::complex<float>>;
// Serialization
std::string tnf_str = serializer(tn, path);

Tensor A({"i", "j"}, {2, 2}, {{1, 0}, {0, 1}, {0, -1}, {1, 0}});
Tensor B({"j", "k"}, {2, 2}, {{1, 0}, {0, 0}, {0, 0}, {1, 0}});
Tensor C({"k"}, {2}, {{1, 0}, {0, 0}});
// Deserialization
Jet::TensorNetworkFile<Tensor> tnf_obj = serializer(tnf_str);

Jet::TensorNetwork<Tensor> tn;
tn.AddTensor(A, {"A", "hermitian"});
tn.AddTensor(B, {"B", "identity", "real"});
tn.AddTensor(C, {"C", "vec", "real"});
return 0;
}

Jet::PathInfo path(tn, {{0, 2}, {2, 1}});
.. code-tab:: py

Jet::TensorNetworkSerializer<Tensor> serializer;
import jet

// ...
A = jet.Tensor(["i", "j"], [2, 2], [1, 1j, -1j, 1])
B = jet.Tensor(["j", "k"], [2, 2], [1, 0, 0, 1])
C = jet.Tensor(["k"], [2], [1, 0])

return 0;
}
tn = jet.TensorNetwork()
tn.add_tensor(A, ["A", "hermitian"])
tn.add_tensor(B, ["B", "identity", "real"])
tn.add_tensor(C, ["C", "vec", "real"])

path = jet.PathInfo(tn, [(0, 2), (2, 1)]);

serializer = jet.TensorNetworkSerializer();

# Serialization
tnf_str = serializer(tn, path);

# Deserialization
tnf_obj = serializer(tnf_str)


Serialization
-------------
To serialize, call the serializer with a tensor network (and an optional path):
To serialize a tensor network (and, optionally, a contraction path), call the
serializer with a tensor network (and the contraction path):

.. code-block:: cpp
.. tabs::

// ... (1)
.. code-tab:: c++

std::string tn_json = serializer(tn, path);
std::cout << tn_json << std::endl;
// Serialization
std::string tnf_str = serializer(tn, path);
std::cout << tnf_str << std::endl;

The (formatted) output of this program will be:
.. code-tab:: py

# Serialization
tnf_str = serializer(tn, path);
print(tnf_str)

The (formatted) output of this program is

.. code-block:: json

Expand All @@ -89,16 +129,24 @@ The (formatted) output of this program will be:

Deserialization
---------------
To deserialize a tensor network, call the serializer with a string:
To deserialize a tensor network (and, optionally, a contraction path), call the
serializer with a string:

.. tabs::

.. code-block:: cpp
.. code-tab:: c++

// ... (2)
// Deserialization
Jet::TensorNetworkFile<Tensor> tnf_obj = serializer(tn_json);
Jet::TensorNetwork<Tensor> tn = tnf_obj.tensors;
Jet::PathInfo path = tnf_obj.path.value(); // Uses std::optional.

Jet::TensorNetworkFile<Tensor> tensor_file = serializer(tn_json);
.. code-tab:: py

Jet::TensorNetwork<Tensor> tn_copy = tensor_file.tensors;
Jet::PathInfo path_copy = tensor_file.path.value(); // Uses std::optional.
# Deserialization
tnf_obj = serializer(tn_json)
tn = tnf_obj.tensors
path = tnf_obj.path


JSON Schema
Expand Down
Loading