{
  "cells": [
    {
      "cell_type": "markdown",
      "id": "76d7b924",
      "metadata": {},
      "source": [
        "---\n",
        "title: \"グローバーのアルゴリズム\"\n",
        "description: \"グローバーのアルゴリズムを用いて、非構造化データベースを2倍の速度で検索する。\"\n",
        "---\n",
        "\n",
        "{/* cspell:ignore fontsize */}\n",
        "\n",
        "<span id=\"grovers-algorithm\" />\n",
        "\n",
        "# グローバーのアルゴリズム\n",
        "\n",
        "*所要時間の目安：Eagle r3 プロセッサで1分未満（注：これはあくまで目安です。 （実行時間は異なる場合があります。）*\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "88aa4204",
      "metadata": {},
      "source": [
        "<span id=\"learning-outcomes\" />\n",
        "\n",
        "## 学習成果\n",
        "\n",
        "このチュートリアルを完了すると、以下の内容を理解できるようになります：\n",
        "\n",
        "* 1つ以上の計算基底状態をマークするグローバー・オラクルを構築する方法\n",
        "* Qiskitのcircuitライブラリにある関 `grover_operator()` 数の使い方\n",
        "* 特定の問題に対して、Grover反復法の最適な反復回数を決定する方法\n",
        "* IBM Quantum のサンプラープリミティブを使用して、グローバーのアルゴリズムを実行する方法\n",
        "\n",
        "<span id=\"prerequisites\" />\n",
        "\n",
        "## 前提条件\n",
        "\n",
        "以下のトピックについて、あらかじめ理解しておくことをお勧めします：\n",
        "\n",
        "* [量子アルゴリズムの基礎：グローバーのアルゴリズム](/learning/courses/fundamentals-of-quantum-algorithms/grover-algorithm/introduction)\n",
        "* [量子情報の基礎](/learning/courses/basics-of-quantum-information)\n",
        "\n",
        "<span id=\"background\" />\n",
        "\n",
        "## 背景\n",
        "\n",
        "Amplitude Amplification（振幅増幅）は、汎用的な量子アルゴリズム、あるいはサブルーチンであり、いくつかの古典的アルゴリズムに対して2乗の速度向上を実現できる。 [グローバーのアルゴリズムは、](https://arxiv.org/abs/quant-ph/9605043) 非構造化検索問題においてこの計算速度の向上を初めて実証したものである。 グローバーの探索問題を定式化するには、1つ以上の計算基底状態を「探求対象の状態」としてマークするオラクル関数と、マークされた状態の振幅を増幅し、その結果として残りの状態を抑制する増幅回路が必要となる。\n",
        "\n",
        "ここでは、Groverのオラクルを構築し、Qiskit回路ライブラリの [`grover_operator()`](/docs/api/qiskit/qiskit.circuit.library.grover_operator) Qiskit回路ライブラリからGroverの探索インスタンスを簡単にセットアップする方法を示す。 ランタイム `Sampler` プリミティブは、グローバー回路のシームレスな実行を可能にする。\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "5bbba268",
      "metadata": {},
      "source": [
        "<span id=\"requirements\" />\n",
        "\n",
        "## 要件\n",
        "\n",
        "このチュートリアルを始める前に、以下のものがインストールされていることを確認してください：\n",
        "\n",
        "* Qiskit SDK v2.0 以降、 [可視化](/docs/api/qiskit/visualization)機能を搭載\n",
        "* Qiskit Runtime v0.22 以降 (`pip install qiskit-ibm-runtime`)\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "bfccad15",
      "metadata": {},
      "source": [
        "<span id=\"setup\" />\n",
        "\n",
        "## セットアップ\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 1,
      "id": "e2cb0472",
      "metadata": {},
      "outputs": [],
      "source": [
        "# Built-in modules\n",
        "import math\n",
        "\n",
        "# Imports from Qiskit\n",
        "from qiskit import QuantumCircuit\n",
        "from qiskit.circuit.library import grover_operator, MCMTGate, ZGate\n",
        "from qiskit.visualization import plot_distribution\n",
        "from qiskit.transpiler.preset_passmanagers import generate_preset_pass_manager\n",
        "\n",
        "# Imports from qiskit-ibm-runtime\n",
        "from qiskit_ibm_runtime import QiskitRuntimeService\n",
        "from qiskit_ibm_runtime import SamplerV2 as Sampler\n",
        "\n",
        "\n",
        "def grover_oracle(marked_states):\n",
        "    \"\"\"Build a Grover oracle for multiple marked states\n",
        "\n",
        "    Here we assume all input marked states have the same number of bits\n",
        "\n",
        "    Parameters:\n",
        "        marked_states (str or list): Marked states of oracle\n",
        "\n",
        "    Returns:\n",
        "        QuantumCircuit: Quantum circuit representing Grover oracle\n",
        "    \"\"\"\n",
        "    if not isinstance(marked_states, list):\n",
        "        marked_states = [marked_states]\n",
        "    # Compute the number of qubits in circuit\n",
        "    num_qubits = len(marked_states[0])\n",
        "\n",
        "    qc = QuantumCircuit(num_qubits)\n",
        "    # Mark each target state in the input list\n",
        "    for target in marked_states:\n",
        "        # Flip target bit-string to match Qiskit bit-ordering\n",
        "        rev_target = target[::-1]\n",
        "        # Find the indices of all the '0' elements in bit-string\n",
        "        zero_inds = [\n",
        "            ind\n",
        "            for ind in range(num_qubits)\n",
        "            if rev_target.startswith(\"0\", ind)\n",
        "        ]\n",
        "        # Add a multi-controlled Z-gate with pre- and post-applied X-gates (open-controls)\n",
        "        # where the target bit-string has a '0' entry\n",
        "        if zero_inds:\n",
        "            qc.x(zero_inds)\n",
        "        qc.compose(MCMTGate(ZGate(), num_qubits - 1, 1), inplace=True)\n",
        "        if zero_inds:\n",
        "            qc.x(zero_inds)\n",
        "    return qc"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "77e41aba",
      "metadata": {},
      "source": [
        "<span id=\"small-scale-simulator-example\" />\n",
        "\n",
        "## 小規模シミュレータの例\n",
        "\n",
        "このセクションでは、実際の量子ハードウェアで同じ問題を処理する前に、ローカルシミュレータを用いて、小規模な環境でグローバーのアルゴリズムの各ステップを順を追って解説します。\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "0c0fb667",
      "metadata": {},
      "source": [
        "<span id=\"step-1-map-classical-inputs-to-a-quantum-problem\" />\n",
        "\n",
        "### ステップ1：古典的な入力を量子問題にマッピングする\n",
        "\n",
        "グローバーのアルゴリズムでは、1つ以上の「マーク付き」計算基底状態を指定する[オラクル](/learning/modules/computer-science/grovers#introduction)が必要となる。「マーク付き」とは、位相が -1 である状態を指す。  制御Zゲート、あるいは $N$ 量子ビットに対するその多重制御の一般化は、 $2^{N}-1$ 状態（`'1'`\\* $N$ ビット列）を表す。  2進表現において基底状態を1つ以上の `'0'` 「1」で表すには、制御Zゲートの前後で対応する量子ビットにXゲートを適用する必要があり、これはその量子ビットに対してオープン制御を行うことと同等である。  以下のコードでは、ビット列表現によって定義された1つ以上の入力基底状態をマークするオラクルを定義します。  この `MCMT` ゲートは、マルチ制御Zゲートを実装するために使用されます。\n",
        "\n"
      ]
    },
    {
      "attachments": {},
      "cell_type": "markdown",
      "id": "bca14740",
      "metadata": {},
      "source": [
        "<span id=\"specific-grovers-instance\" />\n",
        "\n",
        "### 特定のグローバーの実例\n",
        "\n",
        "オラクル関数ができたので、グローバー探索の特定のインスタンスを定義することができる。  この例では、3量子ビットの計算空間で利用可能な8つの計算状態のうち、2つの計算状態をマークする：\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 2,
      "id": "c150298f",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<Image src=\"/docs/images/tutorials/grovers-algorithm/extracted-outputs/c150298f-0.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "execution_count": 2,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "marked_states = [\"011\", \"100\"]\n",
        "\n",
        "oracle = grover_oracle(marked_states)\n",
        "oracle.draw(output=\"mpl\", style=\"iqp\")"
      ]
    },
    {
      "attachments": {},
      "cell_type": "markdown",
      "id": "25487b93",
      "metadata": {},
      "source": [
        "<span id=\"grover-operator\" />\n",
        "\n",
        "### グローバー演算子\n",
        "\n",
        "組み込みのQiskit `grover_operator()` は、オラクル回路を受け取り、オラクル回路そのものと、オラクルによってマークされた状態を増幅する回路からなる回路を返す。  ここでは、 `decompose()` 、演算子内のゲートを見るために回路を使用する：\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 3,
      "id": "283d5265",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<Image src=\"/docs/images/tutorials/grovers-algorithm/extracted-outputs/283d5265-0.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "execution_count": 3,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "grover_op = grover_operator(oracle)\n",
        "grover_op.decompose().draw(output=\"mpl\", style=\"iqp\")"
      ]
    },
    {
      "attachments": {},
      "cell_type": "markdown",
      "id": "83c34dc9",
      "metadata": {},
      "source": [
        "この `grover_op` 回路を繰り返し適用すると、マークされた状態が増幅され、回路からの出力分布において最も確率の高いビット列となる。  このようなアプリケーションの最適な数は、可能な計算状態の総数に対するマークされた状態の比率によって決まる：\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 4,
      "id": "f4c3d4b5",
      "metadata": {},
      "outputs": [],
      "source": [
        "optimal_num_iterations = math.floor(\n",
        "    math.pi\n",
        "    / (4 * math.asin(math.sqrt(len(marked_states) / 2**grover_op.num_qubits)))\n",
        ")"
      ]
    },
    {
      "attachments": {},
      "cell_type": "markdown",
      "id": "e06c8238",
      "metadata": {},
      "source": [
        "<span id=\"full-grover-circuit\" />\n",
        "\n",
        "### フルグローバー回路\n",
        "\n",
        "完全なグローバー実験は、各クビットのハダマードゲートから始まる。すべての計算基底状態の偶数重ね合わせを作り、グローバー演算子(`grover_op`)を最適な回数繰り返す。  ここでは、 `QuantumCircuit.power(INT)` 方式を利用して、グローバー演算子を繰り返し適用する。\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 5,
      "id": "4933ae44",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<Image src=\"/docs/images/tutorials/grovers-algorithm/extracted-outputs/4933ae44-0.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "execution_count": 5,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "qc = QuantumCircuit(grover_op.num_qubits)\n",
        "# Create even superposition of all basis states\n",
        "qc.h(range(grover_op.num_qubits))\n",
        "# Apply Grover operator the optimal number of times\n",
        "qc.compose(grover_op.power(optimal_num_iterations), inplace=True)\n",
        "# Measure all qubits\n",
        "qc.measure_all()\n",
        "qc.draw(output=\"mpl\", style=\"iqp\")"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "0649c854",
      "metadata": {},
      "source": [
        "<span id=\"step-2-optimize-problem-for-quantum-hardware-execution\" />\n",
        "\n",
        "### ステップ2：量子ハードウェア実行に向けた問題の最適化\n",
        "\n",
        "小規模なシミュレーションを行うため、特定のハードウェアをターゲットとせずに回路をトランスパイルします。\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 6,
      "id": "c4f67f35",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<Image src=\"/docs/images/tutorials/grovers-algorithm/extracted-outputs/c4f67f35-0.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "execution_count": 6,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "pm = generate_preset_pass_manager(optimization_level=3)\n",
        "circuit_isa = pm.run(qc)\n",
        "circuit_isa.draw(output=\"mpl\", idle_wires=False, style=\"iqp\")"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "4e0d4d90",
      "metadata": {},
      "source": [
        "<span id=\"step-3-execute-using-qiskit-primitives\" />\n",
        "\n",
        "### ステップ3: `Qiskit primitives`を使用して実行する\n",
        "\n",
        "振幅増幅は、プリミティブ [`SamplerV2`](/docs/api/qiskit-ibm-runtime/sampler-v2) での実行に適したサンプリング問題である。 `StatevectorSampler` ここでは、局所シミュレーションのために から `qiskit.primitives` を使用します。\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 7,
      "id": "7666ad7c",
      "metadata": {},
      "outputs": [],
      "source": [
        "from qiskit.primitives import StatevectorSampler\n",
        "\n",
        "sampler = StatevectorSampler()\n",
        "result = sampler.run([circuit_isa], shots=10_000).result()\n",
        "dist = result[0].data.meas.get_counts()"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "5c8263c7",
      "metadata": {},
      "source": [
        "<span id=\"step-4-post-process-and-return-result-in-desired-classical-format\" />\n",
        "\n",
        "### ステップ4：後処理を行い、結果を希望の古典形式で返す\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 8,
      "id": "a5ef9913",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<Image src=\"/docs/images/tutorials/grovers-algorithm/extracted-outputs/a5ef9913-0.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "execution_count": 8,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "plot_distribution(dist)"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "2b45b2ee",
      "metadata": {},
      "source": [
        "<span id=\"hardware-example\" />\n",
        "\n",
        "## ハードウェアの例\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "5fb22680",
      "metadata": {},
      "source": [
        "<span id=\"steps-1-4\" />\n",
        "\n",
        "### 手順 1～4\n",
        "\n",
        "グローバーのアルゴリズムは、本質的にフォールトトレラントなアルゴリズムである。オラクルと拡散演算子の核心をなす多重制御Zゲートにより、2量子ビットのゲート深さは量子ビット数に応じて非常に急速に増加する（これについては次の節で示す）。 つまり、このアルゴリズムは、現在のノイズの多いハードウェア環境ではスケーラビリティに欠けるということです。 このため、より大規模な問題に取り組むのではなく、前述のシミュレータ例と同じ小規模な範囲でハードウェア実行を実証する。\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "be3c3d9e",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<Image src=\"/docs/images/tutorials/grovers-algorithm/extracted-outputs/be3c3d9e-0.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "execution_count": 9,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "# -------------------------Step 1-------------------------\n",
        "marked_states = [\"011\", \"100\"]\n",
        "\n",
        "oracle = grover_oracle(marked_states)\n",
        "grover_op = grover_operator(oracle)\n",
        "\n",
        "optimal_num_iterations = math.floor(\n",
        "    math.pi\n",
        "    / (4 * math.asin(math.sqrt(len(marked_states) / 2**grover_op.num_qubits)))\n",
        ")\n",
        "\n",
        "qc = QuantumCircuit(grover_op.num_qubits)\n",
        "qc.h(range(grover_op.num_qubits))\n",
        "qc.compose(grover_op.power(optimal_num_iterations), inplace=True)\n",
        "qc.measure_all()\n",
        "\n",
        "# -------------------------Step 2-------------------------\n",
        "service = QiskitRuntimeService()\n",
        "backend = service.least_busy(\n",
        "    operational=True, simulator=False, min_num_qubits=127\n",
        ")\n",
        "\n",
        "target = backend.target\n",
        "pm = generate_preset_pass_manager(target=target, optimization_level=3)\n",
        "circuit_isa = pm.run(qc)\n",
        "\n",
        "# -------------------------Step 3-------------------------\n",
        "sampler = Sampler(mode=backend)\n",
        "sampler.options.default_shots = 10_000\n",
        "sampler.options.environment.job_tags = [\"TUT-GA\"]\n",
        "result = sampler.run([circuit_isa]).result()\n",
        "dist = result[0].data.meas.get_counts()\n",
        "\n",
        "# -------------------------Step 4-------------------------\n",
        "plot_distribution(dist)"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "12e72eab",
      "metadata": {},
      "source": [
        "<span id=\"discussion-two-qubit-gate-depth-scaling\" />\n",
        "\n",
        "## 考察：2量子ビットゲートの深度スケーリング\n",
        "\n",
        "グローバーのアルゴリズムが耐障害性アルゴリズムと見なされる主な理由は、量子ビットの数が増えるにつれて、回路の2量子ビットゲート深度が急速に増加することにある。 オラクル演算子と拡散演算子の両方の核心をなすマルチ制御Zゲートは、制御量子ビットの数に比例して指数関数的に増加する数の2量子ビットゲートに分解される。 さらに、グローバー反復の最適回数が $O(\\sqrt{2^n})$ の割合で増加するという事実も相まって、ノイズの多いハードウェアでは、2量子ビットの全体的な処理深度がすぐに現実的ではなくなってしまう。\n",
        "\n",
        "以下では、量子ビット数を増やしながらグローバー回路を構築し、それらをトランスパイルして、その結果得られる2量子ビットゲートの深さをプロットし、このスケーリングを明らかにする。\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 10,
      "id": "abc6b43c",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "n=3: optimal_iters=2, 2Q depth=39\n",
            "n=4: optimal_iters=3, 2Q depth=111\n",
            "n=5: optimal_iters=4, 2Q depth=466\n",
            "n=6: optimal_iters=6, 2Q depth=1646\n",
            "n=7: optimal_iters=8, 2Q depth=3550\n",
            "n=8: optimal_iters=12, 2Q depth=7989\n",
            "n=9: optimal_iters=17, 2Q depth=14824\n"
          ]
        },
        {
          "data": {
            "text/plain": [
              "<Image src=\"/docs/images/tutorials/grovers-algorithm/extracted-outputs/abc6b43c-1.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "metadata": {},
          "output_type": "display_data"
        }
      ],
      "source": [
        "import matplotlib.pyplot as plt\n",
        "\n",
        "num_qubits_list = list(range(3, 10))\n",
        "two_q_depths = []\n",
        "backend = service.least_busy(\n",
        "    operational=True, simulator=False, min_num_qubits=127\n",
        ")\n",
        "for n in num_qubits_list:\n",
        "    # Mark a single state for simplicity\n",
        "    marked = [\"1\" * n]\n",
        "    oracle_n = grover_oracle(marked)\n",
        "    grover_op_n = grover_operator(oracle_n)\n",
        "\n",
        "    # Optimal number of iterations\n",
        "    num_iters = math.floor(\n",
        "        math.pi / (4 * math.asin(math.sqrt(len(marked) / 2**n)))\n",
        "    )\n",
        "\n",
        "    # Build the full Grover circuit\n",
        "    qc_n = QuantumCircuit(n)\n",
        "    qc_n.h(range(n))\n",
        "    qc_n.compose(grover_op_n.power(num_iters), inplace=True)\n",
        "    qc_n.measure_all()\n",
        "\n",
        "    # Transpile to a basis gate set and count 2Q depth\n",
        "    pm_n = generate_preset_pass_manager(backend=backend, optimization_level=3)\n",
        "    qc_transpiled = pm_n.run(qc_n)\n",
        "\n",
        "    # Compute depth restricted to 2-qubit operations\n",
        "    depth_2q = qc_transpiled.depth(lambda x: x.operation.num_qubits == 2)\n",
        "\n",
        "    two_q_depths.append(depth_2q)\n",
        "    print(f\"n={n}: optimal_iters={num_iters}, 2Q depth={depth_2q}\")\n",
        "\n",
        "# Plot\n",
        "fig, ax = plt.subplots(figsize=(8, 5))\n",
        "ax.plot(\n",
        "    num_qubits_list,\n",
        "    two_q_depths,\n",
        "    \"o-\",\n",
        "    linewidth=2,\n",
        "    markersize=8,\n",
        "    color=\"#6929C4\",\n",
        ")\n",
        "ax.set_xlabel(\"Number of qubits\", fontsize=13)\n",
        "ax.set_ylabel(\"Two-qubit gate depth\", fontsize=13)\n",
        "ax.set_title(\"Grover's algorithm: 2Q depth scaling\", fontsize=14)\n",
        "ax.set_yscale(\"log\")\n",
        "ax.grid(True, alpha=0.3)\n",
        "ax.set_xticks(num_qubits_list)\n",
        "plt.tight_layout()\n",
        "plt.show()"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "f3ddda55",
      "metadata": {},
      "source": [
        "グラフが示すように、2量子ビットゲートの深さは量子ビット数とともに極めて急速に増加し、おおむね指数関数的な増加を示す。 このため、現在のノイズの多い量子ハードウェアでは、問題の規模が非常に小さい場合を除き、グローバーのアルゴリズムは実用的なものとは言えない。 このアルゴリズムは、エラー訂正技術によって深層回路を確実に実行できるようになる将来の耐故障性量子コンピュータにおいて、依然として重要な研究対象である。\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "cf6e8fe6",
      "metadata": {},
      "source": [
        "<span id=\"next-steps\" />\n",
        "\n",
        "## 次のステップ\n",
        "\n",
        "<Admonition type=\"tip\" title=\"推奨事項\">\n",
        "  この作品が興味深かった方は、以下の資料もご参考になるかもしれません：\n",
        "\n",
        "  * [Qiskit 回路ライブラリ： `grover_operator()` API リファレンス](/docs/api/qiskit/qiskit.circuit.library.grover_operator)\n",
        "  * [QAOAチュートリアル](/docs/tutorials/quantum-approximate-optimization-algorithm)および[ユーティリティ規模のQAOAレッスン](/learning/courses/quantum-computing-in-practice/utility-scale-qaoa)では、量子コンピュータを用いた最適化の近未来的な事例を紹介しています\n",
        "  * 短期アルゴリズムについてさらに詳しく知りたい方は、 [「実践クアンタムコンピューティング」](/learning/courses/quantum-computing-in-practice) コースをご覧ください\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": 60
  },
  "nbformat": 4,
  "nbformat_minor": 5
}