{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 量子神经网络初体验\n",
    "\n",
    "[![下载Notebook](https://mindspore-website.obs.cn-north-4.myhuaweicloud.com/website-images/r2.5.0/resource/_static/logo_notebook.svg)](https://mindspore-website.obs.cn-north-4.myhuaweicloud.com/notebook/r2.5.0/mindquantum/zh_cn/advanced/mindspore_initial_experience_of_quantum_neural_network.ipynb) \n",
    "[![下载样例代码](https://mindspore-website.obs.cn-north-4.myhuaweicloud.com/website-images/r2.5.0/resource/_static/logo_download_code.svg)](https://mindspore-website.obs.cn-north-4.myhuaweicloud.com/notebook/r2.5.0/mindquantum/zh_cn/advanced/mindspore_initial_experience_of_quantum_neural_network.py) \n",
    "[![查看源文件](https://mindspore-website.obs.cn-north-4.myhuaweicloud.com/website-images/r2.5.0/resource/_static/logo_source.svg)](https://gitee.com/mindspore/docs/blob/r2.5.0/docs/mindquantum/docs/source_zh_cn/advanced/initial_experience_of_quantum_neural_network.ipynb)\n",
    "\n",
    "## 量子神经网络的结构\n",
    "\n",
    "在MindSpore Quantum中,量子神经网络(Quantum Neural Network, QNN)的结构如下图所示,其通常由三部分构成:\n",
    "\n",
    "(1)一个(或多个)编码线路,用于将经典数据编码到量子数据(通常称为Encoder);\n",
    "\n",
    "(2)一个(或多个)训练线路,用于训练带参量子门中的参数(通常称为Ansatz);\n",
    "\n",
    "(3)一个(或多个)测量,用于检测测量值(例如在`Z`方向上测量,就是某个量子比特的量子态在`Z`轴上的投影,该测量得到的是量子态关于泡利`Z`算符(不限定于泡利`Z`算符,换成其他的算符亦可)的期望值)是否接近于目标期望值。\n",
    "\n",
    "![mindquantum](https://mindspore-website.obs.cn-north-4.myhuaweicloud.com/website-images/r2.5.0/docs/mindquantum/docs/source_zh_cn/images/mindquantum_cn.png)\n",
    "\n",
    "下面,我们通过一个简单的例子来体验一下如何使用MindSpore Quantum。\n",
    "\n",
    "## 简单的例子\n",
    "\n",
    "![example circuit](https://mindspore-website.obs.cn-north-4.myhuaweicloud.com/website-images/r2.5.0/docs/mindquantum/docs/source_zh_cn/images/example_circuit.png)\n",
    "\n",
    "我们搭建如上图所示的量子神经网络,其中Encoder由一个 [H](https://www.mindspore.cn/mindquantum/docs/zh-CN/r0.10/core/gates/mindquantum.core.gates.HGate.html) 门,1个 [RX](https://www.mindspore.cn/mindquantum/docs/zh-CN/r0.10/core/gates/mindquantum.core.gates.RX.html) 门、1个 [RY](https://www.mindspore.cn/mindquantum/docs/zh-CN/r0.10/core/gates/mindquantum.core.gates.RY.html) 门和1个 [RZ](https://www.mindspore.cn/mindquantum/docs/zh-CN/r0.10/core/gates/mindquantum.core.gates.RZ.html) 门构成,Ansatz由1个 [RX](https://www.mindspore.cn/mindquantum/docs/zh-CN/r0.10/core/gates/mindquantum.core.gates.RX.html) 门和1个 [RY](https://www.mindspore.cn/mindquantum/docs/zh-CN/r0.10/core/gates/mindquantum.core.gates.RY.html) 门构成,测量则是作用在第0位量子比特上的泡利`Z`算符。\n",
    "\n",
    "问题描述:我们将Encoder看成是系统对初始量子态的误差影响(参数$\\alpha_0, \\alpha_1$​和$\\alpha_2$​是将原经典数据经过预处理(可选)后得到的某个固定值,即为已知值,在此分别设为0.2, 0.3和0.4)。我们需要训练一个Ansatz来抵消掉这个误差,使得最后的量子态还是处于$|0\\rangle$​态。\n",
    "\n",
    "思路:对末态执行泡利`Z`算符测量,此时的测量值就是此时的量子态关于泡利`Z`算符的期望值。由于$|0\\rangle$​​是算符`Z`的本征态,且本征值为1,容易知道\n",
    "\n",
    "$$\n",
    "\\langle 0|Z|0\\rangle=1.\n",
    "$$\n",
    "\n",
    "也就是说,目标期望值为1。可以通过测量得到的期望值来验证此时的状态是否为$|0\\rangle$。\n",
    "\n",
    "解决方案:通过训练Ansatz中的参数,希望测量值接近于目标期望值,换句话说,我们只需让测量值尽可能接近于$|0\\rangle$态关于泡利`Z`算符对应的期望值,那么此时的状态就是$|0\\rangle$,即Ansatz抵消了Encoder对初始量子态产生的误差。\n",
    "\n",
    "## 环境准备\n",
    "\n",
    "导入本教程所依赖的模块"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [],
   "source": [
    "import numpy as np                                          # 导入numpy库并简写为np\n",
    "from mindquantum.core.circuit import Circuit                # 导入Circuit模块,用于搭建量子线路\n",
    "from mindquantum.core.gates import H, RX, RY, RZ            # 导入量子门H, RX, RY, RZ\n",
    "from mindquantum.core.parameterresolver import PRGenerator  # 导入参数生成器模块"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 搭建Encoder\n",
    "\n",
    "根据图示的量子线路图,我们可以在MindSpore Quantum中搭建Encoder。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {
    "tags": []
   },
   "outputs": [
    {
     "data": {
      "text/html": [
       "<pre style=\"white-space:pre;overflow-x:auto;line-height:normal;font-family:Menlo,'DejaVu Sans Mono',consolas,'Courier New',monospace\"><span style=\"color: #ff0000; text-decoration-color: #ff0000; font-weight: bold\">                 Circuit Summary                 </span>\n",
       "╭──────────────────────┬────────────────────────╮\n",
       "│<span style=\"font-weight: bold\"> </span><span style=\"color: #3b3b95; text-decoration-color: #3b3b95; font-weight: bold\">Info</span><span style=\"font-weight: bold\">                 </span>│<span style=\"font-weight: bold\"> </span><span style=\"color: #3b3b95; text-decoration-color: #3b3b95; font-weight: bold\">value</span><span style=\"font-weight: bold\">                  </span>│\n",
       "├──────────────────────┼────────────────────────┤\n",
       "│ <span style=\"font-weight: bold\">Number of qubit</span>      │ 1                      │\n",
       "├──────────────────────┼────────────────────────┤\n",
       "│ <span style=\"font-weight: bold\">Total number of gate</span> │ 4                      │\n",
       "│ Barrier              │ 0                      │\n",
       "│ Noise Channel        │ 0                      │\n",
       "│ Measurement          │ 0                      │\n",
       "├──────────────────────┼────────────────────────┤\n",
       "│ <span style=\"font-weight: bold\">Parameter gate</span>       │ 3                      │\n",
       "│ 3 encoder parameters │ <span style=\"color: #ffc857; text-decoration-color: #ffc857\">alpha0, alpha1, alpha2</span> │\n",
       "╰──────────────────────┴────────────────────────╯\n",
       "</pre>\n"
      ],
      "text/plain": [
       "\u001b[1;38;2;255;0;0m                 Circuit Summary                 \u001b[0m\n",
       "╭──────────────────────┬────────────────────────╮\n",
       "│\u001b[1m \u001b[0m\u001b[1;38;2;59;59;149mInfo\u001b[0m\u001b[1m                \u001b[0m\u001b[1m \u001b[0m│\u001b[1m \u001b[0m\u001b[1;38;2;59;59;149mvalue\u001b[0m\u001b[1m                 \u001b[0m\u001b[1m \u001b[0m│\n",
       "├──────────────────────┼────────────────────────┤\n",
       "│ \u001b[1mNumber of qubit\u001b[0m      │ 1                      │\n",
       "├──────────────────────┼────────────────────────┤\n",
       "│ \u001b[1mTotal number of gate\u001b[0m │ 4                      │\n",
       "│ Barrier              │ 0                      │\n",
       "│ Noise Channel        │ 0                      │\n",
       "│ Measurement          │ 0                      │\n",
       "├──────────────────────┼────────────────────────┤\n",
       "│ \u001b[1mParameter gate\u001b[0m       │ 3                      │\n",
       "│ 3 encoder parameters │ \u001b[38;2;255;200;87malpha0, alpha1, alpha2\u001b[0m │\n",
       "╰──────────────────────┴────────────────────────╯\n"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "image/svg+xml": [
       "<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"456.8\" height=\"80.0\" xmlns:xlink=\"http://www.w3.org/1999/xlink\"><rect x=\"0\" y=\"0.0\" width=\"456.8\" height=\"80.0\" fill=\"#ffffff\" /><text x=\"20.0\" y=\"40.0\" font-size=\"16px\" dominant-baseline=\"middle\" text-anchor=\"start\" font-family=\"Arial\" font-weight=\"normal\" fill=\"#252b3a\" >q0: </text><line x1=\"48.8\" x2=\"436.8\" y1=\"40.0\" y2=\"40.0\" stroke=\"#adb0b8\" stroke-width=\"1\" /><rect x=\"72.8\" y=\"20.0\" width=\"40.0\" height=\"40\" rx=\"4\" ry=\"4\" stroke=\"#ffffff\" stroke-width=\"0\" fill=\"#5e7ce0\" fill-opacity=\"1\" /><text x=\"92.8\" y=\"40.0\" font-size=\"20px\" dominant-baseline=\"middle\" text-anchor=\"middle\" font-family=\"Arial\" font-weight=\"normal\" fill=\"#ffffff\" >H </text><rect x=\"132.8\" y=\"20.0\" width=\"80.0\" height=\"40\" rx=\"4\" ry=\"4\" stroke=\"#ffffff\" stroke-width=\"0\" fill=\"#fac209\" fill-opacity=\"1\" /><text x=\"172.8\" y=\"36.0\" font-size=\"20px\" dominant-baseline=\"middle\" text-anchor=\"middle\" font-family=\"Arial\" font-weight=\"normal\" fill=\"#ffffff\" >RX </text><text x=\"172.8\" y=\"52.0\" font-size=\"14.0px\" dominant-baseline=\"middle\" text-anchor=\"middle\" font-family=\"Arial\" font-weight=\"normal\" fill=\"#ffffff\" >alpha0 </text><rect x=\"232.8\" y=\"20.0\" width=\"80.0\" height=\"40\" rx=\"4\" ry=\"4\" stroke=\"#ffffff\" stroke-width=\"0\" fill=\"#fac209\" fill-opacity=\"1\" /><text x=\"272.8\" y=\"36.0\" font-size=\"20px\" dominant-baseline=\"middle\" text-anchor=\"middle\" font-family=\"Arial\" font-weight=\"normal\" fill=\"#ffffff\" >RY </text><text x=\"272.8\" y=\"52.0\" font-size=\"14.0px\" dominant-baseline=\"middle\" text-anchor=\"middle\" font-family=\"Arial\" font-weight=\"normal\" fill=\"#ffffff\" >alpha1 </text><rect x=\"332.8\" y=\"20.0\" width=\"80.0\" height=\"40\" rx=\"4\" ry=\"4\" stroke=\"#ffffff\" stroke-width=\"0\" fill=\"#fac209\" fill-opacity=\"1\" /><text x=\"372.8\" y=\"36.0\" font-size=\"20px\" dominant-baseline=\"middle\" text-anchor=\"middle\" font-family=\"Arial\" font-weight=\"normal\" fill=\"#ffffff\" >RZ </text><text x=\"372.8\" y=\"52.0\" font-size=\"14.0px\" dominant-baseline=\"middle\" text-anchor=\"middle\" font-family=\"Arial\" font-weight=\"normal\" fill=\"#ffffff\" >alpha2 </text></svg>"
      ],
      "text/plain": [
       "<mindquantum.io.display.circuit_svg_drawer.SVGCircuit at 0x7f1f78ae3eb0>"
      ]
     },
     "execution_count": 2,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# pylint: disable=W0104\n",
    "alpha = PRGenerator('alpha')          # 初始化参数生成器\n",
    "encoder = Circuit()                   # 初始化量子线路\n",
    "encoder += H.on(0)                    # H门作用在第0位量子比特\n",
    "encoder += RX(alpha.new()).on(0)      # RX(alpha_0)门作用在第0位量子比特\n",
    "encoder += RY(alpha.new()).on(0)      # RY(alpha_1)门作用在第0位量子比特\n",
    "encoder += RZ(alpha.new()).on(0)      # RZ(alpha_2)门作用在第0位量子比特\n",
    "encoder = encoder.no_grad()           # Encoder作为整个量子神经网络的第一层,不用对编码线路中的梯度求导数,因此加入no_grad()\n",
    "encoder.as_encoder()                  # 将量子线路设置为encoder线路\n",
    "encoder.summary()                     # 总结Encoder\n",
    "encoder.svg()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "从对Encoder的Summary中可以看到,该量子线路由4个量子门组成,其中有3个含参量子门且参数为$\\alpha_0,\\alpha_1,\\alpha_2$​​​​,该量子线路调控的量子比特数为1。\n",
    "\n",
    "然后,我们需要对Encoder中的参数进行赋值。由于Encoder中的参数$\\alpha_0, \\alpha_1$​和$\\alpha_2$​分别为已知值0.2、0.3和0.4,因此可以直接对参数进行赋值,并打印此时的状态。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {
    "tags": []
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "(0.5669903122552596-0.1753906567580312j)¦0⟩\n",
      "(0.800814626197614+0.08034947292077024j)¦1⟩\n"
     ]
    }
   ],
   "source": [
    "alpha0, alpha1, alpha2 = 0.2, 0.3, 0.4              # alpha0、alpha1、alpha2为已知的固定值,分别赋值0.2、0.3 和0.4\n",
    "state = encoder.get_qs(pr={'alpha0': alpha0, 'alpha1': alpha1, 'alpha2': alpha2}, ket=True)\n",
    "print(state)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "上述步骤为了展示MindSpore Quantum可以演化量子线路(若量子线路中的量子门带参数,则需要对参数赋值)并得到演化后的末态。从上述打印可以看到,演化后得到的末态为$|0\\rangle$​​​和$|1\\rangle$​​​组成的叠加态,各项对应的振幅为上述打印的状态左边对应的数值。\n",
    "\n",
    "说明:\n",
    "\n",
    "(1)通过调用量子线路的 [get_qs](https://www.mindspore.cn/mindquantum/docs/zh-CN/r0.10/core/circuit/mindquantum.core.circuit.Circuit.html#mindquantum.core.circuit.Circuit.get_qs) 函数,我们能够得到该量子线路在全零态基础上演化出来的量子态。\n",
    "\n",
    "(2)[get_qs](https://www.mindspore.cn/mindquantum/docs/zh-CN/r0.10/core/circuit/mindquantum.core.circuit.Circuit.html#mindquantum.core.circuit.Circuit.get_qs) 的 `pr` 参数代表变分量子线路中的参数值,`ket` 表示是否将量子态输出为右矢形式。\n",
    "\n",
    "## 搭建Ansatz\n",
    "\n",
    "同样地,我们也可以在MindSpore Quantum中搭建Ansatz。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {
    "tags": []
   },
   "outputs": [
    {
     "data": {
      "image/svg+xml": [
       "<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"296.8\" height=\"80.0\" xmlns:xlink=\"http://www.w3.org/1999/xlink\"><rect x=\"0\" y=\"0.0\" width=\"296.8\" height=\"80.0\" fill=\"#ffffff\" /><text x=\"20.0\" y=\"40.0\" font-size=\"16px\" dominant-baseline=\"middle\" text-anchor=\"start\" font-family=\"Arial\" font-weight=\"normal\" fill=\"#252b3a\" >q0: </text><line x1=\"48.8\" x2=\"276.8\" y1=\"40.0\" y2=\"40.0\" stroke=\"#adb0b8\" stroke-width=\"1\" /><rect x=\"72.8\" y=\"20.0\" width=\"80.0\" height=\"40\" rx=\"4\" ry=\"4\" stroke=\"#ffffff\" stroke-width=\"0\" fill=\"#fac209\" fill-opacity=\"1\" /><text x=\"112.8\" y=\"36.0\" font-size=\"20px\" dominant-baseline=\"middle\" text-anchor=\"middle\" font-family=\"Arial\" font-weight=\"normal\" fill=\"#ffffff\" >RX </text><text x=\"112.8\" y=\"52.0\" font-size=\"14.0px\" dominant-baseline=\"middle\" text-anchor=\"middle\" font-family=\"Arial\" font-weight=\"normal\" fill=\"#ffffff\" >theta0 </text><rect x=\"172.8\" y=\"20.0\" width=\"80.0\" height=\"40\" rx=\"4\" ry=\"4\" stroke=\"#ffffff\" stroke-width=\"0\" fill=\"#fac209\" fill-opacity=\"1\" /><text x=\"212.8\" y=\"36.0\" font-size=\"20px\" dominant-baseline=\"middle\" text-anchor=\"middle\" font-family=\"Arial\" font-weight=\"normal\" fill=\"#ffffff\" >RY </text><text x=\"212.8\" y=\"52.0\" font-size=\"14.0px\" dominant-baseline=\"middle\" text-anchor=\"middle\" font-family=\"Arial\" font-weight=\"normal\" fill=\"#ffffff\" >theta1 </text></svg>"
      ],
      "text/plain": [
       "<mindquantum.io.display.circuit_svg_drawer.SVGCircuit at 0x7f1f78a87ca0>"
      ]
     },
     "execution_count": 4,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# pylint: disable=W0104\n",
    "theta = PRGenerator('theta')                 # 初始化参数生成器\n",
    "ansatz = Circuit()                           # 初始化量子线路\n",
    "ansatz += RX(theta.new()).on(0)              # RX(theta_0)门作用在第0位量子比特\n",
    "ansatz += RY(theta.new()).on(0)              # RY(theta_1)门作用在第0位量子比特\n",
    "ansatz.as_ansatz()                           # 将量子线路设置成待训练线路\n",
    "ansatz.svg()                                 # 打印量子线路"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "从对Ansatz的Summary中可以看到,该量子线路由2个量子门组成,其中有2个含参量子门且参数为$\\theta_0, \\theta_1$​​,该量子线路调控的量子比特数为1。\n",
    "\n",
    "然后,对Ansatz中的参数进行赋值。由于Ansatz为需要训练的量子线路,因此Ansatz中的参数$\\theta_0$​​和$\\theta_1$​​可以随机设定,通常默认设为初始值0。我们同样可以打印此时的量子态,不过这并不是必要的步骤,只是为了再次熟悉一下 [get_qs](https://www.mindspore.cn/mindquantum/docs/zh-CN/r0.10/core/circuit/mindquantum.core.circuit.Circuit.html#mindquantum.core.circuit.Circuit.get_qs) 函数。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {
    "tags": []
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "1¦0⟩\n"
     ]
    }
   ],
   "source": [
    "theta0, theta1 = 0, 0                        # 对theta0、theta1进行赋值,设为初始值0、0\n",
    "state = ansatz.get_qs(pr=dict(zip(ansatz.params_name, [theta0, theta1])), ket=True)\n",
    "print(state)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "从上述打印可以看到,此时的状态为$|0\\rangle$​​且振幅为1。这是因为对于Ansatz来说,默认的输入量子态为$|0\\rangle$​​,而且其中的参数$\\theta_0$​​和$\\theta_1$​​都为0,此时的 [RX(0)](https://www.mindspore.cn/mindquantum/docs/zh-CN/r0.10/core/gates/mindquantum.core.gates.RX.html) 门和 [RY(0)](https://www.mindspore.cn/mindquantum/docs/zh-CN/r0.10/core/gates/mindquantum.core.gates.RY.html) 门都相当于 [I](https://www.mindspore.cn/mindquantum/docs/zh-CN/r0.10/core/gates/mindquantum.core.gates.IGate.html) 门,因此整个线路演化的过程就是$|0\\rangle$​​经过$I\\cdot I$,那么最后输出的态当然就是$|0\\rangle$​​​了。\n",
    "\n",
    "那么完整的量子线路就是Encoder加上Ansatz。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {
    "tags": []
   },
   "outputs": [
    {
     "data": {
      "image/svg+xml": [
       "<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"656.8\" height=\"80.0\" xmlns:xlink=\"http://www.w3.org/1999/xlink\"><rect x=\"0\" y=\"0.0\" width=\"656.8\" height=\"80.0\" fill=\"#ffffff\" /><text x=\"20.0\" y=\"40.0\" font-size=\"16px\" dominant-baseline=\"middle\" text-anchor=\"start\" font-family=\"Arial\" font-weight=\"normal\" fill=\"#252b3a\" >q0: </text><line x1=\"48.8\" x2=\"636.8\" y1=\"40.0\" y2=\"40.0\" stroke=\"#adb0b8\" stroke-width=\"1\" /><rect x=\"72.8\" y=\"20.0\" width=\"40.0\" height=\"40\" rx=\"4\" ry=\"4\" stroke=\"#ffffff\" stroke-width=\"0\" fill=\"#5e7ce0\" fill-opacity=\"1\" /><text x=\"92.8\" y=\"40.0\" font-size=\"20px\" dominant-baseline=\"middle\" text-anchor=\"middle\" font-family=\"Arial\" font-weight=\"normal\" fill=\"#ffffff\" >H </text><rect x=\"132.8\" y=\"20.0\" width=\"80.0\" height=\"40\" rx=\"4\" ry=\"4\" stroke=\"#ffffff\" stroke-width=\"0\" fill=\"#fac209\" fill-opacity=\"1\" /><text x=\"172.8\" y=\"36.0\" font-size=\"20px\" dominant-baseline=\"middle\" text-anchor=\"middle\" font-family=\"Arial\" font-weight=\"normal\" fill=\"#ffffff\" >RX </text><text x=\"172.8\" y=\"52.0\" font-size=\"14.0px\" dominant-baseline=\"middle\" text-anchor=\"middle\" font-family=\"Arial\" font-weight=\"normal\" fill=\"#ffffff\" >alpha0 </text><rect x=\"232.8\" y=\"20.0\" width=\"80.0\" height=\"40\" rx=\"4\" ry=\"4\" stroke=\"#ffffff\" stroke-width=\"0\" fill=\"#fac209\" fill-opacity=\"1\" /><text x=\"272.8\" y=\"36.0\" font-size=\"20px\" dominant-baseline=\"middle\" text-anchor=\"middle\" font-family=\"Arial\" font-weight=\"normal\" fill=\"#ffffff\" >RY </text><text x=\"272.8\" y=\"52.0\" font-size=\"14.0px\" dominant-baseline=\"middle\" text-anchor=\"middle\" font-family=\"Arial\" font-weight=\"normal\" fill=\"#ffffff\" >alpha1 </text><rect x=\"332.8\" y=\"20.0\" width=\"80.0\" height=\"40\" rx=\"4\" ry=\"4\" stroke=\"#ffffff\" stroke-width=\"0\" fill=\"#fac209\" fill-opacity=\"1\" /><text x=\"372.8\" y=\"36.0\" font-size=\"20px\" dominant-baseline=\"middle\" text-anchor=\"middle\" font-family=\"Arial\" font-weight=\"normal\" fill=\"#ffffff\" >RZ </text><text x=\"372.8\" y=\"52.0\" font-size=\"14.0px\" dominant-baseline=\"middle\" text-anchor=\"middle\" font-family=\"Arial\" font-weight=\"normal\" fill=\"#ffffff\" >alpha2 </text><rect x=\"432.8\" y=\"20.0\" width=\"80.0\" height=\"40\" rx=\"4\" ry=\"4\" stroke=\"#ffffff\" stroke-width=\"0\" fill=\"#fac209\" fill-opacity=\"1\" /><text x=\"472.8\" y=\"36.0\" font-size=\"20px\" dominant-baseline=\"middle\" text-anchor=\"middle\" font-family=\"Arial\" font-weight=\"normal\" fill=\"#ffffff\" >RX </text><text x=\"472.8\" y=\"52.0\" font-size=\"14.0px\" dominant-baseline=\"middle\" text-anchor=\"middle\" font-family=\"Arial\" font-weight=\"normal\" fill=\"#ffffff\" >theta0 </text><rect x=\"532.8\" y=\"20.0\" width=\"80.0\" height=\"40\" rx=\"4\" ry=\"4\" stroke=\"#ffffff\" stroke-width=\"0\" fill=\"#fac209\" fill-opacity=\"1\" /><text x=\"572.8\" y=\"36.0\" font-size=\"20px\" dominant-baseline=\"middle\" text-anchor=\"middle\" font-family=\"Arial\" font-weight=\"normal\" fill=\"#ffffff\" >RY </text><text x=\"572.8\" y=\"52.0\" font-size=\"14.0px\" dominant-baseline=\"middle\" text-anchor=\"middle\" font-family=\"Arial\" font-weight=\"normal\" fill=\"#ffffff\" >theta1 </text></svg>"
      ],
      "text/plain": [
       "<mindquantum.io.display.circuit_svg_drawer.SVGCircuit at 0x7f1f78a87520>"
      ]
     },
     "execution_count": 6,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# pylint: disable=W0104\n",
    "circuit = encoder.as_encoder() + ansatz.as_ansatz()                   # 完整的量子线路由Encoder和Ansatz组成\n",
    "circuit.svg()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "从对完整的量子线路的Summary中可以看到,该量子线路由6个量子门组成,其中有5个含参量子门且参数为$\\alpha_0,\\alpha_1,\\alpha_2,\\theta_0,\\theta_1$​​​,该量子线路调控的量子比特数为1。\n",
    "\n",
    "## 构建哈密顿量\n",
    "\n",
    "我们对第0位量子比特执行泡利`Z`算符测量,构建对应的哈密顿量。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {
    "tags": []
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "-1 [Z0]\n"
     ]
    }
   ],
   "source": [
    "from mindquantum.core.operators import QubitOperator           # 导入QubitOperator模块,用于构造泡利算符\n",
    "from mindquantum.core.operators import Hamiltonian             # 导入Hamiltonian模块,用于构建哈密顿量\n",
    "\n",
    "ham = Hamiltonian(QubitOperator('Z0', -1))                     # 对第0位量子比特执行泡利Z算符测量,且将系数设置为-1,构建对应的哈密顿量\n",
    "print(ham)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "从上述打印可以看到,此时构建的哈密顿量为对第0位量子比特执行泡利`Z`算符测量,且系数为-1。之所以将系数设为-1,是因为在量子神经网络的训练中,Ansatz中的参数的梯度会一直下降,同时测量值也会一直减少。如果最后收敛于-1,那么此时对应的量子态是$|1\\rangle$而不是$|0\\rangle$​,如下所示\n",
    "\n",
    "$$\n",
    "\\langle 1|Z|1\\rangle=-1.\n",
    "$$\n",
    "\n",
    "而我们所希望得到的是$|0\\rangle$态。所以,将系数设为-1,那么当测量值为-1时,此时对应的量子态就是$|0\\rangle$态,如下所示\n",
    "\n",
    "$$\n",
    "\\langle 0|(-Z)|0\\rangle=-1.\n",
    "$$\n",
    "\n",
    "说明:\n",
    "\n",
    "(1)[QubitOperator](https://www.mindspore.cn/mindquantum/docs/zh-CN/r0.10/core/operators/mindquantum.core.operators.QubitOperator.html) 是作用于量子比特的算子的总和,主要用于构造泡利算符;一般格式如下:`QubitOperator(term=None, coefficient=1.0)`;\n",
    "\n",
    "(2)[Hamiltonian](https://www.mindspore.cn/mindquantum/docs/zh-CN/r0.10/core/operators/mindquantum.core.operators.Hamiltonian.html) 是哈密顿量包装器,主要用于构建哈密顿量,一般格式如下:`Hamiltonian(QubitOperator('X0 Y2', 0.5))`,`X0` 和 `Y2` 表示泡利 `X` 算符作用在第0位量子比特,泡利 `Y` 算符作用在第2位量子比特,系数为0.5。\n",
    "\n",
    "## 生成变分量子线路模拟算子\n",
    "\n",
    "对于上述搭建的量子线路,我们可以在MindSpore Quantum生成一个变分量子线路模拟算子对其进行模拟。\n",
    "\n",
    "首先,为了方便,我们对Encoder和Ansatz中的参数数组分别命名为encoder_names和ansatz_names。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {
    "tags": []
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "encoder_names =  ['alpha0', 'alpha1', 'alpha2'] \n",
      "ansatz_names = ['theta0', 'theta1']\n"
     ]
    }
   ],
   "source": [
    "encoder_names = encoder.params_name                   # Encoder中所有参数组成的数组,encoder.para_name系统会自动生成\n",
    "ansatz_names = ansatz.params_name                     # Ansatz中所有参数组成的数组,ansatz.para_name系统会自动生成\n",
    "\n",
    "print('encoder_names = ', encoder.params_name, '\\nansatz_names =', ansatz.params_name)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "从上述打印可以看到,encoder_names为Encoder中所有参数$\\alpha_0, \\alpha_1, \\alpha_2$​组成的数组,ansatz_names为Ansatz中所有参数$\\theta_0,\\theta_1$​组成的数组,这两个数组会在生成变分量子线路模拟算子时用到。\n",
    "\n",
    "然后,我们通过 [Simulator](https://www.mindspore.cn/mindquantum/docs/zh-CN/r0.10/simulator/mindquantum.simulator.Simulator.html) 模块得到变分量子线路演化和梯度求解的算子。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {
    "tags": []
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Measurement result:  [[0.29552022+0.j]]\n",
      "Gradient of encoder parameters:  [[[0.+0.j 0.+0.j 0.+0.j]]]\n",
      "Gradient of ansatz parameters:  [[[-0.37202556+0.j  0.87992317+0.j]]]\n"
     ]
    }
   ],
   "source": [
    "# 导入Simulator模块\n",
    "from mindquantum.simulator import Simulator\n",
    "\n",
    "# 生成一个基于mqvector后端的模拟器,并设置模拟器的比特数为量子线路的比特数。\n",
    "sim = Simulator('mqvector', circuit.n_qubits)\n",
    "\n",
    "# 获取模拟器基于当前量子态的量子线路演化以及期望、梯度求解算子\n",
    "grad_ops = sim.get_expectation_with_grad(ham,\n",
    "                                         circuit)\n",
    "\n",
    "# Encoder中的alpha0, alpha1, alpha2这三个参数组成的数组,\n",
    "# 将其数据类型转换为float32,并储存在encoder_data中。\n",
    "# MindSpore Quantum支持多样本的batch训练,Encoder数组是两个维度,\n",
    "# 第一个维度为样本,第二个维度为特征(即参数)\n",
    "encoder_data = np.array([[alpha0, alpha1, alpha2]]).astype(np.float32)\n",
    "\n",
    "# Ansatz中的theta0, theta1这两个参数组成的数组,将其数据类型转换为float32,\n",
    "# 并储存在ansatzr_data中,Ansatz数据只有一个维度,特征(即参数)\n",
    "ansatz_data = np.array([theta0, theta1]).astype(np.float32)\n",
    "\n",
    "# 根据Encoder和Ansatz的数据,输出变分量子线路的测量值,Encoder中的参数的导数和Ansatz中的参数的导数\n",
    "measure_result, encoder_grad, ansatz_grad = grad_ops(encoder_data, ansatz_data)\n",
    "\n",
    "print('Measurement result: ', measure_result)\n",
    "print('Gradient of encoder parameters: ', encoder_grad)\n",
    "print('Gradient of ansatz parameters: ', ansatz_grad)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "从上述打印可以看到,测量结果(期望值)为0.29552022,Encoder中的3个参数的导数为0,0,0(因为我们对Encoder设置了no_grad()),Ansatz中的2个参数的导数为-0.37202555,-0.87992316。\n",
    "\n",
    "这里通过 [get_expectation_with_grad](https://www.mindspore.cn/mindquantum/docs/zh-CN/r0.10/simulator/mindquantum.simulator.Simulator.html#mindquantum.simulator.Simulator.get_expectation_with_grad) 产生的只是一个算子,还不能进行训练,要把它放到量子神经网络里面才能进行训练。通过训练Ansatz中的参数,可以使得Ansatz中的参数的导数一直下降并接近于0,那么测量值也就会接近于-1。\n",
    "\n",
    "说明:\n",
    "\n",
    "(1)[Simulator](https://www.mindspore.cn/mindquantum/docs/zh-CN/r0.10/simulator/mindquantum.simulator.Simulator.html) 的 [get_expectation_with_grad](https://www.mindspore.cn/mindquantum/docs/zh-CN/r0.10/simulator/mindquantum.simulator.Simulator.html#mindquantum.simulator.Simulator.get_expectation_with_grad) 用于生成变分量子线路来模拟算子,一般格式如下:\n",
    "\n",
    "```python\n",
    "\n",
    "Simulator.get_expectation_with_grad(ham,\n",
    "                                    circ_right,\n",
    "                                    circ_left,\n",
    "                                    simulator_left,\n",
    "                                    parallel_worker=1)\n",
    "\n",
    "```\n",
    "\n",
    "此函数适用于计算如下模型:\n",
    "\n",
    "$$E=\\left<\\varphi\\right|U^\\dagger_l(\\theta) H U_r(\\theta)\\left|\\psi\\right>$$\n",
    "\n",
    "其中`circ_right`是$U_r$,`circ_left`是$U_l$,当不提供时,默认跟`circ_right`是相同的线路,$\\left|\\psi\\right>$是当前模拟器的量子态,$\\left|\\varphi\\right>$是 `simulator_left` 中的量子态。 `parallel_worker`指定并行数,当需要编码的经典数据是一个batch时,合理设置此参数可以提高计算效率。\n",
    "\n",
    "(2)MindSpore是一个全场景深度学习框架,旨在实现易开发、高效执行、全场景统一部署三大目标,提供支持异构加速的张量可微编程能力,支持云、服务器、边和端多种硬件平台。\n",
    "\n",
    "## 搭建量子神经网络"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "MQLayer<\n",
       "  (evolution): MQOps<1 qubit mqvector VQA Operator>\n",
       "  >"
      ]
     },
     "execution_count": 10,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# pylint: disable=W0104\n",
    "from mindquantum.framework import MQLayer          # 导入MQLayer\n",
    "import mindspore as ms                             # 导入mindspore\n",
    "\n",
    "ms.set_seed(1)                                     # 设置生成随机数的种子\n",
    "ms.set_context(mode=ms.PYNATIVE_MODE, device_target=\"CPU\")\n",
    "\n",
    "QuantumNet = MQLayer(grad_ops)\n",
    "QuantumNet"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "上述打印可以看到,我们已经成功搭建了量子机器学习层,其可以无缝地跟MindSpore中其他的算子构成一张更大的机器学习网络。\n",
    "\n",
    "说明:\n",
    "\n",
    "(1)MindSpore Quantum中的量子线路梯度计算算子都是在`PYNATIVE_MODE`下的,因此需要设置MindSpore的运行模式。\n",
    "\n",
    "(2)我们也可以通过如下代码方式搭建量子机器学习层,只是在MindSpore Quantum中,已经将下述过程封装打包,这样我们就可以直接利用 [MQLayer](https://www.mindspore.cn/mindquantum/docs/zh-CN/r0.10/framework/layer/mindquantum.framework.MQLayer.html) 模块搭建量子机器学习层。对于更复杂的量子-经典混合神经网络,如下搭建方式会展示它的优势。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "```python\n",
    "from mindspore import nn\n",
    "\n",
    "class MQLayer(nn.Cell):\n",
    "    def __init__(self, expectation_with_grad, weight='normal'):\n",
    "        super(MQLayer, self).__init__()\n",
    "        self.evolution = MQOps(expectation_with_grad)\n",
    "        weight_size = len(\n",
    "            self.evolution.expectation_with_grad.ansatz_params_name)\n",
    "        self.weight = Parameter(initializer(weight,\n",
    "                                            weight_size,\n",
    "                                            dtype=ms.float32),\n",
    "                                name='ansatz_weight')\n",
    "\n",
    "    def construct(self, x):\n",
    "        return self.evolution(x, self.weight)\n",
    "\n",
    "```"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 训练\n",
    "\n",
    "我们采用 [Adam](https://www.mindspore.cn/docs/zh-CN/r2.5.0/api_python/nn/mindspore.nn.Adam.html#mindspore.nn.Adam) 优化器优化Ansatz中的参数。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {
    "tags": []
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "0 :  [[0.30633032]]\n",
      "10 :  [[-0.87929225]]\n",
      "20 :  [[-0.9726834]]\n",
      "30 :  [[-0.9935059]]\n",
      "40 :  [[-0.9934296]]\n",
      "50 :  [[-0.996459]]\n",
      "60 :  [[-0.99859095]]\n",
      "70 :  [[-0.9995031]]\n",
      "80 :  [[-0.9998626]]\n",
      "90 :  [[-0.9999718]]\n",
      "100 :  [[-0.9999983]]\n",
      "110 :  [[-0.9999993]]\n",
      "120 :  [[-0.99999785]]\n",
      "130 :  [[-0.9999986]]\n",
      "140 :  [[-0.9999997]]\n",
      "150 :  [[-1.]]\n",
      "160 :  [[-0.99999994]]\n",
      "170 :  [[-1.]]\n",
      "180 :  [[-1.]]\n",
      "190 :  [[-1.]]\n"
     ]
    }
   ],
   "source": [
    "from mindspore.nn import Adam, TrainOneStepCell                   # 导入Adam模块和TrainOneStepCell模块\n",
    "\n",
    "opti = Adam(QuantumNet.trainable_params(), learning_rate=0.5)     # 需要优化的是Quantumnet中可训练的参数,学习率设为0.5\n",
    "net = TrainOneStepCell(QuantumNet, opti)\n",
    "\n",
    "for i in range(200):\n",
    "    res = net(ms.Tensor(encoder_data))\n",
    "    if i % 10 == 0:\n",
    "        print(i, ': ', res)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "从上述打印可以看到,最后测量值收敛于-1。\n",
    "\n",
    "说明:\n",
    "\n",
    "(1)[Adam](https://www.mindspore.cn/docs/zh-CN/r2.5.0/api_python/nn/mindspore.nn.Adam.html#mindspore.nn.Adam) 模块通过自适应矩估计算法更新梯度,可以优化Ansazt中的参数,输入的是神经网络中可训练的参数;一般格式如下:nn.Adam(net.trainable_params(), learning_rate=0.5);\n",
    "\n",
    "(2)[TrainOneStepCell](https://www.mindspore.cn/docs/zh-CN/r2.5.0/api_python/nn/mindspore.nn.TrainOneStepCell.html#mindspore.nn.TrainOneStepCell) 模块为网络训练包类,用优化器包装网络。生成的单元格使用输入“inputs”进行训练,将在构造函数中创建反向图,以更新参数,有不同的并行模式可用于训练。一般格式如下:`nn.TrainOneStepCell(network, optimizer, sens=1.0)`。\n",
    "\n",
    "## 结果呈现\n",
    "\n",
    "由于测量值已经收敛于-1,所以我们可以打印此时Ansatz中的参数。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {
    "tags": []
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[ 2.241999  -1.0756955]\n"
     ]
    }
   ],
   "source": [
    "theta0, theta1 = QuantumNet.weight.asnumpy()\n",
    "\n",
    "print(QuantumNet.weight.asnumpy())"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "从上述打印可以看到,此时Ansatz中的参数$\\theta_1, \\theta_2$分别为2.2420275和-1.0756909。\n",
    "\n",
    "通过 [get_qs](https://www.mindspore.cn/mindquantum/docs/zh-CN/r0.10/core/circuit/mindquantum.core.circuit.Circuit.html#mindquantum.core.circuit.Circuit.get_qs),可以输出量子线路在最优参数时的量子态。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {
    "tags": []
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "(0.371309288022958-0.9285092418490042j)¦0⟩\n",
      "(2.0012262153618066e-05+5.327365456997413e-06j)¦1⟩\n"
     ]
    }
   ],
   "source": [
    "pr = {'alpha0': alpha0, 'alpha1': alpha1, 'alpha2': alpha2, 'theta0': theta0, 'theta1': theta1}\n",
    "state = circuit.get_qs(pr=pr, ket=True)\n",
    "\n",
    "print(state)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "从上述打印可以看到,这就是量子线路在最优参数时的量子态。从其数值表示可以看到,这是一个接近于目标态$|0\\rangle$​​​的态。最后,我们计算一下此量子态与目标态$|0\\rangle$​​​​​的保真度(用于验证两个量子态的相似程度),并将保真度打印。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "metadata": {
    "tags": []
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "0.9999999995711284\n"
     ]
    }
   ],
   "source": [
    "state = circuit.get_qs(pr=pr)\n",
    "fid = np.abs(np.vdot(state, [1, 0]))**2            # 保真度fidelity为向量内积的绝对值的模平方,即计算此时量子态对应的向量与|0>态对应的向量[1,0]的内积的模平方\n",
    "\n",
    "print(fid)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "可以看到,此时的保真度为100.00%,也就是说,该状态与目标态$|0\\rangle$​​的相似程度为100.00%。\n",
    "\n",
    "综上所述,我们搭建了一个简单的量子神经网络,通过训练Ansatz中的参数,抵消了Encoder对初始量子态产生的误差,使得最后的量子态仍为$|0\\rangle$​,且保真度达到100.00%。\n",
    "\n",
    "至此,我们通过MindSpore Quantum完成了对量子神经网络的初体验!赶紧动手体验一下量子编程的乐趣吧!"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "\n",
       "<table border=\"1\">\n",
       "  <tr>\n",
       "    <th>Software</th>\n",
       "    <th>Version</th>\n",
       "  </tr>\n",
       "<tr><td>mindquantum</td><td>0.9.11</td></tr>\n",
       "<tr><td>scipy</td><td>1.10.1</td></tr>\n",
       "<tr><td>numpy</td><td>1.23.5</td></tr>\n",
       "<tr>\n",
       "    <th>System</th>\n",
       "    <th>Info</th>\n",
       "</tr>\n",
       "<tr><td>Python</td><td>3.9.16</td></tr><tr><td>OS</td><td>Linux x86_64</td></tr><tr><td>Memory</td><td>8.3 GB</td></tr><tr><td>CPU Max Thread</td><td>8</td></tr><tr><td>Date</td><td>Sun Dec 31 21:28:06 2023</td></tr>\n",
       "</table>\n"
      ],
      "text/plain": [
       "<mindquantum.utils.show_info.InfoTable at 0x7f1ff025f490>"
      ]
     },
     "execution_count": 15,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "from mindquantum.utils.show_info import InfoTable\n",
    "\n",
    "InfoTable('mindquantum', 'scipy', 'numpy')"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "base",
   "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.9.16"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}