{
  "cells": [
    {
      "cell_type": "markdown",
      "id": "b6d1e3ec",
      "metadata": {},
      "source": [
        "---\n",
        "title: \"Q-CTRLの最適化ソルバーを使用した高次バイナリー最適化\"\n",
        "description: \"Q-CTRL Fire OpalのQiskit関数であるOptimization Solverを使用して、ユーティリティ規模の量子最適化問題を解く\"\n",
        "---\n",
        "\n",
        "{/* cspell:ignore nrows ncols lambdify ILOG histtype stepfilled */}\n",
        "\n",
        "<span id=\"higher-order-binary-optimization-with-q-ctrls-optimization-solver\" />\n",
        "\n",
        "# Q-CTRLの最適化ソルバーを使用した高次バイナリー最適化\n",
        "\n"
      ]
    },
    {
      "attachments": {},
      "cell_type": "markdown",
      "id": "a6f69b77",
      "metadata": {},
      "source": [
        "<Admonition type=\"note\" title=\"注\">\n",
        "  Qiskit 関数は、 IBM Quantum® Premium Plan、Flex Plan、およびオンプレム ( IBM Quantum Platform API 経由) Plan ユーザーだけが利用できる実験的な機能です。 これらはプレビューリリースであり、変更される可能性がある。\n",
        "</Admonition>\n",
        "\n",
        "*使用時間の見積もり：Heron r2 プロセッサーで24分。 (注：これはあくまでも目安です。 ランタイムは異なるかもしれない)。*\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "8bf80006",
      "metadata": {},
      "source": [
        "<span id=\"background\" />\n",
        "\n",
        "## 背景\n",
        "\n",
        "このチュートリアルでは、 [Q-CTRL Fire OpalのQiskit関数であるOptimization Solverを](/docs/guides/q-ctrl-optimization-solver)使用して、高次バイナリ最適化（HOBO）問題を解く方法を説明します。 このチュートリアルで示す例は、3乗項を持つランダム結合156量子ビットのイジング模型の基底状態エネルギーを求めるためにデザインされた最適化問題です。 最適化ソルバーは、目的関数として定義できる一般的な最適化問題に使用できます。\n",
        "\n",
        "この最適化は、量子ハードウェア上で最適化問題を解くためのハードウェアを意識した実装ステップを完全に自動化し、量子実行の[パフォーマンス管理を](/docs/guides/q-ctrl-performance-management)活用することで、ユーティリティ・スケールで正確な解を実現する。 Optimization Solverのワークフローとベンチマーク結果の詳細については、 [発表された原稿を](https://arxiv.org/abs/2406.01743)参照してください。\n",
        "\n",
        "このチュートリアルでは、以下の手順を説明します：\n",
        "\n",
        "1. 問題を目的関数として定義する\n",
        "2. Fire Opal最適化ソルバーを使用してハイブリッドアルゴリズムを実行します\n",
        "3. 結果を評価する\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "55b94021",
      "metadata": {},
      "source": [
        "<span id=\"requirements\" />\n",
        "\n",
        "## 要件\n",
        "\n",
        "このチュートリアルを始める前に、以下のものがインストールされていることを確認してください：\n",
        "\n",
        "* Qiskitファンクション (`pip install qiskit-ibm-catalog`)\n",
        "* SymPy (`pip install sympy`)\n",
        "\n",
        "また、最適化ソルバー機能にアクセスする必要がある。 [フォームにご記入の上](/functions?id=q-ctrl-optimization-solver)、アクセスをリクエストしてください。\n",
        "\n"
      ]
    },
    {
      "attachments": {},
      "cell_type": "markdown",
      "id": "7db2e559",
      "metadata": {},
      "source": [
        "<span id=\"setup\" />\n",
        "\n",
        "## セットアップ\n",
        "\n",
        "まず、必要なパッケージとツールをインポートする。\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 1,
      "id": "c262cb27",
      "metadata": {},
      "outputs": [],
      "source": [
        "# Qiskit Functions Catalog\n",
        "from qiskit_ibm_catalog import QiskitFunctionsCatalog\n",
        "\n",
        "# SymPy tools for constructing objective function\n",
        "from sympy import Poly\n",
        "from sympy import symbols, srepr\n",
        "\n",
        "# Tools for plotting and evaluating results\n",
        "import numpy as np\n",
        "import matplotlib.pyplot as plt\n",
        "from sympy import lambdify"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "df157bba",
      "metadata": {},
      "source": [
        "[IBM Quantum Platform](/) の認証情報を設定してください。この認証情報は、このチュートリアルを通じて、 IBM Quantum Compute Serviceおよび Qiskit Functions への認証に使用されます。\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "b92bd67d",
      "metadata": {},
      "outputs": [],
      "source": [
        "# Credentials\n",
        "\n",
        "# For `token`, use the 44-character API_KEY you created\n",
        "# and saved from the IBM Quantum Platform Home dashboard\n",
        "token = \"<YOUR-API_KEY>\"\n",
        "instance = \"<YOUR_CRN>\""
      ]
    },
    {
      "attachments": {},
      "cell_type": "markdown",
      "id": "988ee237",
      "metadata": {},
      "source": [
        "<span id=\"step-1-define-the-problem-as-an-objective-function\" />\n",
        "\n",
        "## ステップ1：問題を目的関数として定義する\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "6c9bffae",
      "metadata": {},
      "source": [
        "最適化ソルバーは、目的関数またはグラフを入力として受け付ける。 このチュートリアルでは、イジングスピングラス最小化問題を目的関数として定義し、 IBM® デバイスのヘビーヘキソトポロジー用に調整した。\n",
        "\n",
        "この目的関数は3次、2次、1次の項を含んでいるため、従来の2次制約なし2値最適化（QUBO）問題よりも解法がかなり複雑であることが知られているHOBO問題のクラスに分類される。\n",
        "\n",
        "最適化ソルバーによる問題定義と過去の結果の詳細については、 [この技術原稿を](https://arxiv.org/abs/2406.01743)参照されたい。 この問題は、もともと[ロスアラモス国立研究所が発表した論文の](https://arxiv.org/abs/2312.00997)一部として定義・評価されたもので、156量子ビットの IBM Quantum Heronプロセッサのデバイス幅をフルに活用するために適応された。\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 42,
      "id": "0ad66539",
      "metadata": {},
      "outputs": [],
      "source": [
        "qubit_count = 156\n",
        "\n",
        "# Create symbolic variables to represent qubits\n",
        "x = symbols([f\"x[{i}]\" for i in range(qubit_count)])\n",
        "\n",
        "# # Define a polynomial representing a spin glass model\n",
        "spin_glass_poly = Poly(\n",
        "    -4 * x[0] * x[1]\n",
        "    - 8 * x[1] * x[2] * x[3]\n",
        "    + 8 * x[1] * x[2]\n",
        "    + 4 * x[1] * x[3]\n",
        "    - 4 * x[2]\n",
        "    + 8 * x[3] * x[4] * x[5]\n",
        "    - 4 * x[3] * x[5]\n",
        "    - 8 * x[3] * x[16] * x[23]\n",
        "    + 4 * x[3] * x[23]\n",
        "    - 2 * x[3]\n",
        "    - 4 * x[4]\n",
        "    - 8 * x[5] * x[6] * x[7]\n",
        "    + 8 * x[5] * x[6]\n",
        "    + 4 * x[5] * x[7]\n",
        "    - 2 * x[5]\n",
        "    + 8 * x[6] * x[7]\n",
        "    - 4 * x[6]\n",
        "    - 8 * x[7] * x[8] * x[9]\n",
        "    + 4 * x[7] * x[9]\n",
        "    - 8 * x[7] * x[17] * x[27]\n",
        "    + 4 * x[7] * x[27]\n",
        "    - 6 * x[7]\n",
        "    + 8 * x[8] * x[9]\n",
        "    + 8 * x[9] * x[10] * x[11]\n",
        "    - 4 * x[9] * x[11]\n",
        "    - 2 * x[9]\n",
        "    - 8 * x[10] * x[11]\n",
        "    + 4 * x[10]\n",
        "    - 8 * x[11] * x[12] * x[13]\n",
        "    + 4 * x[11] * x[13]\n",
        "    - 8 * x[11] * x[18] * x[31]\n",
        "    + 8 * x[11] * x[18]\n",
        "    + 4 * x[11] * x[31]\n",
        "    - 2 * x[11]\n",
        "    + 8 * x[12] * x[13]\n",
        "    + 8 * x[13] * x[14] * x[15]\n",
        "    - 4 * x[13] * x[15]\n",
        "    - 2 * x[13]\n",
        "    - 8 * x[14] * x[15]\n",
        "    + 4 * x[14]\n",
        "    - 8 * x[15] * x[19] * x[35]\n",
        "    + 8 * x[15] * x[19]\n",
        "    + 4 * x[15] * x[35]\n",
        "    - 2 * x[15]\n",
        "    + 8 * x[16] * x[23]\n",
        "    + 8 * x[17] * x[27]\n",
        "    - 4 * x[17]\n",
        "    + 8 * x[18] * x[31]\n",
        "    - 8 * x[18]\n",
        "    + 8 * x[19] * x[35]\n",
        "    - 8 * x[19]\n",
        "    + 4 * x[20] * x[21]\n",
        "    - 4 * x[20]\n",
        "    - 8 * x[21] * x[22] * x[23]\n",
        "    + 8 * x[21] * x[22]\n",
        "    + 4 * x[21] * x[23]\n",
        "    - 8 * x[21] * x[36] * x[41]\n",
        "    + 4 * x[21] * x[41]\n",
        "    - 4 * x[21]\n",
        "    + 8 * x[22] * x[23]\n",
        "    - 8 * x[22]\n",
        "    + 8 * x[23] * x[24] * x[25]\n",
        "    - 4 * x[23] * x[25]\n",
        "    - 10 * x[23]\n",
        "    - 8 * x[24] * x[25]\n",
        "    + 8 * x[25] * x[26] * x[27]\n",
        "    - 8 * x[25] * x[26]\n",
        "    - 4 * x[25] * x[27]\n",
        "    + 8 * x[25] * x[37] * x[45]\n",
        "    - 8 * x[25] * x[37]\n",
        "    - 4 * x[25] * x[45]\n",
        "    + 14 * x[25]\n",
        "    - 8 * x[26] * x[27]\n",
        "    + 4 * x[26]\n",
        "    + 8 * x[27] * x[28] * x[29]\n",
        "    - 4 * x[27] * x[29]\n",
        "    - 2 * x[27]\n",
        "    - 8 * x[28] * x[29]\n",
        "    - 8 * x[29] * x[30] * x[31]\n",
        "    + 4 * x[29] * x[31]\n",
        "    + 8 * x[29] * x[38] * x[49]\n",
        "    - 8 * x[29] * x[38]\n",
        "    - 4 * x[29] * x[49]\n",
        "    + 6 * x[29]\n",
        "    + 8 * x[30] * x[31]\n",
        "    - 4 * x[30]\n",
        "    - 8 * x[31] * x[32] * x[33]\n",
        "    + 4 * x[31] * x[33]\n",
        "    - 6 * x[31]\n",
        "    + 8 * x[33] * x[34] * x[35]\n",
        "    - 4 * x[33] * x[35]\n",
        "    - 8 * x[33] * x[39] * x[53]\n",
        "    + 8 * x[33] * x[39]\n",
        "    + 4 * x[33] * x[53]\n",
        "    - 6 * x[33]\n",
        "    - 8 * x[34] * x[35]\n",
        "    + 2 * x[35]\n",
        "    + 8 * x[36] * x[41]\n",
        "    - 8 * x[37] * x[45]\n",
        "    + 4 * x[37]\n",
        "    - 8 * x[38] * x[49]\n",
        "    + 4 * x[38]\n",
        "    + 4 * x[40] * x[41]\n",
        "    - 8 * x[41] * x[42] * x[43]\n",
        "    + 4 * x[41] * x[43]\n",
        "    - 8 * x[41]\n",
        "    + 8 * x[42] * x[43]\n",
        "    - 4 * x[42]\n",
        "    - 8 * x[43] * x[44] * x[45]\n",
        "    + 8 * x[43] * x[44]\n",
        "    + 4 * x[43] * x[45]\n",
        "    - 8 * x[43] * x[56] * x[63]\n",
        "    + 4 * x[43] * x[63]\n",
        "    - 6 * x[43]\n",
        "    - 4 * x[44]\n",
        "    - 8 * x[45] * x[46] * x[47]\n",
        "    + 4 * x[45] * x[47]\n",
        "    + 2 * x[45]\n",
        "    + 4 * x[46]\n",
        "    - 8 * x[47] * x[48] * x[49]\n",
        "    + 8 * x[47] * x[48]\n",
        "    + 4 * x[47] * x[49]\n",
        "    - 8 * x[47] * x[57] * x[67]\n",
        "    + 4 * x[47] * x[67]\n",
        "    - 2 * x[47]\n",
        "    - 4 * x[48]\n",
        "    - 8 * x[49] * x[50] * x[51]\n",
        "    + 8 * x[49] * x[50]\n",
        "    + 4 * x[49] * x[51]\n",
        "    - 2 * x[49]\n",
        "    + 8 * x[50] * x[51]\n",
        "    - 8 * x[50]\n",
        "    - 8 * x[51] * x[52] * x[53]\n",
        "    + 8 * x[51] * x[52]\n",
        "    + 4 * x[51] * x[53]\n",
        "    - 8 * x[51] * x[58] * x[71]\n",
        "    + 4 * x[51] * x[71]\n",
        "    - 6 * x[51]\n",
        "    + 8 * x[52] * x[53]\n",
        "    - 8 * x[52]\n",
        "    + 8 * x[53] * x[54] * x[55]\n",
        "    - 8 * x[53] * x[54]\n",
        "    - 4 * x[53] * x[55]\n",
        "    - 2 * x[53]\n",
        "    + 4 * x[54]\n",
        "    - 8 * x[55] * x[59] * x[75]\n",
        "    + 4 * x[55] * x[75]\n",
        "    - 2 * x[55]\n",
        "    + 8 * x[56] * x[63]\n",
        "    + 8 * x[57] * x[67]\n",
        "    - 4 * x[57]\n",
        "    + 8 * x[58] * x[71]\n",
        "    + 8 * x[59] * x[75]\n",
        "    - 4 * x[59]\n",
        "    + 4 * x[60] * x[61]\n",
        "    + 8 * x[61] * x[62] * x[63]\n",
        "    - 4 * x[61] * x[63]\n",
        "    + 8 * x[61] * x[76] * x[81]\n",
        "    - 8 * x[61] * x[76]\n",
        "    - 4 * x[61] * x[81]\n",
        "    - 8 * x[63] * x[64] * x[65]\n",
        "    + 8 * x[63] * x[64]\n",
        "    + 4 * x[63] * x[65]\n",
        "    - 6 * x[63]\n",
        "    + 8 * x[65] * x[66] * x[67]\n",
        "    - 8 * x[65] * x[66]\n",
        "    - 4 * x[65] * x[67]\n",
        "    - 8 * x[65] * x[77] * x[85]\n",
        "    + 4 * x[65] * x[85]\n",
        "    + 2 * x[65]\n",
        "    + 4 * x[66]\n",
        "    - 8 * x[67] * x[68] * x[69]\n",
        "    + 8 * x[67] * x[68]\n",
        "    + 4 * x[67] * x[69]\n",
        "    - 10 * x[67]\n",
        "    + 8 * x[68] * x[69]\n",
        "    - 4 * x[68]\n",
        "    + 8 * x[69] * x[70] * x[71]\n",
        "    - 4 * x[69] * x[71]\n",
        "    - 8 * x[69] * x[78] * x[89]\n",
        "    + 4 * x[69] * x[89]\n",
        "    - 6 * x[69]\n",
        "    + 8 * x[71] * x[72] * x[73]\n",
        "    - 8 * x[71] * x[72]\n",
        "    - 4 * x[71] * x[73]\n",
        "    + 2 * x[71]\n",
        "    - 8 * x[72] * x[73]\n",
        "    + 8 * x[72]\n",
        "    - 8 * x[73] * x[74] * x[75]\n",
        "    + 8 * x[73] * x[74]\n",
        "    + 4 * x[73] * x[75]\n",
        "    - 8 * x[73] * x[79] * x[93]\n",
        "    + 8 * x[73] * x[79]\n",
        "    + 4 * x[73] * x[93]\n",
        "    - 6 * x[73]\n",
        "    + 8 * x[74] * x[75]\n",
        "    - 4 * x[74]\n",
        "    - 10 * x[75]\n",
        "    + 4 * x[76]\n",
        "    + 8 * x[78] * x[89]\n",
        "    - 4 * x[78]\n",
        "    - 4 * x[79]\n",
        "    - 4 * x[80] * x[81]\n",
        "    + 4 * x[80]\n",
        "    - 8 * x[81] * x[82] * x[83]\n",
        "    + 8 * x[81] * x[82]\n",
        "    + 4 * x[81] * x[83]\n",
        "    + 8 * x[82] * x[83]\n",
        "    - 8 * x[82]\n",
        "    - 8 * x[83] * x[84] * x[85]\n",
        "    + 4 * x[83] * x[85]\n",
        "    - 8 * x[83] * x[96] * x[103]\n",
        "    + 4 * x[83] * x[103]\n",
        "    - 2 * x[83]\n",
        "    - 8 * x[85] * x[86] * x[87]\n",
        "    + 8 * x[85] * x[86]\n",
        "    + 4 * x[85] * x[87]\n",
        "    - 6 * x[85]\n",
        "    + 8 * x[86] * x[87]\n",
        "    - 4 * x[86]\n",
        "    - 8 * x[87] * x[88] * x[89]\n",
        "    + 4 * x[87] * x[89]\n",
        "    + 8 * x[87] * x[97] * x[107]\n",
        "    - 8 * x[87] * x[97]\n",
        "    - 4 * x[87] * x[107]\n",
        "    + 2 * x[87]\n",
        "    + 4 * x[88]\n",
        "    - 8 * x[89] * x[90] * x[91]\n",
        "    + 8 * x[89] * x[90]\n",
        "    + 4 * x[89] * x[91]\n",
        "    - 10 * x[89]\n",
        "    + 8 * x[90] * x[91]\n",
        "    - 8 * x[90]\n",
        "    - 8 * x[91] * x[92] * x[93]\n",
        "    + 4 * x[91] * x[93]\n",
        "    - 8 * x[91] * x[98] * x[111]\n",
        "    + 8 * x[91] * x[98]\n",
        "    + 4 * x[91] * x[111]\n",
        "    - 10 * x[91]\n",
        "    + 8 * x[92] * x[93]\n",
        "    - 4 * x[92]\n",
        "    - 8 * x[93] * x[94] * x[95]\n",
        "    + 4 * x[93] * x[95]\n",
        "    - 6 * x[93]\n",
        "    + 8 * x[95] * x[99] * x[115]\n",
        "    - 8 * x[95] * x[99]\n",
        "    - 4 * x[95] * x[115]\n",
        "    + 2 * x[95]\n",
        "    + 4 * x[96]\n",
        "    - 8 * x[97] * x[107]\n",
        "    + 4 * x[97]\n",
        "    - 4 * x[98]\n",
        "    - 8 * x[99] * x[115]\n",
        "    + 4 * x[99]\n",
        "    - 4 * x[100] * x[101]\n",
        "    + 8 * x[101] * x[102] * x[103]\n",
        "    - 8 * x[101] * x[102]\n",
        "    - 4 * x[101] * x[103]\n",
        "    - 8 * x[101] * x[116] * x[121]\n",
        "    + 8 * x[101] * x[116]\n",
        "    + 4 * x[101] * x[121]\n",
        "    + 4 * x[101]\n",
        "    - 8 * x[103] * x[104] * x[105]\n",
        "    + 4 * x[103] * x[105]\n",
        "    + 2 * x[103]\n",
        "    + 8 * x[105] * x[106] * x[107]\n",
        "    - 4 * x[105] * x[107]\n",
        "    - 8 * x[105] * x[117] * x[125]\n",
        "    + 4 * x[105] * x[125]\n",
        "    + 2 * x[105]\n",
        "    - 8 * x[106] * x[107]\n",
        "    + 4 * x[106]\n",
        "    + 8 * x[107] * x[108] * x[109]\n",
        "    - 4 * x[107] * x[109]\n",
        "    + 6 * x[107]\n",
        "    - 4 * x[108]\n",
        "    + 8 * x[109] * x[110] * x[111]\n",
        "    - 4 * x[109] * x[111]\n",
        "    - 8 * x[109] * x[118] * x[129]\n",
        "    + 4 * x[109] * x[129]\n",
        "    + 2 * x[109]\n",
        "    - 8 * x[110] * x[111]\n",
        "    + 4 * x[110]\n",
        "    - 8 * x[111] * x[112] * x[113]\n",
        "    + 8 * x[111] * x[112]\n",
        "    + 4 * x[111] * x[113]\n",
        "    + 2 * x[111]\n",
        "    + 8 * x[112] * x[113]\n",
        "    - 8 * x[112]\n",
        "    - 8 * x[113] * x[114] * x[115]\n",
        "    + 4 * x[113] * x[115]\n",
        "    - 8 * x[113] * x[119] * x[133]\n",
        "    + 4 * x[113] * x[133]\n",
        "    - 2 * x[113]\n",
        "    + 6 * x[115]\n",
        "    - 4 * x[116]\n",
        "    + 4 * x[118]\n",
        "    + 4 * x[119]\n",
        "    + 4 * x[120] * x[121]\n",
        "    - 8 * x[121] * x[122] * x[123]\n",
        "    + 4 * x[121] * x[123]\n",
        "    - 4 * x[121]\n",
        "    + 4 * x[122]\n",
        "    - 8 * x[123] * x[124] * x[125]\n",
        "    + 4 * x[123] * x[125]\n",
        "    - 8 * x[123] * x[136] * x[143]\n",
        "    + 4 * x[123] * x[143]\n",
        "    - 2 * x[123]\n",
        "    + 8 * x[124] * x[125]\n",
        "    - 4 * x[124]\n",
        "    + 8 * x[125] * x[126] * x[127]\n",
        "    - 8 * x[125] * x[126]\n",
        "    - 4 * x[125] * x[127]\n",
        "    + 2 * x[125]\n",
        "    - 8 * x[127] * x[128] * x[129]\n",
        "    + 8 * x[127] * x[128]\n",
        "    + 4 * x[127] * x[129]\n",
        "    + 8 * x[127] * x[137] * x[147]\n",
        "    - 8 * x[127] * x[137]\n",
        "    - 4 * x[127] * x[147]\n",
        "    - 2 * x[127]\n",
        "    + 8 * x[129] * x[130] * x[131]\n",
        "    - 4 * x[129] * x[131]\n",
        "    + 2 * x[129]\n",
        "    - 4 * x[130]\n",
        "    - 8 * x[131] * x[132] * x[133]\n",
        "    + 4 * x[131] * x[133]\n",
        "    - 8 * x[131] * x[138] * x[151]\n",
        "    + 4 * x[131] * x[151]\n",
        "    - 2 * x[131]\n",
        "    + 8 * x[133] * x[134] * x[135]\n",
        "    - 4 * x[133] * x[135]\n",
        "    + 2 * x[133]\n",
        "    - 8 * x[134] * x[135]\n",
        "    + 4 * x[134]\n",
        "    - 8 * x[135] * x[139] * x[155]\n",
        "    + 8 * x[135] * x[139]\n",
        "    + 4 * x[135] * x[155]\n",
        "    + 2 * x[135]\n",
        "    + 8 * x[136] * x[143]\n",
        "    - 4 * x[136]\n",
        "    + 4 * x[138]\n",
        "    + 8 * x[139] * x[155]\n",
        "    - 4 * x[139]\n",
        "    - 4 * x[140] * x[141]\n",
        "    - 8 * x[141] * x[142] * x[143]\n",
        "    + 8 * x[141] * x[142]\n",
        "    + 4 * x[141] * x[143]\n",
        "    + 8 * x[142] * x[143]\n",
        "    - 8 * x[142]\n",
        "    - 8 * x[143] * x[144] * x[145]\n",
        "    + 8 * x[143] * x[144]\n",
        "    + 4 * x[143] * x[145]\n",
        "    - 14 * x[143]\n",
        "    + 8 * x[144] * x[145]\n",
        "    - 8 * x[144]\n",
        "    - 8 * x[145] * x[146] * x[147]\n",
        "    + 8 * x[145] * x[146]\n",
        "    + 4 * x[145] * x[147]\n",
        "    - 6 * x[145]\n",
        "    + 8 * x[146] * x[147]\n",
        "    - 4 * x[146]\n",
        "    - 8 * x[147] * x[148] * x[149]\n",
        "    + 8 * x[147] * x[148]\n",
        "    + 4 * x[147] * x[149]\n",
        "    - 6 * x[147]\n",
        "    - 4 * x[148]\n",
        "    - 8 * x[149] * x[150] * x[151]\n",
        "    + 8 * x[149] * x[150]\n",
        "    + 4 * x[149] * x[151]\n",
        "    - 6 * x[149]\n",
        "    + 8 * x[151] * x[152] * x[153]\n",
        "    - 4 * x[151] * x[153]\n",
        "    + 2 * x[151]\n",
        "    + 8 * x[153] * x[154] * x[155]\n",
        "    - 8 * x[153] * x[154]\n",
        "    - 4 * x[153] * x[155]\n",
        "    + 2 * x[153]\n",
        "    - 8 * x[154] * x[155]\n",
        "    + 4 * x[154]\n",
        "    - 2 * x[155]\n",
        "    + 46,\n",
        "    x,\n",
        "    domain=\"ZZ\",\n",
        ")"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "ac6f36e3",
      "metadata": {},
      "source": [
        "<span id=\"step-2-run-the-hybrid-algorithm-using-the-fire-opal-optimization-solver\" />\n",
        "\n",
        "## ステップ2: Fire Opal Optimization Solverを使用してハイブリッドアルゴリズムを実行する\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "13ba6d0c",
      "metadata": {},
      "source": [
        "最適化ソルバーQiskit Functionを使用してアルゴリズムを実行します。 舞台裏では、最適化ソルバーが問題をハイブリッド量子アルゴリズムにマッピングし、量子回路をエラー抑制付きで実行し、古典的最適化を実行する。\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "bd38bb1e",
      "metadata": {},
      "outputs": [],
      "source": [
        "# Authenticate to the Qiskit Functions Catalog\n",
        "catalog = QiskitFunctionsCatalog(\n",
        "    token=token,\n",
        "    instance=instance,\n",
        ")\n",
        "\n",
        "# Load the function\n",
        "solver = catalog.load(\"q-ctrl/optimization_solver\")"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "12cfe6f5",
      "metadata": {},
      "source": [
        "選択されたデバイスが少なくとも156量子ビットを持つことを確認する。\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "a27adab7",
      "metadata": {},
      "outputs": [],
      "source": [
        "# Specify the target backend name\n",
        "backend_name = \"<CHOOSE_A_BACKEND>\""
      ]
    },