{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "be565231",
   "metadata": {},
   "source": [
    "# 电路基础"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "fcdfed33",
   "metadata": {},
   "source": [
    "## 概述\n",
    "\n",
    "在这篇笔记中,我们将了解 TensorCircuit 中核心对象的基本操作-``tc.Circuit``,它支持无噪声仿真和基于蒙特卡洛轨迹的噪声仿真。更重要的是,几乎所有对 Circuit 对象的操作都是可微分的和可即时编译的,这是成功高效地进行变分量子算法模拟的关键。\n",
    "[WIP note]"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "c51c024b",
   "metadata": {},
   "source": [
    "## 设置"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "id": "98f21e9b",
   "metadata": {},
   "outputs": [],
   "source": [
    "from functools import partial\n",
    "import inspect\n",
    "import sys\n",
    "import numpy as np\n",
    "import tensorflow as tf\n",
    "\n",
    "import tensorcircuit as tc"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "558cdc17",
   "metadata": {},
   "source": [
    "## “Hello World\" 样例"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "id": "b83f24f4",
   "metadata": {},
   "outputs": [],
   "source": [
    "def get_circuit(n):\n",
    "    c = tc.Circuit(n)  # 用 n 个量子比特初始化一个电路对象\n",
    "    for i in range(n):\n",
    "        c.H(i)  # 在每个量子比特上使用 Hadamard 门\n",
    "    c.cnot(0, 1)  # 在第 0 个量子比特上应用带有控制量子比特的 cnot 门\n",
    "    c.CNOT(n - 1, n - 2)  # 大写的 API 也可以正常使用\n",
    "    return c"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "id": "601a072c",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "['i', 'x', 'y', 'z', 'h', 't', 's', 'td', 'sd', 'wroot', 'cnot', 'cz', 'swap', 'cy', 'iswap', 'ox', 'oy', 'oz', 'toffoli', 'fredkin']\n"
     ]
    }
   ],
   "source": [
    "# 打印不含参数的有可能的门\n",
    "print(tc.Circuit.sgates)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "id": "c191ea53",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "i\n",
      "[[1.+0.j 0.+0.j]\n",
      " [0.+0.j 1.+0.j]]\n",
      "x\n",
      "[[0.+0.j 1.+0.j]\n",
      " [1.+0.j 0.+0.j]]\n",
      "y\n",
      "[[0.+0.j 0.-1.j]\n",
      " [0.+1.j 0.+0.j]]\n",
      "z\n",
      "[[ 1.+0.j  0.+0.j]\n",
      " [ 0.+0.j -1.+0.j]]\n",
      "h\n",
      "[[ 0.70710677+0.j  0.70710677+0.j]\n",
      " [ 0.70710677+0.j -0.70710677+0.j]]\n",
      "t\n",
      "[[1.        +0.j         0.        +0.j        ]\n",
      " [0.        +0.j         0.70710677+0.70710677j]]\n",
      "s\n",
      "[[1.+0.j 0.+0.j]\n",
      " [0.+0.j 0.+1.j]]\n",
      "td\n",
      "[[1.        +0.j         0.        +0.j        ]\n",
      " [0.        +0.j         0.70710677-0.70710677j]]\n",
      "sd\n",
      "[[1.+0.j 0.+0.j]\n",
      " [0.+0.j 0.-1.j]]\n",
      "wroot\n",
      "[[ 0.70710677+0.j  -0.5       -0.5j]\n",
      " [ 0.5       -0.5j  0.70710677+0.j ]]\n",
      "cnot\n",
      "[[1.+0.j 0.+0.j 0.+0.j 0.+0.j]\n",
      " [0.+0.j 1.+0.j 0.+0.j 0.+0.j]\n",
      " [0.+0.j 0.+0.j 0.+0.j 1.+0.j]\n",
      " [0.+0.j 0.+0.j 1.+0.j 0.+0.j]]\n",
      "cz\n",
      "[[ 1.+0.j  0.+0.j  0.+0.j  0.+0.j]\n",
      " [ 0.+0.j  1.+0.j  0.+0.j  0.+0.j]\n",
      " [ 0.+0.j  0.+0.j  1.+0.j  0.+0.j]\n",
      " [ 0.+0.j  0.+0.j  0.+0.j -1.+0.j]]\n",
      "swap\n",
      "[[1.+0.j 0.+0.j 0.+0.j 0.+0.j]\n",
      " [0.+0.j 0.+0.j 1.+0.j 0.+0.j]\n",
      " [0.+0.j 1.+0.j 0.+0.j 0.+0.j]\n",
      " [0.+0.j 0.+0.j 0.+0.j 1.+0.j]]\n",
      "cy\n",
      "[[1.+0.j 0.+0.j 0.+0.j 0.+0.j]\n",
      " [0.+0.j 1.+0.j 0.+0.j 0.+0.j]\n",
      " [0.+0.j 0.+0.j 0.+0.j 0.-1.j]\n",
      " [0.+0.j 0.+0.j 0.+1.j 0.+0.j]]\n",
      "iswap\n",
      "[[1.+0.j 0.+0.j 0.+0.j 0.+0.j]\n",
      " [0.+0.j 0.+0.j 0.+1.j 0.+0.j]\n",
      " [0.+0.j 0.+1.j 0.+0.j 0.+0.j]\n",
      " [0.+0.j 0.+0.j 0.+0.j 1.+0.j]]\n",
      "ox\n",
      "[[0.+0.j 1.+0.j 0.+0.j 0.+0.j]\n",
      " [1.+0.j 0.+0.j 0.+0.j 0.+0.j]\n",
      " [0.+0.j 0.+0.j 1.+0.j 0.+0.j]\n",
      " [0.+0.j 0.+0.j 0.+0.j 1.+0.j]]\n",
      "oy\n",
      "[[0.+0.j 0.-1.j 0.+0.j 0.+0.j]\n",
      " [0.+1.j 0.+0.j 0.+0.j 0.+0.j]\n",
      " [0.+0.j 0.+0.j 1.+0.j 0.+0.j]\n",
      " [0.+0.j 0.+0.j 0.+0.j 1.+0.j]]\n",
      "oz\n",
      "[[ 1.+0.j  0.+0.j  0.+0.j  0.+0.j]\n",
      " [ 0.+0.j -1.+0.j  0.+0.j  0.+0.j]\n",
      " [ 0.+0.j  0.+0.j  1.+0.j  0.+0.j]\n",
      " [ 0.+0.j  0.+0.j  0.+0.j  1.+0.j]]\n",
      "toffoli\n",
      "[[1.+0.j 0.+0.j 0.+0.j 0.+0.j 0.+0.j 0.+0.j 0.+0.j 0.+0.j]\n",
      " [0.+0.j 1.+0.j 0.+0.j 0.+0.j 0.+0.j 0.+0.j 0.+0.j 0.+0.j]\n",
      " [0.+0.j 0.+0.j 1.+0.j 0.+0.j 0.+0.j 0.+0.j 0.+0.j 0.+0.j]\n",
      " [0.+0.j 0.+0.j 0.+0.j 1.+0.j 0.+0.j 0.+0.j 0.+0.j 0.+0.j]\n",
      " [0.+0.j 0.+0.j 0.+0.j 0.+0.j 1.+0.j 0.+0.j 0.+0.j 0.+0.j]\n",
      " [0.+0.j 0.+0.j 0.+0.j 0.+0.j 0.+0.j 1.+0.j 0.+0.j 0.+0.j]\n",
      " [0.+0.j 0.+0.j 0.+0.j 0.+0.j 0.+0.j 0.+0.j 0.+0.j 1.+0.j]\n",
      " [0.+0.j 0.+0.j 0.+0.j 0.+0.j 0.+0.j 0.+0.j 1.+0.j 0.+0.j]]\n",
      "fredkin\n",
      "[[1.+0.j 0.+0.j 0.+0.j 0.+0.j 0.+0.j 0.+0.j 0.+0.j 0.+0.j]\n",
      " [0.+0.j 1.+0.j 0.+0.j 0.+0.j 0.+0.j 0.+0.j 0.+0.j 0.+0.j]\n",
      " [0.+0.j 0.+0.j 1.+0.j 0.+0.j 0.+0.j 0.+0.j 0.+0.j 0.+0.j]\n",
      " [0.+0.j 0.+0.j 0.+0.j 1.+0.j 0.+0.j 0.+0.j 0.+0.j 0.+0.j]\n",
      " [0.+0.j 0.+0.j 0.+0.j 0.+0.j 1.+0.j 0.+0.j 0.+0.j 0.+0.j]\n",
      " [0.+0.j 0.+0.j 0.+0.j 0.+0.j 0.+0.j 0.+0.j 1.+0.j 0.+0.j]\n",
      " [0.+0.j 0.+0.j 0.+0.j 0.+0.j 0.+0.j 1.+0.j 0.+0.j 0.+0.j]\n",
      " [0.+0.j 0.+0.j 0.+0.j 0.+0.j 0.+0.j 0.+0.j 0.+0.j 1.+0.j]]\n"
     ]
    }
   ],
   "source": [
    "# 这些门定义的相应矩阵\n",
    "for g in tc.Circuit.sgates:\n",
    "    gf = getattr(tc.gates, g)\n",
    "    print(g)\n",
    "    print(tc.gates.matrix_for_gate(gf()))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "id": "96c15225",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "[{'gatef': h,\n",
       "  'gate': Gate(\n",
       "      name: 'h',\n",
       "      tensor:\n",
       "          array([[ 0.70710677+0.j,  0.70710677+0.j],\n",
       "                 [ 0.70710677+0.j, -0.70710677+0.j]], dtype=complex64),\n",
       "      edges: [\n",
       "          Edge('cnot'[2] -> 'h'[0] ),\n",
       "          Edge('h'[1] -> 'qb-1'[0] )\n",
       "      ]),\n",
       "  'index': (0,),\n",
       "  'name': 'h',\n",
       "  'split': None,\n",
       "  'mpo': False},\n",
       " {'gatef': h,\n",
       "  'gate': Gate(\n",
       "      name: 'h',\n",
       "      tensor:\n",
       "          array([[ 0.70710677+0.j,  0.70710677+0.j],\n",
       "                 [ 0.70710677+0.j, -0.70710677+0.j]], dtype=complex64),\n",
       "      edges: [\n",
       "          Edge('cnot'[3] -> 'h'[0] ),\n",
       "          Edge('h'[1] -> 'qb-2'[0] )\n",
       "      ]),\n",
       "  'index': (1,),\n",
       "  'name': 'h',\n",
       "  'split': None,\n",
       "  'mpo': False},\n",
       " {'gatef': h,\n",
       "  'gate': Gate(\n",
       "      name: 'h',\n",
       "      tensor:\n",
       "          array([[ 0.70710677+0.j,  0.70710677+0.j],\n",
       "                 [ 0.70710677+0.j, -0.70710677+0.j]], dtype=complex64),\n",
       "      edges: [\n",
       "          Edge('cnot'[2] -> 'h'[0] ),\n",
       "          Edge('h'[1] -> 'qb-3'[0] )\n",
       "      ]),\n",
       "  'index': (2,),\n",
       "  'name': 'h',\n",
       "  'split': None,\n",
       "  'mpo': False},\n",
       " {'gatef': cnot,\n",
       "  'gate': Gate(\n",
       "      name: 'cnot',\n",
       "      tensor:\n",
       "          array([[[[1.+0.j, 0.+0.j],\n",
       "                   [0.+0.j, 0.+0.j]],\n",
       "          \n",
       "                  [[0.+0.j, 1.+0.j],\n",
       "                   [0.+0.j, 0.+0.j]]],\n",
       "          \n",
       "          \n",
       "                 [[[0.+0.j, 0.+0.j],\n",
       "                   [0.+0.j, 1.+0.j]],\n",
       "          \n",
       "                  [[0.+0.j, 0.+0.j],\n",
       "                   [1.+0.j, 0.+0.j]]]], dtype=complex64),\n",
       "      edges: [\n",
       "          Edge(Dangling Edge)[0],\n",
       "          Edge('cnot'[3] -> 'cnot'[1] ),\n",
       "          Edge('cnot'[2] -> 'h'[0] ),\n",
       "          Edge('cnot'[3] -> 'h'[0] )\n",
       "      ]),\n",
       "  'index': (0, 1),\n",
       "  'name': 'cnot',\n",
       "  'split': None,\n",
       "  'mpo': False},\n",
       " {'gatef': cnot,\n",
       "  'gate': Gate(\n",
       "      name: 'cnot',\n",
       "      tensor:\n",
       "          array([[[[1.+0.j, 0.+0.j],\n",
       "                   [0.+0.j, 0.+0.j]],\n",
       "          \n",
       "                  [[0.+0.j, 1.+0.j],\n",
       "                   [0.+0.j, 0.+0.j]]],\n",
       "          \n",
       "          \n",
       "                 [[[0.+0.j, 0.+0.j],\n",
       "                   [0.+0.j, 1.+0.j]],\n",
       "          \n",
       "                  [[0.+0.j, 0.+0.j],\n",
       "                   [1.+0.j, 0.+0.j]]]], dtype=complex64),\n",
       "      edges: [\n",
       "          Edge(Dangling Edge)[0],\n",
       "          Edge(Dangling Edge)[1],\n",
       "          Edge('cnot'[2] -> 'h'[0] ),\n",
       "          Edge('cnot'[3] -> 'cnot'[1] )\n",
       "      ]),\n",
       "  'index': (2, 1),\n",
       "  'name': 'cnot',\n",
       "  'split': None,\n",
       "  'mpo': False}]"
      ]
     },
     "execution_count": 5,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "c = get_circuit(3)\n",
    "ir = c.to_qir()  # 电路的中间表示\n",
    "ir"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "id": "9ab7fd6e",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(array([[ 0.70710677+0.j,  0.70710677+0.j],\n",
       "        [ 0.70710677+0.j, -0.70710677+0.j]], dtype=complex64),\n",
       " array([[[[1.+0.j, 0.+0.j],\n",
       "          [0.+0.j, 0.+0.j]],\n",
       " \n",
       "         [[0.+0.j, 1.+0.j],\n",
       "          [0.+0.j, 0.+0.j]]],\n",
       " \n",
       " \n",
       "        [[[0.+0.j, 0.+0.j],\n",
       "          [0.+0.j, 1.+0.j]],\n",
       " \n",
       "         [[0.+0.j, 0.+0.j],\n",
       "          [1.+0.j, 0.+0.j]]]], dtype=complex64))"
      ]
     },
     "execution_count": 6,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "ir[0][\"gatef\"]().tensor, ir[-1][\"gate\"].tensor  # 每个门的实际幺正矩阵"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "id": "ecdc0f1a",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([0.35355335+0.j, 0.35355335+0.j, 0.35355335+0.j, 0.35355335+0.j,\n",
       "       0.35355335+0.j, 0.35355335+0.j, 0.35355335+0.j, 0.35355335+0.j],\n",
       "      dtype=complex64)"
      ]
     },
     "execution_count": 7,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# 计算电路的最终输出量子态\n",
    "c.state()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "id": "64fa321b",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "(0.9999998+0j) 0j\n"
     ]
    }
   ],
   "source": [
    "# 计算一些期望值,比如 <X1>\n",
    "x1 = c.expectation([tc.gates.x(), [1]])\n",
    "\n",
    "# 或 <Z1Z2>\n",
    "z1z2 = c.expectation([tc.gates.z(), [1]], [tc.gates.z(), [2]])\n",
    "\n",
    "print(x1, z1z2)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "id": "c8292569",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "(array([1., 1., 1.], dtype=float32), 0.1250001713634208)\n",
      "(array([0., 0., 1.], dtype=float32), 0.12499997764825821)\n",
      "(array([0., 1., 1.], dtype=float32), 0.12499997764825821)\n",
      "(array([1., 1., 0.], dtype=float32), 0.1249999776482098)\n",
      "(array([1., 1., 0.], dtype=float32), 0.1249999776482098)\n",
      "(array([1., 0., 1.], dtype=float32), 0.12499997019766829)\n",
      "(array([0., 1., 0.], dtype=float32), 0.12499997764825821)\n",
      "(array([1., 1., 0.], dtype=float32), 0.1249999776482098)\n",
      "(array([0., 0., 0.], dtype=float32), 0.12499997764825821)\n",
      "(array([0., 1., 1.], dtype=float32), 0.12499997764825821)\n"
     ]
    }
   ],
   "source": [
    "# 做一些随机取样\n",
    "for _ in range(10):\n",
    "    print(c.perfect_sampling())"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "id": "c2c0bb84",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "tf.Tensor(\n",
      "[0.35355335+0.j 0.35355335+0.j 0.35355335+0.j 0.35355335+0.j\n",
      " 0.35355335+0.j 0.35355335+0.j 0.35355335+0.j 0.35355335+0.j], shape=(8,), dtype=complex64)\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "WARNING:absl:No GPU/TPU found, falling back to CPU. (Set TF_CPP_MIN_LOG_LEVEL=0 and rerun for more info.)\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[0.35355335+0.j 0.35355335+0.j 0.35355335+0.j 0.35355335+0.j\n",
      " 0.35355335+0.j 0.35355335+0.j 0.35355335+0.j 0.35355335+0.j]\n",
      "tensor([0.3536+0.j, 0.3536+0.j, 0.3536+0.j, 0.3536+0.j, 0.3536+0.j, 0.3536+0.j, 0.3536+0.j,\n",
      "        0.3536+0.j])\n"
     ]
    }
   ],
   "source": [
    "# 我们可以轻松地从 NumPy 切换模拟后端!\n",
    "\n",
    "with tc.runtime_backend(\"tensorflow\") as K:\n",
    "    c = get_circuit(3)\n",
    "    print(c.state())\n",
    "\n",
    "with tc.runtime_backend(\"jax\") as K:\n",
    "    c = get_circuit(3)\n",
    "    print(c.state())\n",
    "\n",
    "with tc.runtime_backend(\"pytorch\") as K:\n",
    "    # pytorch 后端无法保证最佳性能和完整功能\n",
    "    c = get_circuit(3)\n",
    "    print(c.state())"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "0cbe17e7",
   "metadata": {},
   "source": [
    "## 参数化量子电路(PQC)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "id": "66192a2d",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "['r', 'cr', 'rx', 'ry', 'rz', 'crx', 'cry', 'crz', 'orx', 'ory', 'orz', 'any', 'exp', 'exp1']\n"
     ]
    }
   ],
   "source": [
    "# 接受参数的量子电路门\n",
    "\n",
    "print(tc.Circuit.vgates)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "id": "bae96276",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "r (theta: float = 0, alpha: float = 0, phi: float = 0) -> tensorcircuit.gates.Gate\n",
      "cr (theta: float = 0, alpha: float = 0, phi: float = 0) -> tensorcircuit.gates.Gate\n",
      "rx (theta: float = 0) -> tensorcircuit.gates.Gate\n",
      "ry (theta: float = 0) -> tensorcircuit.gates.Gate\n",
      "rz (theta: float = 0) -> tensorcircuit.gates.Gate\n",
      "crx (*args: Any, **kws: Any) -> Any\n",
      "cry (*args: Any, **kws: Any) -> Any\n",
      "crz (*args: Any, **kws: Any) -> Any\n",
      "orx (*args: Any, **kws: Any) -> Any\n",
      "ory (*args: Any, **kws: Any) -> Any\n",
      "orz (*args: Any, **kws: Any) -> Any\n",
      "any (unitary: Any, name: str = 'any') -> tensorcircuit.gates.Gate\n",
      "exp (unitary: Any, theta: float, name: str = 'none') -> tensorcircuit.gates.Gate\n",
      "exp1 (unitary: Any, theta: float, name: str = 'none') -> tensorcircuit.gates.Gate\n"
     ]
    }
   ],
   "source": [
    "# 查看每种类型的变量门的关键字参数(类型为浮点数)\n",
    "for g in tc.Circuit.vgates:\n",
    "    print(g, inspect.signature(getattr(tc.gates, g).f))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "id": "55df5ffa",
   "metadata": {},
   "outputs": [],
   "source": [
    "def get_circuit(n, params):\n",
    "    c = tc.Circuit(n)  # 用 n 个量子比特初始化一个电路对象\n",
    "    for i in range(n):\n",
    "        c.rx(i, theta=params[i])  # 应用 rx 门\n",
    "    c.cnot(0, 1)\n",
    "    return c"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "id": "84392f01",
   "metadata": {},
   "outputs": [],
   "source": [
    "K = tc.set_backend(\"tensorflow\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "id": "24ba6d64",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "tf.Tensor(\n",
      "[ 0.6758712 +0.j          0.        -0.36923012j  0.        -0.36923015j\n",
      " -0.20171136-0.j         -0.20171136+0.j          0.        +0.11019541j\n",
      "  0.        -0.36923015j -0.20171136-0.j        ], shape=(8,), dtype=complex64)\n"
     ]
    }
   ],
   "source": [
    "n = 3\n",
    "params = K.ones([n])\n",
    "c = get_circuit(n, params)\n",
    "print(c.state())"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "id": "c85cb07f",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "[{'gatef': rx,\n",
       "  'index': (0,),\n",
       "  'name': 'rx',\n",
       "  'split': None,\n",
       "  'mpo': False,\n",
       "  'parameters': {'theta': <tf.Tensor: shape=(), dtype=complex64, numpy=(1+0j)>},\n",
       "  'gate': Gate(\n",
       "      name: '__unnamed_node__',\n",
       "      tensor:\n",
       "          <tf.Tensor: shape=(2, 2), dtype=complex64, numpy=\n",
       "          array([[0.87758255+0.j        , 0.        -0.47942555j],\n",
       "                 [0.        -0.47942555j, 0.87758255+0.j        ]], dtype=complex64)>,\n",
       "      edges: [\n",
       "          Edge('cnot'[2] -> '__unnamed_node__'[0] ),\n",
       "          Edge('__unnamed_node__'[1] -> 'qb-1'[0] )\n",
       "      ])},\n",
       " {'gatef': rx,\n",
       "  'index': (1,),\n",
       "  'name': 'rx',\n",
       "  'split': None,\n",
       "  'mpo': False,\n",
       "  'parameters': {'theta': <tf.Tensor: shape=(), dtype=complex64, numpy=(1+0j)>},\n",
       "  'gate': Gate(\n",
       "      name: '__unnamed_node__',\n",
       "      tensor:\n",
       "          <tf.Tensor: shape=(2, 2), dtype=complex64, numpy=\n",
       "          array([[0.87758255+0.j        , 0.        -0.47942555j],\n",
       "                 [0.        -0.47942555j, 0.87758255+0.j        ]], dtype=complex64)>,\n",
       "      edges: [\n",
       "          Edge('cnot'[3] -> '__unnamed_node__'[0] ),\n",
       "          Edge('__unnamed_node__'[1] -> 'qb-2'[0] )\n",
       "      ])},\n",
       " {'gatef': rx,\n",
       "  'index': (2,),\n",
       "  'name': 'rx',\n",
       "  'split': None,\n",
       "  'mpo': False,\n",
       "  'parameters': {'theta': <tf.Tensor: shape=(), dtype=complex64, numpy=(1+0j)>},\n",
       "  'gate': Gate(\n",
       "      name: '__unnamed_node__',\n",
       "      tensor:\n",
       "          <tf.Tensor: shape=(2, 2), dtype=complex64, numpy=\n",
       "          array([[0.87758255+0.j        , 0.        -0.47942555j],\n",
       "                 [0.        -0.47942555j, 0.87758255+0.j        ]], dtype=complex64)>,\n",
       "      edges: [\n",
       "          Edge(Dangling Edge)[0],\n",
       "          Edge('__unnamed_node__'[1] -> 'qb-3'[0] )\n",
       "      ])},\n",
       " {'gatef': cnot,\n",
       "  'gate': Gate(\n",
       "      name: 'cnot',\n",
       "      tensor:\n",
       "          <tf.Tensor: shape=(2, 2, 2, 2), dtype=complex64, numpy=\n",
       "          array([[[[1.+0.j, 0.+0.j],\n",
       "                   [0.+0.j, 0.+0.j]],\n",
       "          \n",
       "                  [[0.+0.j, 1.+0.j],\n",
       "                   [0.+0.j, 0.+0.j]]],\n",
       "          \n",
       "          \n",
       "                 [[[0.+0.j, 0.+0.j],\n",
       "                   [0.+0.j, 1.+0.j]],\n",
       "          \n",
       "                  [[0.+0.j, 0.+0.j],\n",
       "                   [1.+0.j, 0.+0.j]]]], dtype=complex64)>,\n",
       "      edges: [\n",
       "          Edge(Dangling Edge)[0],\n",
       "          Edge(Dangling Edge)[1],\n",
       "          Edge('cnot'[2] -> '__unnamed_node__'[0] ),\n",
       "          Edge('cnot'[3] -> '__unnamed_node__'[0] )\n",
       "      ]),\n",
       "  'index': (0, 1),\n",
       "  'name': 'cnot',\n",
       "  'split': None,\n",
       "  'mpo': False}]"
      ]
     },
     "execution_count": 16,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "ir = c.to_qir()\n",
    "ir"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "id": "71ca41e2",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "<tf.Tensor: shape=(2, 2), dtype=complex64, numpy=\n",
       "array([[0.87758255+0.j        , 0.        -0.47942555j],\n",
       "       [0.        -0.47942555j, 0.87758255+0.j        ]], dtype=complex64)>"
      ]
     },
     "execution_count": 17,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# 查看量子门对应的矩阵\n",
    "ir[0][\"gatef\"](**ir[0][\"parameters\"]).tensor"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "id": "eb13a4ef",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "(<tf.Tensor: shape=(), dtype=float32, numpy=0.2919265>, <tf.Tensor: shape=(3,), dtype=complex64, numpy=\n",
      "array([-4.5464873e-01+0.j, -4.5464873e-01+0.j,  2.2351742e-08+0.j],\n",
      "      dtype=complex64)>)\n"
     ]
    }
   ],
   "source": [
    "# 让我们组成一个可微分的量子函数\n",
    "\n",
    "\n",
    "def energy(params):\n",
    "    c = get_circuit(n, params)\n",
    "    return K.real(c.expectation([tc.gates.z(), [1]]))\n",
    "\n",
    "\n",
    "energy_vag = K.value_and_grad(energy)\n",
    "\n",
    "print(energy_vag(params))\n",
    "\n",
    "# 一旦我们有了梯度,我们就可以运行基于梯度的下降的变分优化"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "id": "1a82a3a1",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "(<tf.Tensor: shape=(), dtype=float32, numpy=0.2919265>, <tf.Tensor: shape=(3,), dtype=complex64, numpy=\n",
      "array([-4.5464873e-01+0.j, -4.5464873e-01+0.j,  2.2351742e-08+0.j],\n",
      "      dtype=complex64)>)\n"
     ]
    }
   ],
   "source": [
    "# 并且使其可即时编译以加速\n",
    "\n",
    "energy_vag_jit = K.jit(K.value_and_grad(energy))\n",
    "\n",
    "print(energy_vag_jit(params))\n",
    "# 第一次运行可即时编译的函数会很慢,但是后面的测量会超级快"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "36c710ef",
   "metadata": {},
   "source": [
    "## 电路的高级用法"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "d4e55e05",
   "metadata": {},
   "source": [
    "### 输入状态\n",
    "\n",
    "我们可以从默认的 |0^n> 替换输入状态"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 20,
   "id": "49865f13",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "<tf.Tensor: shape=(8,), dtype=complex64, numpy=\n",
       "array([0.49999997+0.j, 0.49999997+0.j, 0.49999997+0.j, 0.49999997+0.j,\n",
       "       0.        +0.j, 0.        +0.j, 0.        +0.j, 0.        +0.j],\n",
       "      dtype=complex64)>"
      ]
     },
     "execution_count": 20,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "input_state = K.ones([2**n])\n",
    "input_state /= K.norm(input_state)\n",
    "\n",
    "c = tc.Circuit(n, inputs=input_state)\n",
    "c.H(0)\n",
    "c.state()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "47f2a348",
   "metadata": {},
   "source": [
    "### 蒙特卡罗方法噪声模拟\n",
    "\n",
    "``tc.Circuit`` 支持使用蒙特卡罗方法进行噪声模拟,并且它也是可即时编译的! 此外,``tc.DMCircuit`` 支持使用全密度矩阵方法进行噪声模拟。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 21,
   "id": "e17b0b8b",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "tf.Tensor(0j, shape=(), dtype=complex64)\n"
     ]
    }
   ],
   "source": [
    "c = tc.Circuit(n)\n",
    "for i in range(n):\n",
    "    c.H(i)\n",
    "for i in range(n - 1):\n",
    "    c.cnot(i, i + 1)\n",
    "    c.depolarizing(i, px=0.1, py=0.1, pz=0.1)\n",
    "    c.apply_general_kraus(tc.channels.phasedampingchannel(gamma=0.2), i + 1)\n",
    "print(c.expectation([tc.gates.y(), [1]]))"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "ae498792",
   "metadata": {},
   "source": [
    "### 应用任意幺正门\n",
    "\n",
    "只需直接使用 ``any`` API 通过提供相应的幺正矩阵"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 22,
   "id": "1fed32f3",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "<tf.Tensor: shape=(8,), dtype=complex64, numpy=\n",
       "array([0.25+0.j, 0.  +0.j, 0.25+0.j, 0.  +0.j, 0.25+0.j, 0.  +0.j,\n",
       "       0.25+0.j, 0.  +0.j], dtype=complex64)>"
      ]
     },
     "execution_count": 22,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "c = tc.Circuit(n)\n",
    "c.any(0, 1, unitary=K.ones([4, 4]) / K.norm(K.ones([4, 4])))\n",
    "c.state()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "1d64546c",
   "metadata": {},
   "source": [
    "### 指数门\n",
    "\n",
    "如果我们想将门模拟为 $e^{i\\theta G}$ ,其中 $G^2=1$ 是一个矩阵,我们有一个快速有效的门实现,例如\n",
    "`exp1`"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 23,
   "id": "32f50d3a",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "<tf.Tensor: shape=(8,), dtype=complex64, numpy=\n",
       "array([-0.14713009-3.2148516e-01j,  0.35355335+1.4901161e-08j,\n",
       "       -0.14713009+3.2148516e-01j,  0.35355335-1.4901161e-08j,\n",
       "        0.35355335-1.4901161e-08j, -0.14713009+3.2148516e-01j,\n",
       "        0.35355335+1.4901161e-08j, -0.14713009-3.2148516e-01j],\n",
       "      dtype=complex64)>"
      ]
     },
     "execution_count": 23,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "c = tc.Circuit(n)\n",
    "for i in range(n):\n",
    "    c.H(i)\n",
    "for i in range(n - 1):\n",
    "    c.exp1(i, i + 1, theta=K.ones([]), unitary=tc.gates._zz_matrix)\n",
    "c.state()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "934c3885",
   "metadata": {},
   "source": [
    "在上面的例子中 $G=Z\\otimes Z$"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 24,
   "id": "409ed76b",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[[ 1.  0.  0.  0.]\n",
      " [ 0. -1.  0. -0.]\n",
      " [ 0.  0. -1. -0.]\n",
      " [ 0. -0. -0.  1.]]\n"
     ]
    }
   ],
   "source": [
    "print(tc.gates._zz_matrix)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "ce35316b",
   "metadata": {},
   "source": [
    "下面列出了门模块中的常用矩阵"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 25,
   "id": "f8c647b0",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "_cnot_matrix :\n",
      " [[1. 0. 0. 0.]\n",
      " [0. 1. 0. 0.]\n",
      " [0. 0. 0. 1.]\n",
      " [0. 0. 1. 0.]]\n",
      "_cy_matrix :\n",
      " [[ 1.+0.j  0.+0.j  0.+0.j  0.+0.j]\n",
      " [ 0.+0.j  1.+0.j  0.+0.j  0.+0.j]\n",
      " [ 0.+0.j  0.+0.j  0.+0.j -0.-1.j]\n",
      " [ 0.+0.j  0.+0.j  0.+1.j  0.+0.j]]\n",
      "_cz_matrix :\n",
      " [[ 1.  0.  0.  0.]\n",
      " [ 0.  1.  0.  0.]\n",
      " [ 0.  0.  1.  0.]\n",
      " [ 0.  0.  0. -1.]]\n",
      "_fredkin_matrix :\n",
      " [[1. 0. 0. 0. 0. 0. 0. 0.]\n",
      " [0. 1. 0. 0. 0. 0. 0. 0.]\n",
      " [0. 0. 1. 0. 0. 0. 0. 0.]\n",
      " [0. 0. 0. 1. 0. 0. 0. 0.]\n",
      " [0. 0. 0. 0. 1. 0. 0. 0.]\n",
      " [0. 0. 0. 0. 0. 0. 1. 0.]\n",
      " [0. 0. 0. 0. 0. 1. 0. 0.]\n",
      " [0. 0. 0. 0. 0. 0. 0. 1.]]\n",
      "_h_matrix :\n",
      " [[ 0.70710678  0.70710678]\n",
      " [ 0.70710678 -0.70710678]]\n",
      "_i_matrix :\n",
      " [[1. 0.]\n",
      " [0. 1.]]\n",
      "_ii_matrix :\n",
      " [[1. 0. 0. 0.]\n",
      " [0. 1. 0. 0.]\n",
      " [0. 0. 1. 0.]\n",
      " [0. 0. 0. 1.]]\n",
      "_s_matrix :\n",
      " [[1.+0.j 0.+0.j]\n",
      " [0.+0.j 0.+1.j]]\n",
      "_swap_matrix :\n",
      " [[1. 0. 0. 0.]\n",
      " [0. 0. 1. 0.]\n",
      " [0. 1. 0. 0.]\n",
      " [0. 0. 0. 1.]]\n",
      "_t_matrix :\n",
      " [[1.        +0.j         0.        +0.j        ]\n",
      " [0.        +0.j         0.70710678+0.70710678j]]\n",
      "_toffoli_matrix :\n",
      " [[1. 0. 0. 0. 0. 0. 0. 0.]\n",
      " [0. 1. 0. 0. 0. 0. 0. 0.]\n",
      " [0. 0. 1. 0. 0. 0. 0. 0.]\n",
      " [0. 0. 0. 1. 0. 0. 0. 0.]\n",
      " [0. 0. 0. 0. 1. 0. 0. 0.]\n",
      " [0. 0. 0. 0. 0. 1. 0. 0.]\n",
      " [0. 0. 0. 0. 0. 0. 0. 1.]\n",
      " [0. 0. 0. 0. 0. 0. 1. 0.]]\n",
      "_wroot_matrix :\n",
      " [[ 0.70710678+0.j  -0.5       -0.5j]\n",
      " [ 0.5       -0.5j  0.70710678+0.j ]]\n",
      "_x_matrix :\n",
      " [[0. 1.]\n",
      " [1. 0.]]\n",
      "_xx_matrix :\n",
      " [[0. 0. 0. 1.]\n",
      " [0. 0. 1. 0.]\n",
      " [0. 1. 0. 0.]\n",
      " [1. 0. 0. 0.]]\n",
      "_y_matrix :\n",
      " [[ 0.+0.j -0.-1.j]\n",
      " [ 0.+1.j  0.+0.j]]\n",
      "_yy_matrix :\n",
      " [[ 0.+0.j  0.-0.j  0.-0.j -1.+0.j]\n",
      " [ 0.+0.j  0.+0.j  1.-0.j  0.-0.j]\n",
      " [ 0.+0.j  1.-0.j  0.+0.j  0.-0.j]\n",
      " [-1.+0.j  0.+0.j  0.+0.j  0.+0.j]]\n",
      "_z_matrix :\n",
      " [[ 1.  0.]\n",
      " [ 0. -1.]]\n",
      "_zz_matrix :\n",
      " [[ 1.  0.  0.  0.]\n",
      " [ 0. -1.  0. -0.]\n",
      " [ 0.  0. -1. -0.]\n",
      " [ 0. -0. -0.  1.]]\n"
     ]
    }
   ],
   "source": [
    "for name in dir(tc.gates):\n",
    "    if name.endswith(\"_matrix\"):\n",
    "        print(name, \":\\n\", getattr(tc.gates, name))"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "7851cdcd",
   "metadata": {},
   "source": [
    "### 非幺正门\n",
    "\n",
    "``tc.Circuit``由于其张量网络引擎性质而自动支持非幺正电路仿真"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 26,
   "id": "e1805a84",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "<tf.Tensor: shape=(8,), dtype=complex64, numpy=\n",
       "array([0.83373   -0.9888977j, 0.        +0.j       ,\n",
       "       0.63496387-1.2984576j, 0.        +0.j       ,\n",
       "       0.        +0.j       , 0.        +0.j       ,\n",
       "       0.        +0.j       , 0.        +0.j       ], dtype=complex64)>"
      ]
     },
     "execution_count": 26,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "c = tc.Circuit(n)\n",
    "c.exp1(1, unitary=tc.gates._x_matrix, theta=K.ones([]) + 1.0j * K.ones([]))\n",
    "c.state()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "28222612",
   "metadata": {},
   "source": [
    "请注意,在这种情况下,最终量子态不再归一化。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 27,
   "id": "1581cf4f",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\n",
      "Not equal to tolerance rtol=1e-07, atol=0\n",
      "\n",
      "Mismatched elements: 1 / 1 (100%)\n",
      "Max absolute difference: 0.93963802\n",
      "Max relative difference: 0.93963802\n",
      " x: array(1.939638+0.j, dtype=complex64)\n",
      " y: array(1.)\n"
     ]
    }
   ],
   "source": [
    "try:\n",
    "    np.testing.assert_allclose(K.norm(c.state()), 1.0)\n",
    "except AssertionError as e:\n",
    "    print(e)"
   ]
  }
 ],
 "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.0"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}