VQE_CN.ipynb 44.4 KB
Notebook
Newer Older
Q
Quleaf 已提交
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313
{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 变分量子本征求解器\n",
    "\n",
    "<em> Copyright (c) 2021 Institute for Quantum Computing, Baidu Inc. All Rights Reserved. </em>"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 概览\n",
    "\n",
    "目前普遍认为,量子计算在近期很有前景的一个应用是处理量子化学问题 [1-2]。**变分量子本征求解器** (VQE)作为这个研究方向的核心应用之一,为研究者们提供了可以在目前含噪的中等规模量子设备(NISQ device)上研究量子化学的可能 [1-4]。其核心任务是求解一个量子尺度上封闭物理系统的哈密顿量 $\\hat{H}$ 的基态能量及其对应的量子态。主要的实现方法是通过在量子设备上准备一个参数化的试探波函数 $|\\Psi(\\boldsymbol\\theta)\\rangle$ 然后结合经典机器学习中的优化算法(例如梯度下降法)去不断地调整、优化参数 $\\boldsymbol\\theta$ 使得期望值  $\\langle \\Psi(\\boldsymbol\\theta)|\\hat{H}|\\Psi(\\boldsymbol\\theta)\\rangle$ 最小化。这套方案的基本原理是基于 **Rayleigh-Ritz 变分原理**。 \n",
    "\n",
    "$$\n",
    "E_0 = \\min_{\\boldsymbol\\theta} \\langle \\Psi(\\boldsymbol\\theta)|\\hat{H}|\\Psi(\\boldsymbol\\theta)\\rangle.\n",
    "\\tag{1}\n",
    "$$\n",
    "\n",
    "其中 $E_0$ 表示该系统的基态能量。从数值分析的角度来看,该问题可以被理解为求解一个**离散化**哈密顿量 $H$(埃尔米特矩阵)的最小本征值 $\\lambda_{\\min}$ 和其对应的本征向量 $|\\Psi_0\\rangle$。具体的离散化过程是如何通过建立模型实现的,这属于量子化学的专业领域范畴。精确地解释该过程需要很长的篇幅,这超过了本教程所能处理的范围。我们会在下一节背景知识模块粗略的介绍一下相关知识,感兴趣的读者可以参考 `量子化学: 基本原理和从头计算法`系列丛书 [5]。通常来说,为了能在量子设备上处理量子化学问题,哈密顿量 $H$ 会被表示成为泡利算符 $\\{X,Y,Z\\}$ 的加权求和形式。\n",
    "\n",
    "$$\n",
    "H = \\sum_k c_k ~ \\bigg( \\bigotimes_{j=0}^{M-1} \\sigma_j^{(k)} \\bigg),\n",
    "\\tag{2}\n",
    "$$\n",
    "\n",
    "其中 $c_k$ 表示权重系数, $\\sigma_j^{(k)} \\in \\{I,X,Y,Z\\}$ 并且 $M$ 表示所需的量子比特个数。这样一种哈密顿量的表示形式被称为 **泡利字符串**。以下为一个2量子比特的具体例子,\n",
    "\n",
    "$$\n",
    "H= 0.12~Y_0 \\otimes I_1-0.04~X_0\\otimes Z_1.\n",
    "\\tag{3}\n",
    "$$\n",
    "\n",
    "在下一节,我们会补充一些关于电子结构问题的背景知识。本质上讨论的就是上述哈密顿量 $H$ 是如何计算的。对于熟悉相关背景的读者,或者主要关心如何在量桨上实现 VQE 的读者,请直接跳转至第三节分析氢分子($H_2$)基态的具体例子。 "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 背景: 电子结构问题\n",
    "\n",
    "这里,我们集中讨论下量子化学中的一个基本问题 -- **电子结构问题**。更准确的说,我们关心的是给定分子(molecule)的低位能量本征态。这些信息可以帮助我们预测化学反应的速率和分子的稳定结构等等 [6]。假设一个分子由 $N_n$ 个原子核和 $N_e$ 个电子组成,描述该分子系统总能量的哈密顿量算符 $\\hat{H}_{mol}$ 在一次量子化表示下可以写为,\n",
    "\n",
    "$$\n",
    "\\begin{align}\n",
    "\\hat{H}_{\\text{mol}} & = -\\sum_{i}\\frac{\\nabla_{R_i}^2}{2M_i} - \\sum_{i} \\frac{\\nabla_{r_i}^2}{2} -\\sum_{i,j}\\frac{Z_i}{\\lvert R_i - r_j\\lvert} + \\sum_{i,j>i}\\frac{Z_iZ_j}{\\lvert R_i - R_j\\lvert} + \\sum_{i, j>i}\\frac{1}{\\lvert r_i - r_j\\lvert}, \n",
    "\\tag{4}\n",
    "\\end{align}\n",
    "$$\n",
    "\n",
    "其中 $R_i、M_i$ 和 $Z_i$ 分别表示第 $i$ 个原子核的位置、质量和原子序数(原子核内质子数),第 $i$ 个电子的位置则表示为 $r_i$。以上公式右边前两项分别代表原子核和电子的总动能。第三项表示带正电的质子和带负电的电子之间的库伦相互吸引作用。最后两项则表示原子核-原子核之间,电子-电子之间的相互排斥作用。这里,分子哈密顿量 $\\hat{H}_\\text{mol}$ 使用的是原子单位制能量 **哈特里能量**(Hartree),记为 Ha。$1$ 哈特里能量的大小为 $[\\hbar^2/(m_ee^2a_0^2)] = 27.2$ 电子伏或 $630$ 千卡/摩尔,其中 $m_e、e$ 和 $a_0$ 分别表示电子质量、基本电荷和玻尔半径。\n",
    "\n",
    "**注释1:** 在处理电子结构问题时,我们不考虑自旋-轨道耦合以及超精细结构。如果出于计算需要,可以作为微扰加入。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 玻恩-奥本海默近似\n",
    "\n",
    "由于原子核的质量要远大于电子,因而在同样的相互作用下电子的运动速度会比原子核快很多。所以,将原子核所处的位置看成固定 $R_i =$常数 是一种合理的近似。这种通过在时间尺度上将电子行为和原子核行为去耦合的近似处理思想被称为玻恩-奥本海默近似。作为近似的直接结果,公式(4)中原子核的动能项会被消去并且表示原子核-原子核相互排斥作用的项可以被认为是一个能量移位(这个项是与电子位置 $r_i$ 无关的)从而也可以作为常数项被忽略。经过这些步骤后,我们可以把哈密顿量近似为:\n",
    "\n",
    "$$\n",
    "\\begin{align}\n",
    "\\hat{H}_{\\text{electron}} & =  - \\sum_{i} \\frac{\\nabla_{r_i}^2}{2} -\\sum_{i,j}\\frac{Z_i}{\\lvert R_i - r_j\\lvert} + \\sum_{i, j>i}\\frac{1}{\\lvert r_i - r_j\\lvert} \n",
    "\\tag{5},\n",
    "\\end{align}\n",
    "$$\n",
    "\n",
    "在经过以上近似后,分子中多电子结构的能级在理论上可以通过求解以下不含时薛定谔方程获得:\n",
    "\n",
    "$$\n",
    "\\hat{H}_{\\text{electron}} |\\Psi_n \\rangle = E_n |\\Psi_n \\rangle,\n",
    "\\tag{6}\n",
    "$$\n",
    "\n",
    "其中 $n$ 指代能级。值得注意的是,电子哈密顿量中电子-电子相互排斥作用的求和项数会随着电子数 $N_e$ 的增多至 $N_e(N_e-1)/2$ 项。这意味着对于一个含有16个电子的氧分子($O_2$)我们需要计算多达120项的相互排斥作用项。 一般来说,这样的问题是无法从理论上精确求解的。正如狄拉克在 [Quantum mechanics of many-electron systems](https://royalsocietypublishing.org/doi/10.1098/rspa.1929.0094) [7] 所指出的那样,\n",
    "\n",
    "> *The underlying physical laws necessary for the mathematical theory of a large part of physics and the whole of chemistry are thus completely known, and the difficulty is only that the exact application of these laws leads to equations much too complicated to be soluble.* \n",
    "> \n",
    "> -- Paul Dirac (1929)\n",
    "\n",
    "由于解析的方法太复杂,那么我们可以采用数值方法来处理。一个最简单的数值方法(离散化方法)就是把上述作用中无限维度希尔伯特空间离散化为等间距排开的立方体晶格点。在这样一个离散化的空间里,主要运算规则为复数域的线性代数。假设空间的每个轴都离散为等间距排开的 $k$ 个点,则 $N$-电子(为了方便去掉下标 $e$)的多体波函数可以写为 [2]:\n",
    "\n",
    "$$\n",
    "|\\Psi \\rangle = \\sum_{\\mathbf{x_1}, \\ldots, \\mathbf{x_N}} \\psi(\\mathbf{x_1}, \\ldots, \\mathbf{x_N}) \\mathcal{A}(|\\mathbf{x_1}, \\ldots, \\mathbf{x_N}\\rangle).\n",
    "\\tag{7}\n",
    "$$\n",
    "\n",
    "其中坐标 $|\\mathbf{x_j}\\rangle = |r_j\\rangle |\\sigma_j\\rangle$ 记录第 $j$ 个电子的空间位置信息和自旋,$|r_j\\rangle  = |x_j,y_j,z_j\\rangle$ 且 $j\\in \\{1,2,\\cdots,N\\}$, $x_j,y_j,z_j \\in \\{0,1,\\cdots,k-1\\}$ 同时 $\\sigma_j \\in \\{\\downarrow,\\uparrow\\}$ 表示自旋向下和向上。这样一种离散化方式共计需要 $k^{3N}\\times 2^{N}$ 个数据来表示波函数。在这里,$\\mathcal{A}$ 表示反对称化操作(根据泡利不相容原理)并且 $\\psi(\\mathbf{x_1}, \\mathbf{x_2}, \\ldots, \\mathbf{x_N})=\\langle\\mathbf{x_1}, \\mathbf{x_2}, \\ldots, \\mathbf{x_N}|\\Psi\\rangle$。 可以看出,经典计算机存储这样一个波函数需要的内存是随着电子个数呈指数增长的。这使得基于这种离散化的经典数值方法,无法模拟超过几十个电子的系统。那么,我们是不是能够通过量子设备来存储和准备这样一个波函数然后求解基态能量 $E_0$ 呢?在下一节中,我们将以最简单的分子系统 -- 氢分子($H_2$)为例,讲解 VQE 算法。\n",
    "\n",
    "**注释2:** 关于量子化学和现有数值计算方法的综述也超过了本教程的处理范围,我们推荐感兴趣的读者去查阅以下经典教材 Helgaker 等人撰写的 *'Molecular Electronic-Structure Theory'* [6] 以及 Szabo & Ostlund 撰写的 *'Modern Quantum Chemistry: Introduction to Advanced Electronic Structure Theory'* [8]。 如果需要弥补量子计算和量子化学之间知识空缺,请参考以下综述文章 [Quantum chemistry in the age of quantum computing](https://pubs.acs.org/doi/10.1021/acs.chemrev.8b00803) [1] 和  [Quantum computational chemistry](https://journals.aps.org/rmp/abstract/10.1103/RevModPhys.92.015003) [2] 。\n",
    "\n",
    "**注释3:** 对于量子化学中的能量计算,我们期望能够达到 **化学精度**(chemical accuracy)$1.6\\times10^{-3}$ Ha 或者 1 千卡/摩尔。\n",
    "\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 氢分子 $H_2$ 基态能量\n",
    "\n",
    "### 构造电子哈密顿量\n",
    "\n",
    "首先,让我们通过下面几行代码引入必要的 library 和 package。量桨的量子化学工具包是基于 `psi4` 和 `openfermion` 进行开发的,所以需要读者先行安装这两个语言包。在进入下面的教程之前,我们强烈建议您先阅读[哈密顿量的构造](./BuildingMolecule_CN.ipynb)教程,该教程介绍了如何使用量桨的量子化学工具包。\n",
    "\n",
    "**注意:关于环境设置,请参考 [README_CN.md](https://github.com/PaddlePaddle/Quantum/blob/master/README_CN.md).**"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2021-04-30T09:13:45.528201Z",
     "start_time": "2021-04-30T09:13:43.385553Z"
    }
   },
   "outputs": [],
   "source": [
    "import paddle\n",
    "import paddle_quantum.qchem as qchem\n",
    "from paddle_quantum.loss import ExpecVal\n",
    "from paddle_quantum import Hamiltonian\n",
    "from paddle_quantum.state import zero_state, State\n",
    "from paddle_quantum.ansatz import Circuit\n",
    "from paddle_quantum.linalg import dagger\n",
    "from paddle_quantum import Backend\n",
    "\n",
    "import os\n",
    "import matplotlib.pyplot as plt\n",
    "\n",
    "import numpy\n",
    "from numpy import pi as PI\n",
    "from numpy import savez, zeros\n",
    "\n",
    "# 无视警告\n",
    "import warnings\n",
    "warnings.filterwarnings(\"ignore\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "对于具体需要分析的分子,我们需要其**几何构型** (geometry)、**基组**(basis set,例如 STO-3G 基于高斯函数)、**多重度**(multiplicity)以及**分子的净电荷数** (charge) 等多项信息来建模计算出该分子单体积分 (one-body integrations),双体积分(two-body integrations) 以及哈密顿量等信息。接下来,通过量桨的量子化学工具包将分子的哈密顿量提取出来并储存为 paddle quantum 的 `Hamiltonian` 类,方便我们下一步的操作。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2021-04-30T09:13:45.545018Z",
     "start_time": "2021-04-30T09:13:45.531302Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "FCI energy for H2_sto-3g_singlet (2 electrons) is -1.137283834485513.\n",
      "\n",
      "The generated h2 Hamiltonian is \n",
      " -0.09706626861762556 I\n",
      "-0.04530261550868938 X0, X1, Y2, Y3\n",
      "0.04530261550868938 X0, Y1, Y2, X3\n",
      "0.04530261550868938 Y0, X1, X2, Y3\n",
      "-0.04530261550868938 Y0, Y1, X2, X3\n",
      "0.1714128263940239 Z0\n",
      "0.16868898168693286 Z0, Z1\n",
      "0.12062523481381837 Z0, Z2\n",
      "0.16592785032250773 Z0, Z3\n",
      "0.17141282639402394 Z1\n",
      "0.16592785032250773 Z1, Z2\n",
      "0.12062523481381837 Z1, Z3\n",
      "-0.2234315367466399 Z2\n",
      "0.17441287610651626 Z2, Z3\n",
      "-0.2234315367466399 Z3\n"
     ]
    }
   ],
   "source": [
    "geo = qchem.geometry(structure=[['H', [-0., 0., 0.0]], ['H', [-0., 0., 0.74]]])\n",
    "# geo = qchem.geometry(file='h2.xyz')\n",
    "\n",
    "# 将分子信息存储在 molecule 里,包括单体积分(one-body integrations),双体积分(two-body integrations),分子的哈密顿量等\n",
    "molecule = qchem.get_molecular_data(\n",
    "    geometry=geo,\n",
    "    basis='sto-3g',\n",
    "    charge=0,\n",
    "    multiplicity=1,\n",
    "    method=\"fci\",\n",
    "    if_save=True,\n",
    "    if_print=True\n",
    ")\n",
    "# 提取哈密顿量\n",
    "molecular_hamiltonian = qchem.spin_hamiltonian(molecule=molecule,\n",
    "                                               filename=None, \n",
    "                                               multiplicity=1, \n",
    "                                               mapping_method='jordan_wigner',)\n",
    "# 打印结果\n",
    "print(\"\\nThe generated h2 Hamiltonian is \\n\", molecular_hamiltonian)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**注释4:** 生成这个哈密顿量的几何构型中,两个氢原子间的原子间隔(interatomic distance)为 $d = 74$ pm。\n",
    "\n",
    "除了输入分子的几何结构外,我们还支持读取分子的几何构型文件 (`.xyz` 文件),关于量子化学工具包更多的用法请参考[哈密顿量的构造](./BuildingMolecule_CN.ipynb)教程。如果你需要测试更多分子的几何构型,请移步至这个[数据库](http://smart.sns.it/molecules/index.html)。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 搭建量子神经网络(QNN)和试探波函数\n",
    "\n",
    "在实现VQE的过程中,我们首先需要设计量子神经网络QNN(也可以理解为参数化量子电路)来准备试探波函数 $|\\Psi(\\boldsymbol\\theta)\\rangle$。这里,我们提供一个预设好的的深度为 $D$ 层的 4-量子比特的量子电路模板,图中的虚线框内为一层:\n",
    "\n",
    "![Utheta.jpg](https://release-data.cdn.bcebos.com/PIC%2FUtheta.jpg)\n",
    "\n",
    "- 我们预设一些该参数化电路的参数,比如宽度为 $N = 4$ 量子位。\n",
    "\n",
    "- 初始化其中的变量参数,${\\bf{\\theta }}$ 代表我们量子神经网络中的参数组成的向量。\n",
    "\n",
    "接下来我们根据上图中的电路设计,通过 Paddle Quantum 的 `Circuit` 类和内置的 `real_entangled_layer()` 电路模板来高效搭建量子神经网络。 "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [],
   "source": [
    "def U_theta(num_qubits: int, depth: int) -> Circuit:\n",
    "    \"\"\"\n",
    "    Quantum Neural Network\n",
    "    \"\"\"\n",
    "    \n",
    "    # 按照量子比特数量/网络宽度初始化量子神经网络\n",
    "    cir = Circuit(num_qubits)\n",
    "    \n",
    "    # 内置的 {R_y + CNOT} 电路模板\n",
    "    cir.real_entangled_layer(depth = depth)\n",
    "    \n",
    "    # 铺上最后一列 R_y 旋转门\n",
    "    cir.ry()\n",
    "        \n",
    "    return cir"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 配置训练模型 - 损失函数\n",
    "\n",
    "现在我们已经有了数据和量子神经网络的架构,我们将进一步定义训练参数、模型和损失函数。通过作用量子神经网络 $U(\\theta)$ 在初始态 $|0..0\\rangle$ 上,我们将得到输出态 $\\left| {\\psi \\left( {\\bf{\\theta }} \\right)} \\right\\rangle $。进一步,在VQE模型中的损失函数一般由量子态 $\\left| {\\psi \\left( {\\bf{\\theta }} \\right)} \\right\\rangle$ 关于哈密顿量 $H$ 的期望值 (能量期望值 expectation value) 给出,\n",
    "\n",
    "$$\n",
    "\\min_{\\boldsymbol\\theta}  \\mathcal{L}(\\boldsymbol \\theta) = \\min_{\\boldsymbol\\theta} \\langle \\Psi(\\boldsymbol\\theta)|H |\\Psi(\\boldsymbol\\theta)\\rangle\n",
    "= \\min_{\\boldsymbol\\theta} \\sum_k c_k~\\langle \\Psi(\\boldsymbol\\theta)| \\bigotimes_j \\sigma_j^{(k)}|\\Psi(\\boldsymbol\\theta)\\rangle.\n",
    "\\tag{8}\n",
    "$$"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [],
   "source": [
    "class StateNet(paddle.nn.Layer):\n",
    "    \"\"\"\n",
    "    Construct the model net\n",
    "    \"\"\"\n",
    "\n",
    "    def __init__(self, num_qubits: int, depth: int):\n",
    "        super(StateNet, self).__init__()\n",
    "        \n",
    "        self.depth = depth\n",
    "        self.num_qubits = num_qubits\n",
    "        self.cir = U_theta(self.num_qubits, self.depth)\n",
    "        \n",
    "    # 定义损失函数和前向传播机制\n",
    "    def forward(self):\n",
    "        \n",
    "        # 运行电路\n",
    "        state = self.cir(init_state)\n",
    "        # 计算损失函数\n",
    "        loss = loss_func(state)     \n",
    "\n",
    "        return loss, self.cir"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 配置训练模型 - 模型参数\n",
    "\n",
Q
Quleaf 已提交
314
    "在进行量子神经网络的训练之前,我们还需要进行一些训练的超参数设置,主要是学习速率(LR, learning rate)、迭代次数(ITR, iteration)和量子神经网络计算模块的深度(D, Depth)。这里我们设定学习速率为 0.4, 迭代次数为 80 次。读者不妨自行调整来直观感受下超参数调整对训练效果的影响。"
Q
Quleaf 已提交
315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2021-04-30T09:14:03.744957Z",
     "start_time": "2021-04-30T09:14:03.738881Z"
    }
   },
   "outputs": [],
   "source": [
    "ITR = 80  # 设置训练的总迭代次数\n",
    "LR = 0.4   # 设置学习速率\n",
    "D = 2      # 设置量子神经网络中重复计算模块的深度 Depth\n",
    "N = molecular_hamiltonian.n_qubits # 设置参与计算的量子比特数"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 进行训练\n",
    "\n",
    "当训练模型的各项参数都设置完成后,我们将数据转化为 Paddle 中的张量,进而进行量子神经网络的训练。过程中我们用的是Adam Optimizer,也可以调用Paddle中提供的其他优化器。我们将训练过程中的结果存储在summary_data文件中。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "iter: 20 loss: -1.0700\n",
      "iter: 20 Ground state energy: -1.0700 Ha\n",
      "iter: 40 loss: -1.1309\n",
      "iter: 40 Ground state energy: -1.1309 Ha\n",
      "iter: 60 loss: -1.1362\n",
      "iter: 60 Ground state energy: -1.1362 Ha\n",
      "iter: 80 loss: -1.1372\n",
      "iter: 80 Ground state energy: -1.1372 Ha\n",
      "\n",
      "训练后的电路:\n",
      "--Ry(7.856)----*--------------x----Ry(4.698)----*--------------x----Ry(6.277)--\n",
      "               |              |                 |              |               \n",
      "--Ry(1.548)----x----*---------|----Ry(-1.56)----x----*---------|----Ry(5.041)--\n",
      "                    |         |                      |         |               \n",
      "--Ry(3.441)---------x----*----|----Ry(4.474)---------x----*----|----Ry(1.745)--\n",
      "                         |    |                           |    |               \n",
      "--Ry(-0.17)--------------x----*----Ry(1.646)--------------x----*----Ry(3.152)--\n",
      "                                                                               \n"
     ]
    }
   ],
   "source": [
    "# 确定网络的参数维度\n",
    "net = StateNet(N, D)\n",
    "\n",
    "# 一般来说,我们利用Adam优化器来获得相对好的收敛,\n",
    "# 当然你可以改成SGD或者是RMS prop.\n",
    "opt = paddle.optimizer.Adam(learning_rate=LR, parameters=net.parameters())\n",
    "\n",
    "# 定义初始态\n",
    "init_state = zero_state(N)\n",
    "\n",
    "# 定义损失函数\n",
    "loss_func = ExpecVal(molecular_hamiltonian)\n",
    "\n",
    "# 记录优化结果\n",
    "summary_iter, summary_loss = [], []\n",
    "\n",
    "# 优化循环\n",
    "for itr in range(1, ITR + 1):\n",
    "\n",
    "    # 前向传播计算损失函数\n",
    "    loss, cir = net()\n",
    "\n",
    "    # 在动态图机制下,反向传播极小化损失函数\n",
    "    loss.backward()\n",
    "    opt.minimize(loss)\n",
    "    opt.clear_grad()\n",
    "\n",
    "    # 更新优化结果\n",
    "    summary_loss.append(loss.numpy())\n",
    "    summary_iter.append(itr)\n",
    "\n",
    "    # 打印结果\n",
    "    if itr % 20 == 0:\n",
    "        print(\"iter:\", itr, \"loss:\", \"%.4f\" % loss.numpy())\n",
    "        print(\"iter:\", itr, \"Ground state energy:\", \"%.4f Ha\" \n",
    "                                            % loss.numpy())\n",
    "    if itr == ITR:\n",
    "        print(\"\\n训练后的电路:\") \n",
    "        print(cir)\n",
    "\n",
    "# 储存训练结果到 output 文件夹\n",
    "os.makedirs(\"output\", exist_ok=True)\n",
    "savez(\"./output/summary_data\", iter = summary_iter, \n",
    "                               energy=summary_loss)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 测试效果\n",
    "我们现在已经完成了量子神经网络的训练,通过 VQE 得到的基态能量的估计值大致为 $E_0 \\approx -1.137$ Ha,这与通过 `psi4` 在 sto-3g 基底下使用 FCI (full configuration-interaction) 方法计算得到的基态能量值 $E_0 = -1.13728$ Ha 是在化学精度 $\\varepsilon = 1.6 \\times 10^{-3}$ Ha 内相符合的。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2021-04-30T09:14:21.341323Z",
     "start_time": "2021-04-30T09:14:20.710152Z"
    }
   },
   "outputs": [
    {
     "data": {
      "image/png": "iVBORw0KGgoAAAANSUhEUgAAAY0AAAEGCAYAAACZ0MnKAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjUuMSwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy/YYfK9AAAACXBIWXMAAAsTAAALEwEAmpwYAAAyTklEQVR4nO3deXxU1fn48c9DQghLFpYEWYSAsgUIQSKKFtlBUTaVH7hU1KrVutda4dsNi61btVpr3UWtWLRUBAUVQVBcKkZkX8RCWCRCSNjXJDy/P85NGEISZsgkM5k879drXnfuMvc+GYZ55pxzzzmiqhhjjDH+qBXqAIwxxlQfljSMMcb4zZKGMcYYv1nSMMYY4zdLGsYYY/wWHeoAKluTJk00JSUl1GEYY0y18c033+xQ1aTS9kV80khJSSEzMzPUYRhjTLUhIhvL2mfVU8YYY/xmScMYY4zfLGkYY4zxW8S3aRhTE+Xn57NlyxYOHToU6lBMGIuNjaVly5bUrl3b79dY0jAmAm3ZsoW4uDhSUlIQkVCHY8KQqpKbm8uWLVto06aN36+z6iljItChQ4do3LixJQxTJhGhcePGAZdGLWkYE6EsYZiTOZXPiCWN0hQUwFtvwdKloY7EGGPCiiWN0kRFwZtvwtdfhzoSY4wJK5Y0SiMCycmwfXuoIzHGmLBiSaMsljSMCYr+/ftTUFBQ7jEHDx6kT58+FBYWAlBYWMidd95J586d6dq1K+vXr+fIkSNccMEFx52rb9++ZGVlAfDcc8/xi1/84rjzdu7cmTVr1pxwbLBj2blzJ6NGjfLr/ajuLGmUxZKGMRW2cuVKGjduTHR0+Xf3v/zyy1x66aVERUUB8OCDD9K2bVtWrlzJHXfcwT/+8Q9iYmIYMGAAb775ZqnnWLZsGd27dy9eP3ToEJs2baJdu3YBxXwqsTRs2JC8vDxyc3MDulZ1ZP00ypKUBHv3wqFDEBsb6miMOXUvvADr1wf3nG3bwo03nvSwGTNmMHLkSADS09P58MMPeeqpp2jXrh2tW7fm2WefZerUqUyZMoU33ngDgP379zN9+nS++eYbANq0acOsWbMAGDlyJBMmTOCqq6464VrLly/n+uuvP269ffv2xV/+viojlosvvph3332Xa6+91p93sNqykkZZkpPdMicntHEYU43Nnj2biy++mIKCAvLy8mjatClLly6lW7duLFu2jG7dunHkyBHWr19P0RQGc+fOZfPmzaSnp5Oens71119Po0aNAOjSpQtfl3GDysqVK7n00ktJSUkhJSWFiy66iK5du55wXGXFMmLECN55553gvXlhykoaZSlKGtu3w+mnhzYWYyrCjxJBZTh48CBHjhwhMTGRFStW0KlTJwBWrVpFamoqTz31FJdeeik7duwgMTGx+HVLlizhj3/8IzfffDMAN9xwA2lpaQBERUURExPD3r17iYuLK37N5s2bSUpKKm6/ALjtttto27btCXGtWbOmUmLp0KEDa9euDcI7F96spFEW36RhjAlY3bp1ERH27dvH2rVr6dChA3l5eTRo0ICYmBgyMzPJyMigbt26x/VK3rlzJ/Xq1QNcqWDOnDkMGzaseP/hw4eJLVFlvGzZMjp37nzctlWrVpVa0qisWDZu3BjQcBzVlSWNsjRq5PprWNIw5pQNGTKEDz74gJiYGNasWUNmZibdunXj9ddfJyUlhaZNm9KwYUMKCwuLv6zbt2/Pf//7XwD++te/cvHFFxd/Gefm5pKUlHTCAHvLly8nNTX1uG0rV64sLhX4qqxYZsyYwYgRI4L11oUtSxplqVULmjSxpGFMBRTV81944YV07NiRq666igULFpCZmclrr71WfNzgwYP57LPPALjiiitYvHgxZ555JsuWLePxxx8vPm7+/PkMHTr0hOuUTBp5eXmoKk2bNj3h2MqK5d1332X48OGn8jZVL6oa0Y8ePXroKZswQfXee0/99caEyKpVq0IdQrG0tDTNz89XVdVrr71W58yZc8Ixixcv1quvvvqk5xo1apSuWbOmeL1Pnz66YcMGv+IoeWwwY8nLy9PevXv7FUe4Ke2zAmRqGd+pVtIoj/XVMKbCli5dWtxPY9myZaVWGXXv3p1+/foVd6grzZEjRxg5ciQdOnQISlzBjKVhw4Z8+umnQYkr3NndU+VJSoK8PDeA4Uk6JxljTq6ov0NpfPtYlCYmJoZrrrnmuG3XXnvtcXc7lafkscGOpaawb8LyJCeDKuzYAaedFupojDElBNKRLtI73VUVq54qj912a4wxxwl50hCRRiLykYis85YNSznmdBGZLyKrRWSliNxZJcFZr3BjjDlOyJMGMB6Yp6rtgHneekkFwD2q2gk4F7hVRFJLOS64mjRxSytpGGMMEB5JYwTwqvf8VWBkyQNUNVtVF3vP9wKrgRaVHlnt2q6TnyUNY4wBwiNpNFXVbHDJAUgu72ARSQG6A1+Vc8xNIpIpIpk5Fa1aSkqypGGMMZ4qSRoiMldEVpTyCKjPvYg0AP4D3KWqe8o6TlWfV9UMVc1ISkqqWPDJydamYcwp2LZtG1deeSVt27alR48e9OrVi+nTp1dpDFlZWXTp0sXv4xcsWMAXX3wRtOMiUZXccquqA8vaJyLbRKSZqmaLSDOg1J/1IlIblzCmqOrblRTqiZKT4csv3a23IlV2WWOqM1Vl5MiRjBs3rnhuio0bNzJz5swTji0oKDjpJE1VZcGCBTRo0IDzzjsvKMdVhap+/8KhemomMM57Pg6YUfIAERHgJWC1qj5ecn+lSk52nft27qzSyxpTnX388cfExMQUDykO0Lp1a26//XYAXnnlFUaPHs2wYcMYPHgweXl5jBw5krS0NM4991yWLVsGwMSJE/nLX/5SfI4uXbqQlZVFVlYWnTp14sYbb6Rz584MHjyYgwcPAq7TXrdu3ejVqxdPP/10mTH+7W9/IzU1lbS0NMaOHUtWVhbPPvssf/3rX0lPT2fhwoW8++67nHPOOXTv3p2BAweybdu2Uo/Lycnhsssu4+yzz+bss8/m888/P+F6hYWF3HvvvZx99tmkpaXx3HPPAS4B9e3bl8svv7x4TCw3kof7W/r06UOPHj0YMmQI2dnZgJu69v/+7//o06cPTz75JF9//TVpaWn06tWLe++9t7h01bt3b5YsWVIcw/nnn1/83p6yssYXqaoH0Bh319Q6b9nI294cmO09/wmgwDJgifcY6s/5KzT2lKrqokWql1yiunp1xc5jTBUqOZ7Q+PGqc+e65/n5bv3jj936oUNu/dNP3fq+fW7988/d+u7dbv2rr9x6Xt7Jr//kk0/qXXfdVeb+yZMna4sWLTQ3N1dVVW+77TadOHGiqqrOmzdPu3Xrpqqqf/jDH/TRRx8tfl3nzp11w4YNumHDBo2KitJvv/1WVVVHjx6t//znP1VVtWvXrrpgwQJVVf3Vr36lnTt3LjWGZs2a6aFDh1RVdefOnaVeLy8vT48ePaqqqi+88IL+8pe/LPW4K664QhcuXKiqqhs3btSOHTuecL3nnntOJ02apKqqhw4d0h49euj69et1/vz5Gh8fr5s3b9bCwkI999xzdeHChXrkyBHt1auXbt++XVVVp06dqtddd52qunG0brnlluPel8+9f7D77ruv+G9+5ZVX9M4771RV1bVr12pp34eBjj0V8jKhquYCA0rZvhUY6j3/DAhN3ZBvB7+OHUMSgjHV3a233spnn31GTExM8Wx3gwYNKp4F77PPPuM///kPAP379yc3N5fdu3eXe842bdqQnp4OQI8ePcjKymL37t3s2rWLPn36APDTn/6U999/v9TXp6WlcdVVVzFy5MjiKWlL2rJlC2PGjCE7O5sjR46UOV/G3LlzWbVqVfH6nj17Tpgoas6cOSxbtoxp06YBsHv3btatW0dMTAw9e/akZcuWgJuKNisrq3jyqkGDBgGupNKsWbPi840ZMwaAXbt2sXfv3uKqsiuvvJL33nsPgNGjRzNp0iQeffRRXn755aD0ig950gh71ivcRIAHHzz2PDr6+PU6dY5fr1//+PX4+OPXG57Q/fZEnTt3Lk4CAE8//TQ7duwgIyPD5zr1i5+rVx3jS0SIjo7m6NGjxdt8J0iqU6dO8fOoqCgOHjyIqiJltD1ed911fPvttzRv3pzZs2cza9YsPv30U2bOnMmkSZNYuXLlCa+5/fbb+eUvf8nw4cNZsGABEydOLPXcR48e5csvv6Ru3bql7i/6G5966imGDBly3PYFCxac8LcUFBSgqnTu3Jkvv/yy1PMVvX+lvXdF6tWrx6BBg5gxYwZvvfUWmZmZZR7rr3Bo0whvdetCgwZ2B5UxAejfvz+HDh3imWeeKd524MCBMo+/4IILmDJlCuC+RJs0aUJ8fDwpKSksXrwYgMWLF7Nhw4Zyr5uYmEhCQkLxfBhF5wSYPHkyS5YsYfbs2Rw9epTNmzfTr18/HnnkEXbt2sW+ffuIi4tj7969xa/ZvXs3LVq4LmGvvvpq8faSxw0ePJi///3vxeu+7QhFhgwZwjPPPEN+fj4A3333Hfv37y/zb+nQoQM5OTnFSSM/P7/UxNawYUPi4uKKJ4uaOnXqcftvuOEG7rjjDs4+++zikl1FWNLwhw2RbkxARIR33nmHTz75hDZt2tCzZ0/GjRvHww8/XOrxEydOJDMzk7S0NMaPH1/8BX3ZZZeRl5dHeno6zzzzDO3btz/ptSdPnsytt95Kr169yvzlX1hYyNVXX03Xrl3p3r07d999N4mJiQwbNozp06cXN3BPnDiR0aNH07t3b5oUjRABJxz3t7/9rTj+1NRUnn322ROuecMNN5CamspZZ51Fly5d+PnPf05BQUGZf0dMTAzTpk3jvvvuo1u3bqSnp5d5m+9LL73ETTfdRK9evVBVEhISivf16NGD+Ph4rrvuupO+d/6Q8oo2kSAjI0MrXCR74AHIzoZy7sQwJpysXr2aTp06hToMU0X27dtHgwYNAHjooYfIzs7mySefBGDr1q307duXNWvWUKvWieWE0j4rIvKNqmaccDBW0vBPUUkjwhOsMaZ6mjVrFunp6XTp0oWFCxfy29/+FoDXXnuNc845hz/96U+lJoxTYQ3h/khOhkOHYN8+8LkbwhhjwsGYMWOK76bydc011wR9sigrafjDhkg31VCkVz2bijuVz4glDX8UjV9ljeGmmoiNjSU3N9cShymTqpKbm0tsbGxAr7PqKX80b+6WW7aENg5j/NSyZUu2bNlChUd5NhEtNja2uFOhvyxp+KN+fTchU1ZWqCMxxi+1a9cus/eyMRVh1VP+SkmBjRtDHYUxxoSUJQ1/paS46qlyOuMYY0yks6Thr5QUlzCsXcMYU4NZ0vBX69ZuaVVUxpgazJKGv1q2dMODWmO4MaYGs6Thr+holzgsaRhjajBLGoFo3dqShjGmRrOkEYiUFNixA8oZA98YYyKZJY1ApKS4pZU2jDE1lCWNQBQlDbuDyhhTQ1nSCETjxm5IEStpGGNqKEsagRBxpQ1LGsaYGsqSRqBat3bVUzbktDGmBrKkEaiUFDhwwCZkMsbUSJY0AmV3UBljajBLGoEqGoPKkoYxpgaypBGoevXcnOF2260xpgaypHEqUlJgw4ZQR2GMMVXOksapSEmBH36A/PxQR2KMMVUq5ElDRBqJyEciss5bNizn2CgR+VZE3qvKGE/QujUcPWoTMhljapyQJw1gPDBPVdsB87z1stwJrK6SqMrTooVb/vhjaOMwxpgqFg5JYwTwqvf8VWBkaQeJSEvgYuDFqgmrHMnJbrl9e2jjMMaYKhYOSaOpqmYDeMvkMo57Avg1cPRkJxSRm0QkU0QycyqjE16DBlC3LmzbFvxzG2NMGIuuiouIyFzgtFJ2/cbP118CbFfVb0Sk78mOV9XngecBMjIygj/ehwg0bWolDWNMjVMlSUNVB5a1T0S2iUgzVc0WkWZAad/E5wPDRWQoEAvEi8jrqnp1JYV8csnJVtIwxtQ44VA9NRMY5z0fB8woeYCqTlDVlqqaAowFPg5pwgCXNLZvt4ELjTE1SjgkjYeAQSKyDhjkrSMizUVkdkgjK09yshu40KZ+NcbUIFVSPVUeVc0FBpSyfSswtJTtC4AFlR7YyTRt6pbbt7uGcWOMqQHCoaRRPdltt8aYGsiSxqkqKmlYY7gxpgaxpHGqGjSA2FgraRhjahRLGqeqqK+GlTSMMTWIJY2KKLrt1hhjaghLGhVhScMYU8NY0qiIpk1dPw3rq2GMqSEsaVSE3XZrjKlhLGlUhCUNY0wNY0mjIqyvhjGmhvF7GBERiQUuAXoDzYGDwApglqqurJzwwlxcnPXVMMbUKH4lDRGZCAzDjfn0FW748ligPfCQl1DuUdVllRNmmBKxIdKNMTWKvyWNr1V1Yhn7HheRZKBVcEKqZmwyJmNMDeJXm4aqzjrJ/u2qmhmckKqZpCQraRhjaoyAhkYXkSTgPiAVVz0FgKr2D3Jc1YdvX4369UMdjTHGVKpA756aAqwG2gD3A1nA10GOqXopuu02Jye0cRhjTBUINGk0VtWXgHxV/URVrwfOrYS4qg+77dYYU4MEOnNfvrfMFpGLga1Ay+CGVM1YBz9jTA0SaNJ4QEQSgHuAp4B44O6gR1WdxMdDnTpW0jDG1AgBJQ1Vfc97uhvoF/xwqqGivhpW0jDG1AD+du57CtCy9qvqHUGLqDqyyZiMMTWEvyUN3z4Y9wN/qIRYqq/kZFizJtRRGGNMpfMraajqq0XPReQu33WDSxr79sGBA1CvXqijMcaYSnMqo9yWWU1VYzVq5JY7d4Y2DmOMqWQ2NHowJCa65a5doYzCGGMqnb8N4Xs5VsKoJyJ7inYBqqrxlRFctWFJwxhTQ/jbphFX2YFUa0VJY/fukIZhjDGVza/qKRFpEIxjIlZ8vOuvYW0axpgI52+bxgwReUxELhCR4qFcRaStiPxMRD4ELqycEKuBqCiXOKx6yhgT4fydT2MAMA/4ObBSRHaLSC7wOnAaME5Vp51KACLSSEQ+EpF13rJhGcclisg0EVkjIqtFpNepXK/SJCRY0jDGRDy/hxFR1dnA7EqIYTwwT1UfEpHx3vp9pRz3JPCBql4uIjFAeHWISEy0Ng1jTMQLh1tuRwBFnQVfBUaWPEBE4oELgJcAVPWIqu6qovj8k5hoJQ1jTMQLh6TRVFWzAbxlcinHtAVygMki8q2IvOjbthIWGja0hnBjTMSrkqQhInNFZEUpjxF+niIaOAt4RlW7A/tx1VhlXe8mEckUkcycqppRLyEBDh2Cw4er5nrGGBMCASUNEfmLiHQO9CKqOlBVu5TymAFsE5Fm3vmbAaWNMb4F2KKqX3nr03BJpKzrPa+qGaqakZSUFGi4p8b6ahhjaoBASxprgOdF5CsRudmbkKmiZgLjvOfjgBklD1DVH4HNItLB2zQAWBWEawdPUdKwKipjTAQLKGmo6ouqej5wDZACLBORN0SkIhMyPQQMEpF1wCBvHRFpLiK+d2vdDkwRkWVAOvDnClwz+GwoEWNMDRDodK+ISBTQ0XvsAJYCvxSRn6vq2EDPp6q5uJJDye1bgaE+60uAjEDPX2UsaRhjaoCAkoaIPA4Mx3X0+7OqLvJ2PSwia4MdXLWS4NXUWZuGMSaCBVrSWAH8VlUPlLKvZxDiqb5iYqB+fStpGGMiWqBJYwnQUUR8t+0GNqqq/cROTLSGcGNMRAs0afwDd6vrMtxcGl28541F5GZVnRPk+KoX6xVujIlwgd5ymwV09/pA9AC646qsBgKPBDm26scGLTTGRLhAk0ZHVV1ZtKKqq3BJZH1ww6qmbNBCY0yEC7R66jsReQaY6q2P8bbVAfKDGll11LAh7N0LBQUQHfDdzMYYE/YCLWmMA74H7gLuBtYD1+ISRkU6+EUGG0rEGBPh/P457HXqe1dVBwKPlXLIvqBFVV0V9dXYtQsaNw5pKMYYUxn8LmmoaiFwIEjjTUUm6xVujIlwgVa8HwKWi8hHuOHJAVDVO4IaVXVlScMYE+ECTRqzvIcpTUNvenNLGsaYCBVQ0lDVV0WkLtBKVWv2WFOlqVPHDSdiScMYE6ECnYRpGG4okQ+89XQRmVkJcVVPItZXwxgT0QK95XYibmDCXVA8XHmboEZU3dlc4caYCBZo0igoZWBCDVYwEcHGnzLGRLBAk8YKEbkSiBKRdiLyFPBFJcRVfVnSMMZEsECTxu1AZ+Aw8C9gD653uCmSkODaNNQKYMaYyBPo3VMHgN94D1OaxESXMPbsOdZD3BhjIkSg0722B34FpPi+VlX7Bzesasy3r4YlDWNMhAm0c9+/gWeBF4HC4IcTAXx7hbduHcpIjDEm6AJNGgWq+kylRBIpikoX1lfDGBOBAm0If1dEfiEizUSkUdGjUiKrropKGtZXwxgTgQItaYzzlvf6bFOgbXDCiQANGrgJmOy2W2NMBAr07inr/X0yIjZXuDEmYvlVPSUiv/Z5PrrEvj8HO6hqz5KGMSZC+dumMdbn+YQS+y4MUiyRo2FDawg3xkQkf5OGlPG8tHWTmAh5eaGOwhhjgs7fpKFlPC9t3bRrB7m5sHx5qCMxxpig8jdpdBORPSKyF0jznhetd63E+KqnQYOgUSOYMsXGoDLGRBS/koaqRqlqvKrGqWq097xovXZFAvD6enwkIuu8ZcMyjrtbRFaKyAoR+ZeIxFbkupUqJgb+3/+DlSth6dJQR2OMMUETaOe+yjAemKeq7YB53vpxRKQFcAeQoapdgCiOb5wPP4MHQ5MmVtowxkSUcEgaI4BXveevAiPLOC4aqCsi0UA9YGvlh1YBtWvDmDGwZg0sXnxse34+vPcerLUp1o0x1U84JI2mqpoN4C2TSx6gqj8AfwE2AdnAblWdU9YJReQmEckUkcycnJxKCtsPAwdCcvKx0sbq1XDnnfDcc/Daa6GLyxhjTlGVJA0Rmeu1RZR8jPDz9Q1xJZI2QHOgvohcXdbxqvq8qmaoakZSUlJw/ohTER0NY8fCunVw//1w331w8CB06+ZKIEeOhC42Y4w5BVWSNFR1oKp2KeUxA9gmIs0AvOX2Uk4xENigqjmqmg+8DZxXFbFXWL9+0KyZq6K65BL4xz9g2DCXML77LtTRGWNMQAIdsLAyzMQNhPiQt5xRyjGbgHNFpB5wEBgAZFZZhBURHQ2TJrkSRkqK29a5sxujasUK6NIlpOEZY0wgwqFN4yFgkIisAwZ564hIcxGZDaCqXwHTgMXAclzcz4cm3FPQtOmxhAFuJNw2bazznzGm2gl5SUNVc3Elh5LbtwJDfdb/APyhCkOrXF27wvvvu2qqmJhQR2OMMX4Jh5JGzdS1q7VrGGOqHUsaoeLbrmGMMdWEJY1QsXYNY0w1ZEkjlLp2tf4axphqxZJGKFm7hjGmmrGkEUqpqdauYYypVixphFJcnLVrGGOqFUsaoVbUrpGfH+pIjDHmpCxphJq1axhjqhFLGqGWmuqWK1eGNg5jjPGDJY1Qi4uD006D9etDHYkxxpyUJY1w0KYNZGWFOgpjjDkpSxrhoE0b2LoVDh0KdSTGGFMuSxrhICXFTQe7aVOoIzHGmHJZ0ggHbdq45YYNoY3DGGNOwpJGOGjaFGJjrV3DGBP2LGmEAxFX2rCShjEmzFnSCBcpKa6koRrqSIwxpkyWNMJFmzawfz/k5IQ6EmOMKZMljXCRkuKWVkVljAljljTCRVHSsMZwY0wYs6QRLurWdcOJWEnDGBPGLGmEExtOxBgT5ixphBMbTsQYE+YsaYQTG07EGBPmLGmEExtOxBgT5ixphBMbTsQYE+YsaYQTG07EGBPmLGmEGxtOxBgTxkKeNERktIisFJGjIpJRznEXishaEfleRMZXZYxVyoYTMcaEsZAnDWAFcCnwaVkHiEgU8DRwEZAKXCEiqVUTXhUr6hn+3XchDcMYY0oT8qShqqtVde1JDusJfK+q61X1CDAVGFH50YVAu3bQpAnMnh3qSIwx5gQhTxp+agFs9lnf4m2LPNHRMGIELF8O69aFOhpjjDlOdFVcRETmAqeVsus3qjrDn1OUsq3MlmIRuQm4CaBVq1Z+xRhWhgyBqVPh7bfhvvuO37d+Pfz733D4MBw9CgUF0KEDXH21u/vKGGMqUZUkDVUdWMFTbAFO91lvCWwt53rPA88DZGRkVL/bkOrWhQsvdEnjxx/dQIYAe/bApElw8KDr0xEVBfn58NZbcMYZcN55oY3bGBPxqkv11NdAOxFpIyIxwFhgZohjqlzDh7ukMMMriKnCX/8Ku3bBn/4ETz4Jjz8OTzzhGs9feMHGrDLGVLqQJw0RGSUiW4BewCwR+dDb3lxEZgOoagFwG/AhsBp4S1VXhirmKtGoEfTpAx99BHv3ulJHZibceKMrVRSJioJbboEdO1yJwxhjKlGVVE+VR1WnA9NL2b4VGOqzPhuoWbcUXXopzJsHTz0FX30FP/kJXHTRicelpsKAATB9ulu2iMx7BIwxoRfykoYpR6tWkJEBX37p2jBuu63sxu5rr4U6deDZZ603uTGm0ljSCHdXXOHaLMaPh/r1yz4uMdHdQbVkCXzxRRUFZ4ypaSxphLv27V31VNu2Jz/2oovccS++aI3ixphKYUkjkkRFwc03u0bxN98M7rmzs11D+9tvW/WXMTVYyBvCTZB16uQaw995BwYOrFij+IEDMGcOfPrp8b3Td+xwd3FZZ0JjahwraUSiYDSKHz4Mv/89vPSSO8f118PLL7shTt5911WBWYnDmBrHShqRKDERrroKnn/e3XkVaE/xwkJ4+GE30u748XD++cf2/exnbjljhitp/OxnVuIwpgaxkkakGjr01HqKq8LTT8PXX7tOg74JA44limHDXOJ4/fWghm2MCW+WNCKVb0/xRx6B7dv9e93rr7te6GPHlt6REFziuPFGGDzYNY5/9VXw4jbGhDVLGpEsNdW1RSxd6hLIP/9Zdqlj40Z48EGXBC68EK68svxzi8DPf+6GNHniCf+TkjGmWhON8MbMjIwMzczMDHUYoZWTA6++Cp98Ag0bwjnnuN7mrVq5DoPTp8PChW503VGjYPRoV1LxR3Y23HUXtGzp2kGirZnMmOpORL5R1VKn37akUZOsXQtvvOEauPftO7a9Th03qu6oURAXF/h5P/8cHnrI3Vl1ww3Bi9cYExLlJQ37WViTdOgA99/vGrt37oRNm1ybx9lnQ0LCqZ/3/PPhkktcw3hCgmuELznkyQ8/uLaPH39018zJcXOBDB7s2k7q1q3Y32aMqRJW0jDBkZ8PDzwAixe7kkvfvq6TYVaWG6l3rTcNfFwcJCW5edAPHnTT2tav7+7GGjYM4uND+VcYY7DqKUsaVen772H2bNd+cuSI29aqlUsgffpA48bHH79unZu+9ssvISbGHTd8uGsjKc+hQ1CrlnuNMSaogpY0ROgITAbOAn6jyl/KOO424C7gDCBJlR3e9hHAJOAoUADcpcpnInQAfAdLagv8XpUnRHgUGAYcAf4HXKfKLhFqAy96sUQDr6nyYMlYLGmEyL59rq9Hq1ZuEMWTdQDcvNk1yC9Y4EotPXpAz55uDvQjR1wP9bw82LrVVXXt3OleFxvrSicJCS4hFZViGjU6vlG+du1j++PjrUOiMeUIZtJIBloDI4Gd5SSN7sBOYAGQ4ZM0GgD7VVER0oC3VOlY4rVRwA/AOapsFGEw8LEqBSI8DKDKfSJcCQxXZawI9YBVQF9VsnzPZ0mjmtm9G95/H2bNclPb+kpIcGNptWgBzZq5tpk9e9xj1y7IzXXtJQcOlH+NmBg4/XRXhda3r+tBb4wpFrSGcFW2A9tFuPgkx33rLnzCdp9bdqgPlJaxBgD/U2Wj95o5Pvv+C1xedDqgvgjRQF1cSWSPv3+LCVMJCa5j4eWXuwQSE+PaSGrX9r90cOCAK4kUFrp1VVdayc11DfA5ObBypRtXa/JkN9HVgAFuadVdxpSryu+eEmEU8CCQDKUmn7HAv8p4+fUcq8aaBowAsoF6wN2q5AU3WhMy0dEntn/4q1499yipXbvj1zdvdo308+fDokWuQf6881zbyxlnuDaTWrVcssrOhg0b3GPTJlddVlh4LDE1bXp8KSg+3jX6169/LNkVFrqqN3CJ0KrITDVU5UlDlenAdBEuwLVvDCzaJ0IMMByYUPJ1IvwG1w4yxdvUEygEmgMNgYUizFVlfeX+BSZinH66GxH4pz91d3EtWACffeaGUSlL7drudfXquVJJdLRLBuvWudeWrO4Vca/Jzz9+n4hLHHXquOSSmOgeCQluX36+Kx3l58Pevceq4Q4ccLcn16/vHgkJ0Ly5u3GgZUtITnbnrFvXxXb06ImvP3z42KN27WNx+D5iYo4vdZWW4FTd+YuWR48eS6RFybQo8daq5a7l+xA5/lF0DlX3EDn+9bVquU6nRcebkDhp0hDhVuBGb3WoKluDcWFVPhXhDBGaFLV5ABcBi1XZViKGccAlwADV4iqtK4EPVMnHVZl9DmRA8JLGhAluSooBA1x77O9+57oV9Ovn/r9NnOi6JPTuDfv3uztOhw1zP1b37HGjcowa5dpzd+50Q0Bdfrlr492xAx57DMaMgfR0133hySfd4LRduri23r//Ha65xk2RsXGjG+n8+uvdD+b1691YhDfe6NqZ161zI5fffDO0bg2rV8Nrr7lpxVu0gBUrYMoUuPNOOO00Nyvsm2/CPfe4duNvvoFp0+DXv3adxhctcu3SEya4H81ffOFGRP/tb9131cKF7iapiRPdd8z8+W7qjUmT3HfVvHkwd657DwA+/NC95oEH3Prs2e4aEye69Zkz3Wgnv/udW58+HdascdcHF9v69S4+gKlT3Xt0zz1ufcoUV+t0111u/dVX3Xflbbe59Zdfdv9mt9zi1l94wS1vvBGIiuKZL9OpE5/O9a//AjIz+fsrDYiLzWdcnyw4epQnPulOUrtErrqtIURF8dhj7n0dO9ad55FHoO2AAi4/Pxt+/JEHn29Exya5jOqyDg4fZtKss+jWdi/De+XA0aNMfKM9PZtnM7T997B3L799tye9E1cwJP4T99lbfiUDT1/LgNYbKKifwO+WjGFw2o/0+8lODu85zMSZZzG09Up6H1zC/kUreWDVpQxr+hHnNVrDnvy6PPj9aEa1WETPhLXsPFyPR/53GZc3+5weif9jx5F4HvvfSMY0X0h6wgZ+PJTIkxuGc1WLBXSJ38QPBxvx96xLuKblx3SK28LGA0k8u/Eirj/9I9o1yGb9/qa8sGkIN7b6kLb1t7FuXzNe3jyIm1u/T+t6Oaze25LXtvTntpT3aFE3jxV7WjHlh77c2WYmp8XuYsnuNry5tTf3nPEOTWL28M2uM5iWfT6/PuM/NIzZz6Kd7Zj+Yy8mnPlv4msf5Iu8jry7rSe/bfcm9aMPszA3ldk5ZzOx/RvUiSpg/o6uzMnpzqQOr7vP3o405uak82DavyAqig+3pbMwpwMPpP3bffa2prNoR1smpr4Fqsz8oQdLd6fwu85vgwjTf+jJmr0tmND1PYiKYtrGDNbvTebXXWa7z976nvxwoCH3dHLrUzacR87hOO7q+KH77K3vzd6CutzWcS6I8PK63hw+WptbOi0AEV74ro/77HVcCCI8s6oPdaLyub7dZwD8fVV/4qIPMq6dm7b5iVWDSIrdy1VnLgIRHls+mBb1dzH2TNdW+8iSwbSN38Hlbb4B4MElF9Ix4UdGnbXRjdIQZCdNGqo8DTwdjIuJcCauvUJFOAuIAXJ9DrmCElVTIlwI3Af0UcW3hXMT0F+E13HVU+cCTwQjTlODxcS4rL8YiAMu6+G2/wA0AcobXSU62pVCTj8d5gIdz4BRPY+9vhuuHA2wAuiZBkOHuPV9QO/+MOQOtz4BGDjMtfAVAL8DBgP9gMNADjC0F/QG9h6F3xyE9K7QchPkFcDUNtCtHrRPh1qNYVYqDE2DDIH9dWFyI7h8CKQegU1H4Pm6MCQdWu+FLQpvJUG/FtD6APxYB95rCRc2hxYHILsuzG4BFzeHFofhh3rwQXMYlQLN82FTffggGUa3gyaHYV0d+LAJjGoBcfthTSx80hSG14e4w/C/RPiiOVxaD+IK4PtG8OVpcHl9qJsPqxJhUVMYVQti8mFlI1jaAi4dDbWPwqqmsOw0uOxyiFJYkQwrmrkx1AoLYXlz+L4ZXHCB9963go1N3S/AWrVgyemwqZFbV4XFrWFrPPTq5Uo+UWdAboJr8wKodSbsbuA+JyJQux3sjXXrqiBnwOEY92tRFfJToCDK/TpUhX3N3XlSU72OtqdBVCF07uzOt7MZxOZDWpo7Lq8Z1E+A1H3u+B+TID4WzjzT7d/SBBpFu1+TIm49OQrOqJyKpEDvnjoNyATicbfN7gNSVdkjwmzgBlW2inAH8GvgNGA7MFuVG0S4D7gGyAcOAveq8pl37nrAZqCtKrt9rvk9UIdjyeW/qtzs3Yk1GUgFBJisyqMlY7a7p4wxJjDWuc+ShjHG+K28pGFDoxtjjPGbJQ1jjDF+s6RhjDHGb5Y0jDHG+M2ShjHGGL9Z0jDGGOM3SxrGGGP8FvH9NEQkB9yIuX5oAsVDmoSTcI0Lwje2cI0LLLZTEa5xQfjGVpG4WqtqUmk7Ij5pBEJEMsvq0BJK4RoXhG9s4RoXWGynIlzjgvCNrbLisuopY4wxfrOkYYwxxm+WNI73fKgDKEO4xgXhG1u4xgUW26kI17ggfGOrlLisTcMYY4zfrKRhjDHGb5Y0jDHG+M2SBiAiF4rIWhH5XkTGhziWl0Vku4is8NnWSEQ+EpF13rJhCOI6XUTmi8hqEVkpIneGUWyxIrJIRJZ6sd0fLrF5cUSJyLci8l6YxZUlIstFZImIZIZLbCKSKCLTRGSN93nrFSZxdfDeq6LHHhG5K0xiu9v77K8QkX95/ycqJa4anzREJAo3ne1FuFkArxCR1BCG9ApwYYlt44F5qtoOmOetV7UC4B5V7YSbWvdW730Kh9gOA/1VtRuQDlwoIueGSWwAdwKrfdbDJS6Afqqa7nM/fzjE9iTwgap2xE2Suzoc4lLVtd57lQ70AA4A00Mdm4i0AO4AMlS1C25S4rGVFpeq1ugH0Av40Gd9AjAhxDGlACt81tcCzbznzYC1YfC+zQAGhVtsuPniFwPnhENsQEvvP2x/4L1w+vcEsoAmJbaFNDbcVNIb8G7SCZe4SolzMPB5OMQGtMBNld0IiAbe8+KrlLhqfEmDY294kS3etnDSVFWzAbxlciiDEZEUoDvwFWESm1cFtAQ3J/1HqhousT0B/Bo46rMtHOICUGCOiHwjIjeFSWxtgRxgslel96KI1A+DuEoaC/zLex7S2FT1B+AvwCYgG9itqnMqKy5LGiClbLP7kMsgIg2A/wB3qeqeUMdTRFUL1VUbtAR6ikiXEIeEiFwCbFfVb0IdSxnOV9WzcFWzt4rIBaEOCPdL+SzgGVXtDuwntNV3JxCRGGA48O9QxwLgtVWMANoAzYH6InJ1ZV3PkoYrWZzus94S2BqiWMqyTUSaAXjL7aEIQkRq4xLGFFV9O5xiK6Kqu4AFuHahUMd2PjBcRLKAqUB/EXk9DOICQFW3esvtuLr5nmEQ2xZgi1dSBJiGSyKhjsvXRcBiVd3mrYc6toHABlXNUdV84G3gvMqKy5IGfA20E5E23i+IscDMEMdU0kxgnPd8HK49oUqJiAAvAatV9fEwiy1JRBK953Vx/4nWhDo2VZ2gqi1VNQX3ufpYVa8OdVwAIlJfROKKnuPqwFeEOjZV/RHYLCIdvE0DgFWhjquEKzhWNQWhj20TcK6I1PP+nw7A3TxQOXGFsjEpXB7AUOA74H/Ab0Icy79w9ZL5uF9dPwMa4xpT13nLRiGI6ye4artlwBLvMTRMYksDvvViWwH83tse8th8YuzLsYbwkMeFaztY6j1WFn3uwyS2dCDT+/d8B2gYDnF5sdUDcoEEn20hjw24H/dDaQXwT6BOZcVlw4gYY4zxm1VPGWOM8ZslDWOMMX6zpGGMMcZvljSMMcb4zZKGMcYYv1nSMNWWiKiIPOaz/isRmRikc78iIpcH41wnuc5obyTX+SW2NxeRad7zdBEZGsRrJorIL0q7ljEnY0nDVGeHgUtFpEmoA/HljZzsr58Bv1DVfr4bVXWrqhYlrXRcn5hAYoguZ3ciUJw0SlzLmHJZ0jDVWQFuHuS7S+4oWVIQkX3esq+IfCIib4nIdyLykIhcJW4+juUicobPaQaKyELvuEu810eJyKMi8rWILBORn/ucd76IvAEsLyWeK7zzrxCRh71tv8d1mnxWRB4tcXyKd2wM8EdgjDeHwxivN/fLXgzfisgI7zXXisi/ReRd3ECEDURknogs9q49wjv9Q8AZ3vkeLbqWd45YEZnsHf+tiPTzOffbIvKBuPkZHgn4X8tEhPJ+jRhTHTwNLAvwS6wb0AnIA9YDL6pqT3ETS90O3OUdlwL0Ac4A5ovImcA1uFFEzxaROsDnIjLHO74n0EVVN/heTESaAw/j5mDYiftCH6mqfxSR/sCvVDWztEBV9YiXXDJU9TbvfH/GDUlyvTd8yiIRmeu9pBeQpqp5XmljlKru8Upj/xWRmbgBALuoG+CxaNTiIrd61+0qIh29WNt7+9JxoxsfBtaKyFOq6jtCtKkBrKRhqjV1I+2+hpuExl9fq2q2qh7GDR1T9KW/HJcoirylqkdVdR0uuXTEjdF0jbhh2L/CDdXQzjt+UcmE4TkbWKBuQLkCYApQkRFlBwPjvRgWALFAK2/fR6qa5z0X4M8isgyYixvyv+lJzv0T3DAUqOoaYCNQlDTmqepuVT2EGw+qdQX+BlNNWUnDRIIncBMvTfbZVoD3o8gbxC3GZ99hn+dHfdaPcvz/iZJj7Cjui/h2Vf3Qd4eI9MUN412a0obfrwgBLlPVtSViOKdEDFcBSUAPVc0XN9purB/nLovv+1aIfX/USFbSMNWe98v6LVyjcpEsXHUQuLkGap/CqUeLSC2vnaMtbia0D4FbxA0Tj4i090aJLc9XQB8RaeI1kl8BfBJAHHuBOJ/1D4HbvWSIiHQv43UJuPk88r22iaKSQcnz+foUl2zwqqVa4f5uYwBLGiZyPAb43kX1Au6LehFu6teySgHlWYv7cn8fuNmrlnkRVzWz2Gs8fo6T/OJWN2vaBGA+blTZxaoayDDV84HUooZwYBIuCS7zYphUxuumABkikolLBGu8eHJxbTErSjbAA/8AokRkOfAmcK1XjWcMgI1ya4wxxn9W0jDGGOM3SxrGGGP8ZknDGGOM3yxpGGOM8ZslDWOMMX6zpGGMMcZvljSMMcb47f8DtpkOLBMvOwQAAAAASUVORK5CYII=",
      "text/plain": [
       "<Figure size 432x288 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "result = numpy.load('./output/summary_data.npz')\n",
    "\n",
    "eig_val, eig_state = numpy.linalg.eig(\n",
    "                     molecular_hamiltonian.construct_h_matrix())\n",
    "min_eig_H = numpy.min(eig_val.real)\n",
    "min_loss = numpy.ones([len(result['iter'])]) * min_eig_H\n",
    "\n",
    "plt.figure(1)\n",
    "func1, = plt.plot(result['iter'], result['energy'], \n",
    "                  alpha=0.7, marker='', linestyle=\"-\", color='r')\n",
    "func_min, = plt.plot(result['iter'], min_loss, \n",
    "                  alpha=0.7, marker='', linestyle=\":\", color='b')\n",
    "plt.xlabel('Number of iteration')\n",
    "plt.ylabel('Energy (Ha)')\n",
    "\n",
    "plt.legend(handles=[\n",
    "    func1,\n",
    "    func_min\n",
    "],\n",
    "    labels=[\n",
    "        r'$\\left\\langle {\\psi \\left( {\\theta } \\right)} '\n",
    "        r'\\right|H\\left| {\\psi \\left( {\\theta } \\right)} \\right\\rangle $',\n",
    "        'Ground-state energy',\n",
    "    ], loc='best')\n",
    "plt.text(-15.5, -1.145, f'{min_eig_H:.5f}', fontsize=10, color='b')\n",
    "#plt.savefig(\"vqe.png\", bbox_inches='tight', dpi=300)\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 通过 VQE 确定原子间隔\n",
    "\n",
    "还记得在前面的注释中提到我们默认使用的两个氢原子间原子间隔为 $74$ pm 吗?VQE 的另一个用法便是通过在不同的原子间隔下多次运行然后观察运行结果的最小值是在什么原子间隔发生的,这个间隔即为估计得真实原子间隔。\n",
    "\n",
    "![vqe-fig-dist](figures/vqe-fig-distance.png)\n",
    "\n",
    "从上图可以看出,最小值确实发生在 $d = 74$ pm (1 pm = $1\\times 10^{-12}$ m) 附近,这是与[实验测得数据](https://cccbdb.nist.gov/exp2x.asp?casno=1333740&charge=0)相符合的 $d_{exp} (H_2) = 74.14$ pm."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "_______\n",
    "\n",
    "## 参考文献\n",
    "\n",
    "[1] Cao, Yudong, et al. Quantum Chemistry in the Age of Quantum Computing. [Chemical reviews 119.19 (2019): 10856-10915.](https://pubs.acs.org/doi/10.1021/acs.chemrev.8b00803)\n",
    "\n",
    "[2] McArdle, Sam, et al. Quantum computational chemistry. [Reviews of Modern Physics 92.1 (2020): 015003.](https://journals.aps.org/rmp/abstract/10.1103/RevModPhys.92.015003)\n",
    "\n",
    "\n",
    "[3] Peruzzo, A. et al. A variational eigenvalue solver on a photonic quantum processor. [Nat. Commun. 5, 4213 (2014).](https://www.nature.com/articles/ncomms5213)\n",
    "\n",
    "[4] Moll, Nikolaj, et al. Quantum optimization using variational algorithms on near-term quantum devices. [Quantum Science and Technology 3.3 (2018): 030503.](https://iopscience.iop.org/article/10.1088/2058-9565/aab822)\n",
    "\n",
    "[5] 徐光宪, 黎乐民, 王德民. 量子化学: 基本原理和从头计算法(上)[M], 第二版. 北京: 科学出版社, 2012; \n",
    "\n",
    "[6] Helgaker, Trygve, Poul Jorgensen, and Jeppe Olsen. Molecular electronic-structure theory. John Wiley & Sons, 2014.\n",
    "\n",
    "[7] Dirac, Paul Adrien Maurice. Quantum mechanics of many-electron systems. [Proceedings of the Royal Society of London. Series A, Containing Papers of a Mathematical and Physical Character 123.792 (1929): 714-733.](https://royalsocietypublishing.org/doi/10.1098/rspa.1929.0094)\n",
    "\n",
    "[8] Szabo, Attila, and Neil S. Ostlund. Modern quantum chemistry: introduction to advanced electronic structure theory. Courier Corporation, 2012."
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "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.13"
  },
  "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
}