Exploring Tensor Network Circuits with Qiskit

Gopal Ramesh Dahale
Qiskit
Published in
7 min readMay 24, 2023

In the world of quantum computing, where immense computational power and information processing capabilities may await, tensor networks have emerged as another powerful tool for representing and manipulating quantum states. But before we delve into the quantum realm, let’s first explore the motivation behind classical tensor networks.

In this blog post, we will showcase how to use Qiskit’s circuit library to construct tensor networks like Matrix Product States (MPS) and Tree Tensor Networks (TTN). With a focus on image classification, we will demonstrate the application of MPS in classifying digits from the MNIST dataset of handwritten numbers.

Tensor Networks

Tensor networks have become a prominent subject of exploration in the realms of quantum computing and machine learning. Their potential extends to efficiently representing complex quantum systems [1]. One of the driving motivations behind leveraging tensor networks stems from their ability to enhance the expressiveness of supervised learning models while optimizing computational resources [2].

Within the realm of tensor networks, two notable forms have emerged: Matrix Product States (MPS) and Tree Tensor Networks (TTN). These forms enable the extension of lower-order states to higher-order ones while preserving their inherent properties. The diagram below illustrates the visual representation of these two classes of tensor networks.

MPS and TTN networks
MPS and TTN Tensor Networks

A detailed guide on tensors and tensor networks can be found at tensornetwork.org.

Tensor-network quantum circuits follow a unique approach where the architecture of the tensor network serves as a blueprint for designing the corresponding quantum circuit. This involves replacing the tensors present in the tensor networks with unitary operations, thereby transforming the network into a quantum circuit. The figure below provides a visual depiction of this conversion process.

The left side of the figure showcases an instance of the tree tensor network (TTN) architecture, while the right side depicts the corresponding quantum circuit. To indicate that a specific unitary operation does not affect a particular qubit and that it is subsequently traced out, we utilize the symbol (\). [3]

MPS Quantum Circuit

To construct each block of the Matrix Product State (MPS), we can use the functionality offered by the RealAmplitudes class in Qiskit. This allows us to have control over the number of layers within each MPS block. For instance, let’s generate a single MPS block consisting of two layers.

block_qubits = 2
layers = 2

# Creating a MPS block with two block qubits and one layer
mps_block = RealAmplitudes(num_qubits=block_qubits, reps=layers)
mps_block.decompose().draw('mpl')
MPS Circuit block with 2 qubits and 2 layers

A bit of jargon to grasp before we delve into constructing an MPS quantum circuit is the concept of bond qubits, denoted as n_d. This term stems from the bond dimension observed in tensor networks. In the context of quantum circuits, bond qubits refer to an integer that indicates the number of qubits shared between adjacent blocks. In our case, we will focus on illustrating examples of MPS quantum circuits where n_d = 1.

def MPS(num_qubits, **kwargs):
"""
Constructs a Matrix Product State (MPS) quantum circuit.

Args:
num_qubits (int): The number of qubits in the circuit.
**kwargs: Additional keyword arguments to be passed to the
RealAmplitudes.

Returns:
QuantumCircuit: The constructed MPS quantum circuit.

"""
qc = QuantumCircuit(num_qubits)
qubits = range(num_qubits)

# Iterate over adjacent qubit pairs
for i, j in zip(qubits[:-1], qubits[1:]):
qc.compose(RealAmplitudes(num_qubits=2,
parameter_prefix=f'θ_{i},{j}',
**kwargs), [i, j],
inplace=True)
qc.barrier(
) # Add a barrier after each block for clarity and separation

return qc

Now let’s construct an MPS circuit on 4 qubits.

MPS circuit on 4 qubits

Tree Tensor Network Quantum Circuit

The TTN follows a tree-like pattern. To design a quantum circuit that has the same connectivity as TTN, we will need a function to generate tuples of qubit indices where the blocks will be placed. The function below achieves the same.

def _generate_tree_tuples(n):
"""
Generate a list of tuples representing the tree structure
of consecutive numbers up to n.

Args:
n (int): The number up to which the tuples are generated.

Returns:
list: A list of tuples representing the tree structure.
"""
tuples_list = []
indices = []

# Generate initial tuples with consecutive numbers up to n
for i in range(0, n, 2):
tuples_list.append((i, i + 1))

indices += [tuples_list]

# Perform iterations until we reach a single tuple
while len(tuples_list) > 1:
new_tuples = []

# Generate new tuples by combining adjacent larger numbers
for i in range(0, len(tuples_list), 2):
new_tuples.append((tuples_list[i][1], tuples_list[i + 1][1]))

tuples_list = new_tuples
indices += [tuples_list]

return indices

With 4 qubits it outputs: [ [(0, 1), (2, 3)], [(1, 3)] ]. Each list represents the tree level and contains the qubit indices for blocks. Now we can define the TTN function.

