{
  "cells": [
    {
      "attachments": {},
      "cell_type": "markdown",
      "id": "f5d21946",
      "metadata": {
        "slideshow": {
          "slide_type": "-"
        }
      },
      "source": [
        "---\n",
        "title: \"反復コード\"\n",
        "description: \"このチュートリアルでは、 IBM 動的回路を用いた基本的な反復コードの構築方法を示します。これは基本的な量子誤り訂正（QEC）の一例です。\"\n",
        "---\n",
        "\n",
        "{/* cspell:ignore pcov REPCODE creference qreference csyndrome qsyndrome qdata fontsize ytick labelsize xtick */}\n",
        "\n",
        "<span id=\"repetition-codes\" />\n",
        "\n",
        "# 反復コード\n",
        "\n",
        "*所要時間の推定値：Heronプロセッサで10秒未満（注：これはあくまで推定値です。 （実行時間は状況によって異なる場合があります。）*\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "4048d4c9",
      "metadata": {},
      "source": [
        "<span id=\"learning-outcomes\" />\n",
        "\n",
        "## 学習成果\n",
        "\n",
        "* 動的回路を用いたビット反転誤り訂正コードの実装方法\n",
        "* 符号化された情報を破壊することなく、量子エラーを検出するためのスタビライザーの測定方法\n",
        "* 訂正済み結果と未訂正の結果を比較して、量子エラー訂正の性能を評価する方法\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "9012c057",
      "metadata": {},
      "source": [
        "<span id=\"prerequisites\" />\n",
        "\n",
        "## 前提条件\n",
        "\n",
        "* [動的回路](/docs/guides/classical-feedforward-and-control-flow)\n",
        "* [量子エラー訂正の基礎](https://arxiv.org/abs/0905.2794)\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "0d182acd",
      "metadata": {},
      "source": [
        "<span id=\"background\" />\n",
        "\n",
        "## 背景\n",
        "\n",
        "リアルタイムの量子エラー訂正（QEC）を可能にするためには、量子プログラムの実行中に量子プログラムの流れを動的に制御し、測定結果に応じて量子ゲートを条件付けできるようにする必要がある。 このチュートリアルでは、QEC の非常に単純な形式である bit-flip コードを実行します。 符号化量子ビットを1回のビット反転エラーから保護できる動的量子回路を実証し、ビット反転符号の性能を評価する。\n",
        "\n",
        "さらにアンシラ量子ビットとエンタングルメントを利用すれば、符号化された量子情報を変換することなく*安定化装置を*測定することができる。 量子スタビライザーコードは、 $k$ 論理量子ビットを $n$ 物理量子ビットにエンコードする。 スタビライザー符号は、パウリ群 $\\Pi^n$ からの支持を得て、離散的な誤り集合を訂正することに重点を置いている。\n",
        "\n",
        "このチュートリアルでは、簡単な量子メモリ実験を用いて、ビットフリップコードについて解説します。 論理状態 $|\\bar{1}\\rangle \\equiv |111\\rangle$ にあるエンコード済み量子ビットを準備し、その後、（エラーを蓄積させるために）複数のアイドル時間を設け、続いてエラーの検出と訂正を行います。 次に、論理誤りの確率をサイクル数（時間）の関数として定量化する。ここで、論理誤りの確率とは、最終測定後に $|\\bar{1}\\rangle$ を復元できない状態にある量子ビットが見つかる確率である（具体的には、誤りに相当する状態は、 $|000\\rangle$、 $|001\\rangle$、 $|010\\rangle$、および $|100\\rangle$ である）。\n",
        "\n",
        "エラー率と時間の関係について、エンコードされていない個々の量子ビットのエラー率と比較するとともに、最終測定後にのみエラーを検出して訂正し、回路の動作中は動的にエラーを訂正しないリピテーションコードを用いた場合とも比較する。\n",
        "\n",
        "注：この繰り返し符号はビット反転エラーの訂正のみが可能であるため、完全な誤り訂正符号ではありません。 しかし、その単純さゆえに、量子コンピュータ上でエラー訂正をどのように実装するかを説明するための良い出発点となります。 以下のメモリ実験では、1種類のエラー（ $|\\bar{1}\\rangle$ が $|\\bar{0}\\rangle$ へと変化するエラー）のみを検証しており、厳密には古典的な情報の保護を実証しているに過ぎない。\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "88672bd6",
      "metadata": {},
      "source": [
        "<span id=\"requirements\" />\n",
        "\n",
        "## 要件\n",
        "\n",
        "このチュートリアルを始める前に、以下のものがインストールされていることを確認してください：\n",
        "\n",
        "* Qiskit SDK v2.0 またはそれ以降、 [可視化](/docs/api/qiskit/visualization)サポート付き\n",
        "* Qiskit Runtime v0.40 またはそれ以降 (`pip install qiskit-ibm-runtime`)\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "14c29e8b",
      "metadata": {},
      "source": [
        "<span id=\"setup\" />\n",
        "\n",
        "## セットアップ\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "71cb35d9",
      "metadata": {},
      "outputs": [],
      "source": [
        "import numpy as np\n",
        "import seaborn as sns\n",
        "import matplotlib.pyplot as plt\n",
        "from scipy.optimize import curve_fit\n",
        "\n",
        "sns.set()\n",
        "plt.rc(\"xtick\", labelsize=20)\n",
        "plt.rc(\"ytick\", labelsize=20)\n",
        "plt.rc(\"lines\", linewidth=3)\n",
        "plt.rc(\"font\", size=20)\n",
        "plt.rc(\"legend\", fontsize=\"large\")\n",
        "plt.rc(\"axes\", labelsize=20)\n",
        "plt.rcParams[\"figure.figsize\"] = 15, 6\n",
        "plt.rcParams[\"legend.title_fontsize\"] = 25"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "1b9fd8ad",
      "metadata": {
        "slideshow": {
          "slide_type": "-"
        }
      },
      "outputs": [],
      "source": [
        "# Qiskit imports\n",
        "from qiskit import (\n",
        "    QuantumCircuit,\n",
        "    QuantumRegister,\n",
        "    ClassicalRegister,\n",
        ")\n",
        "\n",
        "# qiskit-ibm-runtime\n",
        "from qiskit_ibm_runtime import QiskitRuntimeService, SamplerV2 as Sampler\n",
        "from qiskit_ibm_runtime.circuit import MidCircuitMeasure\n",
        "\n",
        "service = QiskitRuntimeService()"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "eb4ccf5d",
      "metadata": {},
      "source": [
        "<span id=\"small-scale-simulator-example\" />\n",
        "\n",
        "## 小規模シミュレータの例\n",
        "\n",
        "本実験の目的は、アイドル遅延中の振幅減衰など、実際のハードウェアノイズ下における論理量子ビットの寿命を測定することであるため、この手順は省略する。ノイズのないシミュレータでは、検出・訂正すべきエラーは発生しないからである。\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "8af23cd0",
      "metadata": {},
      "source": [
        "<span id=\"large-scale-hardware-example\" />\n",
        "\n",
        "## 大規模なハードウェアの例\n",
        "\n",
        "<span id=\"step-1-map-classical-inputs-to-a-quantum-problem\" />\n",
        "\n",
        "### ステップ1：古典的な入力を量子問題に写像する\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "02427c7e",
      "metadata": {},
      "source": [
        "<span id=\"choose-a-backend\" />\n",
        "\n",
        "#### バックエンドを選択してください\n",
        "\n",
        "回路処理中にエラーを検出するには、そのメソッド `MidCircuitMeasure` にアクセスできるバックエンドを選択する必要があります（ [ドキュメント](/docs/guides/execute-dynamic-circuits#mid-circuit-measurements)を参照）。\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "1512c805",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "[<IBMBackend('ibm_pittsburgh')>,\n",
              " <IBMBackend('ibm_boston')>,\n",
              " <IBMBackend('ibm_kingston')>]"
            ]
          },
          "metadata": {},
          "output_type": "display_data"
        }
      ],
      "source": [
        "# You can see all backends that support mid-circuit measurements by running the following code.\n",
        "service.backends(filters=lambda b: \"measure_2\" in b.supported_instructions)"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "b588703a",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "ibm_boston\n"
          ]
        }
      ],
      "source": [
        "# Choose the least busy backend that supports mid-circuit measurements (`measure_2`).\n",
        "\n",
        "backend = service.least_busy(\n",
        "    filters=lambda b: \"measure_2\" in b.supported_instructions,\n",
        "    operational=True,\n",
        "    simulator=False,\n",
        "    dynamic_circuits=True,\n",
        ")\n",
        "# backend = service.backend(backend_name) # alternatively, you could choose a specific backend\n",
        "print(backend.name)"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "09b920c2",
      "metadata": {},
      "source": [
        "<span id=\"build-a-sequence-of-bit-flip-stabilizer-circuits-implementing-multiple-rounds-of-error-detection-and-correction\" />\n",
        "\n",
        "#### 複数回の誤り検出・訂正を行うビットフリップ安定化回路のシーケンスを構築する\n",
        "\n",
        "ビットフリップ符号は、スタビライザー符号の最も単純な例の一つである。 これは、任意のエンコーディング量子ビットで発生する1ビットの反転（X）エラーから状態を保護します。 ビットフリップ誤り $X$ の動作を考えてみましょう。これは、任意の量子ビットに対して $|0\\rangle \\rightarrow |1\\rangle$ および $|1\\rangle \\rightarrow |0\\rangle$ を写像し、その結果、 $\\epsilon = \\{E_0, E_1, E_2 \\} = \\{IIX, IXI, XII\\}$ となります。このコードには5つの量子ビットが必要です。そのうち3つは保護状態を符号化するために使用され（「データ量子ビット」）、残りの2つは安定化測定の補助量子ビットとして使用されます。\n",
        "\n",
        "以下では、(1) データ量子ビットを論理状態 $|\\bar{1} \\rangle$ に準備し、(2) $5 \\mu s$ の遅延を複数サイクル実行した後、誤り訂正（シンドローム量子ビットのリセットを含む）を行い、(3) データ量子ビットの状態を読み出す回路を構築します。\n",
        "\n",
        "また、エラー訂正を使用せずに、 $|1\\rangle$ 状態の寿命を測定するため、3つの参照キュービットを $|1\\rangle$ 状態に準備し、そのまま放置した後、読み出しを行う。\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 194,
      "id": "d36817e7",
      "metadata": {},
      "outputs": [],
      "source": [
        "def build_qc(\n",
        "    qreg_data,\n",
        "    qreg_syndrome,\n",
        "    creg_data,\n",
        "    creg_syndrome,\n",
        "    qreg_ref=None,\n",
        "    creg_ref=None,\n",
        "):\n",
        "    \"\"\"Build a typical error correction circuit\"\"\"\n",
        "    if qreg_ref:\n",
        "        return QuantumCircuit(\n",
        "            qreg_data,\n",
        "            qreg_syndrome,\n",
        "            creg_data,\n",
        "            creg_syndrome,\n",
        "            qreg_ref,\n",
        "            creg_ref,\n",
        "        )\n",
        "    else:\n",
        "        return QuantumCircuit(\n",
        "            qreg_data, qreg_syndrome, creg_data, creg_syndrome\n",
        "        )\n",
        "\n",
        "\n",
        "def encode_bit_flip(circuit, qreg_data, qreg_ref=None) -> QuantumCircuit:\n",
        "    \"\"\"Encode bit-flip. This is done by simply adding a cx\"\"\"\n",
        "\n",
        "    for q in qreg_data:\n",
        "        circuit.x(q)\n",
        "\n",
        "    if qreg_ref:\n",
        "        for q in qreg_ref:\n",
        "            circuit.x(q)\n",
        "\n",
        "    circuit.barrier()\n",
        "\n",
        "    return circuit\n",
        "\n",
        "\n",
        "def measure_syndrome_bit(\n",
        "    circuit, qreg_data, qreg_syndrome, creg_syndrome, qreg_ref=None\n",
        "):\n",
        "    \"\"\"\n",
        "    Measure the syndrome by measuring the parity.\n",
        "    We reset our ancilla qubits after measuring the stabilizer\n",
        "    so we can reuse them for repeated stabilizer measurements.\n",
        "    Because we have already observed the state of the qubit,\n",
        "    we can write the conditional reset protocol directly to\n",
        "    avoid another round of qubit measurement if we used\n",
        "    the `reset` instruction.\n",
        "    \"\"\"\n",
        "    circuit.cx(qreg_data[0], qreg_syndrome[0])\n",
        "    circuit.cx(qreg_data[1], qreg_syndrome[0])\n",
        "    circuit.cx(qreg_data[0], qreg_syndrome[1])\n",
        "    circuit.cx(qreg_data[2], qreg_syndrome[1])\n",
        "    circuit.barrier()\n",
        "\n",
        "    for q_measure, c_measure in zip(qreg_syndrome, creg_syndrome):\n",
        "        circuit.append(MidCircuitMeasure(), [q_measure], [c_measure])\n",
        "\n",
        "    with circuit.if_test((creg_syndrome[0], 1)):\n",
        "        circuit.x(qreg_syndrome[0])\n",
        "    with circuit.if_test((creg_syndrome[1], 1)):\n",
        "        circuit.x(qreg_syndrome[1])\n",
        "\n",
        "    circuit.barrier()\n",
        "    return circuit\n",
        "\n",
        "\n",
        "def apply_correction_bit(circuit, qreg_data, creg_syndrome):\n",
        "    \"\"\"We can detect where an error occurred and correct our state\"\"\"\n",
        "    with circuit.if_test((creg_syndrome, 3)):\n",
        "        circuit.x(qreg_data[0])\n",
        "    with circuit.if_test((creg_syndrome, 1)):\n",
        "        circuit.x(qreg_data[1])\n",
        "    with circuit.if_test((creg_syndrome, 2)):\n",
        "        circuit.x(qreg_data[2])\n",
        "    circuit.barrier()\n",
        "    return circuit\n",
        "\n",
        "\n",
        "def apply_final_readout(\n",
        "    circuit, qreg_data, creg_data, qreg_ref=None, creg_ref=None\n",
        "):\n",
        "    \"\"\"Read out the final measurements\"\"\"\n",
        "\n",
        "    circuit.barrier()\n",
        "    if qreg_ref:\n",
        "        circuit.measure(qreg_ref, creg_ref)\n",
        "    circuit.measure(qreg_data, creg_data)\n",
        "\n",
        "    return circuit"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "0e8ea0be",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<Image src=\"/docs/images/tutorials/repetition-codes/extracted-outputs/0e8ea0be-0.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "execution_count": 195,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "def build_error_correction_sequence(\n",
        "    num_cycles, cycles_per_circuit, nq_ref=3, delay=None\n",
        ") -> QuantumCircuit:\n",
        "    circuits = []\n",
        "    reps = []\n",
        "\n",
        "    qreg_data = QuantumRegister(3, name=\"qdata\")\n",
        "    qreg_syndrome = QuantumRegister(2, name=\"qsyndrome\")\n",
        "    creg_data = ClassicalRegister(3, name=\"cdata\")\n",
        "    creg_syndrome = ClassicalRegister(2, name=\"csyndrome\")\n",
        "    qreg_ref = QuantumRegister(nq_ref, name=\"qreference\")\n",
        "    creg_ref = ClassicalRegister(nq_ref, name=\"creference\")\n",
        "\n",
        "    circuit = build_qc(\n",
        "        qreg_data,\n",
        "        qreg_syndrome,\n",
        "        creg_data,\n",
        "        creg_syndrome,\n",
        "        qreg_ref=qreg_ref,\n",
        "        creg_ref=creg_ref,\n",
        "    )\n",
        "    circuit = encode_bit_flip(circuit, qreg_data, qreg_ref=qreg_ref)\n",
        "\n",
        "    circuit_n = circuit.copy()\n",
        "    circuit_n = apply_final_readout(\n",
        "        circuit_n, qreg_data, creg_data, qreg_ref=qreg_ref, creg_ref=creg_ref\n",
        "    )\n",
        "    circuits.append(circuit_n)\n",
        "    reps.append(0)\n",
        "\n",
        "    for i in range(1, num_cycles + 1):\n",
        "        if delay:\n",
        "            circuit.delay(delay, unit=\"us\")\n",
        "            circuit.barrier()\n",
        "        circuit = measure_syndrome_bit(\n",
        "            circuit,\n",
        "            qreg_data,\n",
        "            qreg_syndrome,\n",
        "            creg_syndrome,\n",
        "            qreg_ref=qreg_ref,\n",
        "        )\n",
        "        circuit = apply_correction_bit(circuit, qreg_data, creg_syndrome)\n",
        "        circuit_n = circuit.copy()\n",
        "        if i % cycles_per_circuit == 0:\n",
        "            circuit_n = apply_final_readout(\n",
        "                circuit_n,\n",
        "                qreg_data,\n",
        "                creg_data,\n",
        "                qreg_ref=qreg_ref,\n",
        "                creg_ref=creg_ref,\n",
        "            )\n",
        "            circuits.append(circuit_n)\n",
        "            reps.append(i)\n",
        "\n",
        "    return circuits, np.array(reps)\n",
        "\n",
        "\n",
        "num_cycles = 40\n",
        "cycles_per_circuit = 4\n",
        "nq_ref = 3\n",
        "circuits, rep_array = build_error_correction_sequence(\n",
        "    num_cycles, cycles_per_circuit, nq_ref=3, delay=5\n",
        ")\n",
        "circuits[1].draw(output=\"mpl\", cregbundle=False, fold=50)"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "609c0c47",
      "metadata": {},
      "source": [
        "<span id=\"step-2-optimize-the-problem-for-quantum-hardware-execution\" />\n",
        "\n",
        "### ステップ 2：量子ハードウェアでの実行に向けて問題を最適化する\n",
        "\n",
        "ジョブの実行総時間を短縮するため、 Qiskit primitives は、ターゲットシステムがサポートする命令および接続方式に準拠した回路およびオブザーバブルのみを受け入れます（これらは「命令セットアーキテクチャ（ISA）回路およびオブザーバブル」と呼ばれます）。 [トランスパイレーションについて詳しくはこちら](/docs/guides/transpile)。\n",
        "\n"
      ]
    },
    {
      "attachments": {},
      "cell_type": "markdown",
      "id": "c8ea2716",
      "metadata": {
        "slideshow": {
          "slide_type": "-"
        }
      },
      "source": [
        "<span id=\"generate-isa-circuits\" />\n",
        "\n",
        "#### ISA回路を生成する\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "cc8f818f",
      "metadata": {},
      "source": [
        "まず、プリセットのパスマネージャーを使用し、最適化レベル3で回路のうち最も長いものをトランスパイルすることで、初期レイアウト（つまり、回路をマッピングする物理量子ビットの選択）を決定します。\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 196,
      "id": "67b55eef",
      "metadata": {
        "slideshow": {
          "slide_type": "-"
        }
      },
      "outputs": [],
      "source": [
        "from qiskit.transpiler.preset_passmanagers import generate_preset_pass_manager\n",
        "\n",
        "pm = generate_preset_pass_manager(backend=backend, optimization_level=3)\n",
        "isa_circuit_ref = pm.run(circuits[-1])"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 197,
      "id": "3e74193a",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "[56, 44, 62, 43, 63, 22, 48, 67]\n"
          ]
        }
      ],
      "source": [
        "init_layout = isa_circuit_ref.layout.initial_index_layout(\n",
        "    filter_ancillas=True\n",
        ")\n",
        "print(init_layout)"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "eaca173c",
      "metadata": {},
      "source": [
        "我々の論理量子メモリと比較対象とする参照キュービットについては、振幅減衰コヒーレンス時間の観点から、現時点で最良のキュービットを選択する（ $T_1$ ）。\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "2aedd3cb",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "[56, 44, 62, 43, 63, 143, 131, 31]\n"
          ]
        }
      ],
      "source": [
        "# get all qubits ordered by T1\n",
        "t1_data = []\n",
        "for i in range(backend.num_qubits):\n",
        "    try:\n",
        "        t1_us = backend.properties().t1(i) * 1e6\n",
        "    except Exception:\n",
        "        t1_us = 0.0\n",
        "    t1_data.append((i, t1_us))\n",
        "\n",
        "t1_data_sorted = sorted(t1_data, key=lambda x: x[1], reverse=True)\n",
        "\n",
        "# exclude the qubits we have already mapped the error correcting code to\n",
        "t1_data_sorted = [\n",
        "    t1_data for t1_data in t1_data_sorted if t1_data[0] not in init_layout[:5]\n",
        "]\n",
        "\n",
        "# use the best qubits in terms of T1 for the reference qubits\n",
        "init_layout = init_layout[:5] + [t1_data[0] for t1_data in t1_data_sorted[:3]]\n",
        "print(init_layout)"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "d6a7766a",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "Amplitude damping decoherence times code data qubits:\n",
            "qubit 56: T1 = 322 mus\n",
            "qubit 44: T1 = 263 mus\n",
            "qubit 62: T1 = 290 mus\n",
            "\n",
            "Amplitude damping decoherence times reference qubits:\n",
            "qubit 143: T1 = 442 mus\n",
            "qubit 131: T1 = 410 mus\n",
            "qubit 31: T1 = 401 mus\n"
          ]
        }
      ],
      "source": [
        "# These are the resulting T1 times\n",
        "properties = backend.properties()\n",
        "print(\"Amplitude damping decoherence times for code data qubits:\")\n",
        "for q in init_layout[:3]:\n",
        "    t1 = properties.t1(q)\n",
        "    print(f\"qubit {q}: T1 = {t1 * 1e6:.0f} mus\")\n",
        "\n",
        "print(\"\\nAmplitude damping decoherence times for reference qubits:\")\n",
        "for q in init_layout[-3:]:\n",
        "    t1 = properties.t1(q)\n",
        "    print(f\"qubit {q}: T1 = {t1 * 1e6:.0f} mus\")"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "ee5da865",
      "metadata": {},
      "outputs": [],
      "source": [
        "# now we transpile all circuits to this initial layout; this way each circuit is run on the same qubits and we can make a fair comparison\n",
        "pm = generate_preset_pass_manager(\n",
        "    backend=backend,\n",
        "    optimization_level=3,\n",
        "    initial_layout=init_layout,\n",
        ")\n",
        "isa_circuits = pm.run(circuits)"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 180,
      "id": "67acea4f",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<Image src=\"/docs/images/tutorials/repetition-codes/extracted-outputs/67acea4f-0.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "execution_count": 180,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "isa_circuits[1].draw(\"mpl\", cregbundle=False, fold=50)"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "bcd61a1f",
      "metadata": {},
      "source": [
        "<span id=\"step-3-execute-using-qiskit-primitives\" />\n",
        "\n",
        "### ステップ 3: `Qiskit primitives` を使用して実行する\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "d53319ba",
      "metadata": {},
      "outputs": [],
      "source": [
        "sampler = Sampler(mode=backend)\n",
        "\n",
        "sampler.options.environment.job_tags = [\"TUT_REPCODE\"]\n",
        "sampler.options.max_execution_time = 600  # this workload is expected to be under 10s, but it is generally a good habit to set a max execution time (here 600s = 10m)"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "437397a5",
      "metadata": {},
      "outputs": [],
      "source": [
        "job = sampler.run(isa_circuits, shots=1000)\n",
        "print(job.job_id())"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 201,
      "id": "b1025c42",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "'DONE'"
            ]
          },
          "execution_count": 201,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "job.status()"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "1b652319",
      "metadata": {},
      "source": [
        "<span id=\"step-4-post-process-and-return-result-in-desired-classical-format\" />\n",
        "\n",
        "### ステップ4：後処理を行い、希望する従来の形式で結果を返す\n",
        "\n",
        "ここでは、3量子ビット反復コードを用いた論理メモリと、符号化されていない個々の参照量子ビットとを、エラー率と時間の関係について比較する。\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 202,
      "id": "ea871eb9",
      "metadata": {},
      "outputs": [],
      "source": [
        "results = job.result()"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "f27099e5",
      "metadata": {},
      "outputs": [],
      "source": [
        "def correct_counts(counts_dict):\n",
        "    \"\"\"\n",
        "    Corrects the measured logical qubit encoded in the repetition code using majority vote\n",
        "    \"\"\"\n",
        "\n",
        "    result = {\"000\": 0, \"111\": 0}\n",
        "    for bitstring, count in counts_dict.items():\n",
        "        key = \"111\" if bitstring.count(\"1\") > 1 else \"000\"\n",
        "        result[key] += count\n",
        "    return result\n",
        "\n",
        "\n",
        "accuracy = []  # logical qubit\n",
        "accuracies_ref = np.zeros(\n",
        "    (len(results), nq_ref)\n",
        ")  # accuracies on individual reference qubits\n",
        "\n",
        "for n, pub_result in enumerate(results):\n",
        "    # logical accuracy (one minus error probability) for active error correction with repetition code\n",
        "    counts = pub_result.data.cdata.get_counts()\n",
        "    shots = sum(counts.values())\n",
        "    counts_corrected = correct_counts(counts)\n",
        "    accuracy.append(counts_corrected.get(\"111\", 0) / shots)\n",
        "\n",
        "    # accuracy for individual physical reference qubits without any error correction\n",
        "    for i in range(nq_ref):\n",
        "        counts = pub_result.data.creference.slice_bits(i).get_counts()\n",
        "        accuracies_ref[n, i] = counts.get(\"1\", 0) / shots\n",
        "\n",
        "accuracy = np.array(accuracy)"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "72ad282b",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "Best-fit effective T1 = 1397 us\n"
          ]
        },
        {
          "data": {
            "text/plain": [
              "<Image src=\"/docs/images/tutorials/repetition-codes/extracted-outputs/72ad282b-1.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "metadata": {},
          "output_type": "display_data"
        }
      ],
      "source": [
        "def error_proba_t1(N, t1):\n",
        "    \"\"\"\n",
        "    Exponential fitting function for amplitude damping vs. number of cycles\n",
        "    \"\"\"\n",
        "\n",
        "    t_cycle = 7.3e-6  # approximate time per cycle = 5 mus delay + 2.3 mus for error correction\n",
        "    return 1 - np.exp(-t_cycle * N / t1)\n",
        "\n",
        "\n",
        "fig, ax = plt.subplots(1, 1, figsize=(15, 5))\n",
        "ax.plot(\n",
        "    rep_array, (1.0 - accuracy) * 100.0, \"ko-\", linewidth=3, label=\"rep code\"\n",
        ")\n",
        "\n",
        "for i in range(nq_ref):\n",
        "    accuracy_1q = accuracies_ref[:, i]\n",
        "    if i == 0:\n",
        "        ax.plot(\n",
        "            rep_array,\n",
        "            (1.0 - accuracy_1q) * 100.0,\n",
        "            \"go-\",\n",
        "            linewidth=1,\n",
        "            label=\"1q reference\",\n",
        "        )\n",
        "    else:\n",
        "        ax.plot(rep_array, (1.0 - accuracy_1q) * 100.0, \"go-\", linewidth=1)\n",
        "\n",
        "params_bf, pcov = curve_fit(\n",
        "    error_proba_t1, rep_array, 1.0 - accuracy, bounds=([0, 5e-3])\n",
        ")\n",
        "t1_bf = params_bf[0]\n",
        "print(f\"Best-fit effective T1 = {t1_bf * 1e6:.0f} us\")\n",
        "error_prob_bf = error_proba_t1(\n",
        "    rep_array, t1_bf\n",
        ")  # np.array([1 - np.exp(-t_cycle * nt/t1) for nt in rep_array])\n",
        "ax.plot(rep_array, error_prob_bf * 100.0, \"k--\", linewidth=1)\n",
        "\n",
        "ax.set_xlabel(\"error correction rounds\")\n",
        "ax.set_ylabel(\"error [%]\")\n",
        "ax.set_ylim(bottom=0)\n",
        "ax.legend(fontsize=15);"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "49c2f443",
      "metadata": {},
      "source": [
        "$|\\bar{1}\\rangle$ 状態の寿命が、最高の（符号化されていない）物理量子ビットと比較しても、明らかに向上していることがわかります。 ただし、この実験では、ビット反転という1種類のエラーのみを修正するものであることに留意してください。 論理量子ビットの寿命を延ばすことはできますか？ 遅延時間の最適化や、 $n=3$ を超える範囲での繰り返しコードの規模拡大などについて検討してみるといいでしょう。\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "next_steps",
      "metadata": {},
      "source": [
        "<span id=\"next-steps\" />\n",
        "\n",
        "## 次のステップ\n",
        "\n",
        "この作品に興味をお持ちの方は、以下の資料もご参考になるかもしれません：\n",
        "\n",
        "<Admonition type=\"tip\" title=\"推奨事項\">\n",
        "  * [「量子エラー訂正の基礎」講座](/learning/courses/foundations-of-quantum-error-correction) - 量子エラー訂正についてさらに詳しく学ぶ\n",
        "  * [時空間符号を用いた低オーバーヘッドのエラー検出チュートリアル](/docs/tutorials/spacetime-codes) - パウリチェックを用いてエラーを検出し、サンプルを事後選択する方法を学びましょう\n",
        "</Admonition>\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "id": "a1b8767d",
      "source": "© IBM Corp., 2017-2026"
    }
  ],
  "metadata": {
    "celltoolbar": "Slideshow",
    "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": 60
  },
  "nbformat": 4,
  "nbformat_minor": 5
}