TensorCircuit: What is inside?#

This part of the documentation is mainly for advanced users and developers who want to learn more about what happened behind the scene and delve into the codebase.

Overview of Modules#

Core Modules:

Backend Agnostic Abstraction:

  • tensorcircuit.backends provides a set of backend API and the corresponding implementation on Numpy, Jax, TensorFlow, and PyTorch backends. These backends are inherited from the TensorNetwork package and are highly customized.

Noisy Simulation Related Modules:

ML Interfaces Related Modules:

  • tensorcircuit.interfaces: Provide interfaces when quantum simulation backend is different from neural libraries. Currently include PyTorch, TensorFlow, NumPy and SciPy optimizer interfaces.

  • tensorcircuit.keras: Provide TensorFlow Keras layers, as well as wrappers of jitted function, save/load from tf side.

  • tensorcircuit.torchnn: Provide PyTorch nn Modules.

MPS and MPO Utiliy Modules:

  • tensorcircuit.quantum: Provide definition and classes for Matrix Product States as well as Matrix Product Operators, we also include various quantum physics and quantum information quantities in this module.

MPS Based Simulator Modules:

Supplemental Modules:

Processing and error mitigation on sample results:

  • tensorcircuit.results: Provide tools to process count dict and to apply error mitigation.

Cloud quantum hardware access module:

  • tensorcircuit.cloud: Provide quantum cloud SDK that can access and program the real quantum hardware.

  • tensorcircuit.compiler: Provide compiler chains to compile and transform quantum circuits.

Shortcuts and Templates for Circuit Manipulation:

  • tensorcircuit.templates: provide handy shortcuts functions for expectation or circuit building patterns.

Applications:

  • tensorcircuit.applications: most code here is not maintained and deprecated, use at your own risk.

Note

Recommend reading order – only read the part of code you care about for your purpose. If you want to get an overview of the codebase, please read tc.circuit followed by tc.cons and tc.gates.

Relation between TensorCircuit and TensorNetwork#

TensorCircuit has a strong connection with the TensorNetwork package released by Google. Since the TensorNetwork package has poor documentation and tutorials, most of the time, we need to delve into the codebase of TensorNetwork to figure out what happened. In other words, to read the TensorCircuit codebase, one may have to frequently refer to the TensorNetwork codebase.

Inside TensorCircuit, we heavily utilize TensorNetwork-related APIs from the TensorNetwork package and highly customized several modules from TensorNetwork by inheritance and rewriting:

  • We implement our own /backends from TensorNetwork’s /backends by adding much more APIs and fixing lots of bugs in TensorNetwork’s implementations on certain backends via monkey patching. (The upstream is inactive and not that responsive anyhow.)

  • We borrow TensorNetwork’s code in /quantum to our tc.quantum module, since TensorNetwork has no __init__.py file to export these MPO and MPS related objects. Of course, we have made substantial improvements since then.

  • We borrow the TensorNetwork’s code in /matrixproductstates as tc.mps_base for bug fixing and jit/AD compatibility, so that we have better support for our MPS based quantum circuit simulator.

Relations of Circuit-like classes#

                                       |- Circuit
                    |- BaseCircuit --- |
AbstractCircuit  ---|                  |- DMCircuitReference --- DMCircuit
                    |- MPSCircuit

QuOperator/QuVector and MPO/MPS#

tensorcircuit.quantum.QuOperator, tensorcircuit.quantum.QuVector and tensorcircuit.quantum.QuAdjointVector are classes adopted from TensorNetwork package. They behave like a matrix/vector (column or row) when interacting with other ingredients while the inner structure is maintained by the tensornetwork for efficiency and compactness.

We use code examples and associated tensor diagrams to illustrate these object abstractions.

Note

QuOperator can express MPOs and QuVector can express MPSs, but they can express more than these fixed structured tensor networks.

import tensornetwork as tn

n1 = tn.Node(np.ones([2, 2, 2]))
n2 = tn.Node(np.ones([2, 2, 2]))
n3 = tn.Node(np.ones([2, 2]))
n1[2]^n2[2]
n2[1]^n3[0]

matrix = tc.quantum.QuOperator(out_edges=[n1[0], n2[0]], in_edges=[n1[1], n3[1]])

n4 = tn.Node(np.ones([2]))
n5 = tn.Node(np.ones([2]))

vector = tc.quantum.QuVector([n4[0], n5[0]])

nvector = matrix @ vector

assert type(nvector) == tc.quantum.QuVector
nvector.eval_matrix()
# array([[16.], [16.], [16.], [16.]])
_images/quop.png

Note how in this example, matrix is not a typical MPO but still can be expressed as QuOperator. Indeed, any tensor network with two sets of dangling edges of the same dimension can be treated as QuOperator. QuVector is even more flexible since we can treat all dangling edges as the vector dimension.

Also, note how ^ is overloaded as tn.connect to connect edges between different nodes in TensorNetwork. And indexing the node gives the edges of the node, eg. n1[0] means the first edge of node n1.

The convention to define the QuOperator is firstly giving out_edges (left index or row index of the matrix) and then giving in_edges (right index or column index of the matrix). The edges list contains edge objects from the TensorNetwork library.

Such QuOperator/QuVector abstraction support various calculations only possible on matrix/vectors, such as matmul (@), adjoint (.adjoint()), scalar multiplication (*), tensor product (|), and partial trace (.partial_trace(subsystems_to_trace_out)). To extract the matrix information of these objects, we can use .eval() or .eval_matrix(), the former keeps the shape information of the tensor network while the latter gives the matrix representation with shape rank 2.

Quantum Cloud SDK: Layerwise API design#

From lower level to higher level, a view of API layers invoking QPU calls

Note

For compiler, error mitigation and results post-processing parts, they can be carefully designed to decouple with the QPU calls, so they are separately implemented in tensorcircuit.compiler and tensorcircuit.results, and they can be independently useful even without tc’s cloud access.