{
  "cells": [
    {
      "cell_type": "markdown",
      "id": "39a1fd9b-a17f-486e-aa7a-38d46b867984",
      "metadata": {},
      "source": [
        "---\n",
        "title: \"유틸리티 I\"\n",
        "description: \"이 강의에서는 2023년 6월 15일자 네이처(Nature) 제618호에 게재된, 우리가 비공식적으로 '유틸리티 논문'이라 부르는 연구에 등장하는 유틸리티 규모 회로를 실행합니다.\"\n",
        "---\n",
        "\n",
        "<span id=\"utility-scale-experiment-i\" />\n",
        "\n",
        "# 유틸리티 규모 실험 I\n",
        "\n",
        "<Admonition type=\"note\">\n",
        "  타미야 오노데라 (2024년 7월 5일)\n",
        "\n",
        "  원본 강의의 [PDF를 다운로드하세요](https://ibm.ent.box.com/public/static/k38xhk5yaqy9b3gjdmu0ynhnd9i4c3e1.zip). 일부 코드 스니펫은 정적 이미지이므로 더 이상 사용되지 않을 수 있습니다.\n",
        "\n",
        "  *이 실험을 실행하는 데 걸리는 대략적인 QPU 시간은 45초입니다.*\n",
        "</Admonition>\n",
        "\n"
      ]
    },
    {
      "attachments": {},
      "cell_type": "markdown",
      "id": "f0d73c71-11ba-4dcb-b230-ecea500e8732",
      "metadata": {},
      "source": [
        "<span id=\"1-introduction-to-the-utility-paper\" />\n",
        "\n",
        "## 1. 실용 논문 소개\n",
        "\n",
        "이 단원에서는 2023년 6월 15일자 Nature 618호에 실린 ['유틸리티 논문'](https://www.nature.com/articles/s41586-023-06096-3) 에 등장하는 유틸리티 규모의 회로를 실행해봅니다. 이 논문은 2D 횡장 아이싱 모델의 시간 진화에 대해 다룹니다. 특히 해밀턴의 시간 역학을 고려합니다,\n",
        "\n",
        "$$\n",
        "H = H_{ZZ} + H_X = - J \\sum_{(i,j)} Z_i Z_j + h \\sum_{i} X_i\n",
        "$$\n",
        "\n",
        "여기서 $J > 0$ 은 $i < j$ 과의 가장 가까운 이웃 스핀의 결합이고 $h$ 은 글로벌 횡단 필드입니다.\n",
        "\n"
      ]
    },
    {
      "attachments": {},
      "cell_type": "markdown",
      "id": "c92cf6bb-df3e-4020-b980-edf17188e096",
      "metadata": {
        "jp-MarkdownHeadingCollapsed": true
      },
      "source": [
        "시간 진화 연산자의 일차 트로터 분해를 통해 초기 상태의 스핀 역학을 시뮬레이션합니다,\n",
        "\n",
        "$$\n",
        "\\begin{aligned}\n",
        " \\exp(-i H_{ZZ} \\delta t) &= \\prod_{(i,j)} \\exp (i J \\delta t Z_i Z_j)  = \\prod_{(i,j)} \\mathrm{R}_{Z_i Z_j} ( - 2 J \\delta t) \\\\\n",
        " \\exp(-i H_X \\delta t) &= \\prod_{i} \\exp (-i h \\delta t X_i )  = \\prod_{i} \\mathrm{R}_{X_i} ( 2 h \\delta t)\n",
        "\\end{aligned}\n",
        "$$\n",
        "\n",
        "에서 진화 시간 $T$ 은 $T / \\delta t$ 트로터 스텝으로 이산화되고 $\\mathrm{R}_{Z_i Z_j}(\\theta_J)$ 과 $\\mathrm{R}_{X_i}(\\theta_h)$ 는 각각 $ZZ$ 및 $X$ 로테이션 게이트입니다.\n",
        "\n",
        "연구진은 헤비헥스 연결성을 갖춘 127큐비트 장치인 IBM Quantum® Eagle 프로세서에서 모든 큐비트에 $X$ 상호작용을, 커플링 맵의 모든 에지에 $ZZ$ 상호작용을 적용하여 실험을 진행했습니다.  '데이터 종속성'으로 인해 모든 $ZZ$ 상호 작용을 동시에 적용할 수 없습니다.  따라서 **커플링 맵에 색상을** 지정하여 레이어로 그룹화합니다. 레이어에 있는 것들은 동일한 색상이 할당되며 병렬로 적용할 수 있습니다.\n",
        "\n",
        "또한 실험의 단순성을 위해 $\\theta_J=-\\pi /2$ 사례에 집중했습니다.\n",
        "\n",
        "이 논문의 새로운 공헌은 상태 벡터 시뮬레이션을 넘어서는 규모의 양자 회로를 구축하고 잡음이 많은 양자 컴퓨터에서 실행하여 신뢰할 수 있는 결과를 추출하는 데 성공했다는 점입니다. 즉, 노이즈가 많은 양자 컴퓨터의 유용성을 입증한 것입니다. 이 과정에서 노이즈가 많은 기기로 인한 오류를 완화하기 위해 확률적 오류 증폭(PEA)과 함께 제로 노이즈 외삽법(ZNE)을 적용했습니다.\n",
        "\n",
        "그때부터 우리는 이러한 실험과 회로를 '유틸리티 스케일'이라고 불렀습니다.\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "fcb359b4-469a-4e37-b260-8bf5044d1f60",
      "metadata": {},
      "source": [
        "<span id=\"11-your-goal\" />\n",
        "\n",
        "### 1.1 당신의 목표\n",
        "\n",
        "이 레슨의 목표는 유틸리티 규모의 회로를 제작하고 이를 Eagle 프로세서에서 실행하는 것입니다.  부분적으로는 PEA가 현재 키스킷의 실험적인 기능이고, 부분적으로는 ZNE를 PEA와 함께 적용하는 데 상당한 시간이 걸리기 때문에 신뢰할 수 있는 결과를 추출하는 것은 이 노트의 범위를 벗어납니다.\n",
        "\n",
        "구체적으로, 논문의 그림 4b 에 해당하는 회로를 만들어 실행하고, '완화되지 않은' 점을 직접 그려보라는 요청을 받습니다.  보시다시피, 이것은 관찰 가능한 것으로 $\\langle Z_{62} \\rangle$ 을 사용하는 127-큐비트 $\\times$ 60층(트로터 스텝 20개) 회로입니다.\n",
        "\n"
      ]
    },
    {
      "attachments": {},
      "cell_type": "markdown",
      "id": "a4aecf28-fc89-42db-ad8f-67e8afacff87",
      "metadata": {},
      "source": [
        "![image.png](https://quantum.cloud.ibm.com/learning/images/courses/utility-scale-quantum-computing/utility-i/utility1.avif)\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "b8c5a5ae-fc75-4fa9-9c70-2de36652f49a",
      "metadata": {},
      "source": [
        "큰 문제처럼 들리나요? 걱정하지 마십시오. 이 과정의 마지막 세 강의는 디딤돌을 제공합니다. 우선, 가짜 장치에서 27큐비트 $\\times$ 6층(트로터 스텝 2개) 회로를 구축하고 실행하는 소규모 실험을 시연하고 $\\langle Z_{13} \\rangle$ 을 관측 장치로 사용합니다.\n",
        "\n",
        "소개는 여기까지입니다. 유틸리티 규모의 모험을 떠나보겠습니다!\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 1,
      "id": "ad57179f-240e-441d-b2e4-e531cd192b45",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "'2.0.2'"
            ]
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "import qiskit\n",
        "\n",
        "qiskit.__version__"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 2,
      "id": "35fff60f-7c73-4492-ace9-ecdc8fd33b0c",
      "metadata": {},
      "outputs": [],
      "source": [
        "#!pip install qiskit_ibm_runtime\n",
        "#!pip install qiskit_aer"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 3,
      "id": "2f7464cc-4190-400f-b947-4f38100b43d2",
      "metadata": {},
      "outputs": [],
      "source": [
        "import matplotlib.pyplot as plt\n",
        "import numpy as np\n",
        "import rustworkx as rx\n",
        "\n",
        "from qiskit import QuantumCircuit, transpile\n",
        "from qiskit.circuit import Parameter\n",
        "from qiskit.circuit.library import YGate\n",
        "from qiskit.quantum_info import SparsePauliOp\n",
        "from qiskit_ibm_runtime import (\n",
        "    QiskitRuntimeService,\n",
        "    fake_provider,\n",
        "    EstimatorV2 as Estimator,\n",
        ")\n",
        "from qiskit_aer import AerSimulator"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "acd628f1-e010-44b7-ba77-cceb3b4198c6",
      "metadata": {},
      "outputs": [],
      "source": [
        "service = QiskitRuntimeService()"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "06556d62-08bc-4c43-a7d0-382b73ec239a",
      "metadata": {},
      "source": [
        "<span id=\"2-preparation\" />\n",
        "\n",
        "## 2. 준비\n",
        "\n",
        "<span id=\"21-construct-rzz-$pi$-/-2\" />\n",
        "\n",
        "### 2.1 RZZ(- $\\pi$ /2)를 구성하라\n",
        "\n",
        "먼저, 일반적으로 RZZ 게이트에는 두 개의 $CX$ 게이트가 필요하다는 것을 관찰하세요.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 5,
      "id": "d0b96520-3a4b-43c4-ade8-85cec68e3e09",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<Image src=\"/learning/images/courses/utility-scale-quantum-computing/utility-i/extracted-outputs/d0b96520-3a4b-43c4-ade8-85cec68e3e09-0.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "execution_count": 5,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "from qiskit.circuit.library import RZZGate\n",
        "\n",
        "θ_h = Parameter(\"$\\\\theta_h$\")\n",
        "qc1 = QuantumCircuit(2)\n",
        "qc1.append(RZZGate(θ_h), [0, 1])\n",
        "qc1.decompose(reps=1).draw(\"mpl\")"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "2770e3d2-d9d1-4bd5-8f00-8d8401f10438",
      "metadata": {},
      "source": [
        "위에서 언급했듯이, 이 실험에서는 특정 각도( $\\pi$ / 2)의 RZZ 게이트에 초점을 맞춥니다.  백서에서 볼 수 있듯이 $CX$ 게이트 하나만으로 구현할 수 있습니다.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 6,
      "id": "14b0ecb2-a8da-484a-bf49-606450bb074a",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<Image src=\"/learning/images/courses/utility-scale-quantum-computing/utility-i/extracted-outputs/14b0ecb2-a8da-484a-bf49-606450bb074a-0.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "execution_count": 6,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "qc2 = QuantumCircuit(2)\n",
        "\n",
        "qc2.sdg([0, 1])\n",
        "qc2.append(YGate().power(1 / 2), [1])\n",
        "qc2.cx(0, 1)\n",
        "qc2.append(YGate().power(1 / 2).adjoint(), [1])\n",
        "\n",
        "qc2.draw(\"mpl\")"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "269a5094-b4e6-4249-b9d5-ea25ded1767e",
      "metadata": {},
      "source": [
        "나중에 참조할 수 있도록 이 회로의 관점에서 게이트를 정의합니다.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 7,
      "id": "2b5fbb1a",
      "metadata": {},
      "outputs": [],
      "source": [
        "rzz = qc2.to_gate(label=\"RZZ\")"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "d89cccac-13a8-49b5-9dab-c1e98f9735c8",
      "metadata": {},
      "source": [
        "새로 정의된 `rzz` 을 무작위로 사용해 보겠습니다.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 8,
      "id": "6753b9a4-90b1-4981-82b2-8177ac258af2",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<Image src=\"/learning/images/courses/utility-scale-quantum-computing/utility-i/extracted-outputs/6753b9a4-90b1-4981-82b2-8177ac258af2-0.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "metadata": {},
          "output_type": "display_data"
        }
      ],
      "source": [
        "qc3 = QuantumCircuit(3)\n",
        "qc3.append(rzz, [0, 1])\n",
        "qc3.append(rzz, [0, 2])\n",
        "display(qc3.draw(\"mpl\"))\n",
        "# display(qc.decompose(reps=1).draw(\"mpl\"))"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "ed9c4589-c996-4199-8dd7-19e8d144a384",
      "metadata": {},
      "source": [
        "이를 더 사용하기 전에 -pi/2 및 새로 정의한 `rzz` 또는 `qc2` 게이트에 대한 `qc1` (RZZ 게이트)의 논리적 동등성을 확인해 보겠습니다:\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 9,
      "id": "b84c6f00-d50a-4874-9fa4-0c81742654e8",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "True"
            ]
          },
          "execution_count": 9,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "from qiskit.quantum_info import Operator\n",
        "\n",
        "op1 = Operator(qc1.assign_parameters([-np.pi / 2]))\n",
        "op2 = Operator(qc2)\n",
        "\n",
        "op1.equiv(op2)"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "ace1a98d-2ef7-4fe8-b67d-7799e7566f5a",
      "metadata": {},
      "source": [
        "<span id=\"22-color-the-coupling-map\" />\n",
        "\n",
        "### 2.2 커플링 맵 채우기\n",
        "\n",
        "백엔드의 커플링 맵에 색상을 지정하는 방법에 대해 알아보겠습니다.  이는 $ZZ$ 상호작용을 레이어로 그룹화하는 데 필요합니다.\n",
        "\n",
        "먼저 백엔드의 커플링 맵을 시각화해 보겠습니다.  현재 모든 IBM 퀀텀 디바이스의 커플링 맵은 육각형으로 되어 있습니다.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 10,
      "id": "84e11b8e-bc74-4f3a-8538-d4d34d069e0f",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<Image src=\"/learning/images/courses/utility-scale-quantum-computing/utility-i/extracted-outputs/84e11b8e-bc74-4f3a-8538-d4d34d069e0f-0.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "execution_count": 10,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "backend = service.least_busy(operational=True, simulator=False)\n",
        "\n",
        "backend.coupling_map.draw()"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "a5fbfce4-c8cc-49fe-831d-31ad59f84c08",
      "metadata": {},
      "source": [
        "커플링 맵에 색을 입히기 위해 그래프와 복잡한 네트워크 작업을 위한 Python 패키지인 [rustworkx를](https://www.rustworkx.org/) 사용합니다.  여러 색상 지정 알고리즘을 제공하지만 모두 휴리스틱 방식이므로 최소한의 색상을 찾는다는 보장은 없습니다.\n",
        "\n",
        "이렇게 말했듯이, 굵은 육각형 그래프는 이분 그래프이므로, 이러한 그래프에 대한 최소 색상을 찾아야 하는 [graph\\_bipartite\\_edge\\_color 를](https://www.rustworkx.org/apiref/rustworkx.graph_bipartite_edge_color.html) 선택합니다.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 11,
      "id": "79d3af17-efa0-4e48-89c5-ad9a962cf83b",
      "metadata": {
        "scrolled": true
      },
      "outputs": [],
      "source": [
        "def color_coupling_map(backend):\n",
        "    graph = backend.coupling_map.graph\n",
        "    undirected_graph = graph.to_undirected(multigraph=False)\n",
        "    edge_color_map = rx.graph_bipartite_edge_color(undirected_graph)\n",
        "    if edge_color_map is None:\n",
        "        edge_color_map = rx.graph_greedy_edge_color(undirected_graph)\n",
        "    # build a map from color to a list of edges\n",
        "    edge_index_map = undirected_graph.edge_index_map()\n",
        "    color_edges_map = {color: [] for color in edge_color_map.values()}\n",
        "    for edge_index, color in edge_color_map.items():\n",
        "        color_edges_map[color].append(\n",
        "            (edge_index_map[edge_index][0], edge_index_map[edge_index][1])\n",
        "        )\n",
        "    return edge_color_map, color_edges_map"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "1a409faf-cb52-4c1c-95bd-beeca2cfd379",
      "metadata": {},
      "source": [
        "육각형 그래프는 세 가지 색상으로 칠해야 합니다.  위의 커플링 맵에서 이를 확인해 보겠습니다.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 12,
      "id": "5cf7f215-2155-498e-a8e8-acc51ccba363",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "ibm_strasbourg, 127-qubit device, 3 colors assigned.\n"
          ]
        }
      ],
      "source": [
        "edge_color_map, color_edges_map = color_coupling_map(backend)\n",
        "print(\n",
        "    f\"{backend.name}, {backend.num_qubits}-qubit device, {len(color_edges_map.keys())} colors assigned.\"\n",
        ")"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "574bb71f-436e-499c-bb23-1adbab9445db",
      "metadata": {},
      "source": [
        "네, 맞습니다!\n",
        "\n",
        "재미를 위해 러스트웍스 시각화 기능을 사용하여 얻은 색상에 커플링 맵을 칠해 보겠습니다.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 13,
      "id": "fb9b6915-5ace-4104-b81d-91666e689f0d",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<Image src=\"/learning/images/courses/utility-scale-quantum-computing/utility-i/extracted-outputs/fb9b6915-5ace-4104-b81d-91666e689f0d-0.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "execution_count": 13,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "color_str_map = {0: \"green\", 1: \"red\", 2: \"blue\"}\n",
        "\n",
        "undirected_graph = backend.coupling_map.graph.to_undirected(multigraph=False)\n",
        "for i in undirected_graph.edge_indices():\n",
        "    undirected_graph.get_edge_data_by_index(i)[\"color\"] = color_str_map[\n",
        "        edge_color_map[i]\n",
        "    ]\n",
        "\n",
        "rx.visualization.graphviz_draw(\n",
        "    undirected_graph, method=\"neato\", edge_attr_fn=lambda edge: {\"color\": edge[\"color\"]}\n",
        ")"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "4ae34f8d-6a46-4d81-bd0d-66a0d6fca588",
      "metadata": {},
      "source": [
        "<span id=\"3-solve-the-trotterized-time-evolution-of-a-2d-ising-model\" />\n",
        "\n",
        "## 3. 이중 자유도( 2D ) 이징 모델의 트로터화 시간 진화 방정식을 풀기.\n",
        "\n",
        "2D Ising 모델의 시간 진화에 대한 유틸리티 페이퍼의 회로를 구성하는 루틴을 정의해 보겠습니다.  이 루틴은 백엔드, 트로터 단계 수를 나타내는 정수, 배리어 삽입을 제어하는 부울의 세 가지 파라미터를 사용합니다.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 14,
      "id": "b9d5dfd9-997f-4d8c-af1f-7927df31bffb",
      "metadata": {},
      "outputs": [],
      "source": [
        "def get_utility_circuit(backend, num_steps: int, barrier: bool = False):\n",
        "    num_qubits = backend.num_qubits\n",
        "    _, color_edges_map = color_coupling_map(backend)\n",
        "    θ_h = Parameter(\"$\\\\theta_h$\")\n",
        "    qc = QuantumCircuit(num_qubits)\n",
        "\n",
        "    for i in range(num_steps):\n",
        "        qc.rx(θ_h, range(num_qubits))\n",
        "\n",
        "        for _, edge_list in color_edges_map.items():\n",
        "            for edge in edge_list:\n",
        "                qc.append(rzz, edge)\n",
        "\n",
        "        if barrier:\n",
        "            qc.barrier()\n",
        "    return qc"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "e6689c89-8321-44e8-8983-82d6b0735751",
      "metadata": {},
      "source": [
        "이미 구성된 회로에 대해 큐비트 매핑 및 라우팅을 수동으로 수행했음을 참고하시기 바랍니다.  따라서 나중에 회로를 트랜스파일링할 때 트랜스파일러에 큐비트 매핑과 라우팅을 요청하지 않습니다(**하지 않아야 합니다**). 곧 보게 되겠지만, 최적화 수준을 1로 설정하고 레이아웃 방법을 \"trivial\"로 설정하여 호출합니다.\n",
        "\n",
        "다음으로 빠른 확인을 위해 구성된 회로에 대한 정보를 가져오는 간단한 루틴을 정의합니다.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 15,
      "id": "5c002120",
      "metadata": {},
      "outputs": [],
      "source": [
        "def get_circuit_info(qc: QuantumCircuit, reps: int = 0):\n",
        "    qc0 = qc.decompose(reps=reps)\n",
        "    return (\n",
        "        f\"{qc0.num_qubits} qubits × {qc0.depth(lambda x: x.operation.num_qubits == 2)} layers ({qc0.depth()}-depth)\"\n",
        "        + \",  \"\n",
        "        + f\"\"\"Gate breakdown: {\", \".join([f\"{k.upper()} {v}\" for k, v in qc0.count_ops().items()])}\"\"\"\n",
        "    )"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "30b69c52-09f0-4d5a-855c-e8f90acd0984",
      "metadata": {},
      "source": [
        "이 루틴을 연습해 보겠습니다.  27 큐비트 $\\times$ 15 레이어(5 트로터 단계)의 회로가 표시되어야 합니다. 가짜 장치에는 28개의 가장자리가 있으므로 28\\*5개의 얽힘 게이지가 있어야 합니다.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 16,
      "id": "af7bdb29-3bdb-4f6e-a53c-76ce935dff03",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<Image src=\"/learning/images/courses/utility-scale-quantum-computing/utility-i/extracted-outputs/af7bdb29-3bdb-4f6e-a53c-76ce935dff03-0.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "metadata": {},
          "output_type": "display_data"
        },
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "27 qubits × 15 layers (20-depth),  Gate breakdown: CIRCUIT-165 140, RX 135, BARRIER 5\n",
            "27 qubits × 15 layers (60-depth),  Gate breakdown: SDG 280, UNITARY 280, CX 140, R 135, BARRIER 5\n"
          ]
        }
      ],
      "source": [
        "backend = fake_provider.FakeTorontoV2()\n",
        "num_steps = 5\n",
        "qc = get_utility_circuit(backend, num_steps, True)\n",
        "\n",
        "display(qc.draw(output=\"mpl\", fold=-1))\n",
        "print(get_circuit_info(qc, reps=0))\n",
        "print(get_circuit_info(qc, reps=1))"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "bf038a4d-4482-4368-8171-8cb4cd828c51",
      "metadata": {},
      "source": [
        "<span id=\"4-solve-the-27-qubit-version-of-the-problem\" />\n",
        "\n",
        "## 4. 27큐비트 버전의 문제를 해결하라.\n",
        "\n",
        "이제 소규모 버전의 유틸리티 실험을 시연합니다. $\\langle Z_{13} \\rangle$ 을 옵저버블로 사용하여 27-큐비트 $\\times$ 6계층(2 트로터 스텝) 회로를 구축하고 AerSimulator 과 가짜 디바이스에서 실행합니다.\n",
        "\n",
        "물론 맵, 최적화, 실행, 사후 처리로 구성된 4단계 워크플로인 '키스킷 패턴'을 따르고 있습니다. 좀 더 구체적으로 설명하자면,\n",
        "\n",
        "* 기존 입력을 양자 계산에 매핑합니다.\n",
        "* 양자 계산을 위해 회로를 최적화하세요.\n",
        "* 프리미티브를 사용하여 회로를 실행합니다.\n",
        "* 클래식 형식으로 결과를 사후 처리하고 반환합니다.\n",
        "\n",
        "다음은 소규모 실험을 위한 회로를 만들기 위한 지도 단계입니다. 그런 다음 AerSimulator 에 대한 최적화 및 실행 세트와 가짜 장치에 대한 최적화 및 실행 세트가 하나씩 있습니다.  마지막으로 결과를 플로팅하는 포스트 프로세스 단계가 있습니다.\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "ad5f3abd-0f25-47ec-9541-16fe83b7e710",
      "metadata": {},
      "source": [
        "<span id=\"41-step-1-map\" />\n",
        "\n",
        "### 4.1 1단계: 지도\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 17,
      "id": "cd9c6774",
      "metadata": {},
      "outputs": [],
      "source": [
        "backend = fake_provider.FakeTorontoV2()  # a 27 qubit fake device.\n",
        "num_steps = 2\n",
        "qc = get_utility_circuit(backend, num_steps)\n",
        "obs = SparsePauliOp.from_sparse_list(\n",
        "    [(\"Z\", [13], 1)], num_qubits=backend.num_qubits\n",
        ")  # Falcon\n",
        "angles = [\n",
        "    0,\n",
        "    0.1,\n",
        "    0.2,\n",
        "    0.3,\n",
        "    0.4,\n",
        "    0.5,\n",
        "    0.6,\n",
        "    0.7,\n",
        "    0.8,\n",
        "    1.0,\n",
        "    np.pi / 2,\n",
        "]  # We try 11 angles for theta_h."
      ]
    },