{
  "cells": [
    {
      "cell_type": "markdown",
      "id": "frontmatter",
      "metadata": {},
      "source": [
        "---\n",
        "title: \"クイック・スタート\"\n",
        "description: \"Pauli伝播の最新バージョンのクイックスタート\"\n",
        "---\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "a9320fa8-31c5-4248-96b0-3549a13dda6f",
      "metadata": {},
      "source": [
        "---\n",
        "title: \"クイック・スタート\"\n",
        "description: \"pauli-prop Qiskit アドオンパッケージのクイックスタートガイド\"\n",
        "---\n",
        "\n",
        "<span id=\"quickstart\" />\n",
        "\n",
        "# クイック・スタート\n",
        "\n",
        "このガイドでは、 1D スピン鎖上の10量子ビットのキック付きイジングモデルの時間的ダイナミクスを、パッケージ `pauli-prop` を用いて古典的にシミュレーションします。\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "3b5bf7dc-1cd8-41d3-b8ce-cc75a66fed8d",
      "metadata": {},
      "source": [
        "<span id=\"prepare-the-inputs-for-pauli-propagation\" />\n",
        "\n",
        "## パウリ伝播のための入力の準備\n",
        "\n",
        "検討対象となるハミルトニアンは以下の通りである：\n",
        "\n",
        "$H = -J\\sum\\limits_{\\langle i,j \\rangle} Z_iZ_j + h\\sum\\limits_iX_i$\n",
        "\n",
        "ここで、 $J>0$ は最近接スピン間の結合を表し、 $i<j$、 $h$ は全横磁場である。 時間発展演算子の1次トロッター分解は、 $20$ 回のトロッターステップにわたる量子回路 $U$ として実装される。 結合定数 $J$ は $J=-\\frac{\\pi}{2}$ に、 $h$ は $\\frac{\\pi}{6}$ にそれぞれ固定される。 $ZZ$ の相互作用は、クリフォードゲートを用いて実装される（ $CX$, $Sdg$, $\\sqrt{Y}$ ）。\n",
        "\n",
        "トロッター化された時間発展を量子回路として実装し、x軸周りの非クリフォード回転には $\\frac{\\pi}{6}$ を用いる。 これらの角度がクリフォード角から遠ざかるほど（例えば、 $\\theta=n\\frac{\\pi}{2}, n \\in \\mathbb{Z}$ のように）、パウリ伝播法を用いたシミュレーションはより困難になります。\n",
        "\n",
        "観測量の選択については、単一サイトにおける平均磁化 $\\frac{1}{N} \\sum_{i=1}^{N} \\langle z_i \\rangle$ を考慮する。ここで、 $N$ はスピンの数である。\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 1,
      "id": "15d5eccf-eef0-4435-b67a-98a8038c400e",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<Image src=\"/docs/images/addons/pauli-prop/guides/quickstart/extracted-outputs/15d5eccf-eef0-4435-b67a-98a8038c400e-0.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "import numpy as np\n",
        "from qiskit import QuantumCircuit\n",
        "from qiskit.quantum_info import SparsePauliOp\n",
        "from qiskit.transpiler import CouplingMap\n",
        "\n",
        "num_qubits = 10\n",
        "coupling_map = CouplingMap.from_line(num_qubits, bidirectional=False)\n",
        "\n",
        "# Num Trotter steps\n",
        "num_steps = 20\n",
        "theta_rx = np.pi / 6\n",
        "\n",
        "# Average single-site magnetization\n",
        "observable = (\n",
        "    SparsePauliOp(\n",
        "        [\n",
        "            \"I\" * iq + \"Z\" + \"I\" * (num_qubits - iq - 1)\n",
        "            for iq in range(num_qubits)\n",
        "        ]\n",
        "    )\n",
        "    / num_qubits\n",
        ")\n",
        "\n",
        "# Create the Trotter circuit\n",
        "num_qubits = 10\n",
        "num_steps = 20\n",
        "theta_rx = np.pi / 6\n",
        "circuit = QuantumCircuit(num_qubits)\n",
        "edges = CouplingMap.from_line(num_qubits, bidirectional=False).get_edges()\n",
        "for _ in range(num_steps):\n",
        "    circuit.rx(theta_rx, [i for i in range(num_qubits)])\n",
        "    for edge in edges:\n",
        "        circuit.sdg(edge)\n",
        "        circuit.ry(np.pi / 2, edge[1])\n",
        "        circuit.cx(edge[0], edge[1])\n",
        "        circuit.ry(-np.pi / 2, edge[1])\n",
        "circuit.draw(\"mpl\", fold=-1)"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "c05fa0f8-605e-4172-8880-0de89360f27d",
      "metadata": {},
      "source": [
        "<span id=\"simulate-the-time-evolution-of-the-system-with-pauli-propagation\" />\n",
        "\n",
        "## パウリ伝播を用いて、系の時間発展をシミュレートする\n",
        "\n",
        "回路（ $U$ ）と観測可能量（ $O$ ）が準備できたら、以下の数ステップでシステムを簡単にシミュレーションできます：\n",
        "\n",
        "* $U$ を、Clifford 部分 $C$ と非 Clifford 部分 $P$ に分割し、 $U=PC$ が成り立つようにする。この際、以下の式を用いる。 `evolve_through_cliffords`\n",
        "* $O$ を $P$ を通じて展開すると、新しい演算子 $O^\\prime$ が得られます。その方法は以下の通りです。 `pauli_prop.propagate_through_circuit`\n",
        "* Qiskitに組み込まれているクリフォード進化のサポート機能を使用して、回路のクリフォード部分において $O^\\prime$ を進化させる\n",
        "* $O^\\prime$ における、完全対角パウリ項（すべての量子ビット `Z` で `I` または のいずれかを含むパウリ項）に関連する係数を合計することで、期待値を $\\langle0|O^\\prime|0\\rangle \\approx \\langle0|U^\\dagger OU|0\\rangle$ と近似する。 なお、これは近似であることに注意してください。これは、 $O^\\prime$ の項を、回路の非クリフォード部分を通じて伝播させる際に切り捨てたためです。\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 2,
      "id": "c8a27469-ab72-4d50-9544-d446af847da5",
      "metadata": {},
      "outputs": [],
      "source": [
        "import time\n",
        "\n",
        "from pauli_prop import evolve_through_cliffords, propagate_through_circuit\n",
        "\n",
        "cliff, non_cliff = evolve_through_cliffords(circuit)\n",
        "\n",
        "max_terms_list = [10**i for i in range(8)]\n",
        "approx_evs = []\n",
        "durations = []\n",
        "for max_terms in max_terms_list:\n",
        "    st = time.perf_counter()\n",
        "    evolved_obs = propagate_through_circuit(\n",
        "        observable, non_cliff, max_terms=max_terms, atol=1e-12, frame=\"h\"\n",
        "    )[0]\n",
        "    evolved_obs.paulis = evolved_obs.paulis.evolve(cliff, frame=\"h\")\n",
        "    durations.append(time.perf_counter() - st)\n",
        "    approx_evs.append(\n",
        "        float(evolved_obs.coeffs[~evolved_obs.paulis.x.any(axis=1)].sum())\n",
        "    )"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "7fb3e72f-20fb-4fd0-a301-2fcc6c0ddad5",
      "metadata": {},
      "source": [
        "より大規模な計算を行うにつれて、期待値による近似の精度は高まります。 この例では、 $4^{10}\\approx10^6$ 付近でパウリ空間全体が飽和しており、これが最後の2つの点の間で曲線が平坦になることに表れています。\n",
        "\n",
        "以下のプロットは単調収束を示していますが、パウリ伝播のシミュレーションは一般的に単調に収束するわけではありません。 この種のプロットでは、「ぎくしゃくした」動きが見られることは珍しくありません。\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 3,
      "id": "f12410aa-ef3b-4ee6-ab35-f7e9001a92b8",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "Text(0.5, 1.0, 'Simulating 20-step 1D Ising Model')"
            ]
          },
          "execution_count": 3,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": [
              "<Image src=\"/docs/images/addons/pauli-prop/guides/quickstart/extracted-outputs/f12410aa-ef3b-4ee6-ab35-f7e9001a92b8-1.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "metadata": {},
          "output_type": "display_data"
        }
      ],
      "source": [
        "import matplotlib.pyplot as plt\n",
        "from qiskit_aer import AerSimulator\n",
        "\n",
        "sim_circ = circuit.copy()\n",
        "sim_circ.save_statevector()\n",
        "backend = AerSimulator(method=\"statevector\")\n",
        "psi = backend.run(sim_circ).result().data()[\"statevector\"]\n",
        "exact_ev = psi.expectation_value(observable)\n",
        "\n",
        "ax1 = plt.gca()\n",
        "ax1.plot(max_terms_list, approx_evs, marker=\"o\", label=\"Approximate\")\n",
        "ax1.axhline(exact_ev, linestyle=\"--\", color=\"green\", label=\"Exact\")\n",
        "ax1.set_xscale(\"log\")\n",
        "ax1.set_xlabel(\"# terms kept\")\n",
        "ax1.set_ylabel(r\"$\\frac{1}{N} \\sum_{i=1}^{N} \\langle z_i \\rangle$\")\n",
        "\n",
        "ax2 = ax1.twinx()\n",
        "ax2.plot(\n",
        "    max_terms_list, durations, marker=\".\", label=\"Runtime\", color=\"orange\"\n",
        ")\n",
        "ax2.set_ylabel(\"Runtime (s)\", color=\"orange\")\n",
        "ax2.set_yscale(\"log\")\n",
        "\n",
        "handles1, labels1 = ax1.get_legend_handles_labels()\n",
        "handles2, labels2 = ax2.get_legend_handles_labels()\n",
        "ax1.legend(handles1 + handles2, labels1 + labels2, loc=\"lower right\")\n",
        "\n",
        "plt.title(f\"Simulating {num_steps}-step 1D Ising Model\")"
      ]
    },
    {
      "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
}