{
  "cells": [
    {
      "cell_type": "markdown",
      "id": "eb419bc5-908c-4f0d-a4ff-c4d13f04e332",
      "metadata": {
        "tags": []
      },
      "source": [
        "---\n",
        "title: \"VQE를 이용한 하이젠베르크 사슬의 기저 상태 에너지 추정\"\n",
        "description: \"하이젠베르크 사슬을 시뮬레이션하고 그 기저 상태 에너지를 추정하기 위한 Qiskit 모델을 구축, 배포 및 실행합니다.\"\n",
        "---\n",
        "\n",
        "{/* cspell:ignore hyperparameters, forall, nabla, nparams */}\n",
        "\n",
        "<span id=\"ground-state-energy-estimation-of-the-heisenberg-chain-with-vqe\" />\n",
        "\n",
        "# VQE를 이용한 하이젠베르크 사슬의 기저 상태 에너지 추정\n",
        "\n",
        "*예상 실행 시간: Heron 프로세서 기준 37분 (참고: 이는 단지 추정치일 뿐입니다.) (실행 시간은 다를 수 있습니다.)*\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "e28ad544",
      "metadata": {},
      "source": [
        "<span id=\"learning-outcomes\" />\n",
        "\n",
        "## 학습 성과\n",
        "\n",
        "* Qiskit을 사용하여 하이젠베르크 스핀 사슬을 양자 해밀토니안으로 모델링하는 방법\n",
        "* SPSA 최적화기를 사용하여 양자 시스템의 기저 상태 에너지를 추정하는 방법\n",
        "* IBM Quantum 의 기본 기능 및 세션을 사용하여 IBM® 양자 하드웨어에서 변분 워크플로를 실행하는 방법\n",
        "\n",
        "<span id=\"prerequisites\" />\n",
        "\n",
        "## 전제조건\n",
        "\n",
        "* [양자 정보의 기초](/learning/courses/basics-of-quantum-information)\n",
        "* [Qiskit 패턴 소개](/docs/guides/intro-to-patterns)\n",
        "* [변동 알고리즘 설계](/learning/courses/variational-algorithm-design)\n",
        "\n",
        "<span id=\"background\" />\n",
        "\n",
        "## 배경\n",
        "\n",
        "하이젠베르크 스핀 사슬은 응집물질 물리학과 양자 자성 분야에서 가장 널리 연구되는 모델 중 하나이다. 이 모델은 상호작용하는 양자 스핀들의 1차원 격자를 묘사하며, 여기서 가장 가까운 이웃 스핀들은 교환 상호작용을 통해 결합되어 있다. 외부 자기장이 가해지는 등방성 하이젠베르크 모델의 해밀토니안은 다음과 같이 주어진다:\n",
        "\n",
        "$H = \\sum_{\\langle i,j \\rangle} \\left( J_x X_i X_j + J_y Y_i Y_j + J_z Z_i Z_j \\right) + \\sum_{i} h_i Z_i,$\n",
        "\n",
        "여기서 $X_i$, $Y_i$, $Z_i$ 는 사이트 $i$ 에 작용하는 파울리 연산자이며, 합 $\\langle i,j \\rangle$ 은 가장 가까운 이웃 쌍에 대해 취해지며, $J_x = J_y = J_z = 0.5$ 는 교환 결합 상수(이 튜토리얼에서는 등방성)이고, $h_i$ 는 사이트에 의존하는 외부 자기장을 나타냅니다. 이 튜토리얼에서는 자기장 값을 $[-1, 1]$ 구간에서 무작위로 추출합니다. 아래 구현에서 “가장 가까운 이웃” 쌍의 집합은 하드웨어 백엔드의 첫 번째 $N$ 큐비트 간의 기본 결합에 의해 결정되며, 이는 장치 토폴로지에 따라 엄격한 선형 사슬을 형성하지 않을 수도 있습니다.\n",
        "\n",
        "이 해밀토니안의 기저 상태 에너지를 이해하는 것은 물리학에서 근본적으로 중요합니다. 기저 상태는 양자 상전이, 얽힘 구조, 그리고 자기 정렬에 관한 정보를 담고 있다. 일반적으로 스핀의 수가 증가함에 따라 힐베르트 공간의 차원이 $2^N$ 의 지수적 비율로 증가하므로(여기서 $N$ 는 스핀의 수를 나타냄), 기저 상태의 정확한 에너지를 계산하는 것은 사실상 불가능해집니다. 따라서 이는 양자 시뮬레이션에 가장 적합한 후보가 됩니다.\n",
        "\n",
        "변분 양자 고유값 해법(VQE)은 해밀토니안의 기저 상태 에너지를 추정하기 위해 고안된 양자-고전 하이브리드 알고리즘이다. 이 방법은 양자 컴퓨터에서 매개변수화된 양자 상태 $|\\psi(\\theta)\\rangle$ (안자츠라고 함)를 준비한 후, 기대값 $\\langle \\psi(\\theta) | H | \\psi(\\theta) \\rangle$ 을 측정하는 방식으로 작동합니다. 그런 다음 고전적 최적화기는 변분 원리를 활용하여 이 에너지를 최소화하기 위해 매개변수 $\\theta$ 를 반복적으로 조정하는데, 변분 원리는 측정된 에너지가 항상 진정한 기저 상태 에너지의 상한이 됨을 보장합니다.\n",
        "\n",
        "이 튜토리얼에서는 단일 큐비트 회전 연산과 얽힘 게이트로 구성된 레이어를 생성하는 Qiskit의 circuit 라이브러리의 ansatz를 `efficient_su2` 사용합니다. 최적화는 SPSA(Simultaneous Perturbation Stochastic Approximation) 알고리즘을 사용하여 수행되며, 이 알고리즘은 매개변수의 개수와 관계없이 반복마다 단 두 번의 함수 평가만으로 기울기를 추정하기 때문에 노이즈가 많은 양자 하드웨어에 매우 적합합니다.\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "bc52f763",
      "metadata": {},
      "source": [
        "<span id=\"requirements\" />\n",
        "\n",
        "## 요구사항\n",
        "\n",
        "이 튜토리얼을 시작하기 전에 다음이 설치되어 있는지 확인하세요:\n",
        "\n",
        "* Qiskit SDK v2.0 또는 그 이후 버전, [시각화](/docs/api/qiskit/visualization) 기능 지원\n",
        "* Qiskit Runtime v0.44 또는 그 이후 (`pip install qiskit-ibm-runtime`)\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "a46e9e3e",
      "metadata": {},
      "source": [
        "<span id=\"setup\" />\n",
        "\n",
        "## 설정\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 1,
      "id": "e7754922",
      "metadata": {},
      "outputs": [],
      "source": [
        "import numpy as np\n",
        "import matplotlib.pyplot as plt\n",
        "from typing import Sequence\n",
        "\n",
        "from qiskit import QuantumCircuit\n",
        "from qiskit.quantum_info import SparsePauliOp\n",
        "from qiskit.primitives import BaseEstimatorV2\n",
        "from qiskit.circuit.library import XGate\n",
        "from qiskit.circuit.library import efficient_su2\n",
        "from qiskit.transpiler import PassManager\n",
        "from qiskit.transpiler.preset_passmanagers import generate_preset_pass_manager\n",
        "from qiskit.transpiler.passes.scheduling import (\n",
        "    ALAPScheduleAnalysis,\n",
        "    PadDynamicalDecoupling,\n",
        ")\n",
        "from qiskit_ibm_runtime import QiskitRuntimeService, Session, EstimatorV2\n",
        "\n",
        "\n",
        "def visualize_results(results):\n",
        "    plt.plot(results[\"cost_history\"], lw=2)\n",
        "    plt.xlabel(\"Number of function evaluations\")\n",
        "    plt.ylabel(\"Energy\")\n",
        "    plt.show()"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "890d9c81",
      "metadata": {},
      "source": [
        "<span id=\"small-scale-example\" />\n",
        "\n",
        "## 간단한 예시\n",
        "\n",
        "이 섹션에서는 Qiskit 패턴의 각 단계를 소규모로 단계별로 살펴보며, 워크플로를 구축해 나가는 과정에서 핵심 구성 요소를 설명합니다.\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "132fb15f-10b4-4d7e-83d8-f512a6f675d1",
      "metadata": {},
      "source": [
        "<span id=\"step-1-map-classical-inputs-to-a-quantum-problem\" />\n",
        "\n",
        "### 1단계: 고전적 입력을 양자 문제에 매핑하기\n",
        "\n",
        "* 입력: 회전 횟수\n",
        "* 출력: 안사츠와 해밀턴의 하이젠베르크 사슬 모델링하기\n",
        "\n",
        "10스핀 하이젠베르크 사슬을 모델링하는 근사 해와 해밀토니안을 도출하라. 이 단계에서는 가장 부하가 적은 백엔드의 결합 맵을 기반으로 10-스핀 하이젠베르크 해밀토니안을 구축하고, 안자츠를 `efficient_su2` 준비할 것입니다.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 2,
      "id": "7e8d2f10-f1d6-4ec2-bac9-9db23499c9e1",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<Image src=\"/docs/images/tutorials/spin-chain-vqe/extracted-outputs/7e8d2f10-f1d6-4ec2-bac9-9db23499c9e1-0.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "execution_count": 2,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "num_spins = 10\n",
        "ansatz = efficient_su2(num_qubits=num_spins, reps=2)\n",
        "\n",
        "service = QiskitRuntimeService()\n",
        "backend = service.least_busy(\n",
        "    operational=True, min_num_qubits=num_spins, simulator=False\n",
        ")\n",
        "\n",
        "coupling = backend.target.build_coupling_map()\n",
        "reduced_coupling = coupling.reduce(list(range(num_spins)))\n",
        "\n",
        "edge_list = reduced_coupling.graph.edge_list()\n",
        "ham_list = []\n",
        "\n",
        "for edge in edge_list:\n",
        "    ham_list.append((\"ZZ\", edge, 0.5))\n",
        "    ham_list.append((\"YY\", edge, 0.5))\n",
        "    ham_list.append((\"XX\", edge, 0.5))\n",
        "\n",
        "for qubit in reduced_coupling.physical_qubits:\n",
        "    ham_list.append((\"Z\", [qubit], np.random.random() * 2 - 1))\n",
        "\n",
        "hamiltonian = SparsePauliOp.from_sparse_list(ham_list, num_qubits=num_spins)\n",
        "\n",
        "ansatz.draw(\"mpl\", style=\"iqp\")"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "ab79119b-5e56-49d8-a20e-1c8e665baec0",
      "metadata": {},
      "source": [
        "<span id=\"step-2-optimize-problem-for-quantum-hardware-execution\" />\n",
        "\n",
        "### 2단계: 양자 하드웨어 실행을 위한 문제 최적화\n",
        "\n",
        "* 입력: 추상 회로, 관찰 가능\n",
        "* 출력: 대상 회로 및 관찰 가능, 선택한 QPU에 최적화됨\n",
        "\n",
        "키스킷의 `generate_preset_pass_manager` 함수를 사용하여 선택한 QPU에 대한 회로의 최적화 루틴을 자동으로 생성합니다. 저희는 사전 설정 패스 관리자 중 가장 높은 수준의 최적화를 제공하는 `optimization_level=3` 을 선택했습니다. 또한 `ALAPScheduleAnalysis` 및 `PadDynamicalDecoupling` 스케줄링 패스를 통해 디코히어런싱 오류를 억제할 수 있습니다.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 3,
      "id": "a0a5f1c8-5c31-4d9f-ae81-37bd67271d44",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<Image src=\"/docs/images/tutorials/spin-chain-vqe/extracted-outputs/a0a5f1c8-5c31-4d9f-ae81-37bd67271d44-0.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "execution_count": 3,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "target = backend.target\n",
        "pm = generate_preset_pass_manager(optimization_level=3, target=target)\n",
        "pm.scheduling = PassManager(\n",
        "    [\n",
        "        ALAPScheduleAnalysis(durations=target.durations()),\n",
        "        PadDynamicalDecoupling(\n",
        "            durations=target.durations(),\n",
        "            dd_sequence=[XGate(), XGate()],\n",
        "            pulse_alignment=target.pulse_alignment,\n",
        "        ),\n",
        "    ]\n",
        ")\n",
        "isa_ansatz = pm.run(ansatz)\n",
        "isa_observable = hamiltonian.apply_layout(isa_ansatz.layout)\n",
        "isa_ansatz.draw(\"mpl\", scale=0.6, style=\"iqp\", fold=-1, idle_wires=False)"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "9e889d0b-30b5-4e6b-84c9-d1f096abf132",
      "metadata": {},
      "source": [
        "<span id=\"step-3-execute-using-qiskit-primitives\" />\n",
        "\n",
        "### 3단계: `Qiskit primitives` 명령어로 실행합니다\n",
        "\n",
        "* 입력: 대상 회로 및 관찰 가능\n",
        "* 출력: 최적화 결과\n",
        "\n",
        "회로 파라미터를 최적화하여 시스템의 예상 기저 상태 에너지를 최소화하십시오. 최적화 과정에서 비용 함수를 계산하려면 `IBM Quantum` 기본 `Estimator` 함수를 사용하십시오.\n",
        "\n",
        "2단계에서 백엔드용 회로를 최적화했으므로, 를 설정하고 `skip_transpilation=True` 최적화된 회로를 전달함으로써 Quantum Compute 서버에서 트랜스파일링을 수행하지 않아도 됩니다. 이 데모에서는 IBM Quantum 프리미티브를 사용하여 QPU에서 실행할 것입니다. statevector 기반 `qiskit` 프리미티브와 함께 실행하려면, IBM Quantum 프리미티브를 사용하는 코드 블록을 주석 처리된 블록으로 대체하십시오.\n",
        "\n",
        "이 튜토리얼에서는 기울기 기반 최적화 알고리즘인 동시 섭동 확률적 근사법(SPSA)을 사용합니다. 다음으로 이에 대해 간략히 소개하고, Qiskit v2.0 을 사용하여 SPSA를 구현하는 코드를 제시합니다.\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "64f97e6f",
      "metadata": {},
      "source": [
        "<span id=\"introducing-spsa\" />\n",
        "\n",
        "### SPSA 소개\n",
        "\n",
        "동시 섭동 확률적 근사법(SPSA) [\\[1\\]](#references) 은 각 반복 단계에서 단 두 번의 함수 호출만으로 전체 기울기 벡터를 근사화하는 최적화 알고리즘이다. $f:\\mathbb{R}^p\\rightarrow \\mathbb{R}$ 를 최적화 대상인 $p$ 매개변수를 갖는 비용 함수라고 하고, $x_i\\in \\mathbb{R}^p$ 를 반복 계산의 $i^{th}$ 단계에서 얻은 매개변수 벡터라고 하자. 경사도를 계산하기 위해, 크기 $p$ 인 임의 벡터 $\\Delta_i$ 를 생성하며, 여기서 각 요소 $\\Delta_{ij}$, $\\forall$, $j\\in \\{1,2,...,p\\}$ 는 $\\{-1, 1\\}$ 에서 균일하게 표본 추출됩니다. 다음으로, 임의 벡터 $\\Delta_i$ 의 각 요소에 작은 값 $c_i$ 를 곱하여 임의의 섭동을 생성합니다. 그러면 기울기는 다음과 같이 추정됩니다\n",
        "\n",
        "$[\\nabla f(x_i)]_j \\approx \\frac{f(x_i + c_i \\Delta_i) - f(x_i - c_i \\Delta_i)}{2c_i\\Delta_{ij}}.$\n",
        "\n",
        "직관적으로 볼 때, 기울기 추정 과정에서 무작위 섭동이 가해지므로, 잡음으로 인해 발생하는 $f$ 의 정확한 값에 대한 미세한 편차는 용인되고 고려될 수 있을 것으로 예상됩니다. 사실 SPSA는 노이즈에 특히 강하다는 것으로 알려져 있으며, 각 반복마다 단 두 번의 하드웨어 호출만 필요로 합니다. 따라서 이는 변분 알고리즘을 구현하는 데 있어 가장 선호되는 최적화 기법 중 하나입니다.\n",
        "\n",
        "이 튜토리얼에서는 $i^{th}$ 반복 과정의 하이퍼파라미터인 $a_i$ 와 $c_i$ 가 다음과 같이 계산됩니다\n",
        "\n",
        "$a_i = \\frac{a}{(A + i + 1)^\\alpha} \\quad \\text{and} \\quad c_i = \\frac{c}{(i+1)^\\gamma},$\n",
        "\n",
        "여기서 상수 값은 $A = 30$, $\\alpha = 0.9$, $a = 0.3$, $c = 0.1$, $\\gamma = 0.4$ 로 설정된다. 이 값들은 [\\[2\\]](#references) 에서 선정되었다. SPSA에서 우수한 성능을 이끌어내기 위해서는 하이퍼파라미터를 적절하게 조정해야 합니다.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 4,
      "id": "73a9352c",
      "metadata": {},
      "outputs": [],
      "source": [
        "def spsa(\n",
        "    fun, x0, args=(), A=30, alpha=0.9, a=0.3, c=0.1, gamma=0.4, maxiter=100\n",
        "):\n",
        "    nparams = len(x0)\n",
        "    x = np.copy(x0)\n",
        "\n",
        "    for i in range(maxiter):\n",
        "        a_i = a / (A + i + 1) ** alpha\n",
        "        c_i = c / (i + 1) ** gamma\n",
        "        delta_i = np.random.choice([-1, 1], nparams)\n",
        "\n",
        "        # two hardware calls\n",
        "        eval_1 = fun(x + c_i * delta_i, *args)\n",
        "        eval_2 = fun(x - c_i * delta_i, *args)\n",
        "\n",
        "        # compute the gradient and update the parameters\n",
        "        grad = (eval_1 - eval_2) / (2 * c_i) * np.reciprocal(delta_i)\n",
        "        x = x - a_i * grad\n",
        "\n",
        "    return x"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 8,
      "id": "32ca3b6a",
      "metadata": {},
      "outputs": [],
      "source": [
        "def cost_func(\n",
        "    params: Sequence,\n",
        "    ansatz: QuantumCircuit,\n",
        "    hamiltonian: SparsePauliOp,\n",
        "    estimator: BaseEstimatorV2,\n",
        "    cost_history_dict: dict,\n",
        ") -> float:\n",
        "    \"\"\"Ground state energy evaluation.\"\"\"\n",
        "    energy = (\n",
        "        estimator.run([(ansatz, hamiltonian, [params])]).result()[0].data.evs\n",
        "    )\n",
        "\n",
        "    cost_history_dict[\"iters\"] += 1\n",
        "    cost_history_dict[\"prev_vector\"] = list(params)\n",
        "    cost_history_dict[\"cost_history\"].append(float(energy[0]))\n",
        "\n",
        "    print(\n",
        "        f\"Fx Iters. done: {cost_history_dict['iters']} [Current cost: {round(energy[0], 5)}]\",\n",
        "        end=\"\\r\",\n",
        "    )\n",
        "\n",
        "    return energy\n",
        "\n",
        "\n",
        "def solve(x0, isa_ansatz, isa_observable, maxiter=150):\n",
        "    cost_history_dict = {\n",
        "        \"prev_vector\": None,\n",
        "        \"iters\": 0,\n",
        "        \"cost_history\": [],\n",
        "        \"y_min\": None,\n",
        "    }\n",
        "\n",
        "    # Evaluate the problem using a QPU via `qiskit-ibm-runtime`\n",
        "    with Session(backend=backend) as session:\n",
        "        estimator = EstimatorV2(mode=session)\n",
        "        estimator.skip_transpilation = True\n",
        "        estimator.options.environment.job_tags = [\"TUT_HSVQE\"]\n",
        "        x_opt = spsa(\n",
        "            cost_func,\n",
        "            x0=x0,\n",
        "            args=(isa_ansatz, isa_observable, estimator, cost_history_dict),\n",
        "            maxiter=maxiter,\n",
        "        )\n",
        "\n",
        "        y_min = cost_func(\n",
        "            x_opt, isa_ansatz, isa_observable, estimator, cost_history_dict\n",
        "        )\n",
        "\n",
        "    return y_min, cost_history_dict"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 9,
      "id": "f418b372",
      "metadata": {},
      "outputs": [],
      "source": [
        "np.random.seed(42)\n",
        "num_params = ansatz.num_parameters\n",
        "params = 2 * np.pi * np.random.random(num_params)"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "3bf42923",
      "metadata": {},
      "source": [
        "여기서 우리는. `maxiter = 50`를 설정합니다. 각 반복 단계에서 기울기를 계산하기 위해 함수를 두 번 호출해야 하므로, 총 함수 호출 횟수는 $2 \\times \\text{maxiter}$ 가 됩니다. 더 정확한 에너지 추정을 위해 이 값을 더 큰 `maxiter` 수치로 늘릴 수 있습니다.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 10,
      "id": "1732ce37",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "Fx Iters. done: 101 [Current cost: -3.03843]"
          ]
        }
      ],
      "source": [
        "maxiter = 50\n",
        "spsa_min, spsa_history = solve(\n",
        "    params, isa_ansatz, isa_observable, maxiter=maxiter\n",
        ")"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "33abbb3f-6245-4610-a05d-e2bc4cc551f0",
      "metadata": {},
      "source": [
        "<span id=\"step-4-post-process-and-return-result-in-desired-classical-format\" />\n",
        "\n",
        "### 4단계: 후처리 수행 및 원하는 클래식 형식으로 결과 반환\n",
        "\n",
        "* 입력: 최적화 과정 중 기저 상태 에너지 추정값\n",
        "* 출력: 예상 기저 상태 에너지\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 11,
      "id": "e5b58771-d543-4e75-9746-fbc7b28e4360",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "Estimated ground state energy: [-3.03842968]\n"
          ]
        }
      ],
      "source": [
        "print(f\"Estimated ground state energy: {spsa_min}\")"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 12,
      "id": "ecd7762a",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<Image src=\"/docs/images/tutorials/spin-chain-vqe/extracted-outputs/ecd7762a-0.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "metadata": {},
          "output_type": "display_data"
        }
      ],
      "source": [
        "results = {\n",
        "    \"spsa\": spsa_history,\n",
        "}\n",
        "\n",
        "visualize_results(spsa_history)"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "a3f4171f",
      "metadata": {},
      "source": [
        "<span id=\"large-scale-hardware-example\" />\n",
        "\n",
        "## 대규모 하드웨어 예시\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "746e6133",
      "metadata": {},
      "source": [
        "이 튜토리얼에는 대규모 하드웨어 예제가 포함되어 있지 않습니다. 큐비트 수가 증가함에 따라, VQE는 [‘불모의 고원](/learning/courses/variational-algorithm-design/optimization-loops#barren-plateaus) 현상’으로 인해 중대한 난관에 직면하게 됩니다. 즉, 비용 함수의 기울기가 시스템 규모에 따라 지수적으로 사라지기 때문에, 대규모 회로의 경우 최적화가 사실상 불가능해집니다. 여기에 하드웨어 노이즈까지 더해지면, VQE를 더 큰 스핀 사슬로 확장하더라도 신뢰할 수 있는 재현성 있는 결과를 얻지 못하게 됩니다. 이러한 한계를 극복하는 방법에 대해서는 아래의 ‘다음 단계’ 섹션을 참조하십시오.\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "8f14492c",
      "metadata": {},
      "source": [
        "<span id=\"challenge\" />\n",
        "\n",
        "## 문제점\n",
        "\n",
        "하이젠베르크 체인에 대한 VQE 구현이 정상적으로 작동하는 것을 확인했으니, 다음을 시도해 보세요:\n",
        "\n",
        "1. `reps=3`**안자츠 깊이를 조절해 보세요:** 의 `efficient_su2` 매개변수를 `reps` 수정해 보세요(예를 들어, 와 를 시도해 `reps=1` 보세요). 안자츠 깊이는 추정된 기저 상태 에너지와 수렴 속도에 어떤 영향을 미치나요? 어떤 시점에서 수익의 감소나 불안정성이 나타나나요?\n",
        "2. **SPSA 하이퍼파라미터 조정:** 학습률 스케줄링 파라미터(`a`, `c`, `alpha`, `gamma`, `A`)를 조정하고, 이것이 수렴에 어떤 영향을 미치는지 관찰합니다. 여기서 사용된 기본 설정보다 더 빨리 수렴하는 구성을 찾을 수 있나요?\n",
        "3. **결합 토폴로지를 비교해 보세요:** 백엔드의 기본 결합 맵을 사용하는 대신, 간단한 최인접 노드 선형 체인을 구성해 보고 그 결과를 비교해 보세요. 물리적 하드웨어의 연결성이 트랜스파일된 회로의 깊이와 최종 에너지 추정치에 어떤 영향을 미치나요?\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "217a9379",
      "metadata": {},
      "source": [
        "<span id=\"references\" />\n",
        "\n",
        "## 참조\n",
        "\n",
        "\\[1] 스팔, J. C. (2002). 확률적 최적화를 위한 동시 섭동 알고리즘의 구현.\n",
        "IEEE 항공우주 및 전자 시스템 학회지, 34(3), 817-823.\n",
        "\n",
        "\\[2] Sahin, M. Emre 외 (2025). Qiskit Machine Learning : 양자 하드웨어 및 고전 시뮬레이터에서 대규모 양자 머신러닝 작업을 수행하기 위한 오픈소스 라이브러리입니다. arXiv:2505.17756.\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "8aefe54c",
      "metadata": {},
      "source": [
        "<span id=\"next-steps\" />\n",
        "\n",
        "## 다음 단계\n",
        "\n",
        "<Admonition type=\"tip\" title=\"권장사항\">\n",
        "  이 글이 흥미로웠다면, 다음 자료도 관심 있게 읽어보실 수 있습니다:\n",
        "\n",
        "  * **샘플 기반 양자 대각화(SQD)를 시도해 보세요:** 이 튜토리얼에서 살펴본 바와 같이, VQE는 ‘불모의 고원’ 현상과 높은 측정 오버헤드로 인해 대규모 적용 시 어려움을 겪습니다. IBM 더 확장성이 뛰어난 대안으로 [‘샘플 기반 양자 대각화(SQD)](/docs/addons/qiskit-addon-sqd) ’를 개발했다. VQE와 달리, SQD는 변분 최적화를 완전히 배제합니다. 대신, 양자 컴퓨터가 샘플을 생성하고, 고전 컴퓨터가 해당 샘플들이 스팬하는 부분공간에 해밀토니안을 투영한 뒤 이를 대각화합니다. 이는 훨씬 적은 수의 측정만으로, 또한 ‘바렌 플레이토’ 현상의 영향을 받지 않으면서 기저 상태 에너지의 상한값을 제공해 줍니다. [SQD 튜토리얼](/docs/tutorials/sample-based-quantum-diagonalization) 을 따라 이 접근 방식이 실제로 어떻게 적용되는지 확인해 보세요.\n",
        "  * \\*\\*‘양자 대각화 \\*\\*[알고리즘’](/learning/courses/quantum-diagonalization-algorithms) 강좌 살펴보기: IBM Quantum Learning 의 ‘양자 대각화 알고리즘’ 강좌를 통해 VQE와 SQD의 장단점을 포함한 두 알고리즘에 대한 이해를 심화해 보세요.\n",
        "</Admonition>\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.5,
    "qpuSeconds": 2220
  },
  "nbformat": 4,
  "nbformat_minor": 5
}