{
  "cells": [
    {
      "cell_type": "markdown",
      "id": "a10c2a41-ab48-4da5-bbe1-a16fd47906fe",
      "metadata": {},
      "source": [
        "---\n",
        "title: \"니시모리 상전이\"\n",
        "description: \"이 튜토리얼은 퀀텀 컴퓨팅 시스템( IBM ) 양자 프로세서에서 니시모리 위상 전이를 구현하는 방법을 보여줍니다.\"\n",
        "---\n",
        "\n",
        "{/* cspell:ignore Verresen Layden Tantivasadakarn Vishwanath Trebst */}\n",
        "\n",
        "<span id=\"nishimori-phase-transition\" />\n",
        "\n",
        "# 니시모리 상전이\n",
        "\n",
        "*예상 소요 시간: Heron r2 프로세서에서 3분 (참고: 이는 단지 예상치일 뿐입니다.) (실행 시간은 다를 수 있습니다.)*\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "6113a1ff-5cc0-433a-afd7-5aadc97bb28f",
      "metadata": {},
      "source": [
        "<span id=\"learning-outcomes\" />\n",
        "\n",
        "## 학습 성과\n",
        "\n",
        "* 니시모리 상전이 현상을 이해하고, 이것이 무작위 결합 이징 모델에서 장거리 얽힘의 출현으로 어떻게 나타나는지 파악한다.\n",
        "* 회로 중간 측정과 정수심 회로를 사용하여 양자 하드웨어에서 *측정 기반 얽힘 생성* (GEM) 프로토콜을 구현한다.\n",
        "* 실험 데이터에서 자화도의 2점 상관관계와 정규화된 분산을 추출하여 이 전이 현상을 특성화한다.\n",
        "\n",
        "<span id=\"prerequisites\" />\n",
        "\n",
        "## 전제조건\n",
        "\n",
        "* 『 [Measure qubits](/docs/guides/measure-qubits) 』 가이드, 특히 GEM 프로토콜이 기반으로 하는 회로 중간 측정 관련 섹션.\n",
        "* [Qiskit Aer 기본 요소를 사용한 정확한 시뮬레이션과 잡음이 포함된 시뮬레이션](/docs/guides/simulate-with-qiskit-aer). 이것이 바로 소규모 섹션이 실행되는 방식입니다.\n",
        "* [동적 회로를 이용한 장거리 얽힘](/docs/tutorials/long-range-entanglement) : 동일한 측정 기반 얽힘 패러다임을 사용하는 관련 튜토리얼입니다.\n",
        "* [헤비-헥스 격자(Heavy-hex lattice)](https://www.ibm.com/quantum/blog/heavy-hex-lattice), 즉 플라켓 격자가 구축된 헤비-헥스-플라켓( IBM® ) 하드웨어 토폴로지.\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "838ac5c7-0819-4482-8875-c57db88ba82a",
      "metadata": {},
      "source": [
        "<span id=\"background\" />\n",
        "\n",
        "## 배경\n",
        "\n",
        "이 튜토리얼에서는 양자 프로세서에서 니시모리 상전이를 구현하는 방법을 설명합니다. 이 실험은 원래 [*“일정 깊이의 양자 회로에서 오류 임계값을 넘어서는 니시모리 전이 구현”이라는*](https://arxiv.org/abs/2309.02863) 논문에서 처음 소개되었다.\n",
        "\n",
        "니시모리 상전이란 무작위 결합 이징 모델에서 단거리 및 장거리 정렬 상 사이의 전이를 말한다. 양자 컴퓨터에서 장거리 정렬 상은 장치 전체에 걸쳐 큐비트들이 얽혀 있는 상태로 나타납니다. 이 고도로 얽힌 상태는 *‘측정을 통한 얽힘 생성* (GEM)’ 프로토콜을 사용하여 구현됩니다. GEM 프로토콜은 회로 중간 측정 방식을 활용함으로써, 깊이가 일정하게 유지되는 회로만을 사용하여 장치 전체에 걸쳐 큐비트를 얽힐 수 있게 합니다. 이 튜토리얼에서는 [GEM Suite](https://github.com/qiskit-community/gem-suite) 소프트웨어 패키지에 포함된 GEM 프로토콜 구현을 사용합니다.\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "4091005d-ecd5-40c9-b90f-263e49a4cc16",
      "metadata": {},
      "source": [
        "<span id=\"requirements\" />\n",
        "\n",
        "## 요구사항\n",
        "\n",
        "이 튜토리얼을 시작하기 전에 다음이 설치되어 있는지 확인하세요:\n",
        "\n",
        "* Qiskit SDK v1.0 또는 이후 버전, [시각화](/docs/api/qiskit/visualization) 지원 기능 포함\n",
        "* Qiskit Runtime v0.22 또는 그 이후 (`pip install qiskit-ibm-runtime`)\n",
        "* Qiskit Aer v0.14 이상 (`pip install qiskit-aer`)\n",
        "* GEM Suite (`pip install gem-suite`)\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "210b8730-ca3e-46d9-b8b0-64c36f13df8e",
      "metadata": {},
      "source": [
        "<span id=\"setup\" />\n",
        "\n",
        "## 설정\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 1,
      "id": "4ad70734-54f8-400a-8399-188ee8a0f3ac",
      "metadata": {},
      "outputs": [],
      "source": [
        "import matplotlib.pyplot as plt\n",
        "import warnings\n",
        "\n",
        "from collections import defaultdict\n",
        "\n",
        "from qiskit_ibm_runtime import QiskitRuntimeService\n",
        "from qiskit_aer import AerSimulator\n",
        "\n",
        "from qiskit.transpiler import generate_preset_pass_manager\n",
        "\n",
        "from gem_suite import PlaquetteLattice\n",
        "from gem_suite.experiments import GemExperiment"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "281ec87e-3f50-44b6-8e6f-a906b92fba74",
      "metadata": {},
      "source": [
        "<span id=\"small-scale-simulator-example\" />\n",
        "\n",
        "## 소규모 시뮬레이터 예시\n",
        "\n",
        "`AerSimulator`이 섹션에서는 노이즈가 없는 환경에서 전체 워크플로를 단계별로 살펴봅니다. 플라켓 격자는 단일 플라켓(12 큐비트)으로 제한되어 있어 시뮬레이션 규모를 작고 빠르게 유지하면서도, GEM 프로토콜의 모든 단계, 즉 회로 중간 측정, $R_{ZZ}$ 각도 스윕, 디코딩, 정규화 분산 분석을 모두 수행할 수 있습니다. 나중에 동일한 워크플로를 여러 개의 플라켓과 실제 하드웨어상의 전체 격자 구조로 확장합니다.\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "39f59f3a-eb2a-4160-9da2-2bb83c58771c",
      "metadata": {},
      "source": [
        "<span id=\"step-1-map-classical-inputs-to-a-quantum-problem\" />\n",
        "\n",
        "### 1단계: 고전적 입력을 양자 문제에 매핑하기\n",
        "\n",
        "GEM 프로토콜은 격자로 표현되는 큐비트 연결성을 가진 양자 프로세서에서 작동합니다. 오늘날의 IBM Quantum® 프로세서들은 [헤비-헥스](https://www.ibm.com/quantum/blog/heavy-hex-lattice) 격자를 사용합니다. 프로세서상의 큐비트는 격자 내의 어느 단위 셀을 차지하고 있는지에 따라 *플라켓* 으로 묶입니다. 큐비트가 하나 이상의 단위 셀에 존재할 수 있기 때문에, 플라켓들은 서로 교집합을 이루지 않습니다. 헤비-헥스 격자에서, 하나의 플라켓은 12개의 큐비트를 포함합니다. 플라켓 자체도 격자를 형성하며, 두 플라켓은 큐비트를 하나라도 공유할 경우 서로 연결됩니다. 무거운 헥스 격자에서, 인접한 플라켓들은 세 개의 큐비트를 공유한다.\n",
        "\n",
        "`PlaquetteLattice`GEM Suite 소프트웨어 패키지에서 GEM 프로토콜을 구현하기 위한 기본 클래스는 로, 이는 플라켓 격자(헤비-헥스 격자와는 구별됨)를 나타냅니다. A는 `PlaquetteLattice` 큐비트 결합 맵을 통해 초기화될 수 있다. 현재는 헤비-헥스 커플링 맵만 지원됩니다.\n",
        "\n",
        "다음 코드 셀은 양자 처리 장치(QPU)의 결합 맵을 기반으로 플라켓 격자를 초기화합니다. 플라켓 격자가 항상 하드웨어 전체를 아우르는 것은 아닙니다. 예를 들어, `ibm_torino` 는 총 133개의 큐비트를 가지고 있지만, 이 장치에 들어갈 수 있는 가장 큰 플라켓 격자는 그중 125개만 사용하며, 18개의 플라켓으로 구성됩니다. `ibm_pittsburgh` (156 큐비트) 역시 144개의 큐비트를 21개의 플라켓에 배치합니다. 큐비트 수가 다른 다른 헤비-헥스 QPU의 경우에도 동일한 패턴이 나타납니다.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "553dbafe-1778-4971-83c3-0408605b701d",
      "metadata": {},
      "outputs": [],
      "source": [
        "service = QiskitRuntimeService()\n",
        "backend = service.least_busy(\n",
        "    operational=True, simulator=False, min_num_qubits=127\n",
        ")\n",
        "aer_backend = AerSimulator.from_backend(backend)\n",
        "plaquette_lattice = PlaquetteLattice.from_coupling_map(backend.coupling_map)\n",
        "\n",
        "print(f\"Number of qubits in backend: {backend.num_qubits}\")\n",
        "print(\n",
        "    f\"Number of qubits in plaquette lattice: {len(list(plaquette_lattice.qubits()))}\"\n",
        ")\n",
        "print(f\"Number of plaquettes: {len(list(plaquette_lattice.plaquettes()))}\")"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "0bf43539-d782-44a9-ba4e-a1b6c7510803",
      "metadata": {},
      "source": [
        "플래퀘트 격자를 그래프로 표현한 다이어그램을 생성하여 시각화할 수 있습니다. 다이어그램에서 플라켓은 레이블이 지정된 육각형으로 표시되며, 두 플라켓이 큐비트를 공유하는 경우 가장자리로 연결됩니다.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 3,
      "id": "625882a4-faeb-4d96-b441-c989f43c4dea",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<Image src=\"/docs/images/tutorials/nishimori-phase-transition/extracted-outputs/625882a4-faeb-4d96-b441-c989f43c4dea-0.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "execution_count": 3,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "plaquette_lattice.draw_plaquettes()"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "2f0a6b73-d1d2-4117-80cf-6fe3adbb82c5",
      "metadata": {},
      "source": [
        "`plaquettes` 방법을 사용하여 포함된 큐비트와 같은 개별 플라켓에 대한 정보를 검색할 수 있습니다.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 4,
      "id": "e412a612-c7d5-4689-840a-2383dd538f06",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "PyPlaquette(index=0, qubits=[3, 4, 5, 6, 7, 16, 17, 23, 24, 25, 26, 27], neighbors=[4, 3, 1])"
            ]
          },
          "execution_count": 4,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "# Get a list of the plaquettes\n",
        "plaquettes = list(plaquette_lattice.plaquettes())\n",
        "# Display information about plaquette 0\n",
        "plaquettes[0]"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "75edf1b4-f95f-4ff7-9e3c-2e810711636f",
      "metadata": {},
      "source": [
        "플라퀘트 격자를 형성하는 기본 큐비트의 다이어그램을 생성할 수도 있습니다.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 5,
      "id": "a19d63ce-3572-4081-a008-c1332fbbe303",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<Image src=\"/docs/images/tutorials/nishimori-phase-transition/extracted-outputs/a19d63ce-3572-4081-a008-c1332fbbe303-0.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "execution_count": 5,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "plaquette_lattice.draw_qubits()"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "e7b0f54b-5bc2-42bb-b4d4-1346f0a902e3",
      "metadata": {},
      "source": [
        "이 다이어그램에는 큐비트 레이블과 연결된 큐비트를 나타내는 가장자리 외에도 GEM 프로토콜과 관련된 세 가지 추가 정보가 포함되어 있습니다:\n",
        "\n",
        "* 각 큐비트는 음영 처리(회색)되거나 음영 처리되지 않습니다. 음영 처리된 큐비트는 Ising 모델의 사이트를 나타내는 \"사이트\" 큐비트이며, 음영 처리되지 않은 큐비트는 사이트 큐비트 간의 상호작용을 중재하는 데 사용되는 \"본드\" 큐비트입니다.\n",
        "* 각 사이트 큐비트에는 (A) 또는 (B) 레이블이 붙어 있으며, 이는 사이트 큐비트가 GEM 프로토콜에서 수행할 수 있는 두 가지 역할 중 하나를 나타냅니다(역할은 나중에 설명합니다).\n",
        "* 각 변은 여섯 가지 색상 중 하나로 색칠되어, 변들이 여섯 개의 그룹으로 나뉩니다. 이러한 분할 방식은 2-큐비트 게이트를 어떻게 병렬화할 수 있는지를 결정할 뿐만 아니라, 잡음이 있는 양자 프로세서에서 서로 다른 오류 발생량을 초래할 가능성이 있는 다양한 스케줄링 패턴을 결정하기도 합니다. 그룹 내의 변들은 서로 겹치지 않기 때문에, 두 큐비트 게이트로 구성된 레이어를 해당 변들에 동시에 적용할 수 있다. 사실, 여섯 가지 색을 두 가지 색으로 이루어진 세 그룹으로 나눌 수 있는데, 이때 각 두 가지 색으로 이루어진 그룹의 합집합은 여전히 서로 교집합이 없도록 할 수 있다. 따라서 모든 에지를 활성화하는 데는 2-큐비트 게이트 3층만 있으면 됩니다. 이 방식으로 6가지 색상을 나누는 방법은 12가지가 있으며, 이러한 각 분할 방식은 서로 다른 3단계 게이트 일정을 만들어 냅니다.\n",
        "\n",
        "플라켓 격자를 생성했으니, 다음 단계는 플라켓 격자와 실험을 실행할 백엔드를 모두 전달하여 객체를 `GemExperiment` 초기화하는 것입니다. 이 `GemExperiment` 클래스는 회로 생성, 작업 제출, 데이터 분석 등을 포함하여 GEM 프로토콜의 실제 구현을 관리합니다. 다음 코드 셀은 실험 클래스를 초기화하면서 플라켓 격자를 단일 플라켓(12 큐비트)으로 제한하여, 시뮬레이션을 소규모로 유지하고 실행 속도를 높입니다. 실제 하드웨어로 확장할 때는 풀 플라켓 격자가 사용됩니다.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 6,
      "id": "02357c6e-5c83-4ac0-811d-22602d9f33d5",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<Image src=\"/docs/images/tutorials/nishimori-phase-transition/extracted-outputs/02357c6e-5c83-4ac0-811d-22602d9f33d5-0.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "execution_count": 6,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "# Filter the plaquette lattice down to a single plaquette (12 qubits)\n",
        "# so the AerSimulator run stays fast. The full lattice is used later\n",
        "# in the large-scale hardware example.\n",
        "gem_exp = GemExperiment(plaquette_lattice.filter([9]), backend=aer_backend)\n",
        "\n",
        "# visualize the plaquette lattice after filtering\n",
        "plaquette_lattice.filter([9]).draw_qubits()"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "3234e018-a1a8-47b7-b10c-57d6f7f77ff1",
      "metadata": {},
      "source": [
        "GEM 프로토콜 회로는 다음 단계에 따라 구축됩니다:\n",
        "\n",
        "1. 모든 큐비트에 Hadamard 게이트를 적용하여 모든 $|+\\rangle$ 상태를 준비합니다.\n",
        "2. 연결된 모든 큐비트 쌍 사이에 ‘ $R_{ZZ}$ ’ 게이트를 적용합니다. 게이트를 세 겹으로 쌓아 이 작업을 수행할 수 있습니다. 각 $R_{ZZ}$ 게이트는 사이트 큐비트와 결합 큐비트에 작용합니다. 사이트 큐비트에 (B) 라벨이 붙어 있다면, 각도는 $\\frac{\\pi}{2}$ 로 고정됩니다. 사이트 큐비트에 (A) 라벨이 붙어 있다면, 각도가 변할 수 있어 서로 다른 회로가 생성됩니다. 기본적으로 각도 범위는 $0$ 에서 $\\frac{\\pi}{2}$ 까지(양 끝점 포함)의 구간을 균등한 간격으로 나눈 21개 지점으로 설정되어 있습니다.\n",
        "3. 각 본드 큐비트를 파울리 $X$ 기저에서 측정한다. 큐비트는 파울리 $Z$ 기저로 측정되므로, 큐비트를 측정하기 전에 하다마르 게이트를 적용하면 됩니다.\n",
        "\n",
        "이 자습서 소개에 인용된 논문에서는 $R_{ZZ}$ 각도에 대해 다른 규칙을 사용하며, 이 자습서에서 사용하는 규칙과 2배 차이가 납니다.\n",
        "\n",
        "세 번째 단계에서는 본드 큐비트만 측정됩니다. 사이트 큐비트가 어떤 상태에 머무르는지 이해하기 위해서는, 2단계에서 사이트 큐비트(A)에 적용된 $R_{ZZ}$ 각도가 $\\frac{\\pi}{2}$ 와 같다고 가정해 보는 것이 도움이 된다. 이 경우, 사이트 큐비트는 GHZ 상태와 유사한 고도로 얽힌 상태로 남게 되며,\n",
        "\n",
        "$$\n",
        "\\lvert \\text{GHZ} \\rangle = \\lvert 00 \\cdots 00 \\rangle + \\lvert 11 \\cdots 11 \\rangle.\n",
        "$$\n",
        "\n",
        "측정 결과의 무작위성으로 인해, 사이트 큐비트의 실제 상태는 장거리 질서를 띤 다른 상태, 예를 들어 $\\lvert 00110 \\rangle + \\lvert 11001 \\rangle$ 일 수도 있다. 그러나 측정 결과를 바탕으로 한 복호화 연산을 적용함으로써 GHZ 상태를 복원할 수 있다. $R_{ZZ}$ 각도가 $\\frac{\\pi}{2}$ 에서 감소하더라도, 임계 각도까지는 장거리 질서가 여전히 회복될 수 있으며, 이 임계 각도는 잡음이 없는 경우 대략 $0.3 \\pi$ 입니다. 이 각도 이하에서는 결과적인 상태가 더 이상 장거리 얽힘을 나타내지 않습니다. 장거리 질서의 유무 사이의 이러한 전환을 니시모리 상전이라고 한다.\n",
        "\n",
        "위의 설명에서 사이트 큐비트는 측정되지 않은 상태로 남겨졌으며, 양자 게이트를 적용하여 디코딩 연산을 수행할 수 있습니다. GEM 스위트에서 구현된 실험에서는, 사이트 큐비트가 실제로 측정되며, 디코딩 연산은 고전적인 사후 처리 단계에서 수행됩니다.\n",
        "\n",
        "위의 설명에서, 디코딩 연산은 해당 위치의 큐비트에 양자 게이트를 적용하여 양자 상태를 복원함으로써 수행될 수 있다. 그러나 (예를 들어 특성 분석과 같은) 상태를 즉시 측정하는 것이 목적이라면, 사이트 큐비트와 본드 큐비트를 함께 측정한 다음, 고전적인 사후 처리 단계에서 디코딩 연산을 적용할 수 있습니다.\n",
        "\n",
        "GEM 프로토콜 회로는 2단계에서 ‘ $R_{ZZ}$ ’ 각도에 의존할 뿐만 아니라(기본적으로 21개의 값을 순차적으로 탐색함), $R_{ZZ}$ 게이트의 세 계층을 구현하는 데 사용되는 스케줄링 패턴에도 의존합니다. 앞서 언급한 바와 같이, 이러한 스케줄링 패턴은 총 12가지가 있습니다. 따라서, 이 실험에서 회로의 총 개수는 $21 \\times 12 = 252$ 입니다.\n",
        "\n",
        "이 실험의 회로는 클래스의 `GemExperiment` 메서드를 `circuits` 사용하여 생성할 수 있습니다.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 7,
      "id": "8e2ade62-9a57-42c3-9a85-3fe2dec3c426",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "Total number of circuits: 252\n"
          ]
        }
      ],
      "source": [
        "circuits = gem_exp.circuits()\n",
        "print(f\"Total number of circuits: {len(circuits)}\")"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "56c3c656-dcfa-4ca0-9df9-2d97c187c685",
      "metadata": {},
      "source": [
        "이 튜토리얼에서는 하나의 스케줄링 패턴만 고려하는 것으로 충분합니다. 다음 코드 셀은 실험을 첫 번째 스케줄링 패턴으로 제한합니다. 결과적으로 이 실험에는 각 $R_{ZZ}$ 각도마다 하나씩 총 21개의 회로만 있습니다.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 8,
      "id": "4f8a2c73-752d-47b9-95d5-83439933fc08",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "Total number of circuits: 21\n",
            "RZZ angles:\n",
            "[0.         0.07853982 0.15707963 0.23561945 0.31415927 0.39269908\n",
            " 0.4712389  0.54977871 0.62831853 0.70685835 0.78539816 0.86393798\n",
            " 0.9424778  1.02101761 1.09955743 1.17809725 1.25663706 1.33517688\n",
            " 1.41371669 1.49225651 1.57079633]\n"
          ]
        }
      ],
      "source": [
        "# Restrict experiment to the first scheduling pattern\n",
        "gem_exp.set_experiment_options(schedule_idx=0)\n",
        "\n",
        "# There are less circuits now\n",
        "circuits = gem_exp.circuits()\n",
        "print(f\"Total number of circuits: {len(circuits)}\")\n",
        "\n",
        "# Print the RZZ angles swept over\n",
        "print(f\"RZZ angles:\\n{gem_exp.parameters()}\")"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "7011dc79-8561-42ef-909b-00fd8be9ef34",
      "metadata": {},
      "source": [
        "다음 코드 셀은 인덱스 5에 회로의 다이어그램을 그립니다. 다이어그램의 크기를 줄이기 위해 회로 끝에 있는 측정 게이트가 제거됩니다.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 9,
      "id": "fd57d483-c70b-4ad5-b309-15750ad38bac",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<Image src=\"/docs/images/tutorials/nishimori-phase-transition/extracted-outputs/fd57d483-c70b-4ad5-b309-15750ad38bac-0.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "execution_count": 9,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "# Get the circuit at index 5\n",
        "circuit = circuits[5]\n",
        "# Remove the final measurements to ease visualization\n",
        "circuit.remove_final_measurements()\n",
        "# Draw the circuit\n",
        "circuit.draw(\"mpl\", fold=-1, scale=0.5)"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "a3aa063b-44cf-49f3-9e12-23b2f6a1c85b",
      "metadata": {},
      "source": [
        "<span id=\"step-2-optimize-problem-for-quantum-hardware-execution\" />\n",
        "\n",
        "### 2단계: 양자 하드웨어 실행을 위한 문제 최적화\n",
        "\n",
        "하드웨어에서 실행하기 위해 양자 회로를 트랜스파일링하는 과정은 일반적으로 [여러 단계를](/docs/guides/transpiler-stages) 거칩니다. 일반적으로 가장 많은 계산 오버헤드가 발생하는 단계는 큐비트 배치를 결정하고, 하드웨어의 큐비트 연결 구조에 맞춰 2-큐비트 게이트를 배선하며, 게이트 수와 회로 깊이를 최소화하기 위해 회로를 최적화하는 과정입니다. GEM 프로토콜에서는 하드웨어 연결성이 이미 프로토콜 설계에 포함되어 있으므로 레이아웃 및 라우팅 단계가 필요하지 않습니다. 이 회로에는 이미 큐비트 배치가 이루어져 있으며, 2큐비트 게이트는 이미 기본 연결에 매핑되어 있습니다. 또한, $R_{ZZ}$ 의 각도가 변할 때 회로의 구조를 유지하기 위해서는 매우 기본적인 회로 최적화만 수행해야 합니다.\n",
        "\n",
        "`GemExperiment` 클래스는 실험을 실행할 때 회로를 투명하게 투명화합니다. 레이아웃 및 라우팅 단계는 기본적으로 아무것도 하지 않도록 이미 재정의되어 있으며, 회로 최적화는 단일 큐비트 게이트만 최적화하는 수준에서 수행됩니다. 그러나 `set_transpile_options` 메서드를 사용하여 추가 옵션을 재정의하거나 전달할 수 있습니다. 시각화를 위해 다음 코드 셀은 이전에 표시된 회로를 수동으로 트랜스파일링하고 트랜스파일링된 회로를 그립니다.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 10,
      "id": "e9b99d48-8d33-46b5-bff5-480ab1c1c1f2",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<Image src=\"/docs/images/tutorials/nishimori-phase-transition/extracted-outputs/e9b99d48-8d33-46b5-bff5-480ab1c1c1f2-0.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "execution_count": 10,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "# Demonstrate setting transpile options\n",
        "gem_exp.set_transpile_options(\n",
        "    optimization_level=1  # This is the default optimization level\n",
        ")\n",
        "pass_manager = generate_preset_pass_manager(\n",
        "    backend=aer_backend,\n",
        "    initial_layout=list(gem_exp.physical_qubits),\n",
        "    **dict(gem_exp.transpile_options),\n",
        ")\n",
        "transpiled = pass_manager.run(circuit)\n",
        "transpiled.draw(\"mpl\", idle_wires=False, fold=-1, scale=0.5)"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "8d0dcd59-54ef-4af8-9213-0784ef94b838",
      "metadata": {},
      "source": [
        "<span id=\"step-3-execute-using-qiskit-primitives\" />\n",
        "\n",
        "### 3단계: `Qiskit primitives` 명령어로 실행합니다\n",
        "\n",
        "하드웨어에서 GEM 프로토콜 회로를 실행하려면 `GemExperiment` 객체의 `run` 메서드를 호출합니다. 각 회로에서 샘플링할 샷 수를 지정할 수 있습니다. `run` 메서드는 변수에 저장해야 하는 [ExperimentData](https://qiskit-community.github.io/qiskit-experiments/stubs/qiskit_experiments.framework.ExperimentData.html) 객체를 반환하며, 이 객체를 변수에 저장해야 합니다. `run` 메서드는 작업이 완료될 때까지 기다리지 않고 작업만 제출하므로 비차단 호출이라는 점에 유의하세요.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 11,
      "id": "6171a383-dd58-4e3f-88aa-bbec7b5870df",
      "metadata": {},
      "outputs": [],
      "source": [
        "exp_data = gem_exp.run(shots=10_000)"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "71e81552-0d33-4950-8d45-e6c0a8a056c9",
      "metadata": {},
      "source": [
        "결과를 기다리려면 `ExperimentData` 객체의 `block_for_results` 메서드를 호출합니다. 이 호출은 작업이 완료될 때까지 통역사가 중단됩니다.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 12,
      "id": "ed14a067-35ba-4ffc-8534-4ae5ec6bc4c9",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "ExperimentData(GemExperiment, 90bf2a90-f729-4c4e-a6da-664aecb11039, job_ids=['04a7c405-47fd-46ca-aa4b-aaf7e339cfbe'], metadata=<5 items>, figure_names=['two_point_correlation.svg', 'normalized_variance.svg', 'plaquette_ops.svg', 'bond_ops.svg'])"
            ]
          },
          "execution_count": 12,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "# The noiseless AerSimulator produces zero-variance UFloat objects in the\n",
        "# analysis, which triggers a harmless warning from the `uncertainties`\n",
        "# library. Suppress it so the output stays clean.\n",
        "with warnings.catch_warnings():\n",
        "    warnings.filterwarnings(\n",
        "        \"ignore\", message=\"Using UFloat objects with std_dev==0\"\n",
        "    )\n",
        "    exp_data.block_for_results()\n",
        "exp_data"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "36e0570b-f091-45f2-bb83-143edbc3b433",
      "metadata": {},
      "source": [
        "<span id=\"step-4-post-process-and-return-result-in-desired-classical-format\" />\n",
        "\n",
        "### 4단계: 후처리 수행 및 원하는 클래식 형식으로 결과 반환\n",
        "\n",
        "$R_{ZZ}$ 각도 $\\frac{\\pi}{2}$ 에서 디코딩된 상태는 노이즈가 없을 때 GHZ 상태가 됩니다. 측정된 비트스트링의 자화도를 플로팅하여 GHZ 상태의 장거리 순서를 시각화할 수 있습니다. 자화 $M$ 는 단일 큐비트 폴리 $Z$ 연산자의 합으로 정의됩니다,\n",
        "\n",
        "$$\n",
        "M = \\sum_{j=1}^N Z_j,\n",
        "$$\n",
        "\n",
        "여기서 $N$ 는 사이트 큐비트의 개수이다. 비트열에 대한 이 값은 0의 개수와 1의 개수 사이의 차와 같습니다. GHZ 상태를 측정하면 0으로만 구성된 상태와 1로만 구성된 상태가 동등한 확률로 나타나므로, 자화 방향은 절반의 시간 동안 $+N$ 이고, 나머지 절반의 시간 동안 $-N$ 이 될 것이다. 잡음으로 인한 오차가 존재할 경우 다른 값들도 나타날 수 있지만, 잡음이 그리 크지 않다면 분포는 여전히 $+N$ 및 $-N$ 근처에서 최대값을 보일 것입니다.\n",
        "\n",
        "디코딩 전 원시 비트스트링의 경우, 자화 분포는 노이즈가 없는 경우 균일하게 무작위 비트스트링의 분포와 동일합니다.\n",
        "\n",
        "다음 코드 셀은 $\\frac{\\pi}{2}$ 의 $R_{ZZ}$ 각도에서 원시 비트스트링과 디코딩된 비트스트링의 자화도를 플롯합니다.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 13,
      "id": "8ead3582-16df-4616-836c-bdce867ad6b8",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "Text(0.5, 1.0, 'Magnetization distribution with and without decoding')"
            ]
          },
          "execution_count": 13,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": [
              "<Image src=\"/docs/images/tutorials/nishimori-phase-transition/extracted-outputs/8ead3582-16df-4616-836c-bdce867ad6b8-1.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "metadata": {},
          "output_type": "display_data"
        }
      ],
      "source": [
        "def magnetization_distribution(\n",
        "    counts_dict: dict[str, int],\n",
        ") -> dict[str, float]:\n",
        "    \"\"\"Compute magnetization distribution from counts dictionary.\"\"\"\n",
        "    # Construct dictionary from magnetization to count\n",
        "    mag_dist = defaultdict(float)\n",
        "    for bitstring, count in counts_dict.items():\n",
        "        mag = bitstring.count(\"0\") - bitstring.count(\"1\")\n",
        "        mag_dist[mag] += count\n",
        "    # Normalize\n",
        "    shots = sum(counts_dict.values())\n",
        "    for mag in mag_dist:\n",
        "        mag_dist[mag] /= shots\n",
        "    return mag_dist\n",
        "\n",
        "\n",
        "# Get counts dictionaries with and without decoding\n",
        "data = exp_data.data()\n",
        "# Get the last data point, which is at the angle for the GHZ state\n",
        "raw_counts = data[-1][\"counts\"]\n",
        "# Without decoding\n",
        "site_indices = [\n",
        "    i for i, q in enumerate(gem_exp.plaquettes.qubits()) if q.role == \"Site\"\n",
        "]\n",
        "site_raw_counts = defaultdict(int)\n",
        "for key, val in raw_counts.items():\n",
        "    site_str = \"\".join(key[-1 - i] for i in site_indices)\n",
        "    site_raw_counts[site_str] += val\n",
        "# With decoding\n",
        "_, site_decoded_counts = gem_exp.plaquettes.decode_outcomes(\n",
        "    raw_counts, return_counts=True\n",
        ")\n",
        "\n",
        "# Compute magnetization distribution\n",
        "raw_magnetization = magnetization_distribution(site_raw_counts)\n",
        "decoded_magnetization = magnetization_distribution(site_decoded_counts)\n",
        "\n",
        "# Plot\n",
        "plt.bar(*zip(*raw_magnetization.items()), label=\"raw\")\n",
        "plt.bar(*zip(*decoded_magnetization.items()), label=\"decoded\", width=0.3)\n",
        "plt.legend()\n",
        "plt.xlabel(\"Magnetization\")\n",
        "plt.ylabel(\"Frequency\")\n",
        "plt.title(\"Magnetization distribution with and without decoding\")"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "90a7ae7a-5175-421f-bda9-bc6b986bdf5f",
      "metadata": {},
      "source": [
        "장거리 주문을 보다 엄격하게 특성화하려면 다음과 같이 정의된 평균 2점 상관관계( $f$ )를 조사할 수 있습니다\n",
        "\n",
        "$$\n",
        "f = \\frac{1}{N^2} \\left(\\langle M^2 \\rangle - \\langle M \\rangle ^2\\right).\n",
        "$$\n",
        "\n",
        "값이 클수록 얽힘 정도가 심함을 나타냅니다. `GemExperiment` 클래스는 실험 데이터 처리의 일부로 디코딩된 비트스트링에 대해 이 값을 자동으로 계산합니다. 실험 데이터 클래스의 `figure` 메서드를 통해 액세스할 수 있는 수치를 저장합니다. 이 경우 그림의 이름은 `two_point_correlation` 입니다.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 14,
      "id": "4ecb25c8-e572-49af-a879-9943039db131",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<Image src=\"/docs/images/tutorials/nishimori-phase-transition/extracted-outputs/4ecb25c8-e572-49af-a879-9943039db131-0.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "execution_count": 14,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "exp_data.figure(\"two_point_correlation\")"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "f2f3e7e2-2a8b-4790-8ba7-b190c4ed1049",
      "metadata": {},
      "source": [
        "니시모리 상 전이의 임계점을 결정하려면 다음과 같이 정의된 $M^2 / N$ 의 정규화된 분산을 살펴볼 수 있습니다\n",
        "\n",
        "$$\n",
        "g = \\frac{1}{N^3} \\left(\\langle M^4 \\rangle - \\langle M^2 \\rangle^2\\right),\n",
        "$$\n",
        "\n",
        "는 자화 제곱의 변동량을 정량화한 값입니다. 이 값은 니시모리 상전이 임계점에서 최대화됩니다. 노이즈가 없는 경우 임계점은 대략 $0.3 \\pi$ 에서 발생합니다. 노이즈가 있는 경우 임계점은 더 높게 이동하지만 임계점이 $0.5 \\pi$ 이하에서 발생하는 한 상전이가 여전히 관찰됩니다.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 15,
      "id": "2b351d68-3924-445a-94ef-047b16214e8a",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<Image src=\"/docs/images/tutorials/nishimori-phase-transition/extracted-outputs/2b351d68-3924-445a-94ef-047b16214e8a-0.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "execution_count": 15,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "exp_data.figure(\"normalized_variance\")"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "a94e0cbe-8429-487c-b203-50a8b2eacee3",
      "metadata": {},
      "source": [
        "<span id=\"large-scale-hardware-example\" />\n",
        "\n",
        "## 대규모 하드웨어 예시\n",
        "\n",
        "시뮬레이터에서 프로토콜을 검증했으므로, 이제 실험 규모를 확대하여 [‘설정’](#setup) 섹션에서 선택한 실제 양자 하드웨어 백엔드에서 실행할 수 있습니다. 이 예제에서는 두 가지 더 큰 문제 규모를 사용합니다:\n",
        "\n",
        "* **6개의 플라켓(\\~49 큐비트)** : 하드웨어 노이즈 하에서 임계점이 우측으로 이동하는 현상을 이미 보여주는 중간 규모의 실험이다.\n",
        "* `ibm_pittsburgh`**전체 플라켓 격자** : 장치의 헤비-헥스 토폴로지가 지원하는 모든 플라켓(예: 에서 `ibm_torino` 18개 플라켓 / 125 큐비트 또는 에서 21개 플라켓 / 144 큐비트)에 대해, 일정한 깊이의 회로를 사용하여 장치 전체에 걸쳐 큐비트 간 얽힘을 생성합니다.\n",
        "\n",
        "아래의 단일 코드 셀은 독립적으로 작동합니다. 이 셀은 백엔드의 결합 맵을 기반으로 플라켓 격자를 구축하고 두 실험을 모두 실행하므로, 이 섹션은 소규모 실험 섹션을 먼저 실행하지 않고도 [‘Setup’](#setup) 셀들 이후에 바로 실행할 수 있습니다.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "08581c09-a6a5-4a56-9fc4-abf22b063c6a",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "Total number of circuits (full lattice): 21\n"
          ]
        },
        {
          "data": {
            "text/plain": [
              "<Image src=\"/docs/images/tutorials/nishimori-phase-transition/extracted-outputs/08581c09-a6a5-4a56-9fc4-abf22b063c6a-1.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "metadata": {},
          "output_type": "display_data"
        },
        {
          "data": {
            "text/plain": [
              "<Image src=\"/docs/images/tutorials/nishimori-phase-transition/extracted-outputs/08581c09-a6a5-4a56-9fc4-abf22b063c6a-2.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "metadata": {},
          "output_type": "display_data"
        },
        {
          "data": {
            "text/plain": [
              "<Image src=\"/docs/images/tutorials/nishimori-phase-transition/extracted-outputs/08581c09-a6a5-4a56-9fc4-abf22b063c6a-3.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "execution_count": 16,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "# -------------------------Step 1-------------------------\n",
        "# Initialize the runtime service, pick a real quantum hardware backend,\n",
        "# and build the plaquette lattice from its coupling map. This is repeated\n",
        "# from the small-scale example so this cell can run standalone after the\n",
        "# Setup section. The full plaquette lattice is the \"large-scale\" target;\n",
        "# a six-plaquette subset (range(3, 9)) is also used to show an intermediate\n",
        "# scaling step.\n",
        "service = QiskitRuntimeService()\n",
        "backend = service.least_busy(\n",
        "    operational=True, simulator=False, min_num_qubits=127\n",
        ")\n",
        "plaquette_lattice = PlaquetteLattice.from_coupling_map(backend.coupling_map)\n",
        "\n",
        "# Build a GemExperiment for the full plaquette lattice and one for the\n",
        "# six-plaquette subset, each restricted to a single scheduling pattern so\n",
        "# the experiment has one circuit per RZZ angle (21 circuits total).\n",
        "gem_exp_full = GemExperiment(plaquette_lattice, backend=backend)\n",
        "gem_exp_full.set_experiment_options(schedule_idx=0)\n",
        "gem_exp_6 = GemExperiment(\n",
        "    plaquette_lattice.filter(range(3, 9)), backend=backend\n",
        ")\n",
        "gem_exp_6.set_experiment_options(schedule_idx=0)\n",
        "\n",
        "circuits = gem_exp_full.circuits()\n",
        "print(f\"Total number of circuits (full lattice): {len(circuits)}\")\n",
        "\n",
        "# -------------------------Step 2-------------------------\n",
        "# GemExperiment transpiles internally for the target backend: the layout\n",
        "# and routing stages are overridden because the plaquette lattice already\n",
        "# matches the hardware connectivity, and optimization is restricted so the\n",
        "# RZZ angle structure is preserved. The code below manually transpiles one\n",
        "# circuit from the six-plaquette experiment with the same settings this\n",
        "# experiment will use, and draws it for inspection. (The full-lattice\n",
        "# transpiled circuit has too many qubits to visualize cleanly, so the\n",
        "# six-plaquette circuit is used here as a representative example.)\n",
        "gem_exp_6.set_transpile_options(optimization_level=1)\n",
        "circuits_6 = gem_exp_6.circuits()\n",
        "pass_manager = generate_preset_pass_manager(\n",
        "    backend=backend,\n",
        "    initial_layout=list(gem_exp_6.physical_qubits),\n",
        "    **dict(gem_exp_6.transpile_options),\n",
        ")\n",
        "transpiled = pass_manager.run(circuits_6[5])\n",
        "display(transpiled.draw(\"mpl\", idle_wires=False, fold=-1, scale=0.5))\n",
        "\n",
        "# -------------------------Step 3-------------------------\n",
        "# Run both problem sizes on real hardware:\n",
        "#   1. Six plaquettes (~49 qubits) — an intermediate scale-up.\n",
        "#   2. The full plaquette lattice — every plaquette the device supports.\n",
        "exp_data_6 = gem_exp_6.run(shots=10_000, job_tags=[\"TUT_NPT\"])\n",
        "exp_data_full = gem_exp_full.run(shots=10_000, job_tags=[\"TUT_NPT\"])\n",
        "exp_data_6.block_for_results()\n",
        "exp_data_full.block_for_results()\n",
        "\n",
        "# -------------------------Step 4-------------------------\n",
        "# Plot the normalized variance at each scale. The peak marks the critical\n",
        "# point of the Nishimori transition; as the system grows, hardware noise\n",
        "# shifts the peak rightward.\n",
        "display(exp_data_6.figure(\"normalized_variance\"))\n",
        "exp_data_full.figure(\"normalized_variance\")"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "da03c8eb-5ec5-4c9c-8eb7-d44c5948b43c",
      "metadata": {},
      "source": [
        "사용된 백엔드의 잡음 수준에 따라, 더 큰 크기에서의 정규화 분산 곡선은 스윕 각도 범위 내에서 뚜렷한 피크를 보이지 않을 수도 있다는 점에 유의하십시오. 위의 시뮬레이션 결과에서, 피크는 스윕의 오른쪽 끝인 $0.5 \\pi$ 까지 밀려났습니다(6-플라켓 및 전체 격자 시뮬레이션 모두에 대한 분석 보고서 `critical_angle = 0.5000` 참조). 이는 하드웨어 노이즈로 인해 임계점이 프로토콜의 물리적으로 의미 있는 각도 범위의 경계로(또는 그 바로 너머로) 이동했음을 의미하므로, 이 전환은 해당 스윕이 식별할 수 있는 범위의 가장자리에 위치하게 됩니다.\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "6abd9701-58e4-43a8-a1d7-279506570de4",
      "metadata": {},
      "source": [
        "<span id=\"conclusion\" />\n",
        "\n",
        "## 결론\n",
        "\n",
        "이 튜토리얼에서는 GEM 프로토콜을 사용하여 양자 프로세서에서 니시모리 상전이를 구현했습니다. 후처리 과정에서 검토한 지표들, 특히 2점 상관관계와 정규화된 분산은 장거리 얽힘 상태를 생성하는 장치의 능력을 평가하는 기준이 됩니다. 이러한 벤치마크는 GEM 프로토콜의 활용 범위를 흥미로운 물리 현상을 탐구하는 것을 넘어 확장합니다. 이 프로토콜의 일환으로, 귀하는 상수 깊이의 회로만을 사용하여 장치 전체에 걸쳐 큐비트를 얽힘 상태로 만들었습니다. 이 성과는 프로토콜이 회로 중간 측정 방식을 활용했기 때문에 비로소 가능했습니다. 이 실험에서는 얽힘 상태를 즉시 측정했으나, 이 상태를 추가적인 양자 처리 과정에 활용하여 더 깊이 탐구해 볼 수도 있을 것이다.\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "717f22c6-4945-4719-b9ba-ae44cde58da8",
      "metadata": {},
      "source": [
        "<span id=\"next-steps\" />\n",
        "\n",
        "## 다음 단계\n",
        "\n",
        "<Admonition type=\"tip\" title=\"권장사항\">\n",
        "  이 글이 흥미로웠다면, 다음 자료도 참고해 보시기 바랍니다:\n",
        "\n",
        "  * [동적 회로를 이용한 장거리 얽힘](/docs/tutorials/long-range-entanglement)\n",
        "  * [반복 코드](/docs/tutorials/repetition-codes)\n",
        "  * [고전적인 피드포워드 및 제어 흐름](/docs/guides/classical-feedforward-and-control-flow)\n",
        "</Admonition>\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "bf0dc8db-004f-4567-8162-f09be453b434",
      "metadata": {},
      "source": [
        "<span id=\"references\" />\n",
        "\n",
        "## 참조\n",
        "\n",
        "\\[1] E. H. Chen, 『 G.-Y 』. Zhu, R., Verresen, A., Seif, E., Bäumer, D., Layden, N., Tantivasadakarn, G., Zhu, S., Sheldon, A., Vishwanath, S., Trebst, A., Kandala, A. *일정 깊이의 양자 회로에서 오류 임계값을 넘어서는 니시모리 전이 구현.* [arXiv:2309.02863](https://arxiv.org/abs/2309.02863) (2023).\n",
        "\n",
        "\\[2.] [GEM Suite](https://github.com/qiskit-community/gem-suite) 소프트웨어 패키지.\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"
    },
    "hours": 1,
    "qpuSeconds": 180
  },
  "nbformat": 4,
  "nbformat_minor": 4
}