{
  "cells": [
    {
      "cell_type": "markdown",
      "id": "828c3465-62a7-4c42-b376-e3ec32f67595",
      "metadata": {},
      "source": [
        "---\n",
        "title: \"소음 학습 도우미\"\n",
        "description: \"qiskit-ibm-runtime에서 워크로드를 실행할 때 생성된 노이즈 모델을 저장하기 위해 노이즈 학습 보조 프로그램을 사용해 보세요\"\n",
        "---\n",
        "\n",
        "<span id=\"noise-learning-helper\" />\n",
        "\n",
        "# 소음 학습 도우미\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "40a246f5-4efd-4fb0-861b-c4e013c1572a",
      "metadata": {
        "tags": [
          "version-info"
        ]
      },
      "source": [
        "{/*\n",
        "  DO NOT EDIT THIS CELL!!!\n",
        "  This cell's content is generated automatically by a script. Anything you add\n",
        "  here will be removed next time the notebook is run. To add new content, create\n",
        "  a new cell before or after this one.\n",
        "  */}\n",
        "\n",
        "<Accordion>\n",
        "  <AccordionItem title=\"패키지 버전\">\n",
        "    이 페이지의 코드는 다음 요구 사항을 사용하여 개발되었습니다.\n",
        "    다음 버전 이상을 사용하는 것이 좋습니다.\n",
        "\n",
        "    ```\n",
        "    qiskit[all]~=2.5.2\n",
        "    qiskit-ibm-runtime~=0.47.0\n",
        "    samplomatic~=0.21.0\n",
        "    ```\n",
        "  </AccordionItem>\n",
        "</Accordion>\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "cce93074-df51-4760-9fce-5a520c3bc59a",
      "metadata": {},
      "source": [
        "오류 완화 기법인 [PEA와](/docs/guides/error-mitigation-and-suppression-techniques#pea) [PEC는](/docs/guides/error-mitigation-and-suppression-techniques#pec) 모두 [파울리-린드블라드(Pauli-Lindblad) 노이즈 모델을](https://arxiv.org/abs/2201.09866) 기반으로 한 노이즈 학습 구성 요소를 활용하며, 이는 일반적으로 하나 이상의 작업을 제출한 후 실행 중에 관리되는데, 이때 `qiskit-ibm-runtime` 피팅된 노이즈 모델에 대한 로컬 액세스 권한은 전혀 부여되지 않습니다. 그러나 `qiskit-ibm-runtime`v0.27.1 를 기준으로, 이러한 노이즈 학습 실험 결과를 얻기 위해 및 관련 [`NoiseLearnerOptions`](/docs/api/qiskit-ibm-runtime/options-noise-learner-options) 클래스가 [`NoiseLearner`](/docs/api/qiskit-ibm-runtime/noise-learner) 생성되었습니다. 이러한 결과는 로컬에 파일로 `NoiseLearnerResult` 저장하여 추후 실험에서 입력 데이터로 활용할 수 있습니다. 이 페이지에서는 해당 기능의 사용법과 관련 옵션에 대한 개요를 제공합니다.\n",
        "\n",
        "또한, `qiskit-ibm-runtime`v0.47.0 부터 Executor 기본 유형과 호환되는 새로운 `NoiseLearnerV3` 클래스가 추가되었습니다. 이 새로운 버전은 [지시형 실행](/docs/guides/directed-execution-model) 모델의 일부이기도 하며, 학습하고자 하는 레이어를 명시적으로 지정할 수 있는 기능을 제공합니다.\n",
        "\n",
        "<Admonition type=\"note\">\n",
        "  `NoiseLearner` EstimatorV2 에서만 작동하며, `NoiseLearnerV3` Executor에서만 작동합니다.\n",
        "</Admonition>\n",
        "\n",
        "<span id=\"noiselearner\" />\n",
        "\n",
        "## `NoiseLearner`\n",
        "\n",
        "<span id=\"overview\" />\n",
        "\n",
        "### 개요\n",
        "\n",
        "이 `NoiseLearner` 수업에서는 하나(또는 그 이상)의 회로에 대해 파울리-린드블라드 잡음 모델을 기반으로 잡음 과정을 규명하는 실험을 수행합니다. 이 클래스는 학습 실험을 실행하는 `run()` 메서드를 갖추고 있으며, 회로 목록이나 [PUB](/docs/guides/primitive-input-output) 를 입력으로 받아, 학습된 노이즈 채널과 제출된 작업에 대한 메타데이터를 포함하는 `NoiseLearnerResult` 객체를 반환합니다. 다음은 헬퍼 프로그램의 사용법을 보여주는 코드 예시입니다.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 1,
      "id": "d9a5320d-8ec6-483a-9ecf-931b0f5f5d13",
      "metadata": {},
      "outputs": [],
      "source": [
        "from qiskit import QuantumCircuit\n",
        "from qiskit.transpiler import CouplingMap\n",
        "from qiskit.transpiler import generate_preset_pass_manager\n",
        "\n",
        "from qiskit_ibm_runtime import QiskitRuntimeService, EstimatorV2\n",
        "from qiskit_ibm_runtime.noise_learner import NoiseLearner\n",
        "from qiskit_ibm_runtime.options import (\n",
        "    NoiseLearnerOptions,\n",
        "    ResilienceOptionsV2,\n",
        "    EstimatorOptions,\n",
        ")\n",
        "\n",
        "# Build a circuit with two entangling layers\n",
        "num_qubits = 27\n",
        "edges = list(CouplingMap.from_line(num_qubits, bidirectional=False))\n",
        "even_edges = edges[::2]\n",
        "odd_edges = edges[1::2]\n",
        "\n",
        "circuit = QuantumCircuit(num_qubits)\n",
        "for pair in even_edges:\n",
        "    circuit.cx(pair[0], pair[1])\n",
        "for pair in odd_edges:\n",
        "    circuit.cx(pair[0], pair[1])\n",
        "\n",
        "# Choose a backend to run on\n",
        "service = QiskitRuntimeService()\n",
        "backend = service.least_busy()\n",
        "\n",
        "# Transpile the circuit for execution\n",
        "pm = generate_preset_pass_manager(backend=backend, optimization_level=3)\n",
        "circuit_to_learn = pm.run(circuit)\n",
        "\n",
        "# Instantiate a NoiseLearner object and execute the noise learning program\n",
        "learner = NoiseLearner(mode=backend)\n",
        "job = learner.run([circuit_to_learn])\n",
        "noise_model = job.result()"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "ef141d65-d14d-4e2b-9813-b8766e29fdb9",
      "metadata": {},
      "source": [
        "그 결과로 생성된 것은 대상 회로에 속하는 각 얽힘 계층에 대한 [노이즈](https://arxiv.org/abs/2201.09866) 모델을 포함하는 [`LayerError`](/docs/api/qiskit-ibm-runtime/results-layer-error) 객체들의 목록입니다 `NoiseLearnerResult.data` . 각 레이어는 회로와 큐비트 레이블 집합의 형태로 레이어 정보를 저장하며 `LayerError` , 주어진 레이어에 대해 [`PauliLindbladError`](/docs/api/qiskit-ibm-runtime/results-pauli-lindblad-error) 학습된 노이즈 모델 정보도 함께 저장합니다.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 2,
      "id": "a9be8ff1-7494-407c-853c-50d471a2f55f",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "Noise learner result contains 2 entries and has the following type:\n",
            " <class 'qiskit_ibm_runtime.utils.noise_learner_result.NoiseLearnerResult'>\n",
            "\n",
            "Each element of `NoiseLearnerResult` then contains an object of type:\n",
            " <class 'qiskit_ibm_runtime.utils.noise_learner_result.LayerError'>\n",
            "\n",
            "And each of these `LayerError` objects possess data on the generators for the error channel: \n",
            "['IIIIIIIIIIIIIIIIIIIIIIIIIIX', 'IIIIIIIIIIIIIIIIIIIIIIIIIIY',\n",
            " 'IIIIIIIIIIIIIIIIIIIIIIIIIIZ', 'IIIIIIIIIIIIIIIIIIIIIIIIIXI',\n",
            " 'IIIIIIIIIIIIIIIIIIIIIIIIIXX', 'IIIIIIIIIIIIIIIIIIIIIIIIIXY',\n",
            " 'IIIIIIIIIIIIIIIIIIIIIIIIIXZ', 'IIIIIIIIIIIIIIIIIIIIIIIIIYI',\n",
            " 'IIIIIIIIIIIIIIIIIIIIIIIIIYX', 'IIIIIIIIIIIIIIIIIIIIIIIIIYY',\n",
            " 'IIIIIIIIIIIIIIIIIIIIIIIIIYZ', 'IIIIIIIIIIIIIIIIIIIIIIIIIZI',\n",
            " 'IIIIIIIIIIIIIIIIIIIIIIIIIZX', 'IIIIIIIIIIIIIIIIIIIIIIIIIZY',\n",
            " 'IIIIIIIIIIIIIIIIIIIIIIIIIZZ', 'IIIIIIIIIIIIIIIIIIIIIIIIXII',\n",
            " 'IIIIIIIIIIIIIIIIIIIIIIIIXXI', 'IIIIIIIIIIIIIIIIIIIIIIIIXYI',\n",
            " 'IIIIIIIIIIIIIIIIIIIIIIIIXZI', 'IIIIIIIIIIIIIIIIIIIIIIIIYII',\n",
            " 'IIIIIIIIIIIIIIIIIIIIIIIIYXI', 'IIIIIIIIIIIIIIIIIIIIIIIIYYI',\n",
            " 'IIIIIIIIIIIIIIIIIIIIIIIIYZI', 'IIIIIIIIIIIIIIIIIIIIIIIIZII',\n",
            " 'IIIIIIIIIIIIIIIIIIIIIIIIZXI', 'IIIIIIIIIIIIIIIIIIIIIIIIZYI',\n",
            " 'IIIIIIIIIIIIIIIIIIIIIIIIZZI', 'IIIIIIIIIIIIIIIIIIIIIIIXIII',\n",
            " 'IIIIIIIIIIIIIIIIIIIIIIIXXII', 'IIIIIIIIIIIIIIIIIIIIIIIXYII',\n",
            " 'IIIIIIIIIIIIIIIIIIIIIIIXZII', 'IIIIIIIIIIIIIIIIIIIIIIIYIII',\n",
            " 'IIIIIIIIIIIIIIIIIIIIIIIYXII', 'IIIIIIIIIIIIIIIIIIIIIIIYYII',\n",
            " 'IIIIIIIIIIIIIIIIIIIIIIIYZII', 'IIIIIIIIIIIIIIIIIIIIIIIZIII',\n",
            " 'IIIIIIIIIIIIIIIIIIIIIIIZXII', 'IIIIIIIIIIIIIIIIIIIIIIIZYII',\n",
            " 'IIIIIIIIIIIIIIIIIIIIIIIZZII', 'IIIIIIIIIIIIIIIIIIIIIIXIIII',\n",
            " 'IIIIIIIIIIIIIIIIIIIIIIXXIII', 'IIIIIIIIIIIIIIIIIIIIIIXYIII',\n",
            " 'IIIIIIIIIIIIIIIIIIIIIIXZIII', 'IIIIIIIIIIIIIIIIIIIIIIYIIII',\n",
            " 'IIIIIIIIIIIIIIIIIIIIIIYXIII', 'IIIIIIIIIIIIIIIIIIIIIIYYIII',\n",
            " 'IIIIIIIIIIIIIIIIIIIIIIYZIII', 'IIIIIIIIIIIIIIIIIIIIIIZIIII',\n",
            " 'IIIIIIIIIIIIIIIIIIIIIIZXIII', 'IIIIIIIIIIIIIIIIIIIIIIZYIII',\n",
            " 'IIIIIIIIIIIIIIIIIIIIIIZZIII', 'IIIIIIIIIIIIIIIIIIIIIXIIIII',\n",
            " 'IIIIIIIIIIIIIIIIIIIIIXIIIIX', 'IIIIIIIIIIIIIIIIIIIIIXIIIIY',\n",
            " 'IIIIIIIIIIIIIIIIIIIIIXIIIIZ', 'IIIIIIIIIIIIIIIIIIIIIYIIIII',\n",
            " 'IIIIIIIIIIIIIIIIIIIIIYIIIIX', 'IIIIIIIIIIIIIIIIIIIIIYIIIIY',\n",
            " 'IIIIIIIIIIIIIIIIIIIIIYIIIIZ', 'IIIIIIIIIIIIIIIIIIIIIZIIIII',\n",
            " 'IIIIIIIIIIIIIIIIIIIIIZIIIIX', 'IIIIIIIIIIIIIIIIIIIIIZIIIIY',\n",
            " 'IIIIIIIIIIIIIIIIIIIIIZIIIIZ', 'IIIIIIIIIIIIIIIIIIIIXIIIIII',\n",
            " 'IIIIIIIIIIIIIIIIIIIIXIXIIII', 'IIIIIIIIIIIIIIIIIIIIXIYIIII',\n",
            " 'IIIIIIIIIIIIIIIIIIIIXIZIIII', 'IIIIIIIIIIIIIIIIIIIIYIIIIII',\n",
            " 'IIIIIIIIIIIIIIIIIIIIYIXIIII', 'IIIIIIIIIIIIIIIIIIIIYIYIIII',\n",
            " 'IIIIIIIIIIIIIIIIIIIIYIZIIII', 'IIIIIIIIIIIIIIIIIIIIZIIIIII',\n",
            " 'IIIIIIIIIIIIIIIIIIIIZIXIIII', 'IIIIIIIIIIIIIIIIIIIIZIYIIII', ...]\n",
            "\n",
            "Along with the error rates: \n",
            "[0.00037 0.00043 0.00032 ... 0.00031 0.00035 0.00017]\n",
            "\n"
          ]
        }
      ],
      "source": [
        "import numpy\n",
        "\n",
        "print(\n",
        "    f\"Noise learner result contains {len(noise_model.data)} entries\"\n",
        "    f\" and has the following type:\\n {type(noise_model)}\\n\"\n",
        ")\n",
        "print(\n",
        "    f\"Each element of `NoiseLearnerResult` then contains\"\n",
        "    f\" an object of type:\\n {type(noise_model.data[0])}\\n\"\n",
        ")\n",
        "# Results are truncated\n",
        "with numpy.printoptions(threshold=200):\n",
        "    print(\n",
        "        f\"And each of these `LayerError` objects possess\"\n",
        "        f\" data on the generators for the error channel: \\n\"\n",
        "        f\"{noise_model.data[0].error.generators}\\n\"\n",
        "    )\n",
        "# Results are truncated\n",
        "with numpy.printoptions(threshold=200):\n",
        "    print(\n",
        "        f\"Along with the error rates: \\n{noise_model.data[0].error.rates}\\n\"\n",
        "    )"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "faa3892e-30a5-48f7-87dd-39ab1b0846d9",
      "metadata": {},
      "source": [
        "노이즈 학습 결과의 `LayerError.error` 속성에는 적합된 폴리 린드블래드 모델의 생성자와 오류율이 포함되어 있으며, 다음과 같은 형식을 갖습니다\n",
        "\n",
        "$\\Lambda(\\rho) = \\exp{\\sum_j r_j \\left(P_j \\rho P_j^\\dagger - \\rho\\right)},$\n",
        "\n",
        "여기서 $r_j$ 은 `LayerError.rates` 과 $P_j$ 은 `LayerError.generators` 에 지정된 폴리 연산자입니다.\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "fc0000e6-e77a-4b87-a9ee-262f904953fc",
      "metadata": {},
      "source": [
        "<span id=\"noise-learning-options\" />\n",
        "\n",
        "### 소음 학습 옵션\n",
        "\n",
        "객체를 `NoiseLearner` 생성할 때 여러 입력 옵션 중에서 선택할 수 있습니다. 이러한 옵션들은 클래스에 `qiskit_ibm_runtime.options.NoiseLearnerOptions` 포함되어 있으며, 학습할 최대 레이어 수, 무작위화 횟수, 트위링 전략 등을 지정할 수 있는 기능을 포함합니다. 자세한 내용은 API 문서를 [`NoiseLearnerOptions`](/docs/api/qiskit-ibm-runtime/options-noise-learner-options) 참조하십시오.\n",
        "\n",
        "다음은 실험에서 `NoiseLearner` 를 `NoiseLearnerOptions` 사용하는 방법을 보여주는 간단한 예시입니다:\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 3,
      "id": "fcd1bd93-405d-4cfb-a5d1-bb646404aa58",
      "metadata": {},
      "outputs": [],
      "source": [
        "# Build a GHZ circuit\n",
        "circuit = QuantumCircuit(10)\n",
        "circuit.h(0)\n",
        "circuit.cx(range(0, 9), range(1, 10))\n",
        "# Choose a backend to run on\n",
        "service = QiskitRuntimeService()\n",
        "backend = service.least_busy()\n",
        "\n",
        "# Transpile the circuit for execution\n",
        "pm = generate_preset_pass_manager(backend=backend, optimization_level=3)\n",
        "circuit_to_run = pm.run(circuit_to_learn)\n",
        "\n",
        "# Instantiate a NoiseLearnerOptions object\n",
        "learner_options = NoiseLearnerOptions(\n",
        "    max_layers_to_learn=3, num_randomizations=32, twirling_strategy=\"all\"\n",
        ")\n",
        "\n",
        "# Instantiate a NoiseLearner object and execute the noise learning program\n",
        "learner = NoiseLearner(mode=backend, options=learner_options)\n",
        "job = learner.run([circuit_to_run])\n",
        "noise_model = job.result()"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "d952d0cc-497b-45ae-a55e-2b611ebbe4a3",
      "metadata": {},
      "source": [
        "<span id=\"input-noise-model-to-a-primitive\" />\n",
        "\n",
        "### 노이즈 모델을 프리미티브에 입력\n",
        "\n",
        "회로에서 학습된 노이즈 모델은 IBM Quantum`EstimatorV2` 프라이머리트의 입력으로도 사용할 수 있습니다. 이는 몇 가지 다른 방법으로 기본형에 전달될 수 있습니다. 다음 세 가지 예제는 노이즈 모델을 `estimator.options` 속성에 직접 전달하는 방법, Estimator 프리미티브를 인스턴스화하기 전에 `ResilienceOptionsV2` 객체를 사용하는 방법, 그리고 적절한 형식으로 구성된 딕셔너리를 전달하는 방법을 보여줍니다.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 4,
      "id": "9826013a-f9fd-4d72-baa7-dc5395b81007",
      "metadata": {},
      "outputs": [],
      "source": [
        "# Pass the noise model to the `estimator.options` attribute directly\n",
        "estimator = EstimatorV2(mode=backend)\n",
        "estimator.options.resilience.layer_noise_model = noise_model"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 5,
      "id": "7ab10595-5c20-4954-9001-70b8879926b4",
      "metadata": {},
      "outputs": [],
      "source": [
        "# Specify options through a ResilienceOptionsV2 object\n",
        "resilience_options = ResilienceOptionsV2(layer_noise_model=noise_model)\n",
        "estimator_options = EstimatorOptions(resilience=resilience_options)\n",
        "estimator = EstimatorV2(mode=backend, options=estimator_options)"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 6,
      "id": "17b1f8de-fe14-4998-898b-ecd409a5efd3",
      "metadata": {},
      "outputs": [],
      "source": [
        "# Specify options by using a dictionary\n",
        "options_dict = {\n",
        "    \"resilience_level\": 2,\n",
        "    \"resilience\": {\"layer_noise_model\": noise_model},\n",
        "}\n",
        "\n",
        "estimator = EstimatorV2(mode=backend, options=options_dict)"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "8c167b65-2e9a-41b9-b593-edfe80a2fde4",
      "metadata": {},
      "source": [
        "노이즈 모델이 객체에 `EstimatorV2` 전달되면, 이를 사용하여 평소와 같이 워크로드를 실행하고 오류 완화 작업을 수행할 수 있습니다.\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "dad71939-7fe2-42f0-90fe-6974fe0854e7",
      "metadata": {},
      "source": [
        "<span id=\"NoiseLearnerV3\" />\n",
        "\n",
        "<span id=\"noiselearnerv3\" />\n",
        "\n",
        "## NoiseLearnerV3\n",
        "\n",
        "<span id=\"overview\" />\n",
        "\n",
        "### 개요\n",
        "\n",
        "`NoiseLearner`와 마찬가지로, 이 `NoiseLearnerV3` 클래스는 하나 이상의 회로에 대해 파울리-린드블라드 잡음 모델을 기반으로 잡음 과정을 규명하는 실험을 수행합니다. 이 `run()` 메서드는 명령어 목록을 인수로 받으며, 각 명령어는 [ISA](/docs/guides/transpile#instruction-set-architecture) 연산을 포함하는 트위얼드 주석이 [`BoxOp`](/docs/api/qiskit/qiskit.circuit.BoxOp) 달린 객체여야 합니다.\n",
        "\n",
        "작업의 `NoiseLearnerV3` 결과에는 각 입력 명령어마다 하나씩, 총 개수의 [`NoiseLearnerV3Result`](/docs/api/qiskit-ibm-runtime/results-noise-learner-v3-result) 객체 목록이 포함됩니다.\n",
        "다음 코드는 헬퍼 프로그램을 사용하는 방법을 보여줍니다.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 7,
      "id": "0bbd2c21-6045-4954-aee9-339e6b060805",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "Found 3 unique layers\n",
            "Each instruction is of type <class 'qiskit.circuit.controlflow.box.BoxOp'>\n",
            "And has annotations: [Twirl(group='pauli', dressing='left', decomposition='rzsx'), InjectNoise(ref='r223A', modifier_ref='', site='after')]\n"
          ]
        }
      ],
      "source": [
        "from qiskit import QuantumCircuit\n",
        "from qiskit.transpiler import CouplingMap\n",
        "from qiskit.transpiler import generate_preset_pass_manager\n",
        "\n",
        "from qiskit_ibm_runtime import QiskitRuntimeService, Executor\n",
        "from qiskit_ibm_runtime.noise_learner_v3 import NoiseLearnerV3\n",
        "from samplomatic.transpiler import generate_boxing_pass_manager\n",
        "from samplomatic.utils import find_unique_box_instructions\n",
        "\n",
        "\n",
        "# Build a circuit with two entangling layers\n",
        "num_qubits = 27\n",
        "edges = list(CouplingMap.from_line(num_qubits, bidirectional=False))\n",
        "even_edges = edges[::2]\n",
        "odd_edges = edges[1::2]\n",
        "\n",
        "circuit = QuantumCircuit(num_qubits)\n",
        "for pair in even_edges:\n",
        "    circuit.cx(pair[0], pair[1])\n",
        "for pair in odd_edges:\n",
        "    circuit.cx(pair[0], pair[1])\n",
        "\n",
        "# Choose a backend to run on\n",
        "service = QiskitRuntimeService()\n",
        "backend = service.least_busy()\n",
        "\n",
        "# Transpile the circuit for execution\n",
        "pm = generate_preset_pass_manager(backend=backend, optimization_level=3)\n",
        "isa_circuit = pm.run(circuit)\n",
        "\n",
        "# Run the boxing pass manager to group instructions into annotated boxes\n",
        "boxing_pm = generate_boxing_pass_manager(\n",
        "    enable_gates=True,\n",
        "    enable_measures=False,\n",
        "    inject_noise_targets=\"gates\",  # no measurement mitigation\n",
        "    inject_noise_strategy=\"uniform_modification\",\n",
        ")\n",
        "boxed_circuit = boxing_pm.run(isa_circuit)\n",
        "\n",
        "# Find unique boxed instructions\n",
        "unique_box_instructions = find_unique_box_instructions(boxed_circuit.data)\n",
        "print(f\"Found {len(unique_box_instructions)} unique layers\")\n",
        "print(\n",
        "    f\"Each instruction is of type {type(unique_box_instructions[0].operation)}\"\n",
        ")\n",
        "print(\n",
        "    f\"And has annotations: {unique_box_instructions[0].operation.annotations}\"\n",
        ")\n",
        "\n",
        "# Instantiate a NoiseLearnerV3 object and execute the noise learning program\n",
        "learner = NoiseLearnerV3(backend)\n",
        "learner.options.shots_per_randomization = 128\n",
        "learner.options.num_randomizations = 32\n",
        "learner_job = learner.run(unique_box_instructions)\n",
        "learner_result = learner_job.result()"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "937986c1-b08d-4218-ae5d-c9dbfbf4a0cf",
      "metadata": {},
      "source": [
        "작업 결과는 객체들의 `NoiseLearnerV3Result` 목록으로, 입력된 각 명령어 집합마다 하나의 객체가 포함됩니다. `NoiseLearnerV3Result` 에는 객체를 [`PauliLindbladMap`](/docs/api/qiskit/qiskit.quantum_info.PauliLindbladMap) 반환하는 메서드가 `to_pauli_lindblad_map()` 있으며, 이 객체에는 생성기, 오류율 등을 추출하는 메서드들이 포함되어 있습니다.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 8,
      "id": "4a9b686b-cf8d-4986-8fff-83eedda1f2c1",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "The Noise learner V3 result contains 3 entries and each has the following type:\n",
            " <class 'qiskit_ibm_runtime.results.noise_learner_v3.NoiseLearnerV3Result'>\n",
            "\n",
            "After converting to PauliLindbladMap, you can extract data  on the generators for the error channel (truncated to 3): \n",
            "<QubitSparsePauliList with 3 elements on 27 qubits: [X_5, Y_5, Z_5]>\n",
            "\n",
            "Along with the error rates (truncated to 3): \n",
            "[2.3e-04 9.0e-05 1.1e-04]\n",
            "\n"
          ]
        }
      ],
      "source": [
        "print(\n",
        "    f\"The Noise learner V3 result contains {len(learner_result)} entries\"\n",
        "    f\" and each has the following type:\\n {type(learner_result[0])}\\n\"\n",
        ")\n",
        "noise_map = learner_result[0].to_pauli_lindblad_map()\n",
        "print(\n",
        "    f\"After converting to PauliLindbladMap, you can extract data \"\n",
        "    f\" on the generators for the error channel \"\n",
        "    f\"(truncated to 3): \\n{noise_map.generators()[:3]}\\n\"\n",
        ")\n",
        "with numpy.printoptions(threshold=20):\n",
        "    print(\n",
        "        f\"Along with the error rates \"\n",
        "        f\"(truncated to 3): \\n{noise_map.rates[:3]}\\n\"\n",
        "    )"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "baa61d6a-7efc-498b-bccd-260871e174df",
      "metadata": {},
      "source": [
        "<span id=\"noise-learning-options\" />\n",
        "\n",
        "### 소음 학습 옵션\n",
        "\n",
        "`NoiseLearnerV3` 무작위화 횟수 및 레이어 쌍의 깊이 등 여러 가지 옵션을 지원합니다. 기본 유형과 마찬가지로, 객체를 `NoiseLearnerV3` 생성하는 도중이나 생성 후에 옵션을 지정할 수 있습니다. 앞서 소개한 코드 예제에서는 및 `num_randomizations` `shots_per_randomization` 옵션을 설정하는 방법을 보여주었습니다. 자세한 내용은 API 문서를 [`NoiseLearnerV3Options`](/docs/api/qiskit-ibm-runtime/options-models-noise-learner-v3-options) 참조하십시오.\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "e76e997d-506f-4607-a89a-e4723c640a44",
      "metadata": {},
      "source": [
        "<span id=\"input-a-noise-model-to-executor\" />\n",
        "\n",
        "### Executor에 노이즈 모델을 입력합니다\n",
        "\n",
        "Executor는 회로 어노테이션(samplex 형식) 및 옵션에 명시된 설계 의도를 따릅니다. `InjectNoise` 는 노이즈를 삽입할 위치를 지정하는 주석이며, samplex 인수는 `pauli_lindblad_maps` 사용할 노이즈 맵을 지정합니다.\n",
        "\n",
        "앞의 예제에서 소개된 회로는 박싱 패스 관리자를 통해 실행되며, 이 관리자는 명령어를 주석이 달린 박스 단위로 묶습니다. 이해를 돕기 위해 관련 코드를 여기에 추가합니다.\n",
        "\n",
        "* `inject_noise_targets=”gates”` 얽힘 생성자가 포함된 상자에 주석을 `InjectNoise` 추가하도록 지정합니다.\n",
        "* `inject_noise_strategy=\"uniform_modification\"` ... 주석이 달린 `InjectNoise` 모든 동등한 상자에 동일한 `ref` 와 `modifier_ref` 를 할당하도록 지정합니다.\n",
        "  * `InjectNoise.ref` 해당 상자에 소음 모델을 할당하는 데 사용되는 고유 식별자입니다.\n",
        "  * `InjectNoise.modifier_ref` 상자에 할당된 노이즈 모델을 곱셈 계수를 사용하여 조정할 수 있습니다.\n",
        "\n",
        "```python\n",
        "boxing_pm = generate_boxing_pass_manager(\n",
        "    enable_gates=True,\n",
        "    enable_measures=False,\n",
        "    inject_noise_targets=\"gates\",  # no measurement mitigation\n",
        "    inject_noise_strategy=\"uniform_modification\",\n",
        ")\n",
        "```\n",
        "\n",
        "이전 예제의 회로에는 세 개의 상자가 포함되어 있으며, 그중 두 개에는 서로 다른 `ref` 속성을 가진 주석이 포함되어 `InjectNoise` 있습니다(두 상자가 서로 동일하지 않기 때문입니다).\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 9,
      "id": "3b86853b-6766-4cf6-9a6b-2ea1008aea42",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "Annotations of box #0: [Twirl(group='pauli', dressing='left', decomposition='rzsx'), InjectNoise(ref='r223A', modifier_ref='r223A', site='after')]\n",
            "\n",
            "Annotations of box #1: [Twirl(group='pauli', dressing='left', decomposition='rzsx'), InjectNoise(ref='r621A', modifier_ref='r621A', site='after')]\n",
            "\n",
            "Annotations of box #2: [Twirl(group='pauli', dressing='right', decomposition='rzsx')]\n",
            "\n"
          ]
        }
      ],
      "source": [
        "# box_circuit comes from the example above\n",
        "for idx, instruction in enumerate(boxed_circuit):\n",
        "    # The `InjectNoise` annotation defines which boxes to inject noise.\n",
        "    print(f\"Annotations of box #{idx}: {instruction.operation.annotations}\\n\")"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "3ab1e503-b36a-46bd-b5d1-2735c3d0a82d",
      "metadata": {},
      "source": [
        "작업의 `NoiseLearnerV3` 결과는 Executor로 전달되기 전에 사전(dictionary) 형식으로 변환되어야 합니다. 이 사전의 키는 속성이며, 값은 해당 `InjectNoise.ref` 속성에 대응하는 노이즈 맵입니다. 이 매핑은 Executor에게 어떤 노이즈 모델을 어디에 주입해야 하는지 알려줍니다.\n",
        "\n",
        "다음 코드는 이전 예제의 회로와 결과를 `NoiseLearnerV3` 가져와 Executor에 전달하는 방법을 보여줍니다. Executor는 주입된 노이즈 모델을 적용한 회로 변형을 생성하고 이를 하드웨어에서 실행합니다.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 10,
      "id": "96d59082-7adc-482a-b57f-0f7a5c3eb217",
      "metadata": {},
      "outputs": [],
      "source": [
        "from qiskit_ibm_runtime.quantum_program import QuantumProgram\n",
        "from samplomatic import build\n",
        "\n",
        "# Generate a quantum program\n",
        "program = QuantumProgram(shots=1000)\n",
        "\n",
        "# Build the template circuit and samplex pair\n",
        "template_circuit, samplex = build(boxed_circuit)\n",
        "\n",
        "# Convert the NoiseLearnerV3 result to a dictionary\n",
        "noise_maps = learner_result.to_dict(\n",
        "    instructions=unique_box_instructions, require_refs=False\n",
        ")\n",
        "\n",
        "# Append the samplex item and execute\n",
        "program.append_samplex_item(\n",
        "    template_circuit,\n",
        "    samplex=samplex,\n",
        "    samplex_arguments={\n",
        "        \"pauli_lindblad_maps\": noise_maps,\n",
        "    },\n",
        ")\n",
        "\n",
        "executor = Executor(backend)\n",
        "executor_job = executor.run(program)"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "936c08fb-7838-4d61-9060-092b479e7909",
      "metadata": {},
      "source": [
        "<span id=\"next-steps\" />\n",
        "\n",
        "## 다음 단계\n",
        "\n",
        "<Admonition type=\"tip\" title=\"권장사항\">\n",
        "  * [EstimatorOptions API 참조](/docs/api/qiskit-ibm-runtime/options-estimator-options) 및 [ResilienceOptionsV2 API 참조를](/docs/api/qiskit-ibm-runtime/options-resilience-options-v2) 검토하세요.\n",
        "  * 사용 가능한 [오류 완화 및 억제 기법에](error-mitigation-and-suppression-techniques) 대해 자세히 알아보세요.\n",
        "  * [에스티메이터 노이즈 관리](/docs/guides/estimator-noise-management) 기능을 구현하는 방법을 알아보세요.\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"
    }
  },
  "nbformat": 4,
  "nbformat_minor": 4
}