
    {
      "cell_type": "markdown",
      "id": "ffbe9f79",
      "metadata": {},
      "source": [
        "ソルバーは目的関数の文字列表現を受け付ける。\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 43,
      "id": "1834cb22",
      "metadata": {},
      "outputs": [],
      "source": [
        "# Convert the objective function to string format\n",
        "spin_glass_poly_as_str = srepr(spin_glass_poly)"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "98213fe9",
      "metadata": {},
      "outputs": [],
      "source": [
        "# Run the problem\n",
        "spin_glass_job = solver.run(\n",
        "    problem=spin_glass_poly_as_str,\n",
        "    run_options={\"backend_name\": backend_name},\n",
        ")"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "d25caa83",
      "metadata": {},
      "source": [
        "使い慣れた [Qiskit Serverless APIを使って](/docs/guides/serverless)、Qiskit Functionのワークロードの状態をチェックできます：\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "77a8ded0",
      "metadata": {},
      "outputs": [],
      "source": [
        "# Get job status\n",
        "spin_glass_job.status()"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "7cd96271",
      "metadata": {},
      "source": [
        "ソルバーは、解と関連するメタデータ（解のビット列、反復回数、変数とビット列のマッピングなど）を辞書として返します。 ソルバーの入力と出力の完全な定義については、 [ドキュメントを]()チェックしてほしい。\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "bd8bd878",
      "metadata": {},
      "outputs": [],
      "source": [
        "# Poll for results\n",
        "result = spin_glass_job.result()"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 54,
      "id": "2bddbcbc",
      "metadata": {},
      "outputs": [],
      "source": [
        "# Get the final bitstring distribution and set the number of shots\n",
        "distribution = result[\"final_bitstring_distribution\"]"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "50b94af2",
      "metadata": {},
      "source": [
        "<span id=\"step-3-evaluate-results\" />\n",
        "\n",
        "## ステップ3：結果を評価する\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 31,
      "id": "f6f6e93a",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "Minimum ground state energy: -242.0\n"
          ]
        }
      ],
      "source": [
        "# Get the solution ground state energy\n",
        "print(f\"Minimum ground state energy: {result[\"solution_bitstring_cost\"]}\")"
      ]
    },
    {
      "attachments": {},
      "cell_type": "markdown",
      "id": "733431ad",
      "metadata": {},
      "source": [
        "ソルバーが正しい解を見つけ、それを古典的な最適化ソフトウェアを使って検証した。 このユーティリティスケールの問題は複雑であるため、 [IBM ILOG CPLEX Optimization Studio (CPLEX)](https://www.ibm.com/products/ilog-cplex-optimization-studio) や [Gurobi Optimizationの](https://www.gurobi.com/)ような、古典的に解くには高度な最適化ソフトウェアが必要である。\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "40406a33",
      "metadata": {},
      "source": [
        "結果の質を視覚的に分析する方法として、ビット列とその確率からコスト値を計算して結果をプロットすることができる。 比較のために、ランダムにサンプリングされたビット列の分布と結果を並べてみる。 アルゴリズムが一貫してより低いコストを発見する場合、量子アルゴリズムが最適化問題を効果的に解いていることを示唆している。\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "a481c257",
      "metadata": {},
      "outputs": [],
      "source": [
        "def plot_cost_histogram(\n",
        "    costs, probabilities, distribution, qubit_count, bitstring_cost\n",
        "):\n",
        "    \"\"\"Plots a histogram comparing the cost distributions of\n",
        "    Q-CTRL Solver and random sampling.\"\"\"\n",
        "\n",
        "    # Set figure DPI for higher resolution and font size for labels\n",
        "    plt.rcParams[\"figure.dpi\"] = 300\n",
        "    plt.rcParams.update({\"font.size\": 6})  # Set default font size to 6\n",
        "\n",
        "    # Define labels and colors for the plot\n",
        "    labels = [\"Q-CTRL Solver\", \"Random Sampling\"]\n",
        "    colors = [\"#680CE9\", \"#E04542\"]\n",
        "\n",
        "    # Calculate total shots (total number of bitstrings in the distribution)\n",
        "    shots = sum(distribution.values())\n",
        "\n",
        "    # Generate random bitstrings for comparison (random sampling)\n",
        "    rng = np.random.default_rng(seed=0)\n",
        "    random_array = rng.integers(\n",
        "        0, 2, size=(shots, qubit_count)\n",
        "    )  # Generate random bitstrings (0 or 1 for each qubit)\n",
        "    random_bitstrings = [\"\".join(row.astype(str)) for row in random_array]\n",
        "\n",
        "    # Compute the cost for each random bitstring\n",
        "    random_costs = [bitstring_cost(k) for k in random_bitstrings]\n",
        "\n",
        "    # Set uniform probabilities for the random sampling\n",
        "    random_probabilities = (\n",
        "        np.ones(shape=(shots,)) / shots\n",
        "    )  # Equal probability for each random bitstring\n",
        "\n",
        "    # Find the minimum and maximum costs for binning the histogram\n",
        "    min_cost = np.min(costs)\n",
        "    max_cost = np.max(random_costs)\n",
        "\n",
        "    # Create a histogram plot with a smaller figure size (4x2 inches)\n",
        "    fig, ax = plt.subplots(nrows=1, ncols=1, figsize=(4, 2))\n",
        "\n",
        "    # Plot histograms for the Q-CTRL solver and random sampling costs\n",
        "    _, _, _ = ax.hist(\n",
        "        [costs, random_costs],  # Data for the two histograms\n",
        "        np.arange(min_cost, max_cost, 2),  # Bins for the histogram\n",
        "        weights=[\n",
        "            probabilities,\n",
        "            random_probabilities,\n",
        "        ],  # Probabilities for each data set\n",
        "        label=labels,  # Labels for the legend\n",
        "        color=colors,  # Colors for each histogram\n",
        "        histtype=\"stepfilled\",  # Filled step histogram\n",
        "        align=\"mid\",  # Align bars to the bin center\n",
        "        alpha=0.8,  # Transparency\n",
        "    )\n",
        "\n",
        "    # Set the x and y labels for the plot\n",
        "    ax.set_xlabel(\"Cost\")\n",
        "    ax.set_ylabel(\"Probability\")\n",
        "\n",
        "    # Add the legend to the plot\n",
        "    ax.legend()\n",
        "\n",
        "    # Show the plot\n",
        "    plt.show()"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 59,
      "id": "a2fe3966",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<Image src=\"/docs/images/tutorials/solve-higher-order-binary-optimization-problems-with-q-ctrls-optimization-solver/extracted-outputs/a2fe3966-0.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "metadata": {},
          "output_type": "display_data"
        }
      ],
      "source": [
        "# Convert spin_glass_poly into a NumPy-compatible function\n",
        "poly_as_numpy_function = lambdify(x, spin_glass_poly.as_expr(), \"numpy\")\n",
        "\n",
        "\n",
        "# Function to compute the cost of a given bitstring using spin_glass_poly\n",
        "def bitstring_cost(bitstring: str) -> float:\n",
        "    # Convert bitstring to a reversed list of integers (0s and 1s)\n",
        "    return float(\n",
        "        poly_as_numpy_function(*[int(b) for b in str(bitstring[::-1])])\n",
        "    )\n",
        "\n",
        "\n",
        "# Calculate the cost of each bitstring in the distribution\n",
        "costs = [bitstring_cost(k) for k, _ in distribution.items()]\n",
        "\n",
        "# Extract probabilities from the bitstring distribution\n",
        "probabilities = np.array([v for _, v in distribution.items()])\n",
        "probabilities = probabilities / sum(\n",
        "    probabilities\n",
        ")  # Normalize to get probabilities\n",
        "\n",
        "plot_cost_histogram(\n",
        "    costs, probabilities, distribution, qubit_count, bitstring_cost\n",
        ")"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "15e35cff",
      "metadata": {},
      "source": [
        "この最適化アルゴリズムの目的は、イジングモデルの最小基底状態を見つけることであるため、値が小さいほど良い解を示す。 したがって、Fire Opal最適化ソルバーによって生成された解は、ランダム選択をはるかに凌駕していることが視覚的に明らかである。\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": 1440
  },
  "nbformat": 4,
  "nbformat_minor": 5
}