{
  "cells": [
    {
      "cell_type": "markdown",
      "id": "alleged-prairie",
      "metadata": {},
      "source": [
        "---\n",
        "title: \"유틸리티 III\"\n",
        "description: \"이 강의는 20 큐비트 이상의 GHZ 회로를 구축하는 내용으로, 측정 시 GHZ 상태의 충실도가 0.5 을 초과하도록 합니다.\"\n",
        "---\n",
        "\n",
        "<span id=\"utility-scale-experiment-iii\" />\n",
        "\n",
        "# 유틸리티 규모 실험 III\n",
        "\n",
        "<Admonition type=\"note\">\n",
        "  토시나리 이토코, 타미야 오노데라, 키후미 누마타 (2024년 7월 19일)\n",
        "\n",
        "  원본 강의의 [PDF를 다운로드하세요](https://ibm.ent.box.com/public/static/fw1538dogvyv0qbfqg8tan1k2fs27mfv.zip). 일부 코드 스니펫은 정적 이미지이므로 더 이상 사용되지 않을 수 있습니다.\n",
        "\n",
        "  *이 첫 번째 실험을 실행하는 데 걸리는 대략적인 QPU 시간은 12m 30초입니다. 아래에 약 4m가 필요한 추가 실험이 있습니다.*\n",
        "\n",
        "  (참고: 이 노트북은 오픈 플랜에서 허용된 시간 내에 평가되지 않을 수 있습니다. 양자 컴퓨팅 리소스를 현명하게 사용하세요.)\n",
        "</Admonition>\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 1,
      "id": "20483d1a-6b31-4569-b817-c9faecc8823b",
      "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": "fa30363a",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "'0.40.1'"
            ]
          },
          "execution_count": 2,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "import qiskit_ibm_runtime\n",
        "\n",
        "qiskit_ibm_runtime.__version__"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 3,
      "id": "78f23522",
      "metadata": {},
      "outputs": [],
      "source": [
        "import numpy as np\n",
        "import rustworkx as rx\n",
        "\n",
        "from qiskit import QuantumCircuit\n",
        "from qiskit.visualization import plot_histogram\n",
        "from qiskit.visualization import plot_gate_map\n",
        "from qiskit.transpiler.preset_passmanagers import generate_preset_pass_manager\n",
        "from qiskit.providers import BackendV2\n",
        "from qiskit.quantum_info import SparsePauliOp\n",
        "\n",
        "from qiskit_ibm_runtime import QiskitRuntimeService\n",
        "from qiskit_ibm_runtime import Sampler, Estimator, Batch, SamplerOptions"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "948a9ac1-2ad3-4969-8b39-bb3d697ad6bb",
      "metadata": {},
      "source": [
        "<span id=\"1-introduction\" />\n",
        "\n",
        "## 1. 소개\n",
        "\n",
        "GHZ 상태와 `Sampler` 에 적용된 분포의 종류에 대해 간략하게 살펴보겠습니다. 그런 다음 이 강의의 목표를 명시적으로 설명하겠습니다.\n",
        "\n",
        "<span id=\"11-ghz-state\" />\n",
        "\n",
        "### 1.1 GHZ 상태\n",
        "\n",
        "$n$ 큐비트에 대한 GHZ 상태(그린버거-혼-자일링거 상태)는 다음과 같이 정의됩니다\n",
        "\n",
        "$$\n",
        "\\frac{1}{\\sqrt 2}(|0\\rangle ^ {\\otimes n}+ |1\\rangle^ {\\otimes n})\n",
        "$$\n",
        "\n",
        "당연히 다음과 같은 양자 회로를 사용하여 6 큐비트를 생성할 수 있습니다.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 4,
      "id": "1bf914c5-e1c6-4664-99c2-69dea3961114",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<Image src=\"/learning/images/courses/utility-scale-quantum-computing/utility-iii/extracted-outputs/1bf914c5-e1c6-4664-99c2-69dea3961114-0.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "execution_count": 4,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "N = 6\n",
        "qc = QuantumCircuit(N, N)\n",
        "\n",
        "qc.h(0)\n",
        "for i in range(N - 1):\n",
        "    qc.cx(0, i + 1)\n",
        "\n",
        "# qc.measure_all()\n",
        "qc.barrier()\n",
        "qc.measure(list(range(N)), list(range(N)))\n",
        "\n",
        "qc.draw(output=\"mpl\", idle_wires=False, scale=0.5)"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 5,
      "id": "7b4cb915-c901-4b6d-839b-2f1ae43601d7",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "Depth: 7\n"
          ]
        }
      ],
      "source": [
        "print(\"Depth:\", qc.depth())"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "c398d524",
      "metadata": {},
      "source": [
        "이전 강의를 통해 더 잘할 수 있다는 것을 알고 있지만 깊이가 너무 크지는 않습니다. 백엔드를 선택하고 이 회로를 트랜스파일해 보겠습니다.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "108bc369",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "'ibm_kingston'"
            ]
          },
          "execution_count": 7,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "service = QiskitRuntimeService()\n",
        "backend = service.least_busy(operational=True, simulator=False)\n",
        "backend.name\n",
        "# or\n",
        "# backend = service.least_busy(operational=True)\n",
        "# backend.name"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 8,
      "id": "2e003078-3707-44d9-86e8-bbc66b095e84",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<Image src=\"/learning/images/courses/utility-scale-quantum-computing/utility-iii/extracted-outputs/2e003078-3707-44d9-86e8-bbc66b095e84-0.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "execution_count": 8,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "pm = generate_preset_pass_manager(3, backend=backend)\n",
        "qc_transpiled = pm.run(qc)\n",
        "qc_transpiled.draw(output=\"mpl\", idle_wires=False, fold=-1)"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 9,
      "id": "18d3524a-43ec-4163-8f53-8e9bf4421e06",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "Depth: 27\n",
            "Two-qubit Depth: 11\n"
          ]
        }
      ],
      "source": [
        "print(\"Depth:\", qc_transpiled.depth())\n",
        "print(\n",
        "    \"Two-qubit Depth:\",\n",
        "    qc_transpiled.depth(filter_function=lambda x: x.operation.num_qubits == 2),\n",
        ")"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "109ff71e",
      "metadata": {},
      "source": [
        "이번에도 트랜스파일된 2쿼비트 깊이는 너무 크지 않습니다. 그러나 더 많은 큐비트에서 GHZ 상태로 작업하려면 회로 최적화에 대해 분명히 생각해야 합니다. `Sampler` 을 사용하여 실행하고 실제 양자 컴퓨터의 결과를 확인해 보겠습니다.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 10,
      "id": "abd0654d-b2dc-4180-821c-6af4977a12e8",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "d147y20n2txg008jvv70\n"
          ]
        }
      ],
      "source": [
        "sampler = Sampler(mode=backend)\n",
        "shots = 40000\n",
        "job = sampler.run([qc_transpiled], shots=shots)\n",
        "job_id = job.job_id()\n",
        "print(job_id)"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 12,
      "id": "f0073d8b-1ad8-4bb7-a2d2-754ce2876ffd",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "'DONE'"
            ]
          },
          "execution_count": 12,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "job.status()"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 13,
      "id": "8ab5b37f-fb87-40a8-8e13-0c6cb3154f64",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<Image src=\"/learning/images/courses/utility-scale-quantum-computing/utility-iii/extracted-outputs/8ab5b37f-fb87-40a8-8e13-0c6cb3154f64-0.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "execution_count": 13,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "job = service.job(job_id)\n",
        "result = job.result()\n",
        "plot_histogram(result[0].data.c.get_counts(), figsize=(30, 5))"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "9965c7c1-babd-444d-8436-2a63bcbe79af",
      "metadata": {},
      "source": [
        "이것은 6-큐비트 GHZ 회로의 결과입니다. 보시다시피 모든 $|0\\rangle$ 및 모든 $|1\\rangle$ 의 상태가 지배적이지만 오류는 상당합니다. Eagle 장치로 얼마나 큰 GHZ 회로를 만들 수 있는지, 그러면서도 올바른 상태가 50% 이상일 가능성이 있는 결과를 얻을 수 있는지 확인해 보겠습니다.\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "9942f911-bfbf-4a16-8349-05bc490885e6",
      "metadata": {},
      "source": [
        "<span id=\"12-your-goal\" />\n",
        "\n",
        "### 1.2 당신의 목표\n",
        "\n",
        "20큐비트 이상의 GHZ 회로를 구축하여 측정 시 **GHZ 상태의 충실도 > 0.5**\n",
        "참고:\n",
        "\n",
        "* Eagle 디바이스(`min_num_qubits=127`)를 사용하고 촬영 횟수를 40,000회로 설정해야 합니다.\n",
        "* `execute_ghz_fidelity` 함수를 사용하여 GHZ 회로를 실행하고 `check_ghz_fidelity_from_jobs` 함수를 사용하여 충실도를 계산해야 합니다.\n",
        "\n",
        "이 연습은 이 과정에서 지금까지 배운 내용을 활용하는 독립적인 연습입니다.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "a316416f-d6c5-4183-b4ef-d6170681d8a4",
      "metadata": {},
      "outputs": [],
      "source": [
        "def execute_ghz_fidelity(\n",
        "    ghz_circuit: QuantumCircuit,  # Quantum circuit to create GHZ state (Circuit after Routing or without Routing), Classical register name is \"c\"\n",
        "    physical_qubits: list[int],  # Physical qubits to represent GHZ state\n",
        "    backend: BackendV2,\n",
        "    sampler_options: dict | SamplerOptions | None = None,\n",
        "):\n",
        "    N_SHOTS = 40_000\n",
        "    N = len(physical_qubits)\n",
        "    base_circuit = ghz_circuit.remove_final_measurements(inplace=False)\n",
        "    # M_k measurement circuits\n",
        "    mk_circuits = []\n",
        "    for k in range(1, N + 1):\n",
        "        circuit = base_circuit.copy()\n",
        "        # change measurement basis\n",
        "        for q in physical_qubits:\n",
        "            circuit.rz(-k * np.pi / N, q)\n",
        "            circuit.h(q)\n",
        "        mk_circuits.append(circuit)\n",
        "\n",
        "    obs = SparsePauliOp.from_sparse_list(\n",
        "        [(\"Z\" * N, physical_qubits, 1)], num_qubits=backend.num_qubits\n",
        "    )\n",
        "    job_ids = []\n",
        "    pm1 = generate_preset_pass_manager(1, backend=backend)\n",
        "    org_transpiled = pm1.run(ghz_circuit)\n",
        "    mk_transpiled = pm1.run(mk_circuits)\n",
        "    with Batch(backend=backend):\n",
        "        sampler = Sampler(options=sampler_options)\n",
        "        sampler.options.twirling.enable_measure = True\n",
        "        job = sampler.run([org_transpiled], shots=N_SHOTS)\n",
        "        job_ids.append(job.job_id())\n",
        "        # print(f\"Sampler job id: {job.job_id()}, shots={N_SHOTS}\")\n",
        "        estimator = Estimator()  # TREX is applied as default\n",
        "        estimator.options.dynamical_decoupling.enable = True\n",
        "        estimator.options.execution.rep_delay = 0.0005\n",
        "        estimator.options.twirling.enable_measure = True\n",
        "        job2 = estimator.run([(circ, obs) for circ in mk_transpiled], precision=1 / 100)\n",
        "        job_ids.append(job2.job_id())\n",
        "        # print(\"Estimator job id:\", job2.job_id())\n",
        "        return [job.job_id(), job2.job_id()]"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 15,
      "id": "f86e4288-9e65-4dd5-81dd-149f1e98d217",
      "metadata": {},
      "outputs": [],
      "source": [
        "def check_ghz_fidelity_from_jobs(\n",
        "    sampler_job,\n",
        "    estimator_job,\n",
        "    num_qubits,\n",
        "    shots=40_000,\n",
        "):\n",
        "    N = num_qubits\n",
        "    sampler_result = sampler_job.result()\n",
        "    counts = sampler_result[0].data.c.get_counts()\n",
        "    all_zero = counts.get(\"0\" * N, 0) / shots\n",
        "    all_one = counts.get(\"1\" * N, 0) / shots\n",
        "    top3 = sorted(counts, key=counts.get, reverse=True)[:3]\n",
        "    print(\n",
        "        f\"N={N}: |00..0>: {counts.get('0'*N, 0)}, |11..1>: {counts.get('1'*N, 0)}, |3rd>: {counts.get(top3[2], 0)} ({top3[2]})\"\n",
        "    )\n",
        "    print(f\"P(|00..0>)={all_zero}, P(|11..1>)={all_one}\")\n",
        "\n",
        "    estimator_result = estimator_job.result()\n",
        "    non_diagonal = (1 / N) * sum(\n",
        "        (-1) ** k * estimator_result[k - 1].data.evs for k in range(1, N + 1)\n",
        "    )\n",
        "    print(f\"REM: Coherence (non-diagonal): {non_diagonal:.6f}\")\n",
        "    fidelity = 0.5 * (all_zero + all_one + non_diagonal)\n",
        "    sigma = 0.5 * np.sqrt(\n",
        "        (1 - all_zero - all_one) * (all_zero + all_one) / shots\n",
        "        + sum(estimator_result[k].data.stds ** 2 for k in range(N)) / (N * N)\n",
        "    )\n",
        "    print(f\"GHZ fidelity = {fidelity:.6f} ± {sigma:.6f}\")\n",
        "    if fidelity - 2 * sigma > 0.5:\n",
        "        print(\"GME (genuinely multipartite entangled) test: Passed\")\n",
        "    else:\n",
        "        print(\"GME (genuinely multipartite entangled) test: Failed\")\n",
        "    return {\n",
        "        \"fidelity\": fidelity,\n",
        "        \"sigma\": sigma,\n",
        "        \"shots\": shots,\n",
        "        \"job_ids\": [sampler_job.job_id(), estimator_job.job_id()],\n",
        "    }"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "ad35a576-9ae4-4d00-af4d-3af0974101e9",
      "metadata": {},
      "source": [
        "이 노트에서는 16큐비트와 30큐비트를 사용하여 좋은 GHZ 상태를 만들기 위한 세 가지 전략을 적용합니다. 이러한 접근 방식은 이전 강의에서 이미 알고 있는 전략을 기반으로 합니다.\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "371c0d79",
      "metadata": {},
      "source": [
        "<span id=\"2-strategy-1-noise-aware-qubit-selection\" />\n",
        "\n",
        "## 2. 전략 1. 잡음 인식 큐비트 선택\n",
        "\n",
        "먼저 백엔드를 지정합니다. 특정 백엔드의 속성으로 광범위하게 작업할 것이므로 `least_busy` 옵션을 사용하는 대신 하나의 백엔드를 지정하는 것이 좋습니다.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 36,
      "id": "119bd751",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "Device ibm_strasbourg Loaded with 127 qubits\n",
            "Two Qubit Gate: ecr\n"
          ]
        }
      ],
      "source": [
        "backend = service.backend(\"ibm_strasbourg\")  # eagle\n",
        "twoq_gate = \"ecr\"\n",
        "print(f\"Device {backend.name} Loaded with {backend.num_qubits} qubits\")\n",
        "print(f\"Two Qubit Gate: {twoq_gate}\")"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "997d7bc9",
      "metadata": {},
      "source": [
        "많은 2큐비트 게이트가 포함된 회로를 만들려고 합니다. 2큐비트 게이트를 구현할 때 오류가 가장 낮은 큐비트를 사용하는 것이 합리적입니다. 보고된 2q-gate 오류를 기반으로 최적의 '큐비트 체인'을 찾는 것은 간단한 문제가 아닙니다. 하지만 사용할 최적의 큐비트를 결정하는 데 도움이 되는 몇 가지 함수를 정의할 수 있습니다.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 37,
      "id": "7bc47055",
      "metadata": {},
      "outputs": [],
      "source": [
        "coupling_map = backend.target.build_coupling_map(twoq_gate)\n",
        "G = coupling_map.graph"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "8615f6d8",
      "metadata": {},
      "outputs": [],
      "source": [
        "def to_edges(path):  # create edges list from node paths\n",
        "    edges = []\n",
        "    prev_node = None\n",
        "    for node in path:\n",
        "        if prev_node is not None:\n",
        "            if G.has_edge(prev_node, node):\n",
        "                edges.append((prev_node, node))\n",
        "            else:\n",
        "                edges.append((node, prev_node))\n",
        "        prev_node = node\n",
        "    return edges\n",
        "\n",
        "\n",
        "def path_fidelity(path, correct_by_duration: bool = True, readout_scale: float = None):\n",
        "    \"\"\"Compute an estimate of the total fidelity of 2-qubit gates on a path.\n",
        "    If `correct_by_duration` is true, each gate fidelity is worsen by\n",
        "    scale = max_duration / duration, that is, gate_fidelity^scale.\n",
        "    If `readout_scale` > 0 is supplied, readout_fidelity^readout_scale\n",
        "    for each qubit on the path is multiplied to the total fielity.\n",
        "    The path is given in node indices form, for example, [0, 1, 2].\n",
        "    An external function `to_edges` is used to obtain edge list, for example, [(0, 1), (1, 2)].\"\"\"\n",
        "    path_edges = to_edges(path)\n",
        "    max_duration = max(backend.target[twoq_gate][qs].duration for qs in path_edges)\n",
        "\n",
        "    def gate_fidelity(qpair):\n",
        "        duration = backend.target[twoq_gate][qpair].duration\n",
        "        scale = max_duration / duration if correct_by_duration else 1.0\n",
        "        # 1.25 = (d+1)/d with d = 4\n",
        "        return max(0.25, 1 - (1.25 * backend.target[twoq_gate][qpair].error)) ** scale\n",
        "\n",
        "    def readout_fidelity(qubit):\n",
        "        return max(0.25, 1 - backend.target[\"measure\"][(qubit,)].error)\n",
        "\n",
        "    total_fidelity = np.prod(\n",
        "        [gate_fidelity(qs) for qs in path_edges]\n",
        "    )  # two qubits gate fidelity for each path\n",
        "    if readout_scale:\n",
        "        total_fidelity *= (\n",
        "            np.prod([readout_fidelity(q) for q in path]) ** readout_scale\n",
        "        )  # multiply readout fidelity\n",
        "    return total_fidelity\n",
        "\n",
        "\n",
        "def flatten(paths, cutoff=None):  # cutoff is for not making run time too large\n",
        "    return [\n",
        "        path\n",
        "        for s, s_paths in paths.items()\n",
        "        for t, st_paths in s_paths.items()\n",
        "        for path in st_paths[:cutoff]\n",
        "        if s < t\n",
        "    ]"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 39,
      "id": "be1971a0",
      "metadata": {},
      "outputs": [],
      "source": [
        "N = 16  # Number of qubits to use in the GHZ circuit\n",
        "num_qubits_in_chain = N"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "d95a798a-90cc-42d8-9461-ab5bd5440aef",
      "metadata": {},
      "source": [
        "위의 함수를 사용해 그래프의 모든 노드 쌍 사이에서 N 큐비트의 모든 단순 경로를 찾겠습니다(참조: [all\\_pairs\\_all\\_simple\\_paths](https://www.rustworkx.org/apiref/rustworkx.all_pairs_all_simple_paths.html#rustworkx-all-pairs-all-simple-paths) ).\n",
        "\n",
        "그런 다음 위에서 만든 `path_fidelity` 함수를 사용하여 경로 충실도가 가장 높은 최적의 큐비트 체인을 찾습니다.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 40,
      "id": "e0b410e7",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "Selecting the best from 6046 candidate paths\n",
            "Predicted (best possible) process fidelity: 0.8929026784775056\n",
            "CPU times: user 284 ms, sys: 10.9 ms, total: 295 ms\n",
            "Wall time: 295 ms\n"
          ]
        }
      ],
      "source": [
        "from functools import partial\n",
        "\n",
        "%%time\n",
        "paths = rx.all_pairs_all_simple_paths(\n",
        "    G.to_undirected(multigraph=False),\n",
        "    min_depth=num_qubits_in_chain,\n",
        "    cutoff=num_qubits_in_chain,\n",
        ")\n",
        "paths = flatten(paths, cutoff=25)  # If you have time, you could set a larger cutoff.\n",
        "if not paths:\n",
        "    raise Exception(\n",
        "        f\"No qubit chain with length={num_qubits_in_chain} exists in {backend.name}. Try smaller num_qubits_in_chain.\"\n",
        "    )\n",
        "\n",
        "print(f\"Selecting the best from {len(paths)} candidate paths\")\n",
        "\n",
        "best_qubit_chain = max(\n",
        "    paths, key=partial(path_fidelity, correct_by_duration=True, readout_scale=1.0)\n",
        ")\n",
        "assert len(best_qubit_chain) == num_qubits_in_chain\n",
        "print(f\"Predicted (best possible) process fidelity: {path_fidelity(best_qubit_chain)}\")"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 41,
      "id": "efc3c14d",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "array([55, 49, 48, 47, 46, 45, 54, 64, 65, 66, 73, 85, 86, 87, 88, 89],\n",
              "      dtype=uint64)"
            ]
          },
          "execution_count": 41,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "np.array(best_qubit_chain)"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "9d364986-c387-4d0d-874c-9a7f10634394",
      "metadata": {},
      "source": [
        "커플링 맵 다이어그램에서 분홍색으로 표시된 최적의 큐비트 체인을 그려보겠습니다.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 42,
      "id": "a1c164a4",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<Image src=\"/learning/images/courses/utility-scale-quantum-computing/utility-iii/extracted-outputs/a1c164a4-0.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "execution_count": 42,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "qubit_color = []\n",
        "for i in range(133):\n",
        "    if i in best_qubit_chain:\n",
        "        qubit_color.append(\"#ff00dd\")  # pink\n",
        "    else:\n",
        "        qubit_color.append(\"#8c00ff\")  # purple\n",
        "plot_gate_map(\n",
        "    backend, qubit_color=qubit_color, qubit_size=50, font_size=25, figsize=(6, 6)\n",
        ")"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "4e66abc7",
      "metadata": {},
      "source": [
        "<span id=\"21-build-a-ghz-circuit-on-the-best-qubit-chain\" />\n",
        "\n",
        "### 2.1 최적 큐비트 체인에 GHZ 회로를 구축하라\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "273f469d-3273-40ee-922d-4ad43e1d53ad",
      "metadata": {},
      "source": [
        "먼저 H 게이트를 적용할 체인 중간에 큐비트를 선택합니다. 이렇게 하면 회로의 깊이가 약 절반으로 줄어듭니다.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 43,
      "id": "1336fba0",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<Image src=\"/learning/images/courses/utility-scale-quantum-computing/utility-iii/extracted-outputs/1336fba0-0.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "execution_count": 43,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "ghz1 = QuantumCircuit(max(best_qubit_chain) + 1, N)\n",
        "ghz1.h(best_qubit_chain[N // 2])\n",
        "for i in range(N // 2, 0, -1):\n",
        "    ghz1.cx(best_qubit_chain[i], best_qubit_chain[i - 1])\n",
        "for i in range(N // 2, N - 1, +1):\n",
        "    ghz1.cx(best_qubit_chain[i], best_qubit_chain[i + 1])\n",
        "ghz1.barrier()  # for visualization\n",
        "ghz1.measure(best_qubit_chain, list(range(N)))\n",
        "ghz1.draw(output=\"mpl\", idle_wires=False, scale=0.5, fold=-1)"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 44,
      "id": "facf25d3-add9-42e2-aeba-506b24a8e516",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "10"
            ]
          },
          "execution_count": 44,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "ghz1.depth()"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 45,
      "id": "71874b6d-eb9b-4ff5-b673-944191f67010",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<Image src=\"/learning/images/courses/utility-scale-quantum-computing/utility-iii/extracted-outputs/71874b6d-eb9b-4ff5-b673-944191f67010-0.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "execution_count": 45,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "pm = generate_preset_pass_manager(1, backend=backend)\n",
        "ghz1_transpiled = pm.run(ghz1)\n",
        "ghz1_transpiled.draw(output=\"mpl\", idle_wires=False, fold=-1)"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 46,
      "id": "9e1609a4-2b1c-43dc-99e0-ed62dbeb89fb",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "Depth: 27\n",
            "Two-qubit Depth: 8\n"
          ]
        }
      ],
      "source": [
        "print(\"Depth:\", ghz1_transpiled.depth())\n",
        "print(\n",
        "    \"Two-qubit Depth:\",\n",
        "    ghz1_transpiled.depth(filter_function=lambda x: x.operation.num_qubits == 2),\n",
        ")"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 47,
      "id": "5a3ad726-e6fb-4de5-a674-f7373845c917",
      "metadata": {},
      "outputs": [],
      "source": [
        "opts = SamplerOptions()"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "0178e4f4-cc5f-44f9-97b7-7393765e53f1",
      "metadata": {},
      "outputs": [],
      "source": [
        "res = execute_ghz_fidelity(\n",
        "    ghz_circuit=ghz1,\n",
        "    physical_qubits=best_qubit_chain,\n",
        "    backend=backend,\n",
        "    sampler_options=opts,\n",
        ")"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 55,
      "id": "d6368f70-1fb7-45ad-bd90-f3ca1b1795dc",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "DONE DONE\n"
          ]
        }
      ],
      "source": [
        "job_s = service.job(res[0])  # Use your job id showed above.\n",
        "job_e = service.job(res[1])\n",
        "print(job_s.status(), job_e.status())"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "cfebc599-d70d-4f1d-95b2-4c2ec60b1ee5",
      "metadata": {},
      "source": [
        "위의 작업 상태가 '완료'가 된 후 다음 셀을 실행하여 `check_ghz_fidelity_from_jobs` 함수를 사용하여 결과를 표시하도록 주의하세요.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 56,
      "id": "7029c582-6b41-4df5-b175-e098e0ee2e74",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "N=16: |00..0>: 153, |11..1>: 8681, |3rd>: 2262 (1111111111101111)\n",
            "P(|00..0>)=0.003825, P(|11..1>)=0.217025\n",
            "REM: Coherence (non-diagonal): 0.073809\n",
            "GHZ fidelity = 0.147329 ± 0.002438\n",
            "GME (genuinely multipartite entangled) test: Failed\n"
          ]
        }
      ],
      "source": [
        "N = 16\n",
        "# Check fidelity from job IDs\n",
        "res = check_ghz_fidelity_from_jobs(\n",
        "    sampler_job=job_s,\n",
        "    estimator_job=job_e,\n",
        "    num_qubits=N,\n",
        ")"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 57,
      "id": "236126cb",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<Image src=\"/learning/images/courses/utility-scale-quantum-computing/utility-iii/extracted-outputs/236126cb-0.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "execution_count": 57,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "result = job_s.result()\n",
        "plot_histogram(result[0].data.c.get_counts(), figsize=(30, 5))"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "3af2c82d-183e-4df0-be45-17fd32ea6c2e",
      "metadata": {},
      "source": [
        "이 결과는 기준을 충족하지 않습니다. 다음 아이디어로 넘어가겠습니다.\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "ce16e4cb",
      "metadata": {},
      "source": [
        "<span id=\"3-strategy-2-balanced-tree-of-qubits\" />\n",
        "\n",
        "## 3. 전략 2. 균형 잡힌 큐비트 트리\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "45d96784",
      "metadata": {},
      "source": [
        "다음 아이디어는 균형 잡힌 큐비트 트리를 찾는 것입니다. 체인이 아닌 트리를 사용하면 회로 깊이가 더 낮아져야 합니다. 그 전에 \"불량\" 판독 오류가 있는 노드와 \"불량\" 게이트 오류가 있는 에지를 커플링 그래프에서 제거합니다.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 58,
      "id": "632768ac",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "Bad readout qubits: [19, 28, 41, 72, 91, 114, 120]\n",
            "Bad ECR gates: []\n"
          ]
        }
      ],
      "source": [
        "BAD_READOUT_ERROR_THRESHOLD = 0.1\n",
        "BAD_ECRGATE_ERROR_THRESHOLD = 0.1\n",
        "bad_readout_qubits = [\n",
        "    q\n",
        "    for q in range(backend.num_qubits)\n",
        "    if backend.target[\"measure\"][(q,)].error > BAD_READOUT_ERROR_THRESHOLD\n",
        "]\n",
        "bad_ecrgate_edges = [\n",
        "    qpair\n",
        "    for qpair in backend.target[\"ecr\"]\n",
        "    if backend.target[\"ecr\"][qpair].error > BAD_ECRGATE_ERROR_THRESHOLD\n",
        "]\n",
        "print(\"Bad readout qubits:\", bad_readout_qubits)\n",
        "print(\"Bad ECR gates:\", bad_ecrgate_edges)"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 59,
      "id": "6775ea6b",
      "metadata": {},
      "outputs": [],
      "source": [
        "g = backend.coupling_map.graph.copy().to_undirected()\n",
        "g.remove_edges_from(\n",
        "    bad_ecrgate_edges\n",
        ")  # remove edge first (otherwise might fail with a NoEdgeBetweenNodes error)\n",
        "g.remove_nodes_from(bad_readout_qubits)"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "2247eb6b-a909-4fa1-91f4-40dfdf5f8d77",
      "metadata": {},
      "source": [
        "불량 에지와 불량 큐비트 없이 커플링 맵 그래프를 그려보겠습니다.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 60,
      "id": "18825a87-4679-4027-af58-31efd24a9a60",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<Image src=\"/learning/images/courses/utility-scale-quantum-computing/utility-iii/extracted-outputs/18825a87-4679-4027-af58-31efd24a9a60-0.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "execution_count": 60,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "qubit_color = []\n",
        "for i in range(133):\n",
        "    if i in bad_readout_qubits:\n",
        "        qubit_color.append(\"#000000\")  # black\n",
        "    else:\n",
        "        qubit_color.append(\"#8c00ff\")  # purple\n",
        "line_color = []\n",
        "for e in backend.target.build_coupling_map().get_edges():\n",
        "    if e in bad_ecrgate_edges:\n",
        "        line_color.append(\"#ffffff\")  # white\n",
        "    else:\n",
        "        line_color.append(\"#888888\")  # gray\n",
        "plot_gate_map(\n",
        "    backend,\n",
        "    qubit_color=qubit_color,\n",
        "    line_color=line_color,\n",
        "    qubit_size=50,\n",
        "    font_size=25,\n",
        "    figsize=(6, 6),\n",
        ")"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "5245dbee-e0fa-485d-a0fc-ce72b2739ccd",
      "metadata": {},
      "source": [
        "이전과 마찬가지로 16-비트 GHZ 상태를 만들려고 합니다.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 61,
      "id": "1affd16e",
      "metadata": {},
      "outputs": [],
      "source": [
        "N = 16"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "b0648130-ab85-477e-b754-94a3e28e2134",
      "metadata": {},
      "source": [
        "`betweenness_centrality` 함수를 호출하여 루트 노드에 대한 큐비트를 찾습니다. 사이 중심성 값이 가장 높은 노드가 그래프의 중앙에 위치합니다. 참조: [https://www.rustworkx.org/tutorial/betweenness\\_centrality.html](https://www.rustworkx.org/tutorial/betweenness_centrality.html)\n",
        "\n",
        "또는 수동으로 선택할 수도 있습니다.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 62,
      "id": "07ad8ee3-46f9-4c7b-ad96-5aaa45407999",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "66"
            ]
          },
          "execution_count": 62,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "# central = 65 #Select the center node manually\n",
        "c_degree = dict(rx.betweenness_centrality(g))\n",
        "central = max(c_degree, key=c_degree.get)\n",
        "central"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "5033164f-652a-4b72-a6f8-5fe52383e3f3",
      "metadata": {},
      "source": [
        "루트 노드에서 시작하여 BFS(폭 우선 검색)로 트리를 생성합니다. 참조: [https://qiskit.org/ecosystem/rustworkx/apiref/rustworkx.bfs\\_search.html #rustworkx-bfs-search](https://qiskit.org/ecosystem/rustworkx/apiref/rustworkx.bfs_search.html#rustworkx-bfs-search)\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 63,
      "id": "9137e5c8",
      "metadata": {},
      "outputs": [],
      "source": [
        "class TreeEdgesRecorder(rx.visit.BFSVisitor):\n",
        "    def __init__(self, N):\n",
        "        self.edges = []\n",
        "        self.N = N\n",
        "\n",
        "    def tree_edge(self, edge):\n",
        "        self.edges.append(edge)\n",
        "        if len(self.edges) >= self.N - 1:\n",
        "            raise rx.visit.StopSearch()\n",
        "\n",
        "\n",
        "vis = TreeEdgesRecorder(N)\n",
        "rx.bfs_search(g, [central], vis)\n",
        "best_qubits = sorted(list(set(q for e in vis.edges for q in (e[0], e[1]))))\n",
        "# print('Tree edges:', vis.edges)"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 64,
      "id": "69c447dc",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "Qubits selected: [54, 55, 63, 64, 65, 66, 67, 68, 69, 70, 73, 83, 84, 85, 86, 87]\n"
          ]
        }
      ],
      "source": [
        "print(\"Qubits selected:\", best_qubits)"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "ea5f9be4-fb66-4231-a9df-b49a510cceb9",
      "metadata": {},
      "source": [
        "커플링 맵 다이어그램에서 분홍색으로 표시된 선택된 큐비트를 플롯해 보겠습니다.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 65,
      "id": "ef18e037-a3ec-4370-bee7-bd71dbc12795",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<Image src=\"/learning/images/courses/utility-scale-quantum-computing/utility-iii/extracted-outputs/ef18e037-a3ec-4370-bee7-bd71dbc12795-0.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "execution_count": 65,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "qubit_color = []\n",
        "for i in range(133):\n",
        "    if i in bad_readout_qubits:\n",
        "        qubit_color.append(\"#000000\")  # black\n",
        "    elif i in best_qubits:\n",
        "        qubit_color.append(\"#ff00dd\")  # pink\n",
        "    else:\n",
        "        qubit_color.append(\"#8c00ff\")  # purple\n",
        "plot_gate_map(\n",
        "    backend,\n",
        "    qubit_color=qubit_color,\n",
        "    line_color=line_color,\n",
        "    qubit_size=50,\n",
        "    font_size=25,\n",
        "    figsize=(6, 6),\n",
        ")"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "c766256c-a9b8-41c1-ad23-1862f1e36b38",
      "metadata": {},
      "source": [
        "큐비트의 트리 구조를 보여드리겠습니다.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 66,
      "id": "8758d3a6",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<Image src=\"/learning/images/courses/utility-scale-quantum-computing/utility-iii/extracted-outputs/8758d3a6-0.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "execution_count": 66,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "from rustworkx.visualization import graphviz_draw\n",
        "\n",
        "tree = rx.PyDiGraph()\n",
        "tree.extend_from_weighted_edge_list(vis.edges)\n",
        "tree.remove_nodes_from([n for n in range(max(best_qubits) + 1) if n not in best_qubits])\n",
        "\n",
        "graphviz_draw(tree, method=\"dot\")"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 67,
      "id": "3bc4b071",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<Image src=\"/learning/images/courses/utility-scale-quantum-computing/utility-iii/extracted-outputs/3bc4b071-0.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "execution_count": 67,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "ghz2 = QuantumCircuit(max(best_qubits) + 1, N)\n",
        "\n",
        "ghz2.h(tree.edge_list()[0][0])  # apply H-gate to the root node\n",
        "# Apply CNOT from the root node to the each edge.\n",
        "for u, v in tree.edge_list():\n",
        "    ghz2.cx(u, v)\n",
        "ghz2.barrier()  # for visualization\n",
        "ghz2.measure(best_qubits, list(range(N)))\n",
        "ghz2.draw(output=\"mpl\", idle_wires=False, scale=0.5)"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 68,
      "id": "fd2978ee-b359-464e-bf7f-eed4a65b1203",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "8"
            ]
          },
          "execution_count": 68,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "ghz2.depth()"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 69,
      "id": "c490e37a-309a-43e3-9b18-3be7c7d8a957",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<Image src=\"/learning/images/courses/utility-scale-quantum-computing/utility-iii/extracted-outputs/c490e37a-309a-43e3-9b18-3be7c7d8a957-0.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "execution_count": 69,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "pm = generate_preset_pass_manager(1, backend=backend)\n",
        "ghz2_transpiled = pm.run(ghz2)\n",
        "ghz2_transpiled.draw(output=\"mpl\", idle_wires=False, fold=-1)"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 70,
      "id": "376dfe4e-53c9-4eb5-988e-2bc7674ddcad",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "Depth: 22\n",
            "Two-qubit Depth: 6\n"
          ]
        }
      ],
      "source": [
        "print(\"Depth:\", ghz2_transpiled.depth())\n",
        "print(\n",
        "    \"Two-qubit Depth:\",\n",
        "    ghz2_transpiled.depth(filter_function=lambda x: x.operation.num_qubits == 2),\n",
        ")"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "f5681336-b72d-4ec9-a60e-2101fa42d87e",
      "metadata": {},
      "source": [
        "이제 회로의 깊이가 체인 구조의 깊이보다 훨씬 낮아졌습니다.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "c56889ab-b8cd-4a7e-90f0-8a05d12e9f3f",
      "metadata": {},
      "outputs": [],
      "source": [
        "res = execute_ghz_fidelity(\n",
        "    ghz_circuit=ghz2,\n",
        "    physical_qubits=best_qubits,\n",
        "    backend=backend,\n",
        "    sampler_options=opts,\n",
        ")"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 74,
      "id": "daf011fe-853c-4e55-89ff-eeab38cb0de4",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "DONE DONE\n"
          ]
        }
      ],
      "source": [
        "job_s = service.job(res[0])  # Use your job id showed above.\n",
        "job_e = service.job(res[1])\n",
        "print(job_s.status(), job_e.status())"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 75,
      "id": "51aee0d4-c896-4d2b-843a-3c58ee7572bb",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "N=16: |00..0>: 9509, |11..1>: 10978, |3rd>: 1795 (1111110111111111)\n",
            "P(|00..0>)=0.237725, P(|11..1>)=0.27445\n",
            "REM: Coherence (non-diagonal): 0.606515\n",
            "GHZ fidelity = 0.559345 ± 0.003188\n",
            "GME (genuinely multipartite entangled) test: Passed\n"
          ]
        }
      ],
      "source": [
        "N = 16\n",
        "# Check fidelity from job IDs\n",
        "res = check_ghz_fidelity_from_jobs(\n",
        "    sampler_job=job_s,\n",
        "    estimator_job=job_e,\n",
        "    num_qubits=N,\n",
        ")"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "7fe25d70-36e3-4442-b150-21ea47143050",
      "metadata": {},
      "source": [
        "균형 잡힌 트리 구조로 기준을 성공적으로 통과했습니다!\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 76,
      "id": "cf8b4dac",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<Image src=\"/learning/images/courses/utility-scale-quantum-computing/utility-iii/extracted-outputs/cf8b4dac-0.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "execution_count": 76,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "result = job_s.result()\n",
        "plot_histogram(result[0].data.c.get_counts(), figsize=(30, 5))"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "40bc77d5-be60-4360-9750-31d0f1459ab0",
      "metadata": {},
      "source": [
        "이제 더 큰 GHZ 상태인 30-큐비트 GHZ 상태를 생성해 보겠습니다.\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "816914ce-52dd-4df5-9943-0acc606240c3",
      "metadata": {},
      "source": [
        "<span id=\"31-n-=-30\" />\n",
        "\n",
        "### 3.1 N = 30\n",
        "\n",
        "저희는 [키스킷 패턴](/docs/guides/intro-to-patterns) 프레임워크를 따를 것입니다.\n",
        "\n",
        "* 1단계: 양자 회로 및 연산자에 문제 매핑하기\n",
        "* 2단계: 대상 하드웨어에 최적화\n",
        "* 3단계: 대상 하드웨어에서 실행\n",
        "* 4단계: 포스트 프로세스 결과\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "20e6b416-eee7-4728-9fef-0de34b5ecbac",
      "metadata": {},
      "source": [
        "<span id=\"step-1-map-problem-to-quantum-circuits-and-operators-and-step-2-optimize-for-target-hardware\" />\n",
        "\n",
        "#### 1단계: 문제를 양자 회로 및 연산자로 매핑하고 2단계: 대상 하드웨어에 최적화\n",
        "\n",
        "여기서는 루트 노드를 수동으로 선택합니다.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 77,
      "id": "5fff1f72-062f-4c3c-84b9-87e3af368f31",
      "metadata": {},
      "outputs": [],
      "source": [
        "central = 62  # Select the center node manually\n",
        "# c_degree = dict(rx.betweenness_centrality(g))\n",
        "# central = max(c_degree, key=c_degree.get)\n",
        "# central"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 78,
      "id": "693e80bb-e967-41be-bd82-85e4346fd6aa",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "Qubits selected: [34, 35, 42, 43, 44, 45, 46, 47, 48, 53, 54, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 71, 73, 77, 84, 85, 86]\n"
          ]
        }
      ],
      "source": [
        "N = 30\n",
        "\n",
        "vis = TreeEdgesRecorder(N)\n",
        "rx.bfs_search(g, [central], vis)\n",
        "best_qubits = sorted(list(set(q for e in vis.edges for q in (e[0], e[1]))))\n",
        "print(\"Qubits selected:\", best_qubits)"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 79,
      "id": "12d3ac00-7dfc-4734-9881-4e6385f2d880",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<Image src=\"/learning/images/courses/utility-scale-quantum-computing/utility-iii/extracted-outputs/12d3ac00-7dfc-4734-9881-4e6385f2d880-0.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "execution_count": 79,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "qubit_color = []\n",
        "for i in range(133):\n",
        "    if i in bad_readout_qubits:\n",
        "        qubit_color.append(\"#000000\")\n",
        "    elif i in best_qubits:\n",
        "        qubit_color.append(\"#ff00dd\")\n",
        "    else:\n",
        "        qubit_color.append(\"#8c00ff\")\n",
        "line_color = []\n",
        "for e in backend.target.build_coupling_map().get_edges():\n",
        "    if e in bad_ecrgate_edges:\n",
        "        line_color.append(\"#ffffff\")\n",
        "    else:\n",
        "        line_color.append(\"#888888\")\n",
        "plot_gate_map(\n",
        "    backend,\n",
        "    qubit_color=qubit_color,\n",
        "    line_color=line_color,\n",
        "    qubit_size=50,\n",
        "    font_size=25,\n",
        "    figsize=(6, 6),\n",
        ")"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 80,
      "id": "6afd6c54-b427-4f34-8c4c-285c0122aebd",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<Image src=\"/learning/images/courses/utility-scale-quantum-computing/utility-iii/extracted-outputs/6afd6c54-b427-4f34-8c4c-285c0122aebd-0.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "execution_count": 80,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "from rustworkx.visualization import graphviz_draw\n",
        "\n",
        "tree = rx.PyDiGraph()\n",
        "tree.extend_from_weighted_edge_list(vis.edges)\n",
        "tree.remove_nodes_from([n for n in range(max(best_qubits) + 1) if n not in best_qubits])\n",
        "\n",
        "graphviz_draw(tree, method=\"dot\")"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "70b0b915-478e-4d65-9840-fb3db3e0fd0e",
      "metadata": {},
      "source": [
        "이 트리의 깊이는 5입니다.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 81,
      "id": "d36cdb58-59fe-474e-9a31-a2d9e806ab59",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<Image src=\"/learning/images/courses/utility-scale-quantum-computing/utility-iii/extracted-outputs/d36cdb58-59fe-474e-9a31-a2d9e806ab59-0.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "execution_count": 81,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "ghz3 = QuantumCircuit(max(best_qubits) + 1, N)\n",
        "\n",
        "ghz3.h(tree.edge_list()[0][0])  # apply H-gate to the root node\n",
        "# Apply CNOT from the root node to the each edge.\n",
        "for u, v in tree.edge_list():\n",
        "    ghz3.cx(u, v)\n",
        "ghz3.barrier()  # for visualization\n",
        "ghz3.measure(best_qubits, list(range(N)))\n",
        "ghz3.draw(output=\"mpl\", idle_wires=False, fold=-1)"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 82,
      "id": "1b1dfb32-bcbf-4107-80df-4b36c166b88b",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "11"
            ]
          },
          "execution_count": 82,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "ghz3.depth()"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 83,
      "id": "46df385d-dd28-4fab-8344-6ef2fd53906d",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<Image src=\"/learning/images/courses/utility-scale-quantum-computing/utility-iii/extracted-outputs/46df385d-dd28-4fab-8344-6ef2fd53906d-0.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "execution_count": 83,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "pm = generate_preset_pass_manager(1, backend=backend)\n",
        "ghz3_transpiled = pm.run(ghz3)\n",
        "ghz3_transpiled.draw(output=\"mpl\", idle_wires=False, fold=-1)"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 84,
      "id": "74af05ba-132e-480d-ac5d-7b3bb4f4f0e4",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "Depth: 31\n",
            "Two-qubit Depth: 9\n"
          ]
        }
      ],
      "source": [
        "print(\"Depth:\", ghz3_transpiled.depth())\n",
        "print(\n",
        "    \"Two-qubit Depth:\",\n",
        "    ghz3_transpiled.depth(filter_function=lambda x: x.operation.num_qubits == 2),\n",
        ")"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "fb74efcc-9db1-49b0-9f53-f5de236c6f29",
      "metadata": {},
      "source": [
        "<span id=\"32-select-a-different-root-node-manually\" />\n",
        "\n",
        "### 3.2 다른 루트 노드를 수동으로 선택하십시오\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 85,
      "id": "fb72a71a-8176-4b62-ac51-5a75469f0256",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "Qubits selected: [23, 24, 25, 34, 35, 42, 43, 44, 45, 46, 47, 48, 49, 50, 54, 55, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 73, 84, 85, 86]\n"
          ]
        }
      ],
      "source": [
        "central = 54\n",
        "\n",
        "vis = TreeEdgesRecorder(N)\n",
        "rx.bfs_search(g, [central], vis)\n",
        "best_qubits = sorted(list(set(q for e in vis.edges for q in (e[0], e[1]))))\n",
        "print(\"Qubits selected:\", best_qubits)"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 86,
      "id": "5e2e2af5-34b5-4bb5-b393-18e87d56db08",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<Image src=\"/learning/images/courses/utility-scale-quantum-computing/utility-iii/extracted-outputs/5e2e2af5-34b5-4bb5-b393-18e87d56db08-0.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "execution_count": 86,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "from rustworkx.visualization import graphviz_draw\n",
        "\n",
        "tree = rx.PyDiGraph()\n",
        "tree.extend_from_weighted_edge_list(vis.edges)\n",
        "tree.remove_nodes_from([n for n in range(max(best_qubits) + 1) if n not in best_qubits])\n",
        "\n",
        "graphviz_draw(tree, method=\"dot\")"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "0c481352-267a-4a34-85aa-32149bc4674a",
      "metadata": {},
      "source": [
        "이 트리의 깊이는 6입니다.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 87,
      "id": "5d81d890-a939-455f-81a6-c7e671671ba5",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<Image src=\"/learning/images/courses/utility-scale-quantum-computing/utility-iii/extracted-outputs/5d81d890-a939-455f-81a6-c7e671671ba5-0.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "execution_count": 87,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "ghz3 = QuantumCircuit(max(best_qubits) + 1, N)\n",
        "\n",
        "ghz3.h(tree.edge_list()[0][0])  # apply H-gate to the root node\n",
        "# Apply CNOT from the root node to the each edge.\n",
        "for u, v in tree.edge_list():\n",
        "    ghz3.cx(u, v)\n",
        "ghz3.barrier()  # for visualization\n",
        "ghz3.measure(best_qubits, list(range(N)))\n",
        "ghz3.draw(output=\"mpl\", idle_wires=False, fold=-1)"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 88,
      "id": "b3ae6f53-c321-4a31-b4c7-8dea94267503",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "11"
            ]
          },
          "execution_count": 88,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "ghz3.depth()"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 89,
      "id": "b9823b6d-a658-40ef-a509-f03e33534af6",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<Image src=\"/learning/images/courses/utility-scale-quantum-computing/utility-iii/extracted-outputs/b9823b6d-a658-40ef-a509-f03e33534af6-0.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "execution_count": 89,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "pm = generate_preset_pass_manager(1, backend=backend)\n",
        "ghz3_transpiled = pm.run(ghz3)\n",
        "ghz3_transpiled.draw(output=\"mpl\", idle_wires=False, fold=-1)"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 90,
      "id": "57a59793-c96b-4286-9ffc-76a3861f454c",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "Depth: 30\n",
            "Two-qubit Depth: 9\n"
          ]
        }
      ],
      "source": [
        "print(\"Depth:\", ghz3_transpiled.depth())\n",
        "print(\n",
        "    \"Two-qubit Depth:\",\n",
        "    ghz3_transpiled.depth(filter_function=lambda x: x.operation.num_qubits == 2),\n",
        ")"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "1b80ecf5-2bc0-4fc4-835e-e4cf40bcf9d9",
      "metadata": {},
      "source": [
        "놀랍게도 트리 깊이는 5에서 6으로 증가한 반면, 2쿼트 깊이는 9에서 8로 감소했습니다! 따라서 후자의 회로를 사용하겠습니다.\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "7046ce9c-cce8-4fca-9875-f9ef78ccc488",
      "metadata": {},
      "source": [
        "<span id=\"step-3-execute-on-target-hardware\" />\n",
        "\n",
        "#### 3단계: 대상 하드웨어에서 실행\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "4ca22249-5efa-4ea1-a88e-f89d3235260b",
      "metadata": {},
      "outputs": [],
      "source": [
        "res = execute_ghz_fidelity(\n",
        "    ghz_circuit=ghz3,\n",
        "    physical_qubits=best_qubits,\n",
        "    backend=backend,\n",
        "    sampler_options=opts,\n",
        ")"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 95,
      "id": "bfbabf7e-421c-4ccd-8dfd-ec8cf5c14ebc",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "DONE DONE\n"
          ]
        }
      ],
      "source": [
        "job_s = service.job(res[0])  # Use your job id showed above.\n",
        "job_e = service.job(res[1])\n",
        "print(job_s.status(), job_e.status())"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "7615f4df-9efe-435a-9521-356041db7b8f",
      "metadata": {},
      "source": [
        "<span id=\"step-4-post-process-results\" />\n",
        "\n",
        "#### 4단계: 결과 후처리\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 96,
      "id": "670788ad-a209-4d0d-9b6d-9961b8d06900",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "N=30: |00..0>: 4, |11..1>: 218, |3rd>: 265 (111111111111111011111111111111)\n",
            "P(|00..0>)=0.0001, P(|11..1>)=0.00545\n",
            "REM: Coherence (non-diagonal): 0.187073\n",
            "GHZ fidelity = 0.096312 ± 0.003254\n",
            "GME (genuinely multipartite entangled) test: Failed\n"
          ]
        }
      ],
      "source": [
        "N = 30\n",
        "# Check fidelity from job IDs\n",
        "res = check_ghz_fidelity_from_jobs(\n",
        "    sampler_job=job_s,\n",
        "    estimator_job=job_e,\n",
        "    num_qubits=N,\n",
        ")"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "6eb15797-36a9-4844-b7ec-14a607f6a784",
      "metadata": {},
      "source": [
        "보시다시피 이 결과는 기준을 충족하지 못했습니다.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 97,
      "id": "66c87870",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<Image src=\"/learning/images/courses/utility-scale-quantum-computing/utility-iii/extracted-outputs/66c87870-0.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "execution_count": 97,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "# It will take some time\n",
        "result = job_s.result()\n",
        "plot_histogram(result[0].data.c.get_counts(), figsize=(30, 5))"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "43a2f073-b19c-46b4-a7b4-40d2c705c3b7",
      "metadata": {},
      "source": [
        "<span id=\"4-strategy-3-run-with-the-error-suppression-options\" />\n",
        "\n",
        "## 4. 전략 3. 오류 억제 옵션으로 실행\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "2c40dc0f-93a0-4fae-980f-b7c5ab449a40",
      "metadata": {},
      "source": [
        "Sampler의 ‘ V2 ’에서 오류 억제 옵션을 설정할 수 있습니다. 자세한 내용은 [샘플러 노이즈 관리](/docs/guides/sampler-noise-management) 가이드와 API [`ExecutionOptionsV2`](/docs/api/qiskit-ibm-runtime/options-execution-options-v2) 참조 문서를 참조하십시오.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 98,
      "id": "04f91676-6218-4875-bc44-5281b83a0718",
      "metadata": {},
      "outputs": [],
      "source": [
        "opts = SamplerOptions()\n",
        "opts.dynamical_decoupling.enable = True\n",
        "opts.execution.rep_delay = 0.0005\n",
        "opts.twirling.enable_gates = True"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "8e630f61-ae43-46ee-85d6-daf0cd89f94d",
      "metadata": {},
      "outputs": [],
      "source": [
        "res = execute_ghz_fidelity(\n",
        "    ghz_circuit=ghz3,\n",
        "    physical_qubits=best_qubits,\n",
        "    backend=backend,\n",
        "    sampler_options=opts,\n",
        ")"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 105,
      "id": "42b659d3-e003-45d4-b460-8a3db6995e34",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "DONE DONE\n"
          ]
        }
      ],
      "source": [
        "job_s = service.job(res[0])  # Use your job id showed above.\n",
        "job_e = service.job(res[1])\n",
        "print(job_s.status(), job_e.status())"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 106,
      "id": "bf3cc6a7-4d02-4f90-a411-57fc2eac0513",
      "metadata": {},
      "outputs": [],
      "source": [
        "N = 30"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 107,
      "id": "1faa3e59-386e-47e3-ae96-101ecb3c08df",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "N=30: |00..0>: 1459, |11..1>: 1543, |3rd>: 359 (111111111111111111111111111110)\n",
            "P(|00..0>)=0.036475, P(|11..1>)=0.038575\n",
            "REM: Coherence (non-diagonal): 0.165532\n",
            "GHZ fidelity = 0.120291 ± 0.003369\n",
            "GME (genuinely multipartite entangled) test: Failed\n"
          ]
        }
      ],
      "source": [
        "# Check fidelity from job IDs\n",
        "res = check_ghz_fidelity_from_jobs(\n",
        "    sampler_job=job_s,\n",
        "    estimator_job=job_e,\n",
        "    num_qubits=N,\n",
        ")"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 108,
      "id": "166856be-ad3a-40d6-837c-3eedda374891",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<Image src=\"/learning/images/courses/utility-scale-quantum-computing/utility-iii/extracted-outputs/166856be-ad3a-40d6-837c-3eedda374891-0.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "execution_count": 108,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "# It will take some time\n",
        "result = job_s.result()\n",
        "plot_histogram(result[0].data.c.get_counts(), figsize=(30, 5))"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "c8547268-3604-4fe9-b52c-f48f0d036647",
      "metadata": {},
      "source": [
        "결과가 개선되었지만 여전히 기준을 충족하지 못했습니다.\n",
        "\n",
        "지금까지 세 가지 아이디어를 살펴봤습니다. 이러한 아이디어를 결합하고 확장하거나 자신만의 아이디어를 떠올려 더 나은 GHZ 회로를 만들 수 있습니다. 이제 목표를 다시 검토해 보겠습니다.\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "70b460c8",
      "metadata": {},
      "source": [
        "<span id=\"5-your-goal-recap\" />\n",
        "\n",
        "## 5. 당신의 목표 (요약)\n",
        "\n",
        "측정 결과가 기준을 충족하도록 20큐비트 이상의 GHZ 회로를 구축합니다: GHZ 상태의 충실도 > 0.5.\n",
        "\n",
        "* Eagle 디바이스(예: `ibm_brisbane`)를 사용하고 촬영 횟수를 40,000회로 설정해야 합니다.\n",
        "* `execute_ghz_fidelity` 함수를 사용하여 GHZ 회로를 실행하고 `check_ghz_fidelity_from_jobs` 함수를 사용하여 충실도를 계산해야 합니다.\n",
        "  기준을 충족하는 가장 큰 큐비트인 GHZ 회로를 찾아야 합니다. 아래에 코드를 작성하고 `check_ghz_fidelity_from_jobs` 함수를 사용하여 결과를 표시합니다.\n",
        "\n",
        "이제 이전 자료에서와 동일한 GHZ 워크플로우를 Heron 기기에서 구현합니다. 이를 통해 Heron 프로세서의 레이아웃과 기능에 대해 어느 정도 경험할 수 있습니다. 새로운 전략이 도입되지 않습니다.\n",
        "\n",
        "*이 다음 실험을 실행하는 데 걸리는 대략적인 QPU 시간은 4분 40초입니다.*\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "2db80d2a-1c87-4d94-a2d5-17db3fddbb96",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "Device ibm_kingston Loaded with 156 qubits\n",
            "Two Qubit Gate: cz\n"
          ]
        }
      ],
      "source": [
        "service = QiskitRuntimeService()\n",
        "backend = service.backend(\"ibm_kingston\")\n",
        "# backend = service.backend(\"ibm_fez\")\n",
        "\n",
        "twoq_gate = \"cz\"\n",
        "print(f\"Device {backend.name} Loaded with {backend.num_qubits} qubits\")\n",
        "print(f\"Two Qubit Gate: {twoq_gate}\")"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 141,
      "id": "5490bc61-0f0d-411b-b9bc-53d68ff2f877",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "Bad readout qubits: [112, 113, 120, 131, 146]\n",
            "Bad CZ gates: [(111, 112), (112, 111), (112, 113), (113, 112), (120, 121), (121, 120), (130, 131), (131, 130), (145, 146), (146, 145), (146, 147), (147, 146)]\n"
          ]
        }
      ],
      "source": [
        "BAD_READOUT_ERROR_THRESHOLD = 0.1\n",
        "BAD_CZGATE_ERROR_THRESHOLD = 0.1\n",
        "bad_readout_qubits = [\n",
        "    q\n",
        "    for q in range(backend.num_qubits)\n",
        "    if backend.target[\"measure\"][(q,)].error > BAD_READOUT_ERROR_THRESHOLD\n",
        "]\n",
        "bad_czgate_edges = [\n",
        "    qpair\n",
        "    for qpair in backend.target[\"cz\"]\n",
        "    if backend.target[\"cz\"][qpair].error > BAD_CZGATE_ERROR_THRESHOLD\n",
        "]\n",
        "print(\"Bad readout qubits:\", bad_readout_qubits)\n",
        "print(\"Bad CZ gates:\", bad_czgate_edges)"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 142,
      "id": "71df32ed-4b7c-4a7a-8fcf-bd508478b6ad",
      "metadata": {},
      "outputs": [],
      "source": [
        "g = backend.coupling_map.graph.copy().to_undirected()\n",
        "g.remove_edges_from(\n",
        "    bad_czgate_edges\n",
        ")  # remove edge first (otherwise might fail with a NoEdgeBetweenNodes error)\n",
        "g.remove_nodes_from(bad_readout_qubits)"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 145,
      "id": "e4336cf4-95e6-41a2-b24c-74d1cec53c36",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<Image src=\"/learning/images/courses/utility-scale-quantum-computing/utility-iii/extracted-outputs/e4336cf4-95e6-41a2-b24c-74d1cec53c36-0.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "execution_count": 145,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "qubit_color = []\n",
        "for i in range(backend.num_qubits):\n",
        "    if i in bad_readout_qubits:\n",
        "        qubit_color.append(\"#000000\")  # black\n",
        "    else:\n",
        "        qubit_color.append(\"#8c00ff\")  # purple\n",
        "line_color = []\n",
        "for e in backend.target.build_coupling_map().get_edges():\n",
        "    if e in bad_czgate_edges:\n",
        "        line_color.append(\"#ffffff\")  # white\n",
        "    else:\n",
        "        line_color.append(\"#888888\")  # gray\n",
        "plot_gate_map(\n",
        "    backend,\n",
        "    qubit_color=qubit_color,\n",
        "    line_color=line_color,\n",
        "    qubit_size=60,\n",
        "    font_size=30,\n",
        "    figsize=(10, 10),\n",
        ")"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 146,
      "id": "5afaf902-a59f-4ae9-b4fb-95b9d861676e",
      "metadata": {},
      "outputs": [],
      "source": [
        "N = 40\n",
        "central = 100  # Select the center node manually\n",
        "# c_degree = dict(rx.betweenness_centrality(g))\n",
        "# central = max(c_degree, key=c_degree.get)\n",
        "# central"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 147,
      "id": "24bf4ea2-dd6f-442e-a989-5c8b29e93847",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "Qubits selected: [61, 65, 76, 77, 80, 81, 82, 83, 84, 85, 86, 87, 96, 97, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 116, 117, 121, 122, 123, 124, 125, 126, 127, 136, 140, 141, 142, 143, 144, 145]\n"
          ]
        }
      ],
      "source": [
        "class TreeEdgesRecorder(rx.visit.BFSVisitor):\n",
        "    def __init__(self, N):\n",
        "        self.edges = []\n",
        "        self.N = N\n",
        "\n",
        "    def tree_edge(self, edge):\n",
        "        self.edges.append(edge)\n",
        "        if len(self.edges) >= self.N - 1:\n",
        "            raise rx.visit.StopSearch()\n",
        "\n",
        "\n",
        "vis = TreeEdgesRecorder(N)\n",
        "rx.bfs_search(g, [central], vis)\n",
        "best_qubits = sorted(list(set(q for e in vis.edges for q in (e[0], e[1]))))\n",
        "print(\"Qubits selected:\", best_qubits)"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 149,
      "id": "e684af6c-aa99-460d-b0f5-9d5042fb80b0",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<Image src=\"/learning/images/courses/utility-scale-quantum-computing/utility-iii/extracted-outputs/e684af6c-aa99-460d-b0f5-9d5042fb80b0-0.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "execution_count": 149,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "qubit_color = []\n",
        "for i in range(backend.num_qubits):\n",
        "    if i in bad_readout_qubits:\n",
        "        qubit_color.append(\"#000000\")\n",
        "    elif i in best_qubits:\n",
        "        qubit_color.append(\"#ff00dd\")\n",
        "    else:\n",
        "        qubit_color.append(\"#8c00ff\")\n",
        "line_color = []\n",
        "for e in backend.target.build_coupling_map().get_edges():\n",
        "    if e in bad_czgate_edges:\n",
        "        line_color.append(\"#ffffff\")\n",
        "    else:\n",
        "        line_color.append(\"#888888\")\n",
        "plot_gate_map(\n",
        "    backend,\n",
        "    qubit_color=qubit_color,\n",
        "    line_color=line_color,\n",
        "    qubit_size=60,\n",
        "    font_size=30,\n",
        "    figsize=(10, 10),\n",
        ")"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 150,
      "id": "f3ff2dd9-a304-409c-a0e4-3b23e85f282e",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<Image src=\"/learning/images/courses/utility-scale-quantum-computing/utility-iii/extracted-outputs/f3ff2dd9-a304-409c-a0e4-3b23e85f282e-0.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "execution_count": 150,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "from rustworkx.visualization import graphviz_draw\n",
        "\n",
        "tree = rx.PyDiGraph()\n",
        "tree.extend_from_weighted_edge_list(vis.edges)\n",
        "tree.remove_nodes_from([n for n in range(max(best_qubits) + 1) if n not in best_qubits])\n",
        "\n",
        "graphviz_draw(tree, method=\"dot\")"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 151,
      "id": "60b6526c-55ed-4621-b91b-4ceeef34de62",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<Image src=\"/learning/images/courses/utility-scale-quantum-computing/utility-iii/extracted-outputs/60b6526c-55ed-4621-b91b-4ceeef34de62-0.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "execution_count": 151,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "ghz_h = QuantumCircuit(max(best_qubits) + 1, N)\n",
        "\n",
        "ghz_h.h(tree.edge_list()[0][0])  # apply H-gate to the root node\n",
        "# Apply CNOT from the root node to the each edge.\n",
        "for u, v in tree.edge_list():\n",
        "    ghz_h.cx(u, v)\n",
        "ghz_h.barrier()  # for visualization\n",
        "ghz_h.measure(best_qubits, list(range(N)))\n",
        "ghz_h.draw(output=\"mpl\", idle_wires=False, fold=-1)"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 152,
      "id": "1365cbef-f587-4a34-9d68-5f1d9afc0f43",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "15"
            ]
          },
          "execution_count": 152,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "ghz_h.depth()"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 153,
      "id": "b96e6342-e08b-4728-8985-7a015ee16797",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<Image src=\"/learning/images/courses/utility-scale-quantum-computing/utility-iii/extracted-outputs/b96e6342-e08b-4728-8985-7a015ee16797-0.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "execution_count": 153,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "pm = generate_preset_pass_manager(1, backend=backend)\n",
        "ghz_h_transpiled = pm.run(ghz_h)\n",
        "ghz_h_transpiled.draw(output=\"mpl\", idle_wires=False, fold=-1)"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 154,
      "id": "614a2f14-aff8-4942-8709-9a40c5e041d9",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "Depth: 45\n",
            "Two-qubit Depth: 13\n"
          ]
        }
      ],
      "source": [
        "print(\"Depth:\", ghz_h_transpiled.depth())\n",
        "print(\n",
        "    \"Two-qubit Depth:\",\n",
        "    ghz_h_transpiled.depth(filter_function=lambda x: x.operation.num_qubits == 2),\n",
        ")"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 155,
      "id": "da2e2f98-b79b-42bd-8fbd-3ccb824c6729",
      "metadata": {},
      "outputs": [],
      "source": [
        "opts = SamplerOptions()\n",
        "opts.dynamical_decoupling.enable = True\n",
        "opts.execution.rep_delay = 0.0005\n",
        "opts.twirling.enable_gates = True"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "0d659b1b-fe1a-4e42-ac8c-08b05514590b",
      "metadata": {},
      "outputs": [],
      "source": [
        "res = execute_ghz_fidelity(\n",
        "    ghz_circuit=ghz_h,\n",
        "    physical_qubits=best_qubits,\n",
        "    backend=backend,\n",
        "    sampler_options=opts,\n",
        ")"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 174,
      "id": "0162d22f-899c-4fed-86b8-dbb45673c2c0",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "RUNNING RUNNING\n"
          ]
        }
      ],
      "source": [
        "job_s = service.job(res[0])  # Use your job id showed above.\n",
        "job_e = service.job(res[1])\n",
        "print(job_s.status(), job_e.status())"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 170,
      "id": "c6d1bad8-381c-4ba9-be2f-b1575741af53",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "N=40: |00..0>: 3186, |11..1>: 3277, |3rd>: 620 (1111111011111111111111111111111111111111)\n",
            "P(|00..0>)=0.07965, P(|11..1>)=0.081925\n",
            "REM: Coherence (non-diagonal): 0.029987\n",
            "GHZ fidelity = 0.095781 ± 0.002619\n",
            "GME (genuinely multipartite entangled) test: Failed\n"
          ]
        }
      ],
      "source": [
        "# Check fidelity from job IDs\n",
        "N = 40\n",
        "res = check_ghz_fidelity_from_jobs(\n",
        "    sampler_job=job_s,\n",
        "    estimator_job=job_e,\n",
        "    num_qubits=N,\n",
        ")"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 171,
      "id": "671f57ea-7117-4d17-998f-73baa6f4463e",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<Image src=\"/learning/images/courses/utility-scale-quantum-computing/utility-iii/extracted-outputs/671f57ea-7117-4d17-998f-73baa6f4463e-0.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "execution_count": 171,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "# It will take some time\n",
        "result = job_s.result()\n",
        "plot_histogram(result[0].data.c.get_counts(), figsize=(30, 5))"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "c817f572-1c67-4ed8-b466-ecdf5c41d88b",
      "metadata": {},
      "source": [
        "축하합니다! 유틸리티 규모의 양자 컴퓨팅에 대한 소개를 완료하셨습니다! 이제 여러분은 양자 우위를 추구하는 데 의미 있는 기여를 할 준비가 되었습니다! IBM 퀀텀®을 개인 양자 여정의 일부로 만들어 주셔서 감사합니다.\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "1ddd145f",
      "metadata": {},
      "source": [
        "<span id=\"post-course-survey\" />\n",
        "\n",
        "## 수강 후 설문조사\n",
        "\n",
        "이 과정을 완료하신 것을 축하드립니다! 잠시 시간을 내어 다음의 [간단한 설문조사에](https://your.feedback.ibm.com/jfe/form/SV_5vvmdT5yFFetkgK) 참여하여 강좌를 개선하는 데 도움을 주세요. 여러분의 피드백은 콘텐츠 제공과 사용자 경험을 개선하는 데 사용됩니다. 감사합니다!\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
}