{
  "cells": [
    {
      "cell_type": "markdown",
      "id": "3445b0b5-7f26-4610-8e1b-5112df1fccb0",
      "metadata": {},
      "source": [
        "---\n",
        "title: \"エラー軽減オプションをEstimatorプリミティブと組み合わせる\"\n",
        "description: \"100Q+IBM Quantum QPUおよび IBM Quantum 推定プリミティブを使用して、ユーティリティ規模の実験におけるエラー低減オプションを組み合わせます。\"\n",
        "---\n",
        "\n",
        "<span id=\"combine-error-mitigation-options-with-the-estimator-primitive\" />\n",
        "\n",
        "# エラー軽減オプションをEstimatorプリミティブと組み合わせる\n",
        "\n",
        "*推定所要時間：Heron r2 プロセッサで 7 分（注：これはあくまで目安です。 （実行時間は異なる場合があります。）*\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "39ba4396-9111-4421-9371-542f067bc816",
      "metadata": {},
      "source": [
        "<span id=\"learning-outcomes\" />\n",
        "\n",
        "## 学習成果\n",
        "\n",
        "このチュートリアルを進める前に、以下の内容についてあらかじめ理解しておいていただくことをお勧めします：\n",
        "\n",
        "* [本ガイド](/docs/guides/error-mitigation-and-suppression-techniques)で解説されている、動的デカップリング、測定誤差の低減、ゲート・トゥワーリング、およびゼロノイズ外挿法の基礎。\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "b27cb482-b77a-4953-a0a4-39df33896d12",
      "metadata": {},
      "source": [
        "<span id=\"prerequisites\" />\n",
        "\n",
        "## 前提条件\n",
        "\n",
        "このチュートリアルを終えた後、ユーザーは以下の点を理解できるようになります：\n",
        "\n",
        "* 前述のエラー軽減手法が、ハードウェア上でどのように選択的に実装されるか。\n",
        "* ハードウェアノイズを低減する能力の点で、両者はどのように比較されるか。\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "018313d1-d959-4011-81df-59bf7c157470",
      "metadata": {},
      "source": [
        "<span id=\"background\" />\n",
        "\n",
        "## 背景\n",
        "\n",
        "このチュートリアルでは、 IBM Quantum 推定器プリミティブで利用可能なエラー抑制およびエラー軽減のオプションについて解説します。 このチュートリアルでは、以下の各メソッドを個別に実装する方法について説明します：\n",
        "\n",
        "* ダイナミック・デカップリング\n",
        "* 測定誤差の軽減\n",
        "* ゲート回転\n",
        "* ゼロノイズ外挿（ZNE）\n",
        "\n",
        "なお、これらの手法を個別に実装する代わりに、 [レジリエンスレベル](/docs/guides/estimator-noise-management) （値は0、1、2をとる `resilience_level` ）を用いて実装することも可能です：\n",
        "\n",
        "* 0：緩和策は実施されていない。\n",
        "* 1：測定誤差の低減が実施されています。\n",
        "* 2：ゲートの回転、測定誤差の低減、およびZNEが実装されています。\n",
        "\n",
        "このチュートリアルでは、回路と観測可能変数を構築し、エラー軽減設定のさまざまな組み合わせを用いて、Estimatorプリミティブを使用してジョブを提出します。 次に、結果をグラフ化して、さまざまな設定による影響を確認します。 このチュートリアルの大部分では、視覚化を容易にするために10キュービットの回路を使用していますが、最後にはワークフローを50キュービットに拡張します。\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "0f3d3378-8dac-489e-bf6d-292e693ec145",
      "metadata": {},
      "source": [
        "<span id=\"requirements\" />\n",
        "\n",
        "## 要件\n",
        "\n",
        "このチュートリアルを始める前に、以下のものがインストールされていることを確認してください：\n",
        "\n",
        "* Qiskit SDK v2.1 またはそれ以降、 [可視化](/docs/api/qiskit/visualization)サポート付き\n",
        "* Qiskit Runtime v0.40 またはそれ以降 (`pip install qiskit-ibm-runtime`)\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "069658fa-fa45-48b8-ab69-2610228bf6e4",
      "metadata": {},
      "source": [
        "<span id=\"setup\" />\n",
        "\n",
        "## セットアップ\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 7,
      "id": "95a72452-e067-4ee5-bcd9-e3bfcf0de208",
      "metadata": {},
      "outputs": [],
      "source": [
        "import matplotlib.pyplot as plt\n",
        "import numpy as np\n",
        "\n",
        "from qiskit.circuit.library import efficient_su2, unitary_overlap\n",
        "from qiskit.quantum_info import SparsePauliOp\n",
        "from qiskit.transpiler.preset_passmanagers import generate_preset_pass_manager\n",
        "\n",
        "from qiskit_ibm_runtime import QiskitRuntimeService\n",
        "from qiskit_ibm_runtime import Batch, EstimatorV2 as Estimator"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "d15c5fde-5046-4d86-86d8-72d1ed748c4e",
      "metadata": {},
      "source": [
        "<span id=\"small-scale-simulator-example\" />\n",
        "\n",
        "## 小規模シミュレータの例\n",
        "\n",
        "シミュレータでは実行時エラーの緩和機能がサポートされていないため、この手順は省略します。\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "b2be0539-4f60-46e8-be1f-8869dae30888",
      "metadata": {},
      "source": [
        "<span id=\"hardware-example\" />\n",
        "\n",
        "## ハードウェアの例\n",
        "\n",
        "<span id=\"step-1-map-classical-inputs-to-a-quantum-problem\" />\n",
        "\n",
        "### ステップ1：古典的な入力を量子問題にマッピングする\n",
        "\n",
        "このウォークスルーでは、古典的な問題が既に量子化されていることを前提としています。 まず、回路と観測可能な量を構築して測定することから始めます。 ここで使用される技術は様々な種類の回路に適用可能ですが、簡便化のため、このチュートリアルではQiskit回路ライブラリに含まれる回路 [`efficient_su2`](/docs/api/qiskit/qiskit.circuit.library.efficient_su2) を使用します。\n",
        "\n",
        "`efficient_su2` これは、量子ビット間の接続性が限られている量子ハードウェア上でも効率的に実行できるように設計されたパラメータ化量子回路であり、最適化や化学といった応用分野の問題を解決するのに十分な表現力を備えています。 これは、パラメータ化された単一量子ビットゲートの層と、2量子ビットゲートの固定パターンを含む層を交互に重ね、所定の回数繰り返すことで構築される。 2量子ビットゲートのパターンは、ユーザーが指定することができます。 ここでは、2量子ビットゲートを可能な限り高密度に配置することで回路の深さを最小限に抑えられるため、組み込みの `pairwise` パターンを使用できます。 このパターンは、線形量子ビット接続のみを用いて実行可能です。\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 8,
      "id": "24abd7ba-bbb8-443b-9e81-866795d39a6c",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<Image src=\"/docs/images/tutorials/combine-error-mitigation-techniques/extracted-outputs/24abd7ba-bbb8-443b-9e81-866795d39a6c-0.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "execution_count": 8,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "n_qubits = 10\n",
        "reps = 1\n",
        "\n",
        "circuit = efficient_su2(n_qubits, entanglement=\"pairwise\", reps=reps)\n",
        "\n",
        "circuit.decompose().draw(\"mpl\", scale=0.7)"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "34fec53b-a8b2-461b-a20d-e8ad54b992fa",
      "metadata": {},
      "source": [
        "観測量として、最後の量子ビットに作用するパウリ演算子 $Z$、すなわち $Z I \\cdots I$ を採用しましょう。\n",
        "なお、最後の量子ビットがこの文字列の最初の要素に対応しているのは、Qiskitがリトルエンディアン表記を採用しているためです。\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 9,
      "id": "9500ba7b-4542-465f-a4e1-60165d6b6d1e",
      "metadata": {},
      "outputs": [],
      "source": [
        "# Z on the last qubit (index -1) with coefficient 1.0\n",
        "observable = SparsePauliOp.from_sparse_list(\n",
        "    [(\"Z\", [-1], 1.0)], num_qubits=n_qubits\n",
        ")"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "46eff743-de9f-4f55-9c47-02c6d6115b80",
      "metadata": {},
      "source": [
        "ここまで来たら、回路を動作させて観測量を測定することができます。 しかし、量子デバイスの出力を正解、つまり回路がエラーなく実行された場合の観測量の理論値と比較することも必要です。 小規模な量子回路の場合、この値は古典コンピュータ上で回路をシミュレーションすることで計算できますが、より大規模な実用レベルの回路では、これは不可能です。 この問題は、「ミラー回路」という手法（「コンピュート・アンコンピュート」とも呼ばれる）を用いて回避することができ、量子デバイスの性能評価を行う際に有用です。\n",
        "\n",
        "<span id=\"mirror-circuit\" />\n",
        "\n",
        "#### ミラー回路\n",
        "\n",
        "ミラー回路技術では、回路の各ゲートを逆順に反転させることで形成される逆回路と回路を連結する。 結果として得られる回路は恒等演算子を実装しており、これは些細なことでシミュレートできる。 元の回路の構造はミラー回路でも維持されるため、ミラー回路を実行しても、量子デバイスが元の回路でどのように動作するかを知ることができる。\n",
        "\n",
        "次のコードセルは、回路にランダムなパラメータを割り当て、その後、[`unitary_overlap`](/docs/api/qiskit/qiskit.circuit.library.unitary_overlap) class を使用してミラー回路を構築します。 回路をミラーリングする前に、 [バリア](/docs/api/qiskit/circuit#qiskit.circuit.Barrier)命令を追加してください。これにより、トランスパイラがバリアの両側にある回路の2つの部分を結合して、ゲートが1つも存在しないトランスパイル済み回路が生成されるのを防ぐことができます。\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 10,
      "id": "4dbde811-1ba9-47a8-85a0-dcaff054ed60",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<Image src=\"/docs/images/tutorials/combine-error-mitigation-techniques/extracted-outputs/4dbde811-1ba9-47a8-85a0-dcaff054ed60-0.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "execution_count": 10,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "# Generate random parameters\n",
        "rng = np.random.default_rng(1234)\n",
        "params = rng.uniform(-np.pi, np.pi, size=circuit.num_parameters)\n",
        "\n",
        "# Assign the parameters to the circuit\n",
        "assigned_circuit = circuit.assign_parameters(params)\n",
        "\n",
        "# Add a barrier to prevent circuit optimization of mirrored operators\n",
        "assigned_circuit.barrier()\n",
        "\n",
        "# Construct mirror circuit\n",
        "mirror_circuit = unitary_overlap(assigned_circuit, assigned_circuit)\n",
        "\n",
        "mirror_circuit.decompose().draw(\"mpl\", scale=0.7)"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "a37c97de-c942-4419-9409-5bcaef9c6876",
      "metadata": {},
      "source": [
        "<span id=\"step-2-optimize-problem-for-quantum-hardware-execution\" />\n",
        "\n",
        "### ステップ2：量子ハードウェア実行に向けた問題の最適化\n",
        "\n",
        "ハードウェア上で動作させる前に、回路を最適化する必要があります。 このプロセスにはいくつかのステップがある：\n",
        "\n",
        "* 回路の仮想量子ビットをハードウェア上の物理量子ビットにマッピングする量子ビットレイアウトを選ぶ。\n",
        "* 接続されていない量子ビット間の相互作用をルーティングするために、必要に応じてスワップゲートを挿入する。\n",
        "* 回路内のゲートを、ハードウェア上で直接実行できる[命令セット・アーキテクチャ（ISA）](/docs/guides/transpile#instruction-set-architecture) 命令に変換します。\n",
        "* 回路の最適化を行い、回路の深さとゲート数を最小化する。\n",
        "\n",
        "Qiskitに組み込まれたトランスパイラは、これらの手順をすべて自動的に実行できます。 この例ではハードウェア効率の良い回路を使用しているため、トランスパイラは相互作用のルーティングにスワップゲートを挿入する必要がない量子ビット配置を選択できるはずです。\n",
        "\n",
        "回路を最適化する前に、使用するハードウェアデバイスを選択する必要があります。 次のコードセルは、127キュービット以上を持ち、かつ最も使用率が低いデバイスを要求します。\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "2c3ea768-0596-4db1-9b51-3ff78ec65818",
      "metadata": {},
      "outputs": [],
      "source": [
        "service = QiskitRuntimeService()\n",
        "backend = service.least_busy(\n",
        "    operational=True, simulator=False, min_num_qubits=127\n",
        ")"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 12,
      "id": "aeaf076c-1c0a-4ec4-af66-49eff621589d",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "<IBMBackend('ibm_fez')>\n"
          ]
        }
      ],
      "source": [
        "print(backend)"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "46280e59-8c9f-4dd9-a365-6a230ceccf42",
      "metadata": {},
      "source": [
        "パスマネージャーを作成し、そのパスマネージャーを回路に対して実行することで、回路を選択したバックエンドにトランスパイルすることができます。 パスマネージャーを作成する簡単な方法は、関数 [`generate_preset_pass_manager`](/docs/api/qiskit/qiskit.transpiler.generate_preset_pass_manager) を使用することです。 [パスマネージャーを使用した](/docs/guides/transpile-with-pass-managers)トランスパイルの詳細については、「パスマネージャーを使用したトランスパイル」を参照してください。\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 13,
      "id": "027e829a-44d3-455e-b2bf-8ce0d7e26b9b",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<Image src=\"/docs/images/tutorials/combine-error-mitigation-techniques/extracted-outputs/027e829a-44d3-455e-b2bf-8ce0d7e26b9b-0.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "execution_count": 13,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "pass_manager = generate_preset_pass_manager(\n",
        "    optimization_level=3, backend=backend, seed_transpiler=1234\n",
        ")\n",
        "isa_circuit = pass_manager.run(mirror_circuit)\n",
        "\n",
        "isa_circuit.draw(\"mpl\", idle_wires=False, scale=0.7, fold=-1)"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "1865671e-2c7a-44dd-8938-fe4637bb5993",
      "metadata": {},
      "source": [
        "トランスパイルされた回路には、現在、ISA命令のみが含まれています。 すべてのゲートは、 $\\sqrt{X}$ ゲート、 $R_z$ 回転、 [およびCZゲート](/docs/api/qiskit/qiskit.circuit.library.CZGate)に分解されています。\n",
        "\n",
        "トランスパイルプロセスは、回路の仮想量子ビットをハードウェア上の物理量子ビットにマッピングした。 量子ビットのレイアウトに関する情報は、トランスパイル回路の `layout` 。 observableも仮想量子ビットで定義されているので、このレイアウトをobservableに適用する必要があります。 [`apply_layout`](/docs/api/qiskit/qiskit.quantum_info.SparsePauliOp#apply_layout)`SparsePauliOp` メソッドで行うことができます。\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 14,
      "id": "12338588-a2d0-4b9c-9e49-e25ec8617b93",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "Original observable:\n",
            "SparsePauliOp(['ZIIIIIIIII'],\n",
            "              coeffs=[1.+0.j])\n",
            "\n",
            "Observable with layout applied:\n",
            "SparsePauliOp(['IIIIIIIIZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII'],\n",
            "              coeffs=[1.+0.j])\n"
          ]
        }
      ],
      "source": [
        "isa_observable = observable.apply_layout(isa_circuit.layout)\n",
        "\n",
        "print(\"Original observable:\")\n",
        "print(observable)\n",
        "print()\n",
        "print(\"Observable with layout applied:\")\n",
        "print(isa_observable)"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "439d4edf-d1ad-49f3-b206-320958be4f82",
      "metadata": {},
      "source": [
        "<span id=\"step-3-execute-using-qiskit-primitives\" />\n",
        "\n",
        "### ステップ3: `Qiskit primitives`を使用して実行する\n",
        "\n",
        "これで、Estimatorプリミティブを使用して回路を実行する準備が整いました。\n",
        "\n",
        "ここでは、5つのジョブを個別に実行します。最初はエラーの抑制や軽減を行わず、その後、 IBM Quantum Compute Service で利用可能なさまざまなエラー抑制および軽減オプションを順次有効にしていきます。 各オプションの詳細については、以下のページを参照してください：\n",
        "\n",
        "* [全オプションの概要](/docs/api/qiskit-ibm-runtime/options)\n",
        "* [ダイナミック・デカップリング](/docs/api/qiskit-ibm-runtime/options-dynamical-decoupling-options)\n",
        "* [測定誤差の緩和とゼロノイズ外挿（ZNE）を含むレジリエンス](/docs/api/qiskit-ibm-runtime/options-resilience-options-v2)\n",
        "* [くるくる回る](/docs/api/qiskit-ibm-runtime/options-twirling-options)\n",
        "\n",
        "これらのジョブは互いに独立して実行できるため、 [バッチモード](/docs/guides/run-jobs-batch)を使用することで、Quantum Compute に実行タイミングの最適化を任せることができます。\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "1114d15b-1408-4f4c-a20f-60f0da722325",
      "metadata": {},
      "outputs": [],
      "source": [
        "pub = (isa_circuit, isa_observable)\n",
        "\n",
        "jobs = []\n",
        "\n",
        "with Batch(backend=backend) as batch:\n",
        "    estimator = Estimator(mode=batch)\n",
        "    estimator.options.environment.job_tags = [\n",
        "        \"TUT_CEM_SS\"\n",
        "    ]  # add tag for this small scale job\n",
        "    # Set number of shots\n",
        "    estimator.options.default_shots = 100_000\n",
        "    # Disable runtime compilation and error mitigation\n",
        "    estimator.options.resilience_level = 0\n",
        "\n",
        "    # Run job with no error mitigation\n",
        "    job0 = estimator.run([pub])\n",
        "    jobs.append(job0)\n",
        "\n",
        "    # Add dynamical decoupling (DD)\n",
        "    estimator.options.dynamical_decoupling.enable = True\n",
        "    estimator.options.dynamical_decoupling.sequence_type = \"XpXm\"\n",
        "    job1 = estimator.run([pub])\n",
        "    jobs.append(job1)\n",
        "\n",
        "    # Add readout error mitigation (DD + TREX)\n",
        "    estimator.options.resilience.measure_mitigation = True\n",
        "    job2 = estimator.run([pub])\n",
        "    jobs.append(job2)\n",
        "\n",
        "    # Add gate twirling (DD + TREX + Gate Twirling)\n",
        "    estimator.options.twirling.enable_gates = True\n",
        "    estimator.options.twirling.num_randomizations = \"auto\"\n",
        "    job3 = estimator.run([pub])\n",
        "    jobs.append(job3)\n",
        "\n",
        "    # Add zero-noise extrapolation (DD + TREX + Gate Twirling + ZNE)\n",
        "    estimator.options.resilience.zne_mitigation = True\n",
        "    estimator.options.resilience.zne.noise_factors = (1, 3, 5)\n",
        "    estimator.options.resilience.zne.extrapolator = (\"exponential\", \"linear\")\n",
        "    job4 = estimator.run([pub])\n",
        "    jobs.append(job4)"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "919517c8-6f42-48d9-a976-53c715c00a4b",
      "metadata": {},
      "source": [
        "<span id=\"step-4-post-process-and-return-result-in-desired-classical-format\" />\n",
        "\n",
        "### ステップ4：後処理を行い、結果を希望の古典形式で返す\n",
        "\n",
        "最後に、データを分析することができる。 ここでは、ジョブ結果を取得し、そこから測定された期待値を抽出し、1標準偏差のエラーバーを含む値をプロットします。\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 16,
      "id": "eef38976-0ca2-429a-b2dc-41aac69605f7",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<Image src=\"/docs/images/tutorials/combine-error-mitigation-techniques/extracted-outputs/eef38976-0ca2-429a-b2dc-41aac69605f7-0.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "metadata": {},
          "output_type": "display_data"
        }
      ],
      "source": [
        "# Retrieve the job results\n",
        "results = [job.result() for job in jobs]\n",
        "\n",
        "# Unpack the PUB results (there's only one PUB result in each job result)\n",
        "pub_results = [result[0] for result in results]\n",
        "\n",
        "# Unpack the expectation values and standard errors\n",
        "expectation_vals = np.array(\n",
        "    [float(pub_result.data.evs) for pub_result in pub_results]\n",
        ")\n",
        "standard_errors = np.array(\n",
        "    [float(pub_result.data.stds) for pub_result in pub_results]\n",
        ")\n",
        "\n",
        "# Plot the expectation values\n",
        "fig, ax = plt.subplots()\n",
        "labels = [\"No mitigation\", \"+ DD\", \"+ TREX\", \"+ Twirling\", \"+ ZNE\"]\n",
        "ax.bar(\n",
        "    range(len(labels)),\n",
        "    expectation_vals,\n",
        "    yerr=standard_errors,\n",
        "    label=\"experiment\",\n",
        ")\n",
        "ax.axhline(y=1.0, color=\"gray\", linestyle=\"--\", label=\"ideal\")\n",
        "ax.set_xticks(range(len(labels)))\n",
        "ax.set_xticklabels(labels)\n",
        "ax.set_ylabel(\"Expectation value\")\n",
        "ax.legend(loc=\"upper left\")\n",
        "\n",
        "plt.show()"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "b400eae8-f38c-4566-82fe-0ccc5ee3f05d",
      "metadata": {},
      "source": [
        "この小さなスケールでは、ほとんどのエラー軽減技術の効果を見ることは難しいが、ゼロノイズ外挿は顕著な改善をもたらす。 しかし、ZNEの結果はエラーバーも大きいため、この改善はタダではないことに注意されたい。\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "958a5d23-ea09-4750-827c-e3bf6c3fa3f4",
      "metadata": {},
      "source": [
        "<span id=\"large-scale-hardware-example\" />\n",
        "\n",
        "## 大規模なハードウェアの例\n",
        "\n",
        "実験を開発する際には、視覚化やシミュレーションを容易にするため、小さな回路から始めることが有用である。 10量子ビット回路でワークフローを開発・テストした今、これを50量子ビットまでスケールアップできます。 以下のコードセルは、このチュートリアルの全手順を繰り返しますが、今回は50量子ビット回路に適用します。\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 17,
      "id": "d7d8408b-faf1-4eda-ab9c-bdeaab01ff53",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<Image src=\"/docs/images/tutorials/combine-error-mitigation-techniques/extracted-outputs/d7d8408b-faf1-4eda-ab9c-bdeaab01ff53-0.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "metadata": {},
          "output_type": "display_data"
        }
      ],
      "source": [
        "n_qubits = 50\n",
        "reps = 1\n",
        "\n",
        "# Construct circuit and observable\n",
        "circuit = efficient_su2(n_qubits, entanglement=\"pairwise\", reps=reps)\n",
        "observable = SparsePauliOp.from_sparse_list(\n",
        "    [(\"Z\", [-1], 1.0)], num_qubits=n_qubits\n",
        ")\n",
        "\n",
        "# Assign parameters to circuit\n",
        "params = rng.uniform(-np.pi, np.pi, size=circuit.num_parameters)\n",
        "assigned_circuit = circuit.assign_parameters(params)\n",
        "assigned_circuit.barrier()\n",
        "\n",
        "# Construct mirror circuit\n",
        "mirror_circuit = unitary_overlap(assigned_circuit, assigned_circuit)\n",
        "\n",
        "# Transpile circuit and observable\n",
        "isa_circuit = pass_manager.run(mirror_circuit)\n",
        "isa_observable = observable.apply_layout(isa_circuit.layout)\n",
        "\n",
        "# Run jobs\n",
        "pub = (isa_circuit, isa_observable)\n",
        "\n",
        "jobs = []\n",
        "\n",
        "with Batch(backend=backend) as batch:\n",
        "    estimator = Estimator(mode=batch)\n",
        "    estimator.options.environment.job_tags = [\n",
        "        \"TUT_CEM_LS\"\n",
        "    ]  # add tag for this large scale job\n",
        "    # Set number of shots\n",
        "    estimator.options.default_shots = 100_000\n",
        "    # Disable runtime compilation and error mitigation\n",
        "    estimator.options.resilience_level = 0\n",
        "\n",
        "    # Run job with no error mitigation\n",
        "    job0 = estimator.run([pub])\n",
        "    jobs.append(job0)\n",
        "\n",
        "    # Add dynamical decoupling (DD)\n",
        "    estimator.options.dynamical_decoupling.enable = True\n",
        "    estimator.options.dynamical_decoupling.sequence_type = \"XpXm\"\n",
        "    job1 = estimator.run([pub])\n",
        "    jobs.append(job1)\n",
        "\n",
        "    # Add readout error mitigation (DD + TREX)\n",
        "    estimator.options.resilience.measure_mitigation = True\n",
        "    job2 = estimator.run([pub])\n",
        "    jobs.append(job2)\n",
        "\n",
        "    # Add gate twirling (DD + TREX + Gate Twirling)\n",
        "    estimator.options.twirling.enable_gates = True\n",
        "    estimator.options.twirling.num_randomizations = \"auto\"\n",
        "    job3 = estimator.run([pub])\n",
        "    jobs.append(job3)\n",
        "\n",
        "    # Add zero-noise extrapolation (DD + TREX + Gate Twirling + ZNE)\n",
        "    estimator.options.resilience.zne_mitigation = True\n",
        "    estimator.options.resilience.zne.noise_factors = (1, 3, 5)\n",
        "    estimator.options.resilience.zne.extrapolator = (\"exponential\", \"linear\")\n",
        "    job4 = estimator.run([pub])\n",
        "    jobs.append(job4)\n",
        "\n",
        "# Retrieve the job results\n",
        "results = [job.result() for job in jobs]\n",
        "\n",
        "# Unpack the PUB results (there's only one PUB result in each job result)\n",
        "pub_results = [result[0] for result in results]\n",
        "\n",
        "# Unpack the expectation values and standard errors\n",
        "expectation_vals = np.array(\n",
        "    [float(pub_result.data.evs) for pub_result in pub_results]\n",
        ")\n",
        "standard_errors = np.array(\n",
        "    [float(pub_result.data.stds) for pub_result in pub_results]\n",
        ")\n",
        "\n",
        "# Plot the expectation values\n",
        "fig, ax = plt.subplots()\n",
        "labels = [\"No mitigation\", \"+ DD\", \"+ TREX\", \"+ Twirling\", \"+ ZNE\"]\n",
        "ax.bar(\n",
        "    range(len(labels)),\n",
        "    expectation_vals,\n",
        "    yerr=standard_errors,\n",
        "    label=\"experiment\",\n",
        ")\n",
        "ax.axhline(y=1.0, color=\"gray\", linestyle=\"--\", label=\"ideal\")\n",
        "ax.set_xticks(range(len(labels)))\n",
        "ax.set_xticklabels(labels)\n",
        "ax.set_ylabel(\"Expectation value\")\n",
        "ax.legend(loc=\"upper left\")\n",
        "\n",
        "plt.show()"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "32d9b036-ea0a-4484-b6ee-036ff732026b",
      "metadata": {},
      "source": [
        "50qubitの結果を先ほどの10qubitの結果と比較すると、以下のことに気づくかもしれない（結果は実行によって異なるかもしれない）：\n",
        "\n",
        "* すべての実験で、結果は理想値により近づき、すべての誤差棒は小さくなっている。\n",
        "* 動的デカップリングを追加したことで、緩和策を講じなかった場合と比べてパフォーマンスが低下した可能性がある。 回路の配置が非常に密集しているため、これは驚くことではない。 動的デカップリングは、回路内に大きなギャップが存在し、その間クビットにゲートが適用されずに待機している場合に、特に有用である。 こうしたギャップが存在しない場合、動的デカップリングは効果を発揮せず、むしろ動的デカップリングパルス自体の誤差によって、パフォーマンスが低下してしまう可能性があります。 10キュービットの回路では、この効果を観測するには規模が小さすぎたのかもしれない。\n",
        "* ゼロノイズ外挿を用いると、結果は理想値に非常に近くなります。 これはZNEの威力を示しています。\n",
        "\n",
        "<span id=\"next-steps\" />\n",
        "\n",
        "## 次のステップ\n",
        "\n",
        "<Admonition type=\"tip\" title=\"推奨事項\">\n",
        "  この内容に興味を持たれた方は、本チュートリアルでは触れられなかった、その他のエラー軽減およびエラー抑制の手法に関する以下の資料もご参照ください：\n",
        "\n",
        "  * [確率的誤差相殺（PEC）](/docs/guides/error-mitigation-and-suppression-techniques#probabilistic-error-cancellation-pec)\n",
        "  * [行列を使用しない測定誤差の低減（ M3 ）](https://qiskit.github.io/qiskit-addon-mthree/) （「 [M3 を使用したSamplerプリミティブの読み出し誤差低減](/docs/tutorials/readout-error-mitigation-sampler/) 」チュートリアルも参照）\n",
        "  * [陰影付きの光錐](https://qiskit.github.io/qiskit-addon-slc/)\n",
        "  * [増幅型吸音（PNA）](https://qiskit.github.io/qiskit-addon-pna/)\n",
        "</Admonition>\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "id": "a1b8767d",
      "source": "© IBM Corp., 2017-2026"
    }
  ],
  "metadata": {
    "kernelspec": {
      "display_name": "Python 3",
      "language": "python",
      "name": "python3"
    },
    "language_info": {
      "codemirror_mode": {
        "name": "ipython",
        "version": 3
      },
      "file_extension": ".py",
      "mimetype": "text/x-python",
      "name": "python",
      "nbconvert_exporter": "python",
      "pygments_lexer": "ipython3",
      "version": "3"
    },
    "hours": 1,
    "qpuSeconds": 420
  },
  "nbformat": 4,
  "nbformat_minor": 4
}