{
  "cells": [
    {
      "cell_type": "markdown",
      "id": "frontmatter",
      "metadata": {},
      "source": [
        "---\n",
        "title: \"クイック・スタート\"\n",
        "description: \"最新バージョンのオペレーターバックプロパゲーション（OBP）のクイックスタート\"\n",
        "---\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "intro",
      "metadata": {},
      "source": [
        "<span id=\"quick-start\" />\n",
        "\n",
        "# クイック・スタート\n",
        "\n",
        "このガイドでは、この `qiskit-addon-obp` パッケージの最小限の動作例を紹介します。 オペレータバックプロパゲーション（OBP）を用いて、末尾のゲートを観測量に吸収させることで、量子回路の深さを削減する。\n",
        "\n",
        "回路 $U$ から末尾のゲートブロックを取り除き、それによって観測量を古典的に共役させたとしても、期待値 $\\langle O \\rangle = \\langle \\psi | U^\\dagger O U | \\psi \\rangle$ は変わらない。 OBPはこの処理を繰り返し適用し、回路の一部を従来の方法で評価することで、ハードウェア上で実行される回路の規模を小さく抑えます。 その代償として、吸収されるゲートごとに観測量が多様なパウリ項へと展開されることになるため、節約された深さと観測量の増加とのバランスを考慮しなければならない。\n",
        "\n",
        "このツールを使って現実的なワークフローを構築し、量子ハードウェア上で実行する方法の例については、 IBM Quantum Platform （ [OBPチュートリアル](/docs/tutorials/operator-back-propagation) ）のチュートリアルをご覧ください。\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "inputs-header",
      "metadata": {},
      "source": [
        "<span id=\"prepare-inputs-for-obp\" />\n",
        "\n",
        "## OBP用の入力データを準備する\n",
        "\n",
        "OBPは、回路スライスのリストと観測可能変数を入力として受け取ります。 これは、回路の末端から観測量へとスライスを1つずつ逆伝播させ、観測量に追加のパウリ項が生じるという代償を払うことで、回路の深さを浅くする。 ここでは、10量子ビットのハイゼンベルクモデルに対する時間発展回路を生成し、ゲート種別ごとに分割します。\n",
        "\n",
        "以下に、元の回路図を示し、続いてスライスの境界を示すバリアを追加して再構成した同じ回路図を示します。各スライスは、1回のバックプロパゲーションステップで観測可能量に吸収できる単位です。\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 1,
      "id": "setup-inputs",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "Original circuit depth: 18\n",
            "Number of slices: 18\n",
            "Observable terms: 1\n"
          ]
        }
      ],
      "source": [
        "import numpy as np\n",
        "from qiskit.quantum_info import SparsePauliOp\n",
        "from qiskit.synthesis import LieTrotter\n",
        "from qiskit.transpiler import CouplingMap\n",
        "from qiskit_addon_utils.problem_generators import (\n",
        "    generate_time_evolution_circuit,\n",
        "    generate_xyz_hamiltonian,\n",
        ")\n",
        "from qiskit_addon_utils.slicing import combine_slices, slice_by_gate_types\n",
        "\n",
        "# Generate a circuit to reduce\n",
        "coupling_map = CouplingMap.from_heavy_hex(3, bidirectional=False)\n",
        "reduced_coupling_map = coupling_map.reduce(\n",
        "    [0, 13, 1, 14, 10, 16, 5, 12, 8, 18]\n",
        ")\n",
        "\n",
        "hamiltonian = generate_xyz_hamiltonian(\n",
        "    reduced_coupling_map,\n",
        "    coupling_constants=(np.pi / 8, np.pi / 4, np.pi / 2),\n",
        "    ext_magnetic_field=(np.pi / 3, np.pi / 6, np.pi / 9),\n",
        ")\n",
        "\n",
        "circuit = generate_time_evolution_circuit(\n",
        "    hamiltonian,\n",
        "    time=0.2,\n",
        "    synthesis=LieTrotter(reps=2),\n",
        ")\n",
        "\n",
        "# Slice the circuit and define an observable\n",
        "slices = slice_by_gate_types(circuit)\n",
        "observable = SparsePauliOp(\"IIIIIIIIIZ\")\n",
        "\n",
        "print(f\"Original circuit depth: {circuit.depth()}\")\n",
        "print(f\"Number of slices: {len(slices)}\")\n",
        "print(f\"Observable terms: {len(observable)}\")"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 2,
      "id": "46efdcfc",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "Original circuit:\n"
          ]
        },
        {
          "data": {
            "text/plain": [
              "<Image src=\"/docs/images/addons/qiskit-addon-obp/guides/quickstart/extracted-outputs/46efdcfc-1.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "metadata": {},
          "output_type": "display_data"
        },
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "Sliced circuit (recombined with barriers for visualization)\n"
          ]
        },
        {
          "data": {
            "text/plain": [
              "<Image src=\"/docs/images/addons/qiskit-addon-obp/guides/quickstart/extracted-outputs/46efdcfc-3.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "execution_count": 2,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "# Recombine the slices with barriers to make the slice boundaries visible\n",
        "sliced_circuit = combine_slices(slices, include_barriers=True)\n",
        "\n",
        "print(\"Original circuit:\")\n",
        "display(circuit.draw(\"mpl\", scale=0.6, fold=-1))\n",
        "print(\"Sliced circuit (recombined with barriers for visualization)\")\n",
        "sliced_circuit.draw(\"mpl\", scale=0.6, fold=-1)"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "obp-header",
      "metadata": {},
      "source": [
        "<span id=\"reduce-circuit-depth-with-obp\" />\n",
        "\n",
        "## OBP を使用して回路の深さを削減する\n",
        "\n",
        "スライスを観測可能対象に吸収するために `backpropagate` 、を呼び出します。 この関数は、展開されたオブザーバブル、伝播されなかった回路スライス、およびこの処理に関するメタデータを返します。\n",
        "\n",
        "放置すると、観測量は $2^n$ のパウリ項に向かって増大する可能性がある。 この成長には上限 `operator_budget` があります。ここでは、クビット単位で可換な群を最大8つまで許容しており、これにより、QPU上で観測量を評価するために必要な試行回数が大まかに決まります。 次のスライスを吸収すると予算を超過してしまう時点で、バックプロパゲーションは停止します。以下の例でもまさにその通りで、観測可能量が8つのコミューティンググループすべてを満たす前に、18個のスライスのうち7個しか吸収されず、処理が停止します。\n",
        "\n",
        "回路をさらに深く掘り下げるには、\\`\\`へのキーワード `truncation_error_budget` 引数を使用して、観測量が大きくなるにつれて、係数の小さいパウリ項を観測量から除外することができます `backpropagate` 。 これにより、観測量の発振が抑制される一方で、切り捨てられるパウリ項の大きさに比例する誤差が生じる。 この2つの予算は相互補完的な関係にあり、併用することも可能です。 `operator_budget` 観測可能なものの*サイズ*を制御し、 `truncation_error_budget` 項を破棄することによって発生する*エラー* を制御します。\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 3,
      "id": "run-obp",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "Backpropagated 7 of 18 slices.\n",
            "Reduced circuit depth: 11 (was 18)\n",
            "Observable grew from 1 to 18 Pauli terms.\n",
            "Filled 8 of 8 commuting groups, exhausting the budget.\n"
          ]
        }
      ],
      "source": [
        "from qiskit_addon_obp import backpropagate\n",
        "from qiskit_addon_obp.utils.simplify import OperatorBudget\n",
        "\n",
        "max_qwc_groups = 8\n",
        "bp_obs, remaining_slices, metadata = backpropagate(\n",
        "    observable,\n",
        "    slices,\n",
        "    operator_budget=OperatorBudget(max_qwc_groups=max_qwc_groups),\n",
        ")\n",
        "\n",
        "reduced_circuit = combine_slices(remaining_slices)\n",
        "num_groups = len(bp_obs.group_commuting(qubit_wise=True))\n",
        "\n",
        "print(\n",
        "    f\"Backpropagated {metadata.num_backpropagated_slices} of {len(slices)} slices.\"\n",
        ")\n",
        "print(\n",
        "    f\"Reduced circuit depth: {reduced_circuit.depth()} (was {circuit.depth()})\"\n",
        ")\n",
        "print(f\"Observable grew from {len(observable)} to {len(bp_obs)} Pauli terms.\")\n",
        "print(\n",
        "    f\"Filled {num_groups} of {max_qwc_groups} commuting groups, exhausting the budget.\"\n",
        ")"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 4,
      "id": "b006625e",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<Image src=\"/docs/images/addons/qiskit-addon-obp/guides/quickstart/extracted-outputs/b006625e-0.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "execution_count": 4,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "reduced_circuit.draw(\"mpl\", scale=0.6, fold=-1)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "id": "a1b8767d",
      "source": "© IBM Corp., 2017-2026"
    }
  ],
  "metadata": {
    "kernelspec": {
      "display_name": "Python 3",
      "language": "python",
      "name": "python3"
    },
    "language_info": {
      "codemirror_mode": {
        "name": "ipython",
        "version": 3
      },
      "file_extension": ".py",
      "mimetype": "text/x-python",
      "name": "python",
      "nbconvert_exporter": "python",
      "pygments_lexer": "ipython3",
      "version": "3"
    }
  },
  "nbformat": 4,
  "nbformat_minor": 5
}