{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# 变分量子奇异值分解 (VQSVD)\n", "\n", " Copyright (c) 2020 Institute for Quantum Computing, Baidu Inc. All Rights Reserved. \n", "\n", "\n", "## 概览\n", "\n", "在本教程中,我们一起学习下经典奇异值分解(SVD)的概念以及我们自主研发的量子神经网络版本的量子奇异值分解 (VQSVD,Variational Quantum Singular Value Decomposition)[1] 是如何运作的。主体部分包括两个具体案例:\n", "\n", "- 分解随机生成的 8x8 复数矩阵\n", "- 应用在图像压缩上的效果\n", "\n", "## 背景\n", "\n", "奇异值分解(SVD)有非常多的应用包括 -- 主成分分析(PCA)、求解线性方程组和推荐系统。其主要任务是给定一个复数矩阵 $M \\in \\mathbb{C}^{m \\times n}$, 找到分解形式:\n", "\n", "$$\n", "M = UDV^\\dagger\n", "$$\n", "\n", "其中 $U_{m\\times m}$ 和 $V^\\dagger_{n\\times n}$ 是酉矩阵(Unitary matrix), 满足性质 $UU^\\dagger = VV^\\dagger = I$。 \n", "- 矩阵 $U$ 的列向量 $\\lvert {u_j}\\rangle$ 被称为左奇异向量(left singular vectors), $\\{\\lvert {u_j}\\rangle\\}_{j=1}^{m}$ 组成一组正交向量基。这些列向量本质上是矩阵 $MM^\\dagger$ 的特征向量。\n", "- 类似的,矩阵 $V$ 的列向量 $\\{\\lvert {v_j}\\rangle\\}_{j=1}^{n}$ 是 $M^\\dagger M$ 的特征向量也组成一组正交向量基。\n", "- 中间矩阵 $D_{m\\times n}$ 的对角元素上存储着由大到小排列的奇异值 $d_j$。 \n", "\n", "我们不妨先来看个简单的例子:(为了方便讨论,我们假设以下出现的 $M$ 都是方阵)\n", "\n", "$$\n", "M = 2*X\\otimes Z + 6*Z\\otimes X + 3*I\\otimes I = \n", "\\begin{bmatrix} \n", "3 &6 &2 &0 \\\\\n", "6 &3 &0 &-2 \\\\\n", "2 &0 &3 &-6 \\\\\n", "0 &-2 &-6 &3 \n", "\\end{bmatrix}\n", "$$\n", "\n", "那么该矩阵的奇异值分解可表示为:\n", "\n", "$$\n", "M = UDV^\\dagger = \n", "\\frac{1}{2}\n", "\\begin{bmatrix} \n", "-1 &-1 &1 &1 \\\\\n", "-1 &-1 &-1 &-1 \\\\\n", "-1 &1 &-1 &1 \\\\\n", "1 &-1 &-1 &1 \n", "\\end{bmatrix}\n", "\\begin{bmatrix} \n", "11 &0 &0 &0 \\\\\n", "0 &7 &0 &0 \\\\\n", "0 &0 &5 &0 \\\\\n", "0 &0 &0 &1 \n", "\\end{bmatrix}\n", "\\frac{1}{2}\n", "\\begin{bmatrix} \n", "-1 &-1 &-1 &-1 \\\\\n", "-1 &-1 &1 &1 \\\\\n", "-1 &1 &1 &-1 \\\\\n", "1 &-1 &1 &-1 \n", "\\end{bmatrix}\n", "$$\n", "\n", "首先,让我们通过下面几行代码引入必要的 library和 package。" ] }, { "cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [], "source": [ "import time\n", "import numpy as np\n", "from progressbar import ProgressBar\n", "from matplotlib import pyplot as plt\n", "from scipy.stats import unitary_group\n", "from scipy.linalg import norm\n", "\n", "import paddle.fluid as fluid\n", "from paddle.complex import matmul, transpose, trace\n", "from paddle_quantum.circuit import *\n", "from paddle_quantum.utils import *\n", "\n", "\n", "# 画出优化过程中的学习曲线\n", "def loss_plot(loss):\n", " '''\n", " loss is a list, this function plots loss over iteration\n", " '''\n", " plt.plot(list(range(1, len(loss)+1)), loss)\n", " plt.xlabel('iteration')\n", " plt.ylabel('loss')\n", " plt.title('Loss Over Iteration')\n", " plt.show()\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## 经典奇异值分解\n", "\n", "那么在了解一些简单的数学背景之后, 我们来学习下如何用 Numpy 完成矩阵的奇异值分解。" ] }, { "cell_type": "code", "execution_count": 2, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "我们想要分解的矩阵 M 是:\n", "[[ 3.+0.j 6.+0.j 2.+0.j 0.+0.j]\n", " [ 6.+0.j 3.+0.j 0.+0.j -2.+0.j]\n", " [ 2.+0.j 0.+0.j 3.+0.j -6.+0.j]\n", " [ 0.+0.j -2.+0.j -6.+0.j 3.+0.j]]\n" ] } ], "source": [ "# 生成矩阵 M\n", "def M_generator():\n", " I = np.array([[1, 0], [0, 1]])\n", " Z = np.array([[1, 0], [0, -1]])\n", " X = np.array([[0, 1], [1, 0]])\n", " Y = np.array([[0, -1j], [1j, 0]])\n", " M = 2 *np.kron(X, Z) + 6 * np.kron(Z, X) + 3 * np.kron(I, I)\n", " return M.astype('complex64')\n", "\n", "print('我们想要分解的矩阵 M 是:')\n", "print(M_generator())" ] }, { "cell_type": "code", "execution_count": 3, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "矩阵的奇异值从大到小分别是:\n", "[11. 7. 5. 1.]\n", "分解出的酉矩阵 U 是:\n", "[[-0.5+0.j -0.5+0.j 0.5+0.j 0.5+0.j]\n", " [-0.5+0.j -0.5+0.j -0.5+0.j -0.5+0.j]\n", " [-0.5+0.j 0.5+0.j -0.5+0.j 0.5+0.j]\n", " [ 0.5+0.j -0.5+0.j -0.5+0.j 0.5+0.j]]\n", "分解出的酉矩阵 V_dagger 是:\n", "[[-0.5+0.j -0.5+0.j -0.5+0.j 0.5+0.j]\n", " [-0.5+0.j -0.5+0.j 0.5+0.j -0.5+0.j]\n", " [-0.5+0.j 0.5+0.j 0.5+0.j 0.5+0.j]\n", " [-0.5+0.j 0.5+0.j -0.5+0.j -0.5+0.j]]\n" ] } ], "source": [ "# 我们只需要以下一行代码就可以完成 SVD \n", "U, D, V_dagger = np.linalg.svd(M_generator(), full_matrices=True)\n", "\n", "# 打印分解结果\n", "print(\"矩阵的奇异值从大到小分别是:\")\n", "print(D)\n", "print(\"分解出的酉矩阵 U 是:\")\n", "print(U)\n", "print(\"分解出的酉矩阵 V_dagger 是:\")\n", "print(V_dagger)" ] }, { "cell_type": "code", "execution_count": 4, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "[[ 3.+0.j 6.+0.j 2.+0.j 0.+0.j]\n", " [ 6.+0.j 3.+0.j 0.+0.j -2.+0.j]\n", " [ 2.+0.j 0.+0.j 3.+0.j -6.+0.j]\n", " [ 0.+0.j -2.+0.j -6.+0.j 3.+0.j]]\n" ] } ], "source": [ "# 再组装回去, 能不能复原矩阵?\n", "M_reconst = np.matmul(U, np.matmul(np.diag(D), V_dagger))\n", "print(M_reconst)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "那当然是可以复原成原来的矩阵 $M$ 的!读者也可以自行修改矩阵,试试看不是方阵的情况。\n", "