{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# Variational Quantum State Diagonalization \n", "\n", " Copyright (c) 2021 Institute for Quantum Computing, Baidu Inc. All Rights Reserved. \n", "\n", "## Overview\n", "\n", "- In this tutorial, we will train a quantum neural network (QNN) through Paddle Quantum to complete the diagonalization of quantum states.\n", "\n", "- First, import the following packages." ] }, { "cell_type": "code", "execution_count": 1, "metadata": { "ExecuteTime": { "end_time": "2021-04-30T09:16:42.117977Z", "start_time": "2021-04-30T09:16:38.578847Z" } }, "outputs": [], "source": [ "import numpy\n", "from numpy import diag\n", "from numpy import pi as PI\n", "import scipy\n", "import scipy.stats\n", "import paddle\n", "from paddle import matmul, trace\n", "from paddle_quantum.circuit import UAnsatz\n", "from paddle_quantum.utils import dagger" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Background\n", "The Variational Quantum State Diagonalization [1-3] aims to output the eigen-spectrum (eigenvalues) of a quantum state. Solving the eigenvalues ​​of quantum states has many applications in quantum computation, such as calculating fidelity and Von Neumann entropy.\n", "\n", "- Quantum state is usually a mixed state which can be expressed as follows: \n", "\n", "$$\n", "\\rho_{\\text{mixed}} = \\sum_i P_i |\\psi_i\\rangle\\langle\\psi_i|. \\tag{1}\n", "$$\n", "\n", "- As an example, we consider a mixed 2-qubit quantum state with eigen-spectrum $[0.5, 0.3, 0.1, 0.1]$." ] }, { "cell_type": "code", "execution_count": 2, "metadata": { "ExecuteTime": { "end_time": "2021-04-30T09:16:42.139676Z", "start_time": "2021-04-30T09:16:42.121581Z" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "[[ 0.2569+0.j -0.012 +0.0435j -0.0492-0.0055j -0.0548+0.0682j]\n", " [-0.012 -0.0435j 0.2959-0.j 0.1061-0.0713j -0.0392-0.0971j]\n", " [-0.0492+0.0055j 0.1061+0.0713j 0.2145-0.j 0.0294-0.1132j]\n", " [-0.0548-0.0682j -0.0392+0.0971j 0.0294+0.1132j 0.2327+0.j ]]\n" ] } ], "source": [ "# Fixed random seed\n", "scipy.random.seed(13) \n", "V = scipy.stats.unitary_group.rvs(4) # Randomly generate a unitary matrix\n", "D = diag([0.5, 0.3, 0.1, 0.1]) # Input the spectrum of the target state rho\n", "V_H = V.conj().T # Conjugate transpose operation\n", "rho = V @ D @ V_H # Generate rho by inverse spectral decomposition\n", "print(numpy.around(rho, 4)) # Print quantum state rho" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Building a quantum neural network\n", "\n", "- In this case, we will learn the eigen-spectrum of quantum state $\\rho$ defined above by training a QNN (also known as the parameterized quantum circuit). Here, we provide a predefined 2-qubit quantum circuit.\n", "\n", "- One can randomly initialize the QNN parameters ${\\bf{\\vec{\\theta }}}$ containing 15 parameters." ] }, { "cell_type": "code", "execution_count": 3, "metadata": { "ExecuteTime": { "end_time": "2021-04-30T09:16:42.152252Z", "start_time": "2021-04-30T09:16:42.144220Z" } }, "outputs": [], "source": [ "N = 2 # The width of the quantum neural network\n", "SEED = 14 # Fixed random seed\n", "THETA_SIZE = 15 # The number of parameters in the quantum neural network\n", "\n", "def U_theta(theta, N):\n", " \"\"\"\n", " Quantum Neural Network\n", " \"\"\"\n", " # Initialize the quantum neural network according to the number of qubits/network width\n", " cir = UAnsatz(N)\n", " # Call the built-in quantum neural network template\n", " cir.universal_2_qubit_gate(theta, [0, 1])\n", " # Return the circuit of the quantum neural network\n", " return cir" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Training model and loss function\n", "\n", "- After setting up the quantum state and the QNN architecture, we will further define the parameters to be trained, loss function, and optimization methods. \n", "- The quantum state obtained by acting the quantum neural network $U(\\theta)$ on $\\rho$ is denoted by $\\tilde\\rho$, and we set the loss function to be the inner product of the quantum state $\\sigma$ and $\\tilde\\rho$ where\n", "\n", "$$\n", "\\sigma=0.1 |00\\rangle\\langle 00| + 0.2 |01\\rangle \\langle 01| + 0.3 |10\\rangle \\langle10| + 0.4 |11 \\rangle\\langle 11|, \\tag{2}\n", "$$\n", "\n", "- In specific, the loss function is defined as the state overlap \n", "\n", "$$\n", "\\mathcal{L}(\\boldsymbol{\\theta}) = \\text{Tr}(\\tilde\\rho\\sigma). \\tag{3}\n", "$$" ] }, { "cell_type": "code", "execution_count": 4, "metadata": { "ExecuteTime": { "end_time": "2021-04-30T09:16:42.172611Z", "start_time": "2021-04-30T09:16:42.155186Z" } }, "outputs": [], "source": [ "# Enter the quantum state sigma \n", "sigma = diag([0.1, 0.2, 0.3, 0.4]).astype('complex128')\n", "\n", "class Net(paddle.nn.Layer):\n", " \"\"\"\n", " Construct the model net\n", " \"\"\"\n", "\n", " def __init__(self, shape, rho, sigma, dtype='float64'):\n", " super(Net, self).__init__()\n", " \n", " \n", " \n", " # Convert Numpy array to Tensor supported in Paddle \n", " self.rho = paddle.to_tensor(rho)\n", " self.sigma = paddle.to_tensor(sigma)\n", " \n", " # Initialize the theta parameter list and fill the initial value with the uniform distribution of [0, 2*pi]\n", " self.theta = self.create_parameter(shape=shape, \n", " default_initializer=paddle.nn.initializer.Uniform(low=0.0, high=2*PI),\n", " dtype=dtype, is_bias=False)\n", "\n", " # Define loss function and forward propagation mechanism\n", " def forward(self, N):\n", " \n", " # Apply quantum neural network\n", " cir = U_theta(self.theta, N)\n", " U = cir.U\n", "\n", " # rho_tilde is the quantum state U*rho*U^dagger \n", " rho_tilde = matmul(matmul(U, self.rho), dagger(U))\n", "\n", " # Calculate the loss function\n", " loss = trace(matmul(self.sigma, rho_tilde))\n", "\n", " return paddle.real(loss), rho_tilde, cir" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Hyper-parameters\n", "\n", "Before training the quantum neural network, we also need to set up several hyper-parameters, mainly the learning rate LR and the number of iterations ITR. Here we set the learning rate to be LR = 0.1 and the number of iterations to ITR = 50. One can adjust these hyper-parameters accordingly and check how they influence the training performance." ] }, { "cell_type": "code", "execution_count": 5, "metadata": { "ExecuteTime": { "end_time": "2021-04-30T09:16:42.468056Z", "start_time": "2021-04-30T09:16:42.457529Z" } }, "outputs": [], "source": [ "ITR = 50 # Set the total number of iterations of training\n", "LR = 0.1 # Set the learning rate" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Training process\n", "\n", "- After setting all the parameters of SSVQE model, we need to convert all the data into Tensor in the PaddlePaddle, and then train the quantum neural network.\n", "- We used Adam Optimizer in training, and one can also call other optimizers provided in Paddle." ] }, { "cell_type": "code", "execution_count": 6, "metadata": { "ExecuteTime": { "end_time": "2021-04-30T09:16:50.340636Z", "start_time": "2021-04-30T09:16:48.778551Z" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "iter: 0 loss: 0.2494\n", "iter: 10 loss: 0.1958\n", "iter: 20 loss: 0.1843\n", "iter: 30 loss: 0.1816\n", "iter: 40 loss: 0.1805\n", "\n", "The trained circuit:\n", "--U----X----Rz(1.489)----*-----------------X----U--\n", " | | | \n", "--U----*----Ry(1.367)----X----Ry(2.749)----*----U--\n", " \n" ] } ], "source": [ "paddle.seed(SEED)\n", "\n", "# Determine the parameter dimension of the network\n", "net = Net(shape=[THETA_SIZE], rho=rho, sigma=sigma)\n", "\n", "# We use Adam optimizer for better performance\n", "# One can change it to SGD or RMSprop.\n", "opt = paddle.optimizer.Adam(learning_rate=LR, parameters=net.parameters())\n", "\n", "# Optimization loop\n", "for itr in range(ITR):\n", "\n", " # Forward propagation calculates the loss function and returns the estimated energy spectrum\n", " loss, rho_tilde, cir = net(N)\n", " rho_tilde_np = rho_tilde.numpy()\n", "\n", " # Back propagation minimizes the loss function\n", " loss.backward()\n", " opt.minimize(loss)\n", " opt.clear_grad()\n", "\n", " # Print training results\n", " if itr% 10 == 0:\n", " print('iter:', itr,'loss:','%.4f'% loss.numpy()[0])\n", " if itr == ITR - 1:\n", " print(\"\\nThe trained circuit:\")\n", " print(cir)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Benchmarking\n", "\n", "After 50 iterations, we have completed the diagonalization procedure. The next step is to verify the results of spectral decomposition by printing out $\\tilde{\\rho} = U(\\boldsymbol{\\theta})\\rho U^\\dagger(\\boldsymbol{\\theta})$. One can see the results are very close to what we expect." ] }, { "cell_type": "code", "execution_count": 7, "metadata": { "ExecuteTime": { "end_time": "2021-04-30T09:16:52.099611Z", "start_time": "2021-04-30T09:16:52.087176Z" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "The estimated spectrum is: [0.49938069 0.29916354 0.10103808 0.10041768]\n", "The target spectrum is: [0.5 0.3 0.1 0.1]\n" ] } ], "source": [ "print(\"The estimated spectrum is:\", numpy.real(numpy.diag(rho_tilde_np)))\n", "print(\"The target spectrum is:\", numpy.diag(D))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "_______\n", "\n", "\n", "## References\n", "\n", "[1] Larose, R., Tikku, A., Neel-judy, É. O., Cincio, L. & Coles, P. J. Variational quantum state diagonalization. [npj Quantum Inf. (2019) doi:10.1038/s41534-019-0167-6.](https://www.nature.com/articles/s41534-019-0167-6)\n", "\n", "[2] Nakanishi, K. M., Mitarai, K. & Fujii, K. Subspace-search variational quantum eigensolver for excited states. [Phys. Rev. Res. 1, 033062 (2019).](https://journals.aps.org/prresearch/pdf/10.1103/PhysRevResearch.1.033062)\n", "\n", "[3] Cerezo, M., Sharma, K., Arrasmith, A. & Coles, P. J. Variational Quantum State Eigensolver. [arXiv:2004.01372 (2020).](https://arxiv.org/pdf/2004.01372.pdf)" ] } ], "metadata": { "kernelspec": { "display_name": "Python 3", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.8.3" }, "toc": { "base_numbering": 1, "nav_menu": {}, "number_sections": true, "sideBar": true, "skip_h1_title": false, "title_cell": "Table of Contents", "title_sidebar": "Contents", "toc_cell": false, "toc_position": {}, "toc_section_display": true, "toc_window_display": false } }, "nbformat": 4, "nbformat_minor": 4 }