
    {
      "cell_type": "markdown",
      "id": "81b39024-a7f4-4a7a-a543-59185def648b",
      "metadata": {},
      "source": [
        "<span id=\"42-steps-2-and-3-optimize-and-execute-simulator\" />\n",
        "\n",
        "### 4.2 단계 2와 3: 최적화 및 실행 (시뮬레이터)\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 18,
      "id": "fa307165-fc74-4b6c-88c5-a2ac36341a3c",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "27 qubits × 6 layers (23-depth),  Gate breakdown: SDG 112, UNITARY 112, CX 56, R 54\n",
            "27 qubits × 6 layers (16-depth),  Gate breakdown: U3 80, CX 56, R 54, U1 32, U 28\n"
          ]
        }
      ],
      "source": [
        "backend_sim = AerSimulator()\n",
        "transpiled_qc_sim = transpile(\n",
        "    qc, backend_sim, optimization_level=1, layout_method=\"trivial\"\n",
        ")\n",
        "transpiled_obs_sim = obs.apply_layout(layout=transpiled_qc_sim.layout)\n",
        "\n",
        "print(get_circuit_info(qc, reps=1))\n",
        "print(get_circuit_info(transpiled_qc_sim, reps=1))"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "0a101b40-5555-41d9-96b2-a8c986ea9903",
      "metadata": {},
      "source": [
        "한 사용자는 2.3 GHz 쿼드 코어 인텔 코어 i7 프로세서와 32GB 3LPDDR4X RAM이 장착된 MacBook Pro를 사용하여 다음 셀을 실행했으며, 이 셀은 macOS 14.5.  벽 시간으로 161ms 걸렸습니다. 노트북마다 조금씩 다릅니다.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 19,
      "id": "178dd8c4-439b-4324-ba1f-687acc57a678",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "CPU times: user 231 ms, sys: 186 ms, total: 417 ms\n",
            "Wall time: 111 ms\n"
          ]
        }
      ],
      "source": [
        "%%time\n",
        "params = [[p] for p in angles]\n",
        "estimator = Estimator(mode=backend_sim)\n",
        "pub = (transpiled_qc_sim, transpiled_obs_sim, params)\n",
        "result_sim = estimator.run([pub]).result()"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "48b684f9-061a-49fd-acb1-3ed7b4bab1f2",
      "metadata": {},
      "source": [
        "<span id=\"43-steps-2-and-3-optimize-and-execute-fake-device\" />\n",
        "\n",
        "### 4.3 단계 2와 3: 최적화 및 실행 (가상 기기)\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 20,
      "id": "f944eeae-8dc5-4ad6-97ad-92f95159956b",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "27 qubits × 6 layers (23-depth),  Gate breakdown: SDG 112, UNITARY 112, CX 56, R 54\n",
            "27 qubits × 6 layers (49-depth),  Gate breakdown: SDG 324, U1 274, H 162, CX 56, U3 14\n"
          ]
        }
      ],
      "source": [
        "backend_fake = fake_provider.FakeTorontoV2()\n",
        "transpiled_qc_fake = transpile(\n",
        "    qc, backend_fake, optimization_level=1, layout_method=\"trivial\"\n",
        ")\n",
        "transpiled_obs_fake = obs.apply_layout(layout=transpiled_qc_fake.layout)\n",
        "\n",
        "print(get_circuit_info(qc, reps=1))\n",
        "print(get_circuit_info(transpiled_qc_fake, reps=1))"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "59adfdfb-0954-42f7-9dd2-c819d04264b6",
      "metadata": {},
      "source": [
        "동일한 사용자가 위와 동일한 환경에서 다음 셀을 실행했을 때, 월 타임 기준 2min 19s 시간이 걸렸습니다.  가짜 장치에서 회로를 실행하면 노이즈 시뮬레이션이 호출되어 정확한 시뮬레이션보다 훨씬 더 오랜 시간이 걸립니다.   가짜 디바이스에서는 더 큰 회로(예: 27쿼비트 $\\times$ 9레이어에 트로터 스텝 3개)를 실행하지 않는 것이 좋습니다.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 21,
      "id": "62d0e0bb-9acb-474a-8d19-b132013131a0",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "CPU times: user 4min 42s, sys: 9.35 s, total: 4min 51s\n",
            "Wall time: 38.3 s\n"
          ]
        }
      ],
      "source": [
        "%%time\n",
        "params = [[p] for p in angles]\n",
        "estimator = Estimator(mode=backend_fake)\n",
        "pub = (transpiled_qc_fake, transpiled_obs_fake, params)\n",
        "result_fake = estimator.run([pub]).result()"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "181e5f61-2830-485c-bd22-a1d70b443ed9",
      "metadata": {},
      "source": [
        "<span id=\"44-step-4-post-process\" />\n",
        "\n",
        "### 4.4 4단계: 후처리\n",
        "\n",
        "정확하고 노이즈가 적은 시뮬레이션의 결과를 플로팅합니다. FakeToronto 에서 노이즈의 심각한 영향을 확인할 수 있습니다.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 22,
      "id": "4cf3cad0-e720-469c-a9ed-e397dae0f2f6",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<Image src=\"/learning/images/courses/utility-scale-quantum-computing/utility-i/extracted-outputs/4cf3cad0-e720-469c-a9ed-e397dae0f2f6-0.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "metadata": {},
          "output_type": "display_data"
        }
      ],
      "source": [
        "plt.plot(angles, result_fake[0].data.evs, \"o\", label=\"Fake Device\")\n",
        "plt.plot(angles, result_sim[0].data.evs, \"o\", label=\"AerSimulator\")\n",
        "plt.xlabel(\"$\\\\mathrm{R_x}$ angle $\\\\theta_h$\")\n",
        "plt.title(\"$\\\\langle Z_{13} \\\\rangle$\")\n",
        "plt.legend()\n",
        "plt.show()"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "1b05966c-efe2-4eb4-b63c-43c07cf81f41",
      "metadata": {},
      "source": [
        "<span id=\"5-solve-the-127-qubit-version-of-the-problem\" />\n",
        "\n",
        "## 5. 127큐비트 버전의 문제를 해결하라\n",
        "\n",
        "처음에 언급한 대로 유틸리티 규모의 실험을 실행하는 것이 목표입니다. $\\langle Z_{62} \\rangle$ 을 옵저버블로 사용하여 127-큐비트, 60-레이어(트로터 스텝 20개) 회로를 생성하고 실행합니다. 적절한 경우 27-큐비트 버전의 코드를 사용하여 직접 이 작업을 수행하는 것이 좋습니다. 하지만 여기에 해결책이 있습니다.\n",
        "\n",
        "**해결 방법:**\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "a18a42dd-5891-4b5f-8c3b-1bc7e1ae4a5e",
      "metadata": {},
      "source": [
        "<span id=\"51-step-1-map\" />\n",
        "\n",
        "### 5.1 1단계: 지도\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "8b900d9a-0351-426a-b25b-19e631fd257e",
      "metadata": {},
      "outputs": [],
      "source": [
        "# backend_map = service.backend(\"ibm_brisbane\")\n",
        "backend_map = service.least_busy(operational=True, simulator=False)\n",
        "\n",
        "num_steps = 20\n",
        "qc = get_utility_circuit(backend_map, num_steps)\n",
        "obs = SparsePauliOp.from_sparse_list(\n",
        "    [(\"Z\", [62], 1)], num_qubits=backend_map.num_qubits\n",
        ")  # Eagle\n",
        "angles = [0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 1.0, np.pi / 2]"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "51ea0288-d8e9-4ee1-bbe8-dc24826a5026",
      "metadata": {},
      "source": [
        "<span id=\"52-steps-2-and-3-optimize-and-execute\" />\n",
        "\n",
        "### 5.2 단계 2와 3: 최적화 및 실행\n",
        "\n",
        "Eagle 프로세서의 커플링 맵에는 144개의 에지가 있습니다.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "f9fadf76-48e3-43a3-b773-8fa3b5fd5f3d",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "156 qubits × 60 layers (221-depth),  Gate breakdown: SDG 7040, UNITARY 7040, CX 3520, R 3120\n",
            "156 qubits × 60 layers (201-depth),  Gate breakdown: RZ 11933, SX 6240, CZ 3520\n"
          ]
        }
      ],
      "source": [
        "# backend = service.backend(\"ibm_brisbane\")\n",
        "backend = backend_map\n",
        "\n",
        "transpiled_qc = transpile(qc, backend, optimization_level=1, layout_method=\"trivial\")\n",
        "transpiled_obs = obs.apply_layout(layout=transpiled_qc.layout)\n",
        "\n",
        "print(get_circuit_info(qc, reps=1))\n",
        "print(get_circuit_info(transpiled_qc))"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 27,
      "id": "2ddff1e1-c868-4300-bdbb-cdd3b6932302",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "job id=d1479n6qf56g0081sxa0\n"
          ]
        }
      ],
      "source": [
        "params = [[p] for p in angles]\n",
        "estimator = Estimator(mode=backend)\n",
        "pub = (transpiled_qc, transpiled_obs, params)\n",
        "job = estimator.run([pub])\n",
        "\n",
        "job_id = job.job_id()\n",
        "print(f\"job id={job_id}\")"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "c497fc9d-aa58-4eb2-851e-369c7209da97",
      "metadata": {},
      "source": [
        "<span id=\"53-post-process\" />\n",
        "\n",
        "### 5.3 후처리\n",
        "\n",
        "유틸리티 백서의 그림 4b 에서 '완화'된 포인트의 값을 확인할 수 있습니다.   이를 결과와 함께 플로팅하세요.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 28,
      "id": "1c4ede0c-e865-41fe-9b38-8ecf39afa64f",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<Image src=\"/learning/images/courses/utility-scale-quantum-computing/utility-i/extracted-outputs/1c4ede0c-e865-41fe-9b38-8ecf39afa64f-0.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "metadata": {},
          "output_type": "display_data"
        }
      ],
      "source": [
        "result_paper = [\n",
        "    1.0171,\n",
        "    1.0044,\n",
        "    0.9563,\n",
        "    0.9602,\n",
        "    0.8394,\n",
        "    0.8120,\n",
        "    0.5466,\n",
        "    0.4556,\n",
        "    0.1953,\n",
        "    0.0141,\n",
        "    0.0117,\n",
        "]\n",
        "\n",
        "# REPLACE WITH YOUR OWN JOB ID\n",
        "job = service.job(job_id)\n",
        "\n",
        "plt.plot(angles, job.result()[0].data.evs, \"o\", label=f\"{job.backend().name}\")\n",
        "plt.plot(angles, result_paper, \"o\", label=\"Utility Paper\")\n",
        "plt.xlabel(\"$\\\\mathrm{R_x}$ angle $\\\\theta_h$\")\n",
        "plt.title(\"$\\\\langle Z_{62} \\\\rangle$\")\n",
        "plt.legend()\n",
        "plt.show()"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "7fb3e103-af1d-4a9f-8016-1a270c5706be",
      "metadata": {},
      "source": [
        "결과가 그림 4b 의 \"완화되지 않음\"과 비슷합니까? 실험 당시의 기기 및 상태에 따라 매우 다를 수 있습니다.  결과 자체에 대해서는 걱정하지 마세요. 코딩을 올바르게 수행했는지 확인합니다.  그렇게 하셨다면, 유틸리티 시대의 출발선에 도달하신 것을 축하드립니다.\n",
        "\n",
        "유틸리티 논문에서와 같이 전 세계의 과학자들은 노이즈가 있는 상황에서도 의미 있는 결과를 도출하기 위해 엄청난 창의력을 발휘했습니다. 이러한 공동 노력의 최종 목표는 양자 우위, 즉 양자 컴퓨터가 기존 컴퓨터보다 더 빠르고, 더 충실하게, 더 저렴하게 산업에서 사용되는 일부 문제를 해결할 수 있는 상태입니다. 이는 단발적인 사건이 아니라 양자 결과의 고전적 재현이 점점 더 오래 걸리는 시대가 될 것이며, 어느 시점에서는 양자 리드 타임이 매우 중요해질 것입니다. 양자 우위에 대해 한 가지 분명한 것은 유틸리티 규모의 실험을 통해서만 얻을 수 있다는 것입니다.  이 과정을 통해 도전과 재미로 가득한 퀘스트에 참여하게 된다면 더할 나위 없이 기쁠 것입니다.\n",
        "\n"
      ]
    },
    {
      "attachments": {},
      "cell_type": "markdown",
      "id": "a346d104-299e-4152-a8ea-5e297d05b6a1",
      "metadata": {},
      "source": [
        "<span id=\"reference\" />\n",
        "\n",
        "## 참조\n",
        "\n",
        "* Kim, Y., Eddins, A., Anand, S. et al. 내결함성 이전에 양자 컴퓨팅의 유용성에 대한 증거. Nature 618, 500-505 (2023). [https://doi.org/10.1038/s41586-023-06096-3](https://doi.org/10.1038/s41586-023-06096-3)\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "id": "a1b8767d",
      "source": "© IBM Corp., 2017-2026"
    }
  ],
  "metadata": {
    "kernelspec": {
      "display_name": "Python 3",
      "language": "python",
      "name": "python3"
    },
    "language_info": {
      "codemirror_mode": {
        "name": "ipython",
        "version": 3
      },
      "file_extension": ".py",
      "mimetype": "text/x-python",
      "name": "python",
      "nbconvert_exporter": "python",
      "pygments_lexer": "ipython3",
      "version": "3"
    },
    "widgets": {
      "application/vnd.jupyter.widget-state+json": {
        "state": {},
        "version_major": 2,
        "version_minor": 0
      }
    }
  },
  "nbformat": 4,
  "nbformat_minor": 5
}