def TTN(num_qubits, **kwargs):
"""
Constructs a Tree Tensor Network (TTN) quantum circuit.

Args:
num_qubits (int): The number of qubits in the circuit.
**kwargs: Additional keyword arguments to be passed to the
RealAmplitudes.

Returns:
QuantumCircuit: The constructed TTN quantum circuit.

Raises:
AssertionError: If the number of qubits is not a power of 2
or zero.
"""
qc = QuantumCircuit(num_qubits)
qubits = range(num_qubits)

# Compute qubit indices
assert num_qubits & (
num_qubits -
1) == 0 and num_qubits != 0, "Number of qubits must be a power of 2"

indices = _generate_tree_tuples(num_qubits)

# Iterate over each layer of TTN indices
for layer_indices in indices:
for i, j in layer_indices:
qc.compose(RealAmplitudes(num_qubits=2,
parameter_prefix=f'θ_{i},{j}',
**kwargs), [i, j],
inplace=True)
qc.barrier(
) # Add a barrier after each layer for clarity and separation

return qc

A TTN circuit on 4 qubits is shown below:

TTN circuit on 4 qubits

MPS for MNIST Binary Classification

We will now perform binary classification of digits 3 and 6 from the MNIST dataset using the MPS quantum circuit. The following preprocessing steps are used:

  1. Filter out images 3 and 6 from the MNIST dataset followed by normalization. We use 50 and 1000 images per class for training and testing respectively thanks to [4]. The labels will be mapped to ± 1 because we will use the Pauli-Z operator for the measurement.
  2. PCA is utilized for dimensionality reduction from 28 x 28 to 4 followed by applying arctan to bound the input values.
Random digits 3 and 6 from the MNIST dataset

Defining the QNN

Using the MPS quantum circuit and Qiskit’s Machine Learning module, we define a Quantum Neural Network.

# Define and create QNN
def create_qnn(n, estimator=None, **kwargs):

feature_map = QuantumCircuit(n)

input_params = ParameterVector(name='x', length=n)

for i in range(n):
feature_map.ry(input_params[i], i)
feature_map.rz(input_params[i], i)

ansatz = MPS(n, reps=1, **kwargs).decompose()

qc = QuantumCircuit(n)
qc.compose(feature_map, inplace=True)
qc.compose(ansatz, inplace=True)

qnn = EstimatorQNN(estimator=estimator,
circuit=qc,
input_params=feature_map.parameters,
weight_params=ansatz.parameters)

return qnn

To map the input data to the higher-order Hilbert space, we employ Ry and Rz gates which also increase the expressibility of the circuit. The MPS circuit acts as a trainable parameterized quantum circuit. Below is the circuit we used for the binary classification:

Quantum Neural Network using MPS on 4 qubits

Ideal Simulation

Using the COBYLA optimizer for 150 iterations we achieved a training and testing accuracy of 96.00% and 97.04%.

QNN convergence plot for ideal simulation

Noisy Simulation

Using the ibmq_manila noisy backend, the classifier was able to correctly identify 91.00% of the training images. On the test set, the accuracy increased to 94.3%

QNN convergence plot for noisy simulation

Conclusion

We explored tensor network circuits using Qiskit. We focused on two prominent tensor network architectures: Matrix Product States (MPS) and Tree Tensor Networks (TTN). These architectures offer a powerful way to represent and manipulate quantum states, making them valuable for quantum computing and machine learning applications.

We showcased the application of MPS in classifying digits from the MNIST dataset, demonstrating how to construct an MPS quantum circuit using Qiskit’s Circuit library. By leveraging the functionality provided by Qiskit, we could easily control the number of layers in each MPS block, allowing for flexible circuit design. We achieved impressive accuracy on both ideal and noisy simulations. The full code is available on GitHub.

However, it’s important to note that tensor network circuits also come with challenges. As the size of the quantum system increases, the number of parameters and resources required grows exponentially, posing scalability limitations. Developing efficient algorithms and hardware implementations for tensor network circuits remains an active area of research.

References

  1. W. Huggins, P. Patil, B. Mitchell, K. B. Whaley, and E. M. Stoudenmire, Quantum Science and Technology 4, 024001 (2019), ISSN 2058–9565, URL http://dx.doi.org/10.1088/2058-9565/aaea94
  2. R. Sengupta, S. Adhikary, I. Oseledets and J. Biamonte. Arxiv, 2022, URL https://doi.org/10.48550/arxiv.2207.02851
  3. Guala, D., Zhang, S., Cruz, E. et al. Practical overview of image classification with tensor-network quantum circuits. Sci Rep 13, 4427 (2023). https://doi.org/10.1038/s41598-023-30258-y
  4. Caro, M.C., Huang, HY., Cerezo, M. et al. Generalization in quantum machine learning from few training data. Nat Commun 13, 4919 (2022). https://doi.org/10.1038/s41467-022-32550-3

--

--

Gopal Ramesh Dahale
Qiskit
Writer for

Quantum enthusiast decoding the mysteries of qubits. Bridging quantum tech and real-world. Exploring the future, one qubit at a time.