{
  "cells": [
    {
      "cell_type": "markdown",
      "id": "frontmatter",
      "metadata": {},
      "source": [
        "---\n",
        "title: \"빠른 시작\"\n",
        "description: \"최신 버전의 Qiskit 전파 소음 흡수 기능에 대한 빠른 시작 가이드\"\n",
        "---\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "0b3182b6",
      "metadata": {},
      "source": [
        "<span id=\"quickstart\" />\n",
        "\n",
        "# 빠른 시작\n",
        "\n",
        "이 가이드에서는 해당 `qiskit-addon-pna` 패키지의 최소 실행 가능한 예제를 보여줍니다. 우리는 소음 완화 관측량을 구축하기 위해 전파형 소음 흡수(PNA)를 사용합니다. 주어진 회로와 파울리-린드블라드 잡음 모델이 있을 때, PNA는 고전적으로 관측량을 역잡음 채널을 통해 전파합니다. 노이즈가 있는 QPU에서 결과 관측량을 측정하면 학습된 게이트 노이즈가 완화됩니다.\n",
        "\n",
        "`NoiseLearnerV3`[지시형 실행](/docs/guides/directed-execution-model) 모델을 활용해 현실적인 워크플로를 구축하고 양자 하드웨어에서 실행하는 방법, 그리고 를 이용한 노이즈 모델 학습 방법을 알아보려면, IBM Quantum Platform 의 [PNA](/docs/tutorials/propagated-noise-absorption) 튜토리얼을 확인해 보세요.\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "a4068f26",
      "metadata": {},
      "source": [
        "<span id=\"1-prepare-the-inputs-for-pna\" />\n",
        "\n",
        "## 1. PNA에 필요한 입력 데이터를 준비합니다\n",
        "\n",
        "PNA는 회로, 잡음 모델 및 관측량을 입력으로 받습니다. 여기서는 1D 사슬을 기반으로 10-큐비트 트로터화 횡자장 이징 모델을 구축합니다. 각 얽힘 게이트에 대해 무작위 2-로컬 파울리-린드블라드 노이즈 모델을 생성하고, 해당 게이트 바로 앞에 Qiskit Aer `PauliLindbladError` 명령어로 삽입합니다. 우리는 측정 대상으로 ‘ weight-4 ’ 파울리-Z 관측량을 선택한다.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 1,
      "id": "4a9a3ced",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<Image src=\"/docs/images/addons/qiskit-addon-pna/guides/quickstart/extracted-outputs/4a9a3ced-0.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "import numpy as np\n",
        "from qiskit import QuantumCircuit\n",
        "from qiskit.quantum_info import SparsePauliOp, pauli_basis\n",
        "from qiskit_aer.noise import PauliLindbladError\n",
        "\n",
        "\n",
        "def random_pauli_lindblad_noise(generators, seed, noise_scale=2e-3):\n",
        "    rates = np.random.default_rng(seed).random(len(generators)) * noise_scale\n",
        "    return PauliLindbladError(generators, rates)\n",
        "\n",
        "\n",
        "def ising_circuit(\n",
        "    num_qubits,\n",
        "    layers,\n",
        "    edge_noise=None,\n",
        "    *,\n",
        "    num_steps=3,\n",
        "    rx_angle=np.pi / 8,\n",
        "    rzz_angle=-np.pi / 2,\n",
        "):\n",
        "    \"\"\"Trotterized transverse-field Ising model; edge_noise=None gives the noiseless circuit.\"\"\"\n",
        "    qc = QuantumCircuit(num_qubits)\n",
        "    for _ in range(num_steps):\n",
        "        qc.rx(rx_angle, range(num_qubits))\n",
        "        for layer in layers:\n",
        "            for edge in layer:\n",
        "                if edge_noise is not None:\n",
        "                    qc.append(\n",
        "                        edge_noise[edge], edge\n",
        "                    )  # inject synthetic gate noise\n",
        "                qc.rzz(rzz_angle, *edge)\n",
        "    return qc\n",
        "\n",
        "\n",
        "num_qubits = 10\n",
        "\n",
        "# Two entangling layers per Trotter step: even and odd bonds of a 1D chain\n",
        "layers = [\n",
        "    [(i, i + 1) for i in range(0, num_qubits - 1, 2)],\n",
        "    [(i, i + 1) for i in range(1, num_qubits - 1, 2)],\n",
        "]\n",
        "edges = [edge for layer in layers for edge in layer]\n",
        "\n",
        "# Random 2-local Pauli-Lindblad noise, one instance per entangling gate\n",
        "two_qubit_paulis = SparsePauliOp(\n",
        "    [p for p in pauli_basis(2) if np.sum(p.x + p.z)]\n",
        ").paulis\n",
        "edge_noise = {\n",
        "    edge: random_pauli_lindblad_noise(two_qubit_paulis, seed=1234 + j)\n",
        "    for j, edge in enumerate(edges)\n",
        "}\n",
        "\n",
        "noisy_circuit = ising_circuit(num_qubits, layers, edge_noise)\n",
        "\n",
        "# A single weight-4 observable: <Z3 Z4 Z5 Z6>\n",
        "observable = SparsePauliOp.from_sparse_list(\n",
        "    [(\"ZZZZ\", [3, 4, 5, 6], 1.0)], num_qubits=num_qubits\n",
        ")\n",
        "\n",
        "noisy_circuit.draw(\"mpl\", fold=-1, scale=0.6)"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "b99617c3",
      "metadata": {},
      "source": [
        "<span id=\"2-generate-the-noise-mitigating-observable\" />\n",
        "\n",
        "## 2. 잡음 완화 관측량을 생성한다\n",
        "\n",
        "[generate\\_noise\\_mitigating\\_observable은](/docs/api/qiskit-addon-pna/qiskit-addon-pna#generate_noise_mitigating_observable) 역잡음 채널의 각 파울리 생성자를 회로 끝까지 전방으로 전파합니다. 그런 다음 관측값은 역 잡음 채널을 통해 역전파되어 새로운 관측값 $\\tilde{O}$ 을 반환합니다. 계산 비용에는 다음 세 가지 주요 매개변수가 영향을 미칩니다:\n",
        "\n",
        "* `max_err_terms`: 전방 전파 과정에서 각 항잡음 생성기에 유지되는 항의 수.\n",
        "* `max_obs_terms`: $\\tilde{O}$ 에 저장된 용어의 수.\n",
        "* `atol`: 계수의 크기가 이 임계값보다 작은 항은 제외됩니다.\n",
        "\n",
        "`atol`클리포드 회로에 가까운 이 작은 회로의 경우, 항의 차수를 높게 설정하고 적당한 값을 사용하므로, $\\tilde{O}$ 의 크기는 작게 유지되며 모든 항을 측정할 수 있습니다.\n",
        "\n",
        "***참고: 이 함수는 Python `multiprocessing`를 사용합니다. 스크립트로 실행할 때는 `guard` 블록 `if __name__ == \"__main__\":` 내에서 호출하십시오.***\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 2,
      "id": "39891ec7",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "Original observable:         1 term\n",
            "Noise-mitigating observable: 207 terms\n"
          ]
        }
      ],
      "source": [
        "from qiskit_addon_pna import generate_noise_mitigating_observable\n",
        "\n",
        "mitigating_observable = generate_noise_mitigating_observable(\n",
        "    noisy_circuit,\n",
        "    observable,\n",
        "    max_err_terms=100_000,\n",
        "    max_obs_terms=100_000,\n",
        "    atol=1e-5,\n",
        "    num_processes=4,\n",
        ")\n",
        "\n",
        "print(f\"Original observable:         {len(observable)} term\")\n",
        "print(f\"Noise-mitigating observable: {len(mitigating_observable)} terms\")"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "f7881a9e",
      "metadata": {},
      "source": [
        "<span id=\"3-mitigate-gate-errors-by-measuring-the-noise-mitigating-observable\" />\n",
        "\n",
        "## 3. 잡음 완화 관측량을 측정하여 게이트 오류를 완화한다\n",
        "\n",
        "여기서 우리는 새로운 관측량이 실험에 영향을 미치는 게이트 노이즈를 효과적으로 완화한다는 것을 알 수 있다.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 3,
      "id": "a56dd204",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "Ideal (noiseless):   0.8073\n",
            "Noisy (unmitigated): 0.6431\n",
            "Mitigated (PNA):     0.8071\n"
          ]
        },
        {
          "data": {
            "text/plain": [
              "<Image src=\"/docs/images/addons/qiskit-addon-pna/guides/quickstart/extracted-outputs/a56dd204-1.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "metadata": {},
          "output_type": "display_data"
        }
      ],
      "source": [
        "import matplotlib.pyplot as plt\n",
        "from qiskit_aer.primitives import EstimatorV2\n",
        "\n",
        "noiseless_circuit = ising_circuit(num_qubits, layers)\n",
        "\n",
        "# density_matrix method at zero precision -> exact expectation values (no shot noise)\n",
        "estimator = EstimatorV2(\n",
        "    options={\n",
        "        \"backend_options\": {\"method\": \"density_matrix\"},\n",
        "        \"default_precision\": 0.0,\n",
        "    }\n",
        ")\n",
        "\n",
        "ideal, noisy, mitigated = (\n",
        "    result.data.evs\n",
        "    for result in estimator.run(\n",
        "        [\n",
        "            (noiseless_circuit, observable),\n",
        "            (noisy_circuit, observable),\n",
        "            (noisy_circuit, mitigating_observable),\n",
        "        ]\n",
        "    ).result()\n",
        ")\n",
        "\n",
        "print(f\"Ideal (noiseless):   {ideal:.4f}\")\n",
        "print(f\"Noisy (unmitigated): {noisy:.4f}\")\n",
        "print(f\"Mitigated (PNA):     {mitigated:.4f}\")\n",
        "\n",
        "fig, ax = plt.subplots()\n",
        "ax.bar(\n",
        "    [\"Noisy\", \"Mitigated\"],\n",
        "    [noisy, mitigated],\n",
        "    width=0.6,\n",
        "    color=[\"#b0b0b0\", \"#4c4c4c\"],\n",
        ")\n",
        "ax.axhline(ideal, color=\"green\", linestyle=\"--\", label=\"Ideal (noiseless)\")\n",
        "ax.set_ylabel(r\"$\\langle Z_3 Z_4 Z_5 Z_6 \\rangle$\")\n",
        "ax.legend()\n",
        "plt.show()"
      ]
    },
    {
      "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"
    }
  },
  "nbformat": 4,
  "nbformat_minor": 5
}