{
  "cells": [
    {
      "cell_type": "markdown",
      "id": "bc51e7bf-e582-49ba-93f8-035624d56ccf",
      "metadata": {},
      "source": [
        "---\n",
        "title: \"量子近似最適化アルゴリズム\"\n",
        "description: \"実用規模で、Qiskitのパターンを用いたQAOAにより最大カット問題を解く。\"\n",
        "---\n",
        "\n",
        "{/* cspell:ignore frameon popcount fval */}\n",
        "\n",
        "<span id=\"quantum-approximate-optimization-algorithm\" />\n",
        "\n",
        "# 量子近似最適化アルゴリズム\n",
        "\n",
        "*使用時間の見積もり：Heron r3 プロセッサーで22分（注：これはあくまでも見積もりです。 ランタイムは異なるかもしれない)。*\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "learning-outcomes-prereqs",
      "metadata": {},
      "source": [
        "<span id=\"learning-outcomes\" />\n",
        "\n",
        "## 学習成果\n",
        "\n",
        "このチュートリアルを完了すると、以下の内容を理解できるようになります：\n",
        "\n",
        "* 古典的な組み合わせ最適化問題（最大カット問題）を量子ハミルトニアンに写像する方法\n",
        "* IBM Quantum Compute Service セッションを使用して、量子近似最適化アルゴリズム（QAOA）を実装および実行する方法\n",
        "* 小規模なシミュレータ例から実用規模のハードウェア実行へとQAOAワークフローを拡張する方法\n",
        "\n",
        "<span id=\"prerequisites\" />\n",
        "\n",
        "## 前提条件\n",
        "\n",
        "以下のトピックについて、あらかじめ確認しておくことをお勧めします：\n",
        "\n",
        "* [量子回路の基礎](/learning/courses/basics-of-quantum-information)\n",
        "* [変分アルゴリズム](/learning/courses/variational-algorithm-design)\n",
        "* [QAOAの詳細](/learning/courses/quantum-computing-in-practice/utility-scale-qaoa) — QAOAアルゴリズムの包括的な解説と、大規模電力システムへの応用\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "de201dbb",
      "metadata": {},
      "source": [
        "<span id=\"background\" />\n",
        "\n",
        "## 背景\n",
        "\n",
        "**量子近似最適化アルゴリズム（QAOA）** は、組み合わせ最適化問題を解くための、量子と古典を組み合わせた反復法である。 このチュートリアルでは、QAOAを用いて**最大カット（max-cut）** 問題を解きます。これは、クラスタリング、ネットワーク科学、統計物理学などの分野で応用されるNP困難な最適化問題です。 辺で結ばれたノードからなるグラフに対し、分割線を横切る辺の数が最大になるように、ノードを2つの集合に分割することを目的とする。\n",
        "\n",
        "![マックスカット問題の図解](https://quantum.cloud.ibm.com/docs/images/tutorials/quantum-approximate-optimization-algorithm/maxcut-illustration.avif)\n",
        "\n",
        "<span id=\"from-classical-optimization-to-quantum-circuits\" />\n",
        "\n",
        "### 古典的最適化から量子回路へ\n",
        "\n",
        "Max-cutは、古典的な二値最適化問題として定式化することができる。 各ノードには、どの集合に属するかを示す二値変数 $x_i \\in \\{0, 1\\}$ が割り当てられる。 目的は、端点が異なる集合に属する辺の数を最大化することです：\n",
        "\n",
        "$$\n",
        "\\max_{x \\in \\{0,1\\}^n} \\sum_{(i,j)} x_i + x_j - 2x_ix_j.\n",
        "$$\n",
        "\n",
        "これは、 $\\min_x\\, x^T Q x$ という形式の**二次制約なし二値最適化（QUBO）** 問題に相当する。標準的な変数置換（ $x_i \\to (1 - Z_i)/2$ ）を用いることで、このQUBOは**コストハミルトニアン**として書き換えることができ、その基底状態が最適解を符号化する。 一般に、このハミルトニアンには二次項と一次項の両方が含まれている：\n",
        "\n",
        "$$\n",
        "H_C = \\sum_{ij} Q_{ij} \\, Z_i Z_j + \\sum_i b_i \\, Z_i.\n",
        "$$\n",
        "\n",
        "ここで検討する非加重最大切断問題では、各辺について線形係数はゼロ（ $b_i = 0$ ）となり、 $Q_{ij} = 1$ となるため、以下のコードで実装するより単純な形 $H_C = \\sum_{(i,j) \\in E} Z_i Z_j$ が得られます。 上記のより一般的な形式は、このワークフローを重み付きグラフやその他のQUBOで表現可能な問題に適用する際に必要となるものです。\n",
        "\n",
        "<span id=\"how-qaoa-works\" />\n",
        "\n",
        "### QAOAの仕組み\n",
        "\n",
        "QAOAは、初期の重ね合わせ状態 $H^{\\otimes n}|0\\rangle$ に対して、 **コスト演算**子 $e^{-i\\gamma_k H_C}$ と**ミキサー演算子**$e^{-i\\beta_k H_m}$ の2つの演算子を交互に重ね合わせて、候補解を生成する。角度 $\\gamma_k$ および $\\beta_k$ は、古典的なフィードバックループで最適化される。量子コンピュータがコスト関数を評価し、古典的な最適化アルゴリズムが収束するまでパラメータを更新する。 この反復ループは、Quantum Compute **セッション**内で実行されます。これにより、反復処理の間、量子デバイスが予約された状態が維持され、レイテンシの低減が図られます。\n",
        "\n",
        "![QAOAレイヤーによる回路図](https://quantum.cloud.ibm.com/docs/images/tutorials/quantum-approximate-optimization-algorithm/circuit-diagram.svg)\n",
        "\n",
        "QUBOからハミルトニアンへの完全な導出を含む、QAOA理論に関するより詳細な解説については、 [QAOAコースのモジュール](/learning/courses/utility-scale-quantum-computing/variational-quantum-algorithms#1-introduction)をご覧ください。\n",
        "\n",
        "このチュートリアルでは、まず5ノードの小さなグラフで最大切断問題を解き、その後、実際のハードウェア上で、同じワークフローを100ノードのユーティリティ規模の問題に拡張します。 *プランの利用に関する注意事項：* このチュートリアルでは「Quantum Compute」 [セッション](/docs/guides/execution-modes#session-mode)を使用していますが、これは「プレミアムプラン」でのみ利用可能です。 「Open Plan」プランをご利用の場合は、このチュートリアルを記載通りに実行することはできません。代わりに、を[ジョブモード ](/docs/guides/execution-modes#job-mode)`Session` に切り替える必要があります（つまり、最適化ループをで囲むのではなく、各反復を独立したジョブとして送信します `Session(...)`）。 ワークフローは引き続き実行されますが、各反復処理において、予約済みのデバイスを再利用するのではなく、キューのレイテンシを全額負担することになります。 詳細については、「 [利用可能なプランの概要](/docs/guides/plans-overview)」 をご覧ください。\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "381800e5",
      "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",
        "また、 [IBM Quantum® Platform](/docs/guides/cloud-setup) 上のインスタンスにアクセスできる必要があります。\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "f5307376",
      "metadata": {},
      "source": [
        "<span id=\"setup\" />\n",
        "\n",
        "## セットアップ\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 1,
      "id": "37b3acfc",
      "metadata": {},
      "outputs": [],
      "source": [
        "import matplotlib.pyplot as plt\n",
        "import rustworkx as rx\n",
        "from rustworkx.visualization import mpl_draw as draw_graph\n",
        "import numpy as np\n",
        "from scipy.optimize import minimize\n",
        "from collections import defaultdict\n",
        "from typing import Sequence\n",
        "\n",
        "\n",
        "from qiskit.quantum_info import SparsePauliOp\n",
        "from qiskit.circuit.library import QAOAAnsatz\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 Session, EstimatorV2 as Estimator\n",
        "from qiskit_ibm_runtime import SamplerV2 as Sampler"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "68fd0b4f-baa4-45dc-9f4c-d9cdff01a651",
      "metadata": {},
      "source": [
        "<span id=\"small-scale-example\" />\n",
        "\n",
        "## 小規模な例\n",
        "\n",
        "このセクションでは、5ノードの小さな最大切断問題のインスタンスを用いて、QAOAワークフローの各ステップを順を追って説明します。 「小規模」と銘打たれてはいるものの、この例は実際の IBM Quantum ハードウェア上で動作します。コードは127キュービット以上のバックエンドを選択し、そこで回路を実行します。\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "0cbca6cb",
      "metadata": {},
      "source": [
        "$n=5$ のノードでグラフを作成し、問題を初期化する。\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 2,
      "id": "6ced6bea",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<Image src=\"/docs/images/tutorials/quantum-approximate-optimization-algorithm/extracted-outputs/6ced6bea-0.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "metadata": {},
          "output_type": "display_data"
        }
      ],
      "source": [
        "n_small = 5\n",
        "\n",
        "graph = rx.PyGraph()\n",
        "graph.add_nodes_from(np.arange(0, n_small, 1))\n",
        "edge_list = [\n",
        "    (0, 1, 1.0),\n",
        "    (0, 2, 1.0),\n",
        "    (0, 4, 1.0),\n",
        "    (1, 2, 1.0),\n",
        "    (2, 3, 1.0),\n",
        "    (3, 4, 1.0),\n",
        "]\n",
        "graph.add_edges_from(edge_list)\n",
        "draw_graph(graph, node_size=600, with_labels=True)"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "a06e4386-d7bd-4914-9baa-36a5cc60e3ab",
      "metadata": {},
      "source": [
        "<span id=\"step-1-map-classical-inputs-to-a-quantum-problem\" />\n",
        "\n",
        "### ステップ1：古典的な入力を量子問題にマッピングする\n",
        "\n",
        "古典グラフを量子**回路**および**演算子**に写像する。 「 [背景](#background) 」で述べたように、重みなし最大切断問題において、コストハミルトニアンは $H_C = \\sum_{(i,j) \\in E} Z_i Z_j$ に還元され、QAOAではパラメータ化されたアンザッツ回路を用いて、 $H_C$ という候補基底状態を生成する。\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "a5b9e551-38a1-4543-b9f1-caaefb0ef3a9",
      "metadata": {},
      "source": [
        "<span id=\"build-the-cost-hamiltonian\" />\n",
        "\n",
        "#### コストハミルトニアンを構築する\n",
        "\n",
        "グラフの辺をパウリ $Z_iZ_j$ 項に変換し、 $H_C$ を構築する（導出については [「背景」](#background) を参照）。\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 3,
      "id": "52d1ba92",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "Cost Function Hamiltonian: SparsePauliOp(['IIIZZ', 'IIZIZ', 'ZIIIZ', 'IIZZI', 'IZZII', 'ZZIII'],\n",
            "              coeffs=[1.+0.j, 1.+0.j, 1.+0.j, 1.+0.j, 1.+0.j, 1.+0.j])\n"
          ]
        }
      ],
      "source": [
        "def build_max_cut_paulis(\n",
        "    graph: rx.PyGraph,\n",
        ") -> list[tuple[str, list[int], float]]:\n",
        "    \"\"\"Convert graph edges to a list of ZZ Pauli terms.\n",
        "\n",
        "    The returned list is in the sparse format expected by\n",
        "    ``SparsePauliOp.from_sparse_list``: each element is\n",
        "    ``(pauli_string, qubit_indices, coefficient)``.\n",
        "    \"\"\"\n",
        "    pauli_list = []\n",
        "    for edge in list(graph.edge_list()):\n",
        "        weight = graph.get_edge_data(edge[0], edge[1])\n",
        "        pauli_list.append((\"ZZ\", [edge[0], edge[1]], weight))\n",
        "    return pauli_list\n",
        "\n",
        "\n",
        "max_cut_paulis = build_max_cut_paulis(graph)\n",
        "cost_hamiltonian = SparsePauliOp.from_sparse_list(max_cut_paulis, n_small)\n",
        "print(\"Cost Function Hamiltonian:\", cost_hamiltonian)"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "33f71b0d-4a2a-4082-8c1a-ce9d2b769048",
      "metadata": {},
      "source": [
        "<span id=\"build-the-qaoa-ansatz-circuit\" />\n",
        "\n",
        "#### QAOAアンザッツ回路を構築する\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "00431c46-30c2-40f9-99df-40baf8da98f6",
      "metadata": {},
      "source": [
        "を使用して `QAOAAnsatz` 、コストハミルトニアンからパラメータ化されたQAOA回路を構築する。 ここでは、（2つのQAOA層、4つのパラメータ： $\\beta_0, \\beta_1, \\gamma_0, \\gamma_1$ ）を使用 `reps=2` する。\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 4,
      "id": "7bd8c6d4-f40f-4a11-a440-0b26d9021b53",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<Image src=\"/docs/images/tutorials/quantum-approximate-optimization-algorithm/extracted-outputs/7bd8c6d4-f40f-4a11-a440-0b26d9021b53-0.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "execution_count": 4,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "circuit = QAOAAnsatz(cost_operator=cost_hamiltonian, reps=2)\n",
        "circuit.measure_all()\n",
        "\n",
        "circuit.draw(\"mpl\")"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 5,
      "id": "315c495a",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "ParameterView([ParameterVectorElement(β[0]), ParameterVectorElement(β[1]), ParameterVectorElement(γ[0]), ParameterVectorElement(γ[1])])"
            ]
          },
          "execution_count": 5,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "circuit.parameters"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "82f70daa-ff68-447a-8064-8b7df7a646cf",
      "metadata": {},
      "source": [
        "<span id=\"step-2-optimize-problem-for-quantum-hardware-execution\" />\n",
        "\n",
        "### ステップ2：量子ハードウェア実行に向けた問題の最適化\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "c08be444-e3ed-4178-a10b-414069b1b411",
      "metadata": {},
      "source": [
        "抽象回路をハードウェア固有の命令に変換する。 このステップでは、量子ビットのマッピング、ゲートの分解、ルーティング、およびエラー抑制を行います。 詳細については、トランスパイル[に関するドキュメント](/docs/guides/transpile)を参照してください。\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 6,
      "id": "3f28a422-805c-4d3d-b5f6-62539e9133bd",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "<IBMBackend('ibm_pittsburgh')>\n"
          ]
        },
        {
          "data": {
            "text/plain": [
              "<Image src=\"/docs/images/tutorials/quantum-approximate-optimization-algorithm/extracted-outputs/3f28a422-805c-4d3d-b5f6-62539e9133bd-1.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "execution_count": 6,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "service = QiskitRuntimeService()\n",
        "backend = service.least_busy(\n",
        "    operational=True, simulator=False, min_num_qubits=127\n",
        ")\n",
        "print(backend)\n",
        "\n",
        "# Create pass manager for transpilation. Level 3 is the most aggressive\n",
        "# preset: slower to transpile, but produces shorter circuits that are\n",
        "# more robust to hardware noise.\n",
        "pm = generate_preset_pass_manager(optimization_level=3, backend=backend)\n",
        "\n",
        "candidate_circuit = pm.run(circuit)\n",
        "candidate_circuit.draw(\"mpl\", fold=False, idle_wires=False)"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "4e75cad7-f599-4937-b5fe-f4d01f53423c",
      "metadata": {},
      "source": [
        "<span id=\"step-3-execute-using-qiskit-primitives\" />\n",
        "\n",
        "### ステップ3: `Qiskit primitives`を使用して実行する\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "9b99ce67-f121-4244-b62a-536be38fea86",
      "metadata": {},
      "source": [
        "QAOAの最適化ループは、反復処理の間、デバイスが確保された状態を維持するために、Quantum Compute [セッション](/docs/guides/execution-modes)内で実行されます。 推定器は各ステップで $\\langle H_C \\rangle$ を評価し、従来の最適化アルゴリズム（COBYLA）は収束するまでパラメータを更新します。\n",
        "\n",
        "![シングルジョブ、バッチ、セッションのランタイムモードの動作を示す図。](https://quantum.cloud.ibm.com/docs/images/tutorials/quantum-approximate-optimization-algorithm/runtime-modes.avif)\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "00b2b0f1-9bad-4ad3-b93e-5cbf40395dbf",
      "metadata": {},
      "source": [
        "初期パラメータを定義し、最適化ループを実行します：\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 7,
      "id": "afa5747f-44dc-4e41-a875-7b6f896f13e2",
      "metadata": {},
      "outputs": [],
      "source": [
        "# QAOA doesn't prescribe principled default angles — any bounded choice\n",
        "# works as a warm start for problems this small. beta and gamma are\n",
        "# periodic (beta in [0, pi] and gamma in [0, 2*pi] modulo the underlying\n",
        "# Pauli-rotation periods), and pi/2 and pi are just midpoints of those\n",
        "# ranges. For harder problems you would typically warm start from known\n",
        "# good angles or transfer parameters from smaller instances.\n",
        "initial_gamma = np.pi\n",
        "initial_beta = np.pi / 2\n",
        "init_params = [initial_beta, initial_beta, initial_gamma, initial_gamma]"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 8,
      "id": "3e64a862",
      "metadata": {},
      "outputs": [],
      "source": [
        "def cost_func_estimator(params, ansatz, hamiltonian, estimator):\n",
        "    # transform the observable defined on virtual qubits to\n",
        "    # an observable defined on all physical qubits\n",
        "    isa_hamiltonian = hamiltonian.apply_layout(ansatz.layout)\n",
        "\n",
        "    pub = (ansatz, isa_hamiltonian, params)\n",
        "    job = estimator.run([pub])\n",
        "\n",
        "    results = job.result()[0]\n",
        "    cost = results.data.evs\n",
        "\n",
        "    objective_func_vals.append(cost)\n",
        "\n",
        "    return cost"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 9,
      "id": "2df241a9",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            " message: Return from COBYLA because the trust region radius reaches its lower bound.\n",
            " success: True\n",
            "  status: 0\n",
            "     fun: -2.0402211719947774\n",
            "       x: [ 3.041e+00  1.212e+00  2.081e+00  4.471e+00]\n",
            "    nfev: 36\n",
            "   maxcv: 0.0\n"
          ]
        }
      ],
      "source": [
        "objective_func_vals = []  # Global variable\n",
        "with Session(backend=backend) as session:\n",
        "    # If using qiskit-ibm-runtime<0.24.0, change `mode=` to `session=`\n",
        "    estimator = Estimator(mode=session)\n",
        "    estimator.options.default_shots = 1000\n",
        "\n",
        "    # Set simple error suppression/mitigation options\n",
        "    estimator.options.dynamical_decoupling.enable = True\n",
        "    estimator.options.dynamical_decoupling.sequence_type = \"XY4\"\n",
        "    estimator.options.twirling.enable_gates = True\n",
        "    estimator.options.twirling.num_randomizations = \"auto\"\n",
        "    estimator.options.environment.job_tags = [\"TUT_QAOA\"]\n",
        "\n",
        "    result = minimize(\n",
        "        cost_func_estimator,\n",
        "        init_params,\n",
        "        args=(candidate_circuit, cost_hamiltonian, estimator),\n",
        "        method=\"COBYLA\",\n",
        "        tol=1e-2,\n",
        "    )\n",
        "    print(result)"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "01d6b81c",
      "metadata": {},
      "source": [
        "オプティマイザーは、コストを削減し、回路のより良いパラメータを見つけることができた。\n",
        "\n",
        "滑らかに下降した後、横ばいになる曲線は、収束の兆候である。 変動が激しく、単調増加・単調減少しない曲線は、通常、上流工程で何らかの対策が必要であることを示しています。一般的な原因としては、評価ごとの試行回数が少なすぎる（推定器の分散が大きい）、初期パラメータが不適切、あるいは回路の深さがハードウェアノイズの影響を強く受けていることが挙げられます。 COBYLAは微分不要であり、中程度のノイズに対しては比較的頑健ですが、ノイズが1ステップあたりの実際のコスト改善効果を上回ると、その線形近似モデルは真の降下とランダムな揺らぎを区別できなくなり、最適化アルゴリズムが迷走してしまいます。\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 10,
      "id": "e14ecc92",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<Image src=\"/docs/images/tutorials/quantum-approximate-optimization-algorithm/extracted-outputs/e14ecc92-0.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "metadata": {},
          "output_type": "display_data"
        }
      ],
      "source": [
        "plt.figure(figsize=(12, 6))\n",
        "plt.plot(objective_func_vals)\n",
        "plt.xlabel(\"Iteration\")\n",
        "plt.ylabel(\"Cost\")\n",
        "plt.show()"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "1f9c8a9c",
      "metadata": {},
      "source": [
        "最適化されたパラメータを設定し、Samplerプリミティブを使用して最終的な分布をサンプリングします。\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 11,
      "id": "2989e76e-4296-4dd8-b065-2b8fced064cf",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<Image src=\"/docs/images/tutorials/quantum-approximate-optimization-algorithm/extracted-outputs/2989e76e-4296-4dd8-b065-2b8fced064cf-0.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "execution_count": 11,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "optimized_circuit = candidate_circuit.assign_parameters(result.x)\n",
        "optimized_circuit.draw(\"mpl\", fold=False, idle_wires=False)"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 12,
      "id": "d8f0e302",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "{18: 0.039, 5: 0.0665, 20: 0.0973, 29: 0.0063, 9: 0.0899, 13: 0.0379, 2: 0.0047, 1: 0.0153, 11: 0.0932, 14: 0.0327, 12: 0.0314, 25: 0.0193, 21: 0.0398, 6: 0.0224, 4: 0.0197, 10: 0.0387, 3: 0.0181, 26: 0.07, 17: 0.0327, 19: 0.0332, 22: 0.0914, 24: 0.007, 0: 0.0033, 8: 0.0066, 30: 0.0158, 28: 0.0169, 27: 0.0222, 16: 0.0073, 7: 0.0057, 23: 0.0062, 15: 0.0054, 31: 0.0041}\n"
          ]
        }
      ],
      "source": [
        "# If using qiskit-ibm-runtime<0.24.0, change `mode=` to `backend=`\n",
        "sampler = Sampler(mode=backend)\n",
        "sampler.options.default_shots = 10000\n",
        "\n",
        "# Set simple error suppression/mitigation options\n",
        "sampler.options.dynamical_decoupling.enable = True\n",
        "sampler.options.dynamical_decoupling.sequence_type = \"XY4\"\n",
        "sampler.options.twirling.enable_gates = True\n",
        "sampler.options.twirling.num_randomizations = \"auto\"\n",
        "\n",
        "sampler.options.environment.job_tags = [\"TUT_QAOA\"]\n",
        "\n",
        "pub = (optimized_circuit,)\n",
        "job = sampler.run([pub], shots=int(1e4))\n",
        "counts_int = job.result()[0].data.meas.get_int_counts()\n",
        "counts_bin = job.result()[0].data.meas.get_counts()\n",
        "shots = sum(counts_int.values())\n",
        "final_distribution_int = {key: val / shots for key, val in counts_int.items()}\n",
        "final_distribution_bin = {key: val / shots for key, val in counts_bin.items()}\n",
        "print(final_distribution_int)"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "dace5fed-5555-4f1c-9109-7f5a31832d04",
      "metadata": {},
      "source": [
        "<span id=\"step-4-post-process-and-return-result-in-desired-classical-format\" />\n",
        "\n",
        "### ステップ4：後処理を行い、結果を希望の古典形式で返す\n",
        "\n",
        "サンプリングされた分布から、最も確率の高いビット列を抽出する。 これは、QAOAが見つけた中で最も優れたカットです。\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 13,
      "id": "d4f7fc70-883f-4b6b-8e92-2fc4afbbea46",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "Result bitstring: [0, 0, 1, 0, 1]\n"
          ]
        }
      ],
      "source": [
        "# auxiliary functions to sample most likely bitstring\n",
        "def to_bitstring(integer, num_bits):\n",
        "    result = np.binary_repr(integer, width=num_bits)\n",
        "    return [int(digit) for digit in result]\n",
        "\n",
        "\n",
        "keys = list(final_distribution_int.keys())\n",
        "values = list(final_distribution_int.values())\n",
        "most_likely = keys[np.argmax(np.abs(values))]\n",
        "most_likely_bitstring = to_bitstring(most_likely, len(graph))\n",
        "most_likely_bitstring.reverse()\n",
        "\n",
        "print(\"Result bitstring:\", most_likely_bitstring)"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 14,
      "id": "650875e9-adbc-43bd-9505-556be2566278",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<Image src=\"/docs/images/tutorials/quantum-approximate-optimization-algorithm/extracted-outputs/650875e9-adbc-43bd-9505-556be2566278-0.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "metadata": {},
          "output_type": "display_data"
        }
      ],
      "source": [
        "plt.rcParams.update({\"font.size\": 10})\n",
        "final_bits = final_distribution_bin\n",
        "values = np.abs(list(final_bits.values()))\n",
        "top_4_values = sorted(values, reverse=True)[:4]\n",
        "positions = []\n",
        "for value in top_4_values:\n",
        "    positions.append(np.where(values == value)[0])\n",
        "fig = plt.figure(figsize=(11, 6))\n",
        "ax = fig.add_subplot(1, 1, 1)\n",
        "plt.xticks(rotation=45)\n",
        "plt.title(\"Result Distribution\")\n",
        "plt.xlabel(\"Bitstrings (reversed)\")\n",
        "plt.ylabel(\"Probability\")\n",
        "ax.bar(list(final_bits.keys()), list(final_bits.values()), color=\"tab:grey\")\n",
        "for p in positions:\n",
        "    ax.get_children()[int(p[0])].set_color(\"tab:purple\")\n",
        "plt.show()"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "207443f2-34d9-424a-a6d7-44707ef1488b",
      "metadata": {},
      "source": [
        "<span id=\"visualize-best-cut\" />\n",
        "\n",
        "#### 最適なカットを可視化する\n",
        "\n",
        "最適なビット列から、元のグラフ上のこの切り取り部分を可視化することができます。\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 15,
      "id": "33135970-8bc4-4fb2-ab87-08726a432ce4",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<Image src=\"/docs/images/tutorials/quantum-approximate-optimization-algorithm/extracted-outputs/33135970-8bc4-4fb2-ab87-08726a432ce4-0.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "metadata": {},
          "output_type": "display_data"
        }
      ],
      "source": [
        "# auxiliary function to plot graphs\n",
        "def plot_result(G, x):\n",
        "    colors = [\"tab:grey\" if i == 0 else \"tab:purple\" for i in x]\n",
        "    pos, _default_axes = rx.spring_layout(G), plt.axes(frameon=True)\n",
        "    rx.visualization.mpl_draw(\n",
        "        G, node_color=colors, node_size=100, alpha=0.8, pos=pos\n",
        "    )\n",
        "\n",
        "\n",
        "plot_result(graph, most_likely_bitstring)"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "2119575f-f3cf-45bc-ae2b-93c046391eb6",
      "metadata": {},
      "source": [
        "それでは、カットの値を計算しましょう：\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 16,
      "id": "2f6a73c4-f5ae-4647-a0dd-d77a13f66388",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "The value of the cut is: 5\n"
          ]
        }
      ],
      "source": [
        "def evaluate_sample(x: Sequence[int], graph: rx.PyGraph) -> float:\n",
        "    assert len(x) == len(\n",
        "        list(graph.nodes())\n",
        "    ), \"The length of x must coincide with the number of nodes in the graph.\"\n",
        "    return sum(\n",
        "        x[u] * (1 - x[v]) + x[v] * (1 - x[u])\n",
        "        for u, v in list(graph.edge_list())\n",
        "    )\n",
        "\n",
        "\n",
        "cut_value = evaluate_sample(most_likely_bitstring, graph)\n",
        "print(\"The value of the cut is:\", cut_value)"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "76a7241e",
      "metadata": {},
      "source": [
        "これほど小さなグラフの場合、真の最適解は総当たり法で容易に見つかるため、QAOAの結果と正確な答えを比較することで、結果を確認することができます。\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 17,
      "id": "0a3b5267",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "Classical optimum (brute force): 5\n",
            "QAOA cut value:                  5\n"
          ]
        }
      ],
      "source": [
        "# Classical baseline: enumerate all 2**n_small bitstrings and take the best cut.\n",
        "def brute_force_max_cut(graph: rx.PyGraph) -> tuple[int, list[int]]:\n",
        "    n = len(list(graph.nodes()))\n",
        "    best_cut = -1\n",
        "    best_x: list[int] = []\n",
        "    for i in range(2**n):\n",
        "        x = [(i >> k) & 1 for k in range(n)]\n",
        "        cut = evaluate_sample(x, graph)\n",
        "        if cut > best_cut:\n",
        "            best_cut = int(cut)\n",
        "            best_x = x\n",
        "    return best_cut, best_x\n",
        "\n",
        "\n",
        "classical_best, classical_x = brute_force_max_cut(graph)\n",
        "print(f\"Classical optimum (brute force): {classical_best}\")\n",
        "print(f\"QAOA cut value:                  {cut_value}\")"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "large-scale-header",
      "metadata": {},
      "source": [
        "<span id=\"large-scale-hardware-example\" />\n",
        "\n",
        "## 大規模なハードウェアの例\n",
        "\n",
        "IBM Quantum Platform では、100キュービットを超える多くのデバイスをご利用いただけます。 100ノードの重み付きグラフ上で最大カット問題を解く対象として、いずれか1つを選択してください。 これは「大規模」な問題です。 このワークフローは、上記と同じ手順に従いますが、対象となるグラフははるかに大規模なものとなります。\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "large-scale-steps-intro",
      "metadata": {},
      "source": [
        "<span id=\"end-to-end-workflow-at-utility-scale\" />\n",
        "\n",
        "### ユーティリティ規模でのエンドツーエンドのワークフロー\n",
        "\n",
        "以下に、100ノードのグラフに対して適用した4つの手順すべてを示します。 構成は小規模なチュートリアルと同じです。つまり、マップ作成、トランスパイル、実行、後処理という流れですが、今回はより大規模な問題を取り上げ、分かりやすくするために以下の4つのセルに分けています。\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "large-scale-helpers",
      "metadata": {},
      "outputs": [],
      "source": [
        "# Precomputed parity lookup table: _PARITY[b] = +1 if popcount(b) is even, else -1.\n",
        "# We use this to vectorize expectation-value evaluation across all Pauli terms.\n",
        "_PARITY = np.array(\n",
        "    [-1 if bin(i).count(\"1\") % 2 else 1 for i in range(256)],\n",
        "    dtype=np.complex128,\n",
        ")\n",
        "\n",
        "\n",
        "def evaluate_sparse_pauli(state: int, observable: SparsePauliOp) -> complex:\n",
        "    \"\"\"Expectation value of a SparsePauliOp on a single computational-basis state.\n",
        "\n",
        "    For a Z-only observable (which QAOA cost Hamiltonians are, after the\n",
        "    QUBO-to-Hamiltonian mapping), the eigenvalue of each Pauli term on a\n",
        "    computational-basis state is simply (-1)**popcount(z_mask AND state),\n",
        "    i.e., the parity of the bitwise-AND of the term's Z-support and the\n",
        "    measured bitstring.\n",
        "\n",
        "    This routine packs the Z-support of every Pauli term into bytes, ANDs\n",
        "    them against the measured state in a single vectorized op, and looks up\n",
        "    the parity in _PARITY. For a 100-qubit / ~hundreds-of-terms Hamiltonian\n",
        "    over 10_000 samples, this is dramatically faster than calling\n",
        "    SparsePauliOp.expectation_value per sample.\n",
        "    \"\"\"\n",
        "    packed_uint8 = np.packbits(observable.paulis.z, axis=1, bitorder=\"little\")\n",
        "    state_bytes = np.frombuffer(\n",
        "        state.to_bytes(packed_uint8.shape[1], \"little\"), dtype=np.uint8\n",
        "    )\n",
        "    reduced = np.bitwise_xor.reduce(packed_uint8 & state_bytes, axis=1)\n",
        "    return np.sum(observable.coeffs * _PARITY[reduced])\n",
        "\n",
        "\n",
        "def best_solution(samples, hamiltonian):\n",
        "    \"\"\"Return the sampled bitstring (as int) with the lowest Hamiltonian cost.\"\"\"\n",
        "    min_cost = float(\"inf\")\n",
        "    min_sol = None\n",
        "    for bit_str in samples.keys():\n",
        "        candidate_sol = int(bit_str)\n",
        "        fval = evaluate_sparse_pauli(candidate_sol, hamiltonian).real\n",
        "        if fval <= min_cost:\n",
        "            min_cost = fval\n",
        "            min_sol = candidate_sol\n",
        "    return min_sol\n",
        "\n",
        "\n",
        "def _plot_cdf(objective_values: dict, ax, color):\n",
        "    x_vals = sorted(objective_values.keys(), reverse=True)\n",
        "    y_vals = np.cumsum([objective_values[x] for x in x_vals])\n",
        "    ax.plot(x_vals, y_vals, color=color)\n",
        "\n",
        "\n",
        "def plot_cdf(dist, ax, title):\n",
        "    _plot_cdf(dist, ax, \"C1\")\n",
        "    ax.vlines(min(list(dist.keys())), 0, 1, \"C1\", linestyle=\"--\")\n",
        "    ax.set_title(title)\n",
        "    ax.set_xlabel(\"Objective function value\")\n",
        "    ax.set_ylabel(\"Cumulative distribution function\")\n",
        "    ax.grid(alpha=0.3)\n",
        "\n",
        "\n",
        "def samples_to_objective_values(samples, hamiltonian):\n",
        "    \"\"\"Convert the samples to values of the objective function.\"\"\"\n",
        "    objective_values = defaultdict(float)\n",
        "    for bit_str, prob in samples.items():\n",
        "        candidate_sol = int(bit_str)\n",
        "        fval = evaluate_sparse_pauli(candidate_sol, hamiltonian).real\n",
        "        objective_values[fval] += prob\n",
        "    return objective_values"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "4dc0c8ff",
      "metadata": {},
      "source": [
        "**ステップ1** ：グラフ、コストハミルトニアン、および仮定を構築する。\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 19,
      "id": "94190344",
      "metadata": {},
      "outputs": [],
      "source": [
        "# Step 1: build the 100-node graph, cost Hamiltonian, and QAOA ansatz.\n",
        "n_large = 100\n",
        "graph_100 = rx.PyGraph()\n",
        "graph_100.add_nodes_from(np.arange(0, n_large, 1))\n",
        "elist = []\n",
        "for edge in backend.coupling_map:\n",
        "    if edge[0] < n_large and edge[1] < n_large:\n",
        "        elist.append((edge[0], edge[1], 1.0))\n",
        "graph_100.add_edges_from(elist)\n",
        "\n",
        "max_cut_paulis_100 = build_max_cut_paulis(graph_100)\n",
        "cost_hamiltonian_100 = SparsePauliOp.from_sparse_list(\n",
        "    max_cut_paulis_100, n_large\n",
        ")\n",
        "\n",
        "circuit_100 = QAOAAnsatz(cost_operator=cost_hamiltonian_100, reps=1)\n",
        "circuit_100.measure_all()"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "c91f0c16",
      "metadata": {},
      "source": [
        "**ステップ 2** : 選択したハードウェアバックエンド向けにトランスパイルします。\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 20,
      "id": "2b59da0e",
      "metadata": {},
      "outputs": [],
      "source": [
        "# Step 2: transpile for hardware.\n",
        "pm = generate_preset_pass_manager(optimization_level=3, backend=backend)\n",
        "candidate_circuit_100 = pm.run(circuit_100)"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "eb2c4d66",
      "metadata": {},
      "source": [
        "**ステップ3** ：セッション内でQAOA最適化ループを実行し、その後サンプリングを行う。\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 21,
      "id": "e5aceab3",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            " message: Return from COBYLA because the trust region radius reaches its lower bound.\n",
            " success: True\n",
            "  status: 0\n",
            "     fun: -17.172689238986344\n",
            "       x: [ 2.574e+00  4.166e+00]\n",
            "    nfev: 28\n",
            "   maxcv: 0.0\n"
          ]
        }
      ],
      "source": [
        "# Step 3: run the QAOA optimization loop on the device, then sample the\n",
        "# final distribution with the optimized parameters.\n",
        "initial_gamma = np.pi\n",
        "initial_beta = np.pi / 2\n",
        "init_params = [initial_beta, initial_gamma]\n",
        "\n",
        "objective_func_vals = []  # Global variable\n",
        "with Session(backend=backend) as session:\n",
        "    estimator = Estimator(mode=session)\n",
        "    estimator.options.default_shots = 1000\n",
        "\n",
        "    # Set simple error suppression/mitigation options\n",
        "    estimator.options.dynamical_decoupling.enable = True\n",
        "    estimator.options.dynamical_decoupling.sequence_type = \"XY4\"\n",
        "    estimator.options.twirling.enable_gates = True\n",
        "    estimator.options.twirling.num_randomizations = \"auto\"\n",
        "    estimator.options.environment.job_tags = [\"TUT_QAOA\"]\n",
        "\n",
        "    result = minimize(\n",
        "        cost_func_estimator,\n",
        "        init_params,\n",
        "        args=(candidate_circuit_100, cost_hamiltonian_100, estimator),\n",
        "        method=\"COBYLA\",\n",
        "    )\n",
        "    print(result)\n",
        "\n",
        "# Assign optimal parameters and sample the final distribution.\n",
        "optimized_circuit_100 = candidate_circuit_100.assign_parameters(result.x)\n",
        "\n",
        "sampler = Sampler(mode=backend)\n",
        "sampler.options.default_shots = 10000\n",
        "\n",
        "# Set simple error suppression/mitigation options\n",
        "sampler.options.dynamical_decoupling.enable = True\n",
        "sampler.options.dynamical_decoupling.sequence_type = \"XY4\"\n",
        "sampler.options.twirling.enable_gates = True\n",
        "sampler.options.twirling.num_randomizations = \"auto\"\n",
        "\n",
        "# Add a unique tag to the job execution\n",
        "sampler.options.environment.job_tags = [\"TUT_QAOA\"]\n",
        "\n",
        "pub = (optimized_circuit_100,)\n",
        "job = sampler.run([pub], shots=int(1e4))\n",
        "\n",
        "counts_int = job.result()[0].data.meas.get_int_counts()\n",
        "shots = sum(counts_int.values())\n",
        "final_distribution_100_int = {\n",
        "    key: val / shots for key, val in counts_int.items()\n",
        "}"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "7f0c5980",
      "metadata": {},
      "source": [
        "**ステップ4** ：サンプリングされた分布を後処理し、最適なカットを抽出する。\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 22,
      "id": "010571f7",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "Result bitstring: [1, 1, 0, 1, 1, 0, 1, 1, 1, 0, 1, 0, 1, 1, 1, 0, 1, 1, 1, 1, 0, 0, 1, 0, 0, 1, 1, 0, 1, 0, 1, 0, 1, 1, 0, 1, 1, 0, 0, 0, 0, 0, 1, 1, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 1, 0, 0, 1, 0, 1, 1, 1, 1, 0, 1, 0, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0]\n",
            "The value of the cut is: 156\n"
          ]
        }
      ],
      "source": [
        "# Step 4: find the best-cost sample and evaluate its cut value.\n",
        "best_sol_100 = best_solution(final_distribution_100_int, cost_hamiltonian_100)\n",
        "best_sol_bitstring_100 = to_bitstring(int(best_sol_100), len(graph_100))\n",
        "best_sol_bitstring_100.reverse()\n",
        "\n",
        "print(\"Result bitstring:\", best_sol_bitstring_100)\n",
        "\n",
        "cut_value_100 = evaluate_sample(best_sol_bitstring_100, graph_100)\n",
        "print(\"The value of the cut is:\", cut_value_100)"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "large-scale-convergence-md",
      "metadata": {},
      "source": [
        "最適化ループで最小化されるコストが収束したことを確認し、結果を可視化する。\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 23,
      "id": "large-scale-viz",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<Image src=\"/docs/images/tutorials/quantum-approximate-optimization-algorithm/extracted-outputs/large-scale-viz-0.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "metadata": {},
          "output_type": "display_data"
        },
        {
          "data": {
            "text/plain": [
              "<Image src=\"/docs/images/tutorials/quantum-approximate-optimization-algorithm/extracted-outputs/large-scale-viz-1.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "metadata": {},
          "output_type": "display_data"
        },
        {
          "data": {
            "text/plain": [
              "<Image src=\"/docs/images/tutorials/quantum-approximate-optimization-algorithm/extracted-outputs/large-scale-viz-2.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "metadata": {},
          "output_type": "display_data"
        }
      ],
      "source": [
        "# Plot convergence\n",
        "plt.figure(figsize=(12, 6))\n",
        "plt.plot(objective_func_vals)\n",
        "plt.xlabel(\"Iteration\")\n",
        "plt.ylabel(\"Cost\")\n",
        "plt.show()\n",
        "\n",
        "# Visualize the cut\n",
        "plot_result(graph_100, best_sol_bitstring_100)\n",
        "\n",
        "# Plot cumulative distribution function\n",
        "result_dist = samples_to_objective_values(\n",
        "    final_distribution_100_int, cost_hamiltonian_100\n",
        ")\n",
        "fig, ax = plt.subplots(1, 1, figsize=(8, 6))\n",
        "plot_cdf(result_dist, ax, backend.name)"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "69ebc85b-6a29-4671-8d16-1ac97f089607",
      "metadata": {},
      "source": [
        "<span id=\"next-steps\" />\n",
        "\n",
        "## 次のステップ\n",
        "\n",
        "この作品が興味深かった方は、以下の資料もご参照ください：\n",
        "\n",
        "<Admonition type=\"tip\" title=\"推奨事項\">\n",
        "  * [QAOAの高度な技術](/docs/tutorials/advanced-techniques-for-qaoa) — QAOAの性能を向上させるための高度な戦略を探る\n",
        "  * [多目的最適化チャレンジ](https://github.com/qiskit-community/qdc-challenges-2025/blob/main/challenges/Track_B/qmoo/qmoo_qdc25.ipynb) — 多目的量子最適化をテーマにしたこのコミュニティチャレンジで、あなたの実力を試してみましょう\n",
        "  * 回路最適化の微調整に関する[トランスパイレーションのドキュメント](/docs/guides/transpile)\n",
        "  * ハードウェア性能向上のための[エラー抑制と軽減](/docs/guides/error-mitigation-and-suppression-techniques)\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": 1320
  },
  "nbformat": 4,
  "nbformat_minor": 5
}