{
  "cells": [
    {
      "cell_type": "markdown",
      "id": "0ff6f833-f5fb-4e9e-a572-445f2ff9ad64",
      "metadata": {},
      "source": [
        "---\n",
        "title: \"원시 입력 및 출력\"\n",
        "description: \"Qiskit SDK 프리미티브의 입력 및 출력 형식(Primitive Unified Blocs, PUB 포함)을 이해한다\"\n",
        "---\n",
        "\n",
        "<span id=\"primitive-inputs-and-outputs\" />\n",
        "\n",
        "# 원시 입력 및 출력\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "36a00905-1855-4fce-9686-20eb01ba72b6",
      "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",
        "    ```\n",
        "  </AccordionItem>\n",
        "</Accordion>\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "203951dd-4da7-4e0d-93f7-3ed7e2cd624b",
      "metadata": {},
      "source": [
        "이 페이지에서는 Qiskit SDK 기본 요소의 입력 및 출력에 대한 개요를 제공합니다. 이러한 기본 유형을 활용하면 **‘기본 유형 통합 블록( PUB )** ’으로 알려진 데이터 구조를 사용하여 벡터화된 워크로드를 효율적으로 정의할 수 있습니다. 이러한 PUB는 워크로드 실행을 위한 기본 작업 단위입니다. 이들은 Sampler 및 Estimator 프리미티브의 `run()` 메서드에 입력으로 사용되며, 해당 메서드는 정의된 워크로드를 작업으로 실행합니다. 그런 다음, 작업이 완료되면 사용된 PUB와 지정된 옵션에 따라 결과가 반환됩니다.\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "c7bc7444-eada-42ec-8f9a-6ec848c40014",
      "metadata": {},
      "source": [
        "<span id=\"pubs\" />\n",
        "\n",
        "<span id=\"overview-of-pubs\" />\n",
        "\n",
        "## PUB 개요\n",
        "\n",
        "프라이머리 `run()` 메서드를 호출할 때, 필수로 필요한 주 인수는 하나 이상의 튜플로 구성된 `list` 튜플 집합이며, 이 튜플들은 프라이머리가 실행하는 각 회로에 하나씩 대응합니다. 이러한 각 튜플은 원시형( PUB )으로 간주되며, 목록 내 각 튜플에 포함되어야 하는 필수 요소는 사용된 원시형에 따라 달라집니다. 이러한 튜플에 제공되는 데이터는 브로드캐스팅을 통해 다양한 형태로 배열될 수 있어 워크로드에 유연성을 제공하며, 이에 대한 규칙은 [다음](#broadcasting-rules) 섹션에서 설명합니다.\n",
        "\n",
        "<span id=\"estimator-pub\" />\n",
        "\n",
        "### 추정기 PUB\n",
        "\n",
        "추정기 프리미티브의 경우 PUB 형식은 최대 4개의 값을 포함해야 합니다:\n",
        "\n",
        "* 단일 `QuantumCircuit`, 하나 이상의 [`Parameter`](/docs/api/qiskit/qiskit.circuit.Parameter) 객체\n",
        "* 추정할 기대값을 지정하는 하나 이상의 관측값 목록으로, 배열로 정렬되어 있습니다(예: 0-d 배열로 표시되는 단일 관측값, 1-d 배열로 표시되는 관측값 목록 등). 데이터는 `Pauli`, `SparsePauliOp`, `PauliList`, `str` 와 같은 `ObservablesArrayLike` 형식 중 하나를 사용할 수 있습니다.\n",
        "  <Admonition type=\"note\">\n",
        "    서로 다른 PUB에 속하지만 동일한 회로를 가진 두 개의 통근 관측량이 있다면, 동일한 측정을 통해 추정되지 않습니다. 각 1차원 측정값( PUB )은 서로 다른 측정 기준을 나타내므로, 각 1차원 측정값( PUB )에 대해 별도의 측정이 필요합니다. 통근 관측값이 동일한 측정값을 사용하여 추정되도록 하려면, 동일한 통근 관측값 그룹( PUB ) 내에 묶여야 합니다.\n",
        "  </Admonition>\n",
        "* 회로를 바인딩할 파라미터 값의 모음입니다. 이는 마지막 인덱스가 회로 `Parameter` 객체 위에 있는 단일 배열형 객체로 지정하거나, 회로에 `Parameter` 객체가 없는 경우 생략(또는 동등하게 `None` 로 설정)할 수 있습니다.\n",
        "* (선택 사항) 추정할 예상 값의 목표 정밀도입니다\n",
        "\n",
        "<span id=\"sampler-pub\" />\n",
        "\n",
        "### 샘플러 PUB\n",
        "\n",
        "샘플러 프리미티브의 경우, PUB 튜플의 형식은 최대 3개의 값을 포함합니다:\n",
        "\n",
        "* 하나 이상의 [`Parameter`](/docs/api/qiskit/qiskit.circuit.Parameter) 객체를 포함할 수 있는 `QuantumCircuit`단일\n",
        "  *참고: 이러한 회로에는 샘플링 대상인 각 큐비트에 대한 측정 지침도 포함되어야 합니다.*\n",
        "* $\\theta_k$ 에 회로를 바인딩할 파라미터 값 모음(런타임에 바인딩해야 하는 `Parameter` 객체가 사용되는 경우에만 필요)\n",
        "* (선택 사항) 회로를 측정할 수 있는 샷 수\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "2bdb4618-e59f-4627-81b6-6828b40258f7",
      "metadata": {},
      "source": [
        "***\n",
        "\n",
        "다음 코드는 해당 `Estimator` 프리미티브에 대한 벡터화된 입력의 예시를 보여줍니다.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 1,
      "id": "e84f14f0-7190-4ab6-ba49-2746c515238c",
      "metadata": {},
      "outputs": [],
      "source": [
        "from qiskit.circuit import (\n",
        "    Parameter,\n",
        "    QuantumCircuit,\n",
        "    ClassicalRegister,\n",
        "    QuantumRegister,\n",
        ")\n",
        "from qiskit.transpiler import generate_preset_pass_manager\n",
        "from qiskit.quantum_info import SparsePauliOp\n",
        "from qiskit.primitives.containers import BitArray\n",
        "from qiskit.primitives import StatevectorEstimator\n",
        "\n",
        "\n",
        "import numpy as np\n",
        "\n",
        "# Define a circuit with two parameters.\n",
        "circuit = QuantumCircuit(2)\n",
        "circuit.h(0)\n",
        "circuit.cx(0, 1)\n",
        "circuit.ry(Parameter(\"a\"), 0)\n",
        "circuit.rz(Parameter(\"b\"), 0)\n",
        "circuit.cx(0, 1)\n",
        "circuit.h(0)\n",
        "\n",
        "# Transpile the circuit without providing a backend\n",
        "pm = generate_preset_pass_manager(optimization_level=1)\n",
        "transpiled_circuit = pm.run(circuit)\n",
        "layout = transpiled_circuit.layout\n",
        "\n",
        "# Now define a sweep over parameter values, the last axis of dimension 2 is\n",
        "# for the two parameters \"a\" and \"b\"\n",
        "params = np.vstack(\n",
        "    [\n",
        "        np.linspace(-np.pi, np.pi, 10),\n",
        "        np.linspace(-4 * np.pi, 4 * np.pi, 10),\n",
        "    ]\n",
        ").T\n",
        "\n",
        "# Define three observables. The inner length-1 lists cause this array of\n",
        "# observables to have shape (3, 1), rather than shape (3,) if they were\n",
        "# omitted.\n",
        "observables = [\n",
        "    [SparsePauliOp([\"XX\", \"IY\"], [0.5, 0.5])],\n",
        "    [SparsePauliOp(\"XX\")],\n",
        "    [SparsePauliOp(\"IY\")],\n",
        "]\n",
        "# Apply the same layout as the transpiled circuit.\n",
        "observables = [\n",
        "    [observable.apply_layout(layout) for observable in observable_set]\n",
        "    for observable_set in observables\n",
        "]\n",
        "\n",
        "# Estimate the expectation value for all 300 combinations of observables\n",
        "# and parameter values, where the pub result will have shape (3, 100).\n",
        "#\n",
        "# This shape is due to our array of parameter bindings having shape\n",
        "# (100, 2), combined with our array of observables having shape (3, 1).\n",
        "estimator = StatevectorEstimator()\n",
        "estimator_pub = (transpiled_circuit, observables, params)\n",
        "\n",
        "# Run the transpiled circuit\n",
        "# using the set of parameters and observables.\n",
        "\n",
        "job = estimator.run([estimator_pub])\n",
        "result = job.result()"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "3acc54a9-ab50-4155-9c2d-c6a75dba816d",
      "metadata": {},
      "source": [
        "<span id=\"broadcasting\" />\n",
        "\n",
        "<span id=\"broadcasting-rules\" />\n",
        "\n",
        "### 방송 규칙\n",
        "\n",
        "PUB는 NumPy 과 동일한 브로드캐스팅 규칙에 따라 여러 배열(옵저버 및 파라미터 값)의 요소를 집계합니다. 이 섹션에서는 이러한 규칙을 간략하게 요약합니다.  자세한 설명은 [NumPy 방송 규칙 문서를](https://numpy.org/doc/stable/user/basics.broadcasting.html) 참조하세요.\n",
        "\n",
        "규칙:\n",
        "\n",
        "* 입력 배열의 차원 개수가 같을 필요는 없습니다.\n",
        "  * 결과 배열은 가장 큰 차원을 가진 입력 배열과 동일한 수의 차원을 갖게 됩니다.\n",
        "  * 각 치수의 크기는 해당 치수의 가장 큰 크기입니다.\n",
        "  * 누락된 치수는 크기가 1로 가정합니다.\n",
        "* 도형 비교는 가장 오른쪽 치수부터 시작하여 왼쪽으로 이어집니다.\n",
        "* 두 치수의 크기가 같거나 둘 중 하나가 1이면 두 치수는 호환됩니다.\n",
        "\n",
        "브로드캐스트하는 배열 쌍의 예입니다:\n",
        "\n",
        "```text\n",
        "A1     (1d array):      1\n",
        "A2     (2d array):  3 x 5\n",
        "Result (2d array):  3 x 5\n",
        "\n",
        "\n",
        "A1     (3d array):  11 x 2 x 7\n",
        "A2     (3d array):  11 x 1 x 7\n",
        "Result (3d array):  11 x 2 x 7\n",
        "```\n",
        "\n",
        "브로드캐스트하지 않는 배열 쌍의 예입니다:\n",
        "\n",
        "```text\n",
        "A1     (1d array):  5\n",
        "A2     (1d array):  3\n",
        "\n",
        "A1     (2d array):      2 x 1\n",
        "# The following would work if the middle dimension were 2,\n",
        "# instead of 5.\n",
        "A2     (3d array):  6 x 5 x 4\n",
        "```\n",
        "\n",
        "`Estimator` 브로드캐스트된 형상의 각 요소에 대해 하나의 기대값 추정치를 반환합니다.\n",
        "\n",
        "다음은 배열 방송으로 표현되는 일반적인 패턴의 몇 가지 예입니다.  함께 제공되는 시각적 표현은 다음 그림에 나와 있습니다:\n",
        "\n",
        "매개변수 값 집합은 n x m 배열로 표시되며, 관측 가능한 배열은 하나 이상의 단일 열 배열로 표시됩니다. 이전 코드의 각 예제에서 매개변수 값 세트는 관찰 가능한 배열과 결합되어 결과 예상값 추정치를 생성합니다.\n",
        "\n",
        "* *예 1* : (단일 관측 항목 브로드캐스트)에는 5x1 배열과 1x1 관측 항목 배열인 파라미터 값 세트가 있습니다.  관찰 항목 배열의 한 항목이 매개변수 값 집합의 각 항목과 결합되어 단일 5x1 배열이 만들어지며, 각 항목은 매개변수 값 집합의 원래 항목과 관찰 항목 배열의 항목이 결합된 것입니다.\n",
        "\n",
        "* *예제 2* : (zip)에는 5x1 매개변수 값 세트와 5x1 관찰 가능 배열이 있습니다.  출력은 5x1 배열이며, 각 항목은 매개변수 값 집합의 n번째 항목과 관찰 가능 항목 배열의 n번째 항목의 조합입니다.\n",
        "\n",
        "* *예 3* : (outer/product)에는 1x6 매개변수 값 집합과 4x1 관찰 가능 항목 배열이 있습니다.  이들의 조합은 매개변수 값 집합의 각 항목을 관찰 가능 항목 배열의 *모든* 항목과 결합하여 4x6 배열을 생성하므로 각 매개변수 값은 출력의 전체 열이 됩니다.\n",
        "\n",
        "* *예 4* : (표준 및 일반화) 3x6 매개변수 값 집합 배열과 두 개의 3x1 관찰 가능 배열이 있습니다.  이를 결합하여 이전 예제와 유사한 방식으로 두 개의 3x6 출력 배열을 만듭니다.\n",
        "\n",
        "![이 그림은 배열 브로드캐스팅을 나타내는 몇 가지 시각적 표현을 보여줍니다. 브로드캐스팅의 ](https://quantum.cloud.ibm.com/docs/images/guides/primitive-input-output/broadcasting.avif \"시각적 표현\")\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 2,
      "id": "37aa226f-d550-42fd-9ab0-60e27757722a",
      "metadata": {},
      "outputs": [],
      "source": [
        "# Broadcast single observable\n",
        "parameter_values = np.random.uniform(size=(5,))  # shape (5,)\n",
        "observables = SparsePauliOp(\"ZZZ\")  # shape ()\n",
        "# >> pub result has shape (5,)\n",
        "\n",
        "# Zip\n",
        "parameter_values = np.random.uniform(size=(5,))  # shape (5,)\n",
        "observables = [\n",
        "    SparsePauliOp(pauli) for pauli in [\"III\", \"XXX\", \"YYY\", \"ZZZ\", \"XYZ\"]\n",
        "]  # shape (5,)\n",
        "# >> pub result has shape (5,)\n",
        "\n",
        "# Outer/Product\n",
        "parameter_values = np.random.uniform(size=(1, 6))  # shape (1, 6)\n",
        "observables = [\n",
        "    [SparsePauliOp(pauli)] for pauli in [\"III\", \"XXX\", \"YYY\", \"ZZZ\"]\n",
        "]  # shape (4, 1)\n",
        "# >> pub result has shape (4, 6)\n",
        "\n",
        "# Standard nd generalization\n",
        "parameter_values = np.random.uniform(size=(3, 6))  # shape (3, 6)\n",
        "observables = [\n",
        "    [\n",
        "        [SparsePauliOp([\"XII\"])],\n",
        "        [SparsePauliOp([\"IXI\"])],\n",
        "        [SparsePauliOp([\"IIX\"])],\n",
        "    ],\n",
        "    [\n",
        "        [SparsePauliOp([\"ZII\"])],\n",
        "        [SparsePauliOp([\"IZI\"])],\n",
        "        [SparsePauliOp([\"IIZ\"])],\n",
        "    ],\n",
        "]  # shape (2, 3, 1)\n",
        "# >> pub result has shape (2, 3, 6)"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "408e47b0-24ca-45b5-b71b-080d8ccf30a6",
      "metadata": {},
      "source": [
        "<Admonition type=\"tip\" title=\"SparsePauliOp\">\n",
        "  `SparsePauliOp` 에 포함된 폴리의 수에 관계없이 각 `SparsePauliOp` 은 이 컨텍스트에서 단일 요소로 계산됩니다. 따라서 이러한 방송 운영원칙의 목적상 다음 요소는 모두 동일한 모양을 갖습니다:\n",
        "\n",
        "  ```text\n",
        "  a = SparsePauliOp(\"Z\") # shape ()\n",
        "  b = SparsePauliOp(\"IIIIZXYIZ\") # shape ()\n",
        "  c = SparsePauliOp.from_list([\"XX\", \"XY\", \"IZ\"]) # shape ()\n",
        "  ```\n",
        "\n",
        "  다음 사업자 목록은 포함된 정보는 동일하지만 형태가 다릅니다:\n",
        "\n",
        "  ```text\n",
        "  list1 = SparsePauliOp.from_list([\"XX\", \"XY\", \"IZ\"])\n",
        "      # list1 has shape ()\n",
        "  list2 = [SparsePauliOp(\"XX\"), SparsePauliOp(\"XY\"), SparsePauliOp(\"IZ\")]\n",
        "      # list2 has shape (3, )\n",
        "  ```\n",
        "</Admonition>\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "f548b270-afa7-480c-a457-c5260791d55b",
      "metadata": {},
      "source": [
        "<span id=\"overview-of-primitive-outputs\" />\n",
        "\n",
        "## 기본 출력 개요\n",
        "\n",
        "하나 이상의 PUB가 실행을 위해 QPU로 전송되고 작업이 성공적으로 완료되면, 해당 데이터는 컨테이너 [`PrimitiveResult`](/docs/api/qiskit/qiskit.primitives.PrimitiveResult) 객체로 반환됩니다. 이 객체에는 각 [`PubResult`](/docs/api/qiskit/qiskit.primitives.PubResult)PUB 에 대한 `PrimitiveResult` 실행 결과를 포함하는 객체들의 반복 가능한 목록이 포함되어 있습니다. 예를 들어, 20개의 PUB로 제출된 작업은 각 PUB 에 하나씩 대응하는 20개의 목록을 포함하는 `PubResults`객체를 `PrimitiveResult` 반환합니다.\n",
        "\n",
        "이 `PubResult` 객체들은 각각 속성과 `data` 선택적 `metadata` 속성을 모두 가지고 있습니다. 이 `data` 속성은 Estimator의 경우 기대값 추정치를, Sampler의 경우 회로 출력의 샘플을 포함하는 사용자 [`DataBin`](/docs/api/qiskit/qiskit.primitives.DataBin) 정의 객체입니다.\n",
        "\n",
        "이 `data` 속성에는 표준 편차와 같은 기타 구현체별 정보도 포함될 수 있습니다. 이 `metadata` 속성에는 관련 PUB 의 실행에 관한 구현체별 추가 정보가 포함될 수 있습니다.\n",
        "\n",
        "다음은 `PrimitiveResult` 데이터 구조의 시각적 개요입니다:\n",
        "\n",
        "<Tabs>\n",
        "  <TabItem value=\"estimator\" label=\"Estimator output\">\n",
        "    ```\n",
        "    └── PrimitiveResult\n",
        "        ├── PubResult[0]\n",
        "        │   ├── metadata\n",
        "        │   └── data  ## In the form of a DataBin object,\n",
        "        |       |     ## which includes data such as the following:\n",
        "        │       ├── evs\n",
        "        │       │   └── List of estimated expectation values in the shape\n",
        "        |       |         specified by the first pub\n",
        "        │       └── stds\n",
        "        │           └── List of calculated standard deviations in the\n",
        "        |                 same shape as above\n",
        "        ├── PubResult[1]\n",
        "        |   ├── metadata\n",
        "        |   └── data  ## In the form of a DataBin object,\n",
        "        |       |     ## which includes data such as the following:\n",
        "        |       ├── evs\n",
        "        |       │   └── List of estimated expectation values in the shape\n",
        "        |       |        specified by the second pub\n",
        "        |       └── stds\n",
        "        |           └── List of calculated standard deviations in the\n",
        "        |                same shape as above\n",
        "        ├── ...\n",
        "        ├── ...\n",
        "        └── ...\n",
        "    ```\n",
        "\n",
        "    <Admonition type=\"note\">\n",
        "      위는 반환될 수 있는 데이터의 예시입니다.  반환되는 실제 데이터는 구현 방식에 따라 달라집니다.\n",
        "    </Admonition>\n",
        "  </TabItem>\n",
        "\n",
        "  <TabItem value=\"sampler\" label=\"Sampler output\">\n",
        "    ```\n",
        "    └── PrimitiveResult\n",
        "        ├── PubResult[0]\n",
        "        │   ├── metadata\n",
        "        │   └── data  ## In the form of a DataBin object\n",
        "        │       ├── NAME_OF_CLASSICAL_REGISTER\n",
        "        │       │   └── BitArray of count data for first PUB (default is 'meas')\n",
        "        |       |\n",
        "        │       └── NAME_OF_ANOTHER_CLASSICAL_REGISTER\n",
        "        │           └── BitArray of count data (exists only if more than one\n",
        "        |                 ClassicalRegister was specified in the circuit)\n",
        "        ├── PubResult[1]\n",
        "        |   ├── metadata\n",
        "        |   └── data  ## In the form of a DataBin object\n",
        "        |       └── NAME_OF_CLASSICAL_REGISTER\n",
        "        |           └── BitArray of count data for second PUB\n",
        "        ├── ...\n",
        "        ├── ...\n",
        "        └── ...\n",
        "    ```\n",
        "  </TabItem>\n",
        "</Tabs>\n",
        "\n",
        "<span id=\"estimator-output\" />\n",
        "\n",
        "### 추정기 출력\n",
        "\n",
        "앞서 언급했듯이, Estimator `PubResult` 프라이머리에서 반환되는 데이터는 구현 방식에 따라 달라집니다. 예를 들어, 기대값의 배열 (`PubResult.data.evs`)과 이에 대응하는 표준편차 (`PubResult.data.stds`)를 포함할 수 있습니다.\n",
        "\n",
        "아래 코드 스니펫은 위에서 만든 작업의 `PrimitiveResult` (및 관련 `PubResult`) 형식에 대해 설명합니다.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 3,
      "id": "7b3ac687-8197-4c50-831c-a349fd8e90a2",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "The result of the submitted job had 1 PUB and has a value:\n",
            " PrimitiveResult([PubResult(data=DataBin(evs=np.ndarray(<shape=(3, 10), dtype=float64>), stds=np.ndarray(<shape=(3, 10), dtype=float64>), shape=(3, 10)), metadata={'target_precision': 0.0, 'circuit_metadata': {}})], metadata={'version': 2})\n",
            "\n",
            "The associated PubResult of this job has the following data bins:\n",
            " DataBin(evs=np.ndarray(<shape=(3, 10), dtype=float64>), stds=np.ndarray(<shape=(3, 10), dtype=float64>), shape=(3, 10))\n",
            "\n",
            "And this DataBin has attributes: dict_keys(['evs', 'stds'])\n",
            "Recall that this shape is due to our array of parameter binding sets having shape (100, 2) -- where 2 is the number of parameters in the circuit -- combined with our array of observables having shape (3, 1).\n",
            "The expectation values measured from this PUB are: \n",
            "[[ 3.06161700e-16  4.52395120e-01  4.36594428e-01  2.16506351e-01\n",
            "   6.33718361e-01 -6.33718361e-01 -2.16506351e-01 -4.36594428e-01\n",
            "  -4.52395120e-01 -3.06161700e-16]\n",
            " [ 1.22464680e-16  6.42787610e-01  9.84807753e-01  8.66025404e-01\n",
            "   3.42020143e-01 -3.42020143e-01 -8.66025404e-01 -9.84807753e-01\n",
            "  -6.42787610e-01 -1.22464680e-16]\n",
            " [ 4.89858720e-16  2.62002630e-01 -1.11618897e-01 -4.33012702e-01\n",
            "   9.25416578e-01 -9.25416578e-01  4.33012702e-01  1.11618897e-01\n",
            "  -2.62002630e-01 -4.89858720e-16]]\n"
          ]
        }
      ],
      "source": [
        "print(\n",
        "    f\"The result of the submitted job had {len(result)} PUB and \"\n",
        "    f\"has a value:\\n {result}\\n\"\n",
        ")\n",
        "print(\n",
        "    f\"The associated PubResult of this job has the following data bins:\"\n",
        "    f\"\\n {result[0].data}\\n\"\n",
        ")\n",
        "print(f\"And this DataBin has attributes: {result[0].data.keys()}\")\n",
        "print(\n",
        "    \"Recall that this shape is due to our array of parameter binding sets \"\n",
        "    \"having shape (100, 2) -- where 2 is the number of parameters in the circuit -- \"\n",
        "    \"combined with our array of observables having shape (3, 1).\"\n",
        ")\n",
        "\n",
        "print(\n",
        "    f\"The expectation values measured from this PUB are: \\n{result[0].data.evs}\"\n",
        ")"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "af092cd2-4388-4cb4-ba2a-a95b0d6b6c1e",
      "metadata": {},
      "source": [
        "<span id=\"sampler-output\" />\n",
        "\n",
        "### 샘플러 출력\n",
        "\n",
        "샘플러 작업이 성공적으로 완료되면 반환된 [`PrimitiveResult`](/docs/api/qiskit/qiskit.primitives.PrimitiveResult) 객체에는 각 샘플러( PUB )마다 하나씩의 [`SamplerPubResult`](/docs/api/qiskit/qiskit.primitives.SamplerPubResult)s 목록이 포함됩니다. 이러한 `SamplerPubResult` 객체의 데이터 빈은 딕셔너리 유사 객체로, 회로 내 각 `ClassicalRegister` 객체당 `BitArray` 하나씩 포함됩니다.\n",
        "\n",
        "`BitArray` 클래스는 주문된 샷 데이터를 위한 컨테이너입니다. 좀 더 자세히 설명하면, 샘플링된 비트스트링을 2차원 배열 안에 바이트 단위로 저장합니다. 이 배열의 가장 왼쪽 축은 정렬된 샷에 대해 실행되고 가장 오른쪽 축은 바이트에 대해 실행됩니다.\n",
        "\n",
        "첫 번째 예로 다음 10큐비트 회로를 살펴보겠습니다:\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 4,
      "id": "f2902d44-e97e-450f-9290-e9a8e1a5b287",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "Databin: DataBin(meas=BitArray(<shape=(), num_shots=1024, num_bits=10>))\n",
            "\n",
            "BitArray: BitArray(<shape=(), num_shots=1024, num_bits=10>)\n",
            "\n",
            "The shape of register `meas` is (1024, 2).\n",
            "\n",
            "The bytes in register `alpha`, shot by shot:\n",
            "[[  3 255]\n",
            " [  0   0]\n",
            " [  3 255]\n",
            " ...\n",
            " [  0   0]\n",
            " [  3 255]\n",
            " [  0   0]]\n",
            "\n"
          ]
        }
      ],
      "source": [
        "from qiskit.primitives import StatevectorSampler\n",
        "\n",
        "# generate a ten-qubit GHZ circuit\n",
        "circuit = QuantumCircuit(10)\n",
        "circuit.h(0)\n",
        "circuit.cx(range(0, 9), range(1, 10))\n",
        "\n",
        "# append measurements with the `measure_all` method\n",
        "circuit.measure_all()\n",
        "\n",
        "# transpile the circuit\n",
        "transpiled_circuit = pm.run(circuit)\n",
        "\n",
        "sampler = StatevectorSampler()\n",
        "\n",
        "# run the Sampler job and retrieve the results\n",
        "\n",
        "job = sampler.run([transpiled_circuit])\n",
        "result = job.result()\n",
        "\n",
        "# the data bin contains one BitArray\n",
        "data = result[0].data\n",
        "print(f\"Databin: {data}\\n\")\n",
        "\n",
        "# to access the BitArray, use the key \"meas\", which is the default name of\n",
        "# the classical register when this is added by the `measure_all` method\n",
        "array = data.meas\n",
        "print(f\"BitArray: {array}\\n\")\n",
        "print(f\"The shape of register `meas` is {data.meas.array.shape}.\\n\")\n",
        "print(f\"The bytes in register `alpha`, shot by shot:\\n{data.meas.array}\\n\")"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "8d7e1188-d7a9-4e1a-a783-25e49a5fa1a2",
      "metadata": {},
      "source": [
        "때로는 바이트 형식을 비트열로 `BitArray` 변환하는 것이 편리할 수 있습니다. 이 `get_count` 메서드는 비트열과 해당 비트열이 나타난 횟수를 대응시키는 딕셔너리를 반환합니다.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 5,
      "id": "0eb3a383-30cd-4a32-8d8d-740264587079",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "Counts: {'1111111111': 484, '0000000000': 540}\n"
          ]
        }
      ],
      "source": [
        "# optionally convert the native BitArray format to a dictionary format\n",
        "counts = data.meas.get_counts()\n",
        "print(f\"Counts: {counts}\")"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "f02341ca-4d0f-421b-9817-47f7b339d057",
      "metadata": {},
      "source": [
        "회로에 하나 이상의 클래식 레지스터가 포함될 경우, 결과는 서로 다른 `BitArray` 객체에 저장됩니다. 다음 예제는 클래식 레지스터를 두 개의 별개의 레지스터로 분할하여 이전 코드 조각을 수정합니다:\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 6,
      "id": "5b294da8-b6b2-4313-aa98-efa4a1903ba4",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "BitArray for register 'alpha': BitArray(<shape=(), num_shots=1024, num_bits=1>)\n",
            "BitArray for register 'beta': BitArray(<shape=(), num_shots=1024, num_bits=9>)\n"
          ]
        }
      ],
      "source": [
        "# generate a ten-qubit GHZ circuit with two classical registers\n",
        "circuit = QuantumCircuit(\n",
        "    qreg := QuantumRegister(10),\n",
        "    alpha := ClassicalRegister(1, \"alpha\"),\n",
        "    beta := ClassicalRegister(9, \"beta\"),\n",
        ")\n",
        "circuit.h(0)\n",
        "circuit.cx(range(0, 9), range(1, 10))\n",
        "\n",
        "# append measurements with the `measure_all` method\n",
        "circuit.measure([0], alpha)\n",
        "circuit.measure(range(1, 10), beta)\n",
        "\n",
        "# transpile the circuit\n",
        "transpiled_circuit = pm.run(circuit)\n",
        "\n",
        "# run the Sampler job and retrieve the results\n",
        "\n",
        "job = sampler.run([transpiled_circuit])\n",
        "result = job.result()\n",
        "\n",
        "# the data bin contains two BitArrays, one per register, and can be accessed\n",
        "# as attributes using the registers' names\n",
        "data = result[0].data\n",
        "print(f\"BitArray for register 'alpha': {data.alpha}\")\n",
        "print(f\"BitArray for register 'beta': {data.beta}\")"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "e384e005-24fe-4d7a-922a-39ae0d9089ab",
      "metadata": {},
      "source": [
        "<span id=\"leveraging-bitarray-objects-for-performant-post-processing\" />\n",
        "\n",
        "#### 객체를 `BitArray` 활용한 고성능 후처리\n",
        "\n",
        "배열은 일반적으로 사전보다 더 나은 성능을 제공하므로, 카운트 사전이 아닌 객체 `BitArray` 자체에 직접 후처리를 수행하는 것이 바람직합니다. 이 `BitArray` 클래스는 일반적인 후처리 작업을 수행하기 위한 다양한 메서드를 제공합니다:\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 7,
      "id": "44c7ee14-2b22-488e-bc58-164099855210",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "The shape of register `alpha` is (1024, 1).\n",
            "The bytes in register `alpha`, shot by shot:\n",
            "[[1]\n",
            " [1]\n",
            " [0]\n",
            " ...\n",
            " [1]\n",
            " [0]\n",
            " [1]]\n",
            "\n",
            "The shape of register `beta` is (1024, 2).\n",
            "The bytes in register `beta`, shot by shot:\n",
            "[[  1 255]\n",
            " [  1 255]\n",
            " [  0   0]\n",
            " ...\n",
            " [  1 255]\n",
            " [  0   0]\n",
            " [  1 255]]\n",
            "\n",
            "The shape of `beta` after post-selection is (0, 2).\n",
            "The bytes in `beta` after post-selection:\n",
            "[]\n",
            "The shape of `beta` after bit-wise slicing is (1024, 1).\n",
            "The bytes in `beta` after bit-wise slicing:\n",
            "[[7]\n",
            " [7]\n",
            " [0]\n",
            " ...\n",
            " [7]\n",
            " [0]\n",
            " [7]]\n",
            "\n",
            "The shape of `beta` after shot-wise slicing is (5, 2).\n",
            "The bytes in `beta` after shot-wise slicing:\n",
            "[[  1 255]\n",
            " [  1 255]\n",
            " [  0   0]\n",
            " [  0   0]\n",
            " [  1 255]]\n",
            "\n",
            "Exp. val. for observable `SparsePauliOp(['ZZZZZZZZZ'],\n",
            "              coeffs=[1.+0.j])` is: -0.02734375\n",
            "Exp. val. for observable `SparsePauliOp(['IIIIIIIIZ'],\n",
            "              coeffs=[1.+0.j])` is: -0.02734375\n",
            "\n",
            "The shape of the merged results is (1024, 2).\n",
            "The bytes of the merged results:\n",
            "[[  3 255]\n",
            " [  3 255]\n",
            " [  0   0]\n",
            " ...\n",
            " [  3 255]\n",
            " [  0   0]\n",
            " [  3 255]]\n",
            "\n"
          ]
        }
      ],
      "source": [
        "print(f\"The shape of register `alpha` is {data.alpha.array.shape}.\")\n",
        "print(f\"The bytes in register `alpha`, shot by shot:\\n{data.alpha.array}\\n\")\n",
        "\n",
        "print(f\"The shape of register `beta` is {data.beta.array.shape}.\")\n",
        "print(f\"The bytes in register `beta`, shot by shot:\\n{data.beta.array}\\n\")\n",
        "\n",
        "# post-select the bitstrings of `beta` based on having sampled \"1\" in `alpha`\n",
        "mask = data.alpha.array == \"0b1\"\n",
        "ps_beta = data.beta[mask[:, 0]]\n",
        "print(f\"The shape of `beta` after post-selection is {ps_beta.array.shape}.\")\n",
        "print(f\"The bytes in `beta` after post-selection:\\n{ps_beta.array}\")\n",
        "\n",
        "# get a slice of `beta` to retrieve the first three bits\n",
        "beta_sl_bits = data.beta.slice_bits([0, 1, 2])\n",
        "print(\n",
        "    f\"The shape of `beta` after bit-wise slicing is {beta_sl_bits.array.shape}.\"\n",
        ")\n",
        "print(f\"The bytes in `beta` after bit-wise slicing:\\n{beta_sl_bits.array}\\n\")\n",
        "\n",
        "# get a slice of `beta` to retrieve the bytes of the first five shots\n",
        "beta_sl_shots = data.beta.slice_shots([0, 1, 2, 3, 4])\n",
        "print(\n",
        "    f\"The shape of `beta` after shot-wise slicing is {beta_sl_shots.array.shape}.\"\n",
        ")\n",
        "print(\n",
        "    f\"The bytes in `beta` after shot-wise slicing:\\n{beta_sl_shots.array}\\n\"\n",
        ")\n",
        "\n",
        "# calculate the expectation value of diagonal operators on `beta`\n",
        "ops = [SparsePauliOp(\"ZZZZZZZZZ\"), SparsePauliOp(\"IIIIIIIIZ\")]\n",
        "exp_vals = data.beta.expectation_values(ops)\n",
        "for o, e in zip(ops, exp_vals):\n",
        "    print(f\"Exp. val. for observable `{o}` is: {e}\")\n",
        "\n",
        "# concatenate the bitstrings in `alpha` and `beta` to \"merge\" the results\n",
        "# of the two registers\n",
        "merged_results = BitArray.concatenate_bits([data.alpha, data.beta])\n",
        "print(f\"\\nThe shape of the merged results is {merged_results.array.shape}.\")\n",
        "print(f\"The bytes of the merged results:\\n{merged_results.array}\\n\")"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "6863da3a-77bd-4b7c-ac95-e5b4dd116180",
      "metadata": {},
      "source": [
        "<span id=\"result-metadata\" />\n",
        "\n",
        "## 결과 메타데이터\n",
        "\n",
        "실행 결과 외에도, 및 `PubResult` `PrimitiveResult` 객체에는 제출된 작업에 대한 선택적 메타데이터 속성이 포함되어 있습니다. 반환되는 메타데이터(있는 경우)는 구현에 따라 다릅니다.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 8,
      "id": "5c08eeaa-8857-4fb6-aa8d-c4916f7354e8",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "The metadata of the PrimitiveResult is:\n",
            "'version' : 2,\n",
            "\n",
            "The metadata of the PubResult result is:\n",
            "'shots' : 1024,\n",
            "'circuit_metadata' : {},\n"
          ]
        }
      ],
      "source": [
        "# Print out the results metadata\n",
        "print(\"The metadata of the PrimitiveResult is:\")\n",
        "for key, val in result.metadata.items():\n",
        "    print(f\"'{key}' : {val},\")\n",
        "\n",
        "print(\"\\nThe metadata of the PubResult result is:\")\n",
        "for key, val in result[0].metadata.items():\n",
        "    print(f\"'{key}' : {val},\")"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "75c67c45-102e-41dd-aebc-9e139b71a02f",
      "metadata": {},
      "source": [
        "<span id=\"next-steps\" />\n",
        "\n",
        "## 다음 단계\n",
        "\n",
        "<Admonition type=\"tip\" title=\"권장사항\">\n",
        "  * [Qiskit SDK](/docs/api/qiskit/primitives) 의 기본 요소 API를 살펴보세요.\n",
        "  * [Qiskit Aer 기본 요소](https://qiskit.github.io/qiskit-aer/apidocs/aer_primitives.html) API를 살펴보세요.\n",
        "  * [IBM Quantum](/docs/guides/qiskit-runtime-primitives) 의 기본 요소에 대해 자세히 알아보세요.\n",
        "  * [Estimator `qiskit-ibm-runtime`](/docs/api/qiskit-ibm-runtime/estimator-v2) API를 살펴보세요.\n",
        "  * [`qiskit-ibm-runtime` Sampler](/docs/api/qiskit-ibm-runtime/sampler-v2) API를 살펴보세요.\n",
        "</Admonition>\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "id": "a1b8767d",
      "source": "© IBM Corp., 2017-2026"
    }
  ],
  "metadata": {
    "celltoolbar": "Raw Cell Format",
    "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
}