{
  "cells": [
    {
      "attachments": {},
      "cell_type": "markdown",
      "id": "da8ce695-8435-4099-b0fd-ade7b298f540",
      "metadata": {},
      "source": [
        "---\n",
        "title: \"コスト関数\"\n",
        "description: \"このレッスンでは、コスト関数とは何か、それが変分アルゴリズムでどのように使用されるか、そしてハミルトニアンとどのように異なるかを説明します。\"\n",
        "---\n",
        "\n",
        "{/* cspell:ignore resil nbsp eigenbasis expvals IIZZ IZIZ IZZI ZIIZ ZZII */}\n",
        "\n",
        "<span id=\"cost-functions\" />\n",
        "\n",
        "# コスト関数\n",
        "\n",
        "このレッスンでは、 *コスト関数を*評価する方法を学ぶ：\n",
        "\n",
        "* まず、 [IBM Quantum のプリミティブ](/docs/guides/primitives)について学びます\n",
        "* *コスト関数* $C(\\vec\\theta)$ を定義する。これは問題固有の関数で、オプティマイザが最小化（または最大化）する問題のゴールを定義する\n",
        "* IBM Quantum のプリミティブを用いて測定戦略を策定し、速度と精度のバランスを最適化する\n",
        "\n",
        " \n",
        "\n",
        "![推定器やサンプラーのようなプリミティブの使用を含む、コスト関数の主要な構成要素を示す図。](https://quantum.cloud.ibm.com/learning/images/courses/variational-algorithm-design/cost-functions/cost-function-workflow.svg)\n",
        "\n"
      ]
    },
    {
      "attachments": {},
      "cell_type": "markdown",
      "id": "4a9b79a9-c040-43d3-a4cf-314277e30eea",
      "metadata": {
        "gloss": {
          "primitives": {
            "text": "Basic and fundamental operations or data type. Qiskit has the Sampler and Estimator primitives to serve as building blocks to easily construct complex workloads, like variational algorithms.",
            "title": "Primitives"
          }
        }
      },
      "source": [
        "<span id=\"primitives\" />\n",
        "\n",
        "## プリミティブ\n",
        "\n",
        "古典的であれ量子的であれ、すべての物理系は異なる状態で存在することができる。 例えば、道路を走る車は、その状態を特徴づける一定の質量、位置、速度、加速度を持つことができる。 同様に、量子系も異なる構成や状態を持つことができるが、測定や状態変化の扱い方が古典系とは異なる。 これにより、 *重ね合わせや* *エンタングルメントといった*量子力学特有の性質が生まれる。 車の状態を速度や加速度などの物理的特性で表現できるように、量子系の状態も数学的対象である*観測量を用いて*表現することができる。\n",
        "\n",
        "量子力学では、状態は正規化された複素列ベクトル、すなわち*ケット* ( $|\\psi\\rangle$ )で表され、観測量はケットに作用するエルミート線形作用素( $\\hat{H}=\\hat{H}^{\\dagger}$ )である。 観測値の固有ベクトル( $|\\lambda\\rangle$ )は*固有状態と*呼ばれる。 ある観測量をその固有状態( $|\\lambda\\rangle$ )の一つについて測定すると、対応する固有値( $\\lambda$ )が読み出される。\n",
        "\n",
        "量子システムの測定方法と測定可能なものに疑問をお持ちの場合、Qiskitは2つの <DefinitionTooltip definition=\"基本的かつ基本的な操作またはデータ型。 QiskitにはSamplerとEstimatorプリミティブがあり、複雑なアルゴリズムのワークロードを簡単に構築するためのビルディングブロックとして機能します。\">プリミティブ</DefinitionTooltip> ：\n",
        "\n",
        "* `Sampler`:量子状態 $|\\psi\\rangle$ が与えられたとき、このプリミティブは計算可能な基底状態の確率を求める。\n",
        "* `Estimator`:量子観測量 $\\hat{H}$ と状態 $|\\psi\\rangle$ が与えられたとき、このプリミティブは $\\hat{H}$ の期待値を計算する。\n",
        "\n"
      ]
    },
    {
      "attachments": {},
      "cell_type": "markdown",
      "id": "00aa7dfa-34f1-440e-bbdb-19b6e6a1aff8",
      "metadata": {},
      "source": [
        "<span id=\"the-sampler-primitive\" />\n",
        "\n",
        "### サンプラープリミティブ\n",
        "\n",
        "`Sampler` プリミティブは、状態 $|\\psi\\rangle$ を準備する量子回路が与えられた場合、計算基礎から各可能な状態 $|k\\rangle$ を得る確率を計算します。次のように計算します\n",
        "\n",
        "$$\n",
        "p_k = |\\langle k | \\psi \\rangle|^2 \\quad \\forall k \\in \\mathbb{Z}_2^n \\equiv \\{0,1,\\cdots,2^n-1\\},\n",
        "$$\n",
        "\n",
        "ここで、 $n$ は量子ビット数であり、 $k$ は、あらゆる可能な出力バイナリ文字列の整数表現 $\\{0,1\\}^n$ （つまり、整数の基数 $2$ ）である。\n",
        "\n",
        "IBM Quantum は、量子デバイス上でこの回路を複数回実行 [`Sampler`](/docs/api/qiskit-ibm-runtime/sampler-v2) し、各実行ごとに測定を行い、復元されたビット列から確率分布を再構築します。 実行回数（または*ショット数* ）が多ければ多いほど、結果はより正確になりますが、それにはより多くの時間と量子リソースが必要となります。\n",
        "\n",
        "しかし、可能な出力の数は、量子ビットの数 $n$ （つまり、 $2^n$ ）とともに指数関数的に増加するため、 *密な*確率分布を捉えるためには、ショットの数も同様に指数関数的に増加する必要がある。 したがって、 `Sampler` は、 *スパースな*確率分布に対してのみ効率的である。ここで、ターゲット状態 $|\\psi\\rangle$ は、計算基底状態の線形結合として表現可能でなければならず、項の数は量子ビット数に応じて最大でも多項式に増加する：\n",
        "\n",
        "$$\n",
        "|\\psi\\rangle = \\sum^{\\text{Poly}(n)}_k w_k |k\\rangle.\n",
        "$$\n",
        "\n",
        "また、 `Sampler` 、可能な全状態のサブセットを表す回路のサブセクションから確率を検索するように構成することもできる。\n",
        "\n"
      ]
    },
    {
      "attachments": {},
      "cell_type": "markdown",
      "id": "96a74b2b-6aa0-4ef1-a8d1-448b591429e4",
      "metadata": {
        "gloss": {
          "pauli": {
            "text": "Set of matrices commonly used in quantum computing to represent and manipulate quantum states, consisting of the identity matrix and the three Pauli matrices (X, Y, and Z).",
            "title": "Pauli Operators"
          }
        }
      },
      "source": [
        "<span id=\"the-estimator-primitive\" />\n",
        "\n",
        "### 推定器プリミティブ\n",
        "\n",
        "`Estimator` プリミティブは、量子状態 $|\\psi\\rangle$ に対する観測値 $\\hat{H}$ の期待値を計算する。ここで、観測値の確率は $p_\\lambda = |\\langle\\lambda|\\psi\\rangle|^2$ のように表すことができ、 $|\\lambda\\rangle$ は観測値 $\\hat{H}$ の固有状態である。期待値は、状態 $|\\psi\\rangle$ の測定のすべての可能な結果 $\\lambda$ (つまり、観測値の固有値) の平均として定義され、対応する確率で重み付けされます：\n",
        "\n",
        "$$\n",
        "\\langle\\hat{H}\\rangle_\\psi := \\sum_\\lambda p_\\lambda \\lambda = \\langle \\psi | \\hat{H} | \\psi \\rangle\n",
        "$$\n",
        "\n",
        "しかし、観測量の期待値を計算できるとは限らない。その固有基底がわからない場合が多いためである。 IBM Quantum は、観測量を、その固有基底が既知である他の観測量の組み合わせに分解することで、実在する量子デバイスにおける期待値を推定する、複雑な代数的手法を用 [`Estimator`](/docs/api/qiskit-ibm-runtime/estimator-v2) いています。\n",
        "\n",
        "もっと簡単に言えば、 `Estimator` 、測定方法を知らない観測可能なものは、 <DefinitionTooltip definition=\"量子コンピュータで量子状態を表現・操作するために一般的に使用される行列の集合で、恒等行列と3つのパウリ行列（X、Y、Z）で構成される。\">パウリ演算子</DefinitionTooltip> と呼ばれる、より単純で測定可能な観測可能なものに分解される。\n",
        "\n"
      ]
    },
    {
      "attachments": {},
      "cell_type": "markdown",
      "id": "6dcabf55-4462-4cf9-b6e4-e7860fd25b31",
      "metadata": {},
      "source": [
        "どの演算子も、 $4^n$ パウリ演算子の組み合わせとして表現できる。\n",
        "\n",
        "$$\n",
        "\\hat{P}_k :=\n",
        "\\sigma_{k_{n-1}}\\otimes \\cdots \\otimes \\sigma_{k_0} \\quad\n",
        "\\forall k \\in \\mathbb{Z}_4^n \\equiv \\{0,1,\\cdots,4^n-1\\}, \\\\\n",
        "$$\n",
        "\n",
        "条件\n",
        "\n",
        "$$\n",
        "\\hat{H} = \\sum^{4^n-1}_{k=0} w_k \\hat{P}_k\n",
        "$$\n",
        "\n",
        "ここで、 $n$ は量子ビット数、 $k \\equiv k_{n-1} \\cdots k_0$ は $k_l \\in \\mathbb{Z}_4 \\equiv \\{0, 1, 2, 3\\}$ （つまり、整数の底 $4$ ）、 $(\\sigma_0, \\sigma_1, \\sigma_2, \\sigma_3) := (I, X, Y, Z)$。\n",
        "\n",
        "この分解を行った後、 `Estimator` 、（元の回路から）各観測値 $\\hat{P}_k$ に対して新しい回路 $V_k|\\psi\\rangle$ を導出し、計算基底におけるパウリ観測値を効果的に*対角化*し、それを測定する。 パウリ観測量を簡単に測定できるのは、 $V_k$。\n",
        "\n",
        "$\\hat{P}_{k}$ それぞれについて、 `Estimator` 量子デバイス上で対応する回路を複数回実行し、計算基礎で出力状態を測定し、各可能な出力 $j$ を得る確率 $p_{kj}$ を計算する。次に、各出力に対応する $P_k$ の固有値 $\\lambda_{kj}$ $j$ を探し、 $w_k$ を乗算し、すべての結果を合計して、与えられた状態 $|\\psi\\rangle$ に対する観測値 $\\hat{H}$ の期待値を求める。\n",
        "\n",
        "$$\n",
        "\\langle\\hat{H}\\rangle_\\psi =\n",
        "\\sum_{k=0}^{4^n-1} w_k \\sum_{j=0}^{2^n-1}p_{kj} \\lambda_{kj},\n",
        "$$\n",
        "\n"
      ]
    },
    {
      "attachments": {},
      "cell_type": "markdown",
      "id": "dcffb899-ef2d-4dca-b2a7-11c197d45ed0",
      "metadata": {
        "gloss": {
          "sampling": {
            "text": "The process of taking several measurements of one or several things.",
            "title": "Sampling"
          }
        }
      },
      "source": [
        "$4^n$ Paulisの期待値を計算するのは非現実的（つまり指数関数的に大きくなる）であるため、 `Estimator` 、大量の $w_k$ がゼロである場合（つまり*密ではなく* *疎な*パウリ分解）にのみ効率的となる。 形式的には、この計算が*効率的に解ける*ためには、0でない項の数が量子ビット数 $n$ に対して多項式に増加しなければならない： $\\hat{H} = \\sum^{\\text{Poly}(n)}_k w_k \\hat{P}_k.$\n",
        "\n",
        "読者は、 `Sampler` で説明したように、確率 <DefinitionTooltip definition=\"1つまたは複数の物事について、いくつかの測定を行うプロセス。\">サンプリング</DefinitionTooltip> も効率的である必要がある、という暗黙の前提に気づくかもしれない\n",
        "\n",
        "$$\n",
        "\\langle\\hat{H}\\rangle_\\psi =\n",
        "\\sum_{k}^{\\text{Poly}(n)} w_k \\sum_{j}^{\\text{Poly}(n)}p_{kj} \\lambda_{kj}.\n",
        "$$\n",
        "\n"
      ]
    },
    {
      "attachments": {},
      "cell_type": "markdown",
      "id": "c1547f3e-3c05-46d9-be5a-3e7e4141dc92",
      "metadata": {},
      "source": [
        "<span id=\"guided-example-to-calculate-expectation-values\" />\n",
        "\n",
        "### 期待値を計算するためのガイド付き例\n",
        "\n",
        "1量子ビットの状態 $|+\\rangle := H|0\\rangle = \\frac{1}{\\sqrt{2}}(|0\\rangle + |1\\rangle)$、観測可能であるとする\n",
        "\n",
        "$$\n",
        "\\begin{aligned}\n",
        "\\hat{H}\n",
        "& = \\begin{pmatrix}\n",
        "-1 & 2 \\\\\n",
        "2 & 1 \\\\\n",
        "\\end{pmatrix}\\\\[1mm]\n",
        "& = 2X - Z\n",
        "\n",
        "\\end{aligned}\n",
        "$$\n",
        "\n",
        "理論的期待値は以下の通りである。 $\\langle\\hat{H}\\rangle_+ = \\langle+|\\hat{H}|+\\rangle = 2.$\n",
        "\n",
        "この観測値を測定する方法を知らないので、期待値を直接計算することはできず、 $\\langle\\hat{H}\\rangle_+ = 2\\langle X \\rangle_+ - \\langle Z \\rangle_+ $ として表現し直す必要がある。 $\\langle+|X|+\\rangle = 1$, と $\\langle+|Z|+\\rangle = 0$.\n",
        "\n",
        "$\\langle X \\rangle_+$ と $\\langle Z \\rangle_+$ を直接計算する方法を見てみよう。 $X$ と $Z$ は交わらない（つまり、同じ固有ベーシスを共有しない）ので、同時に測定することはできず、したがって補助回路が必要となる：\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 1,
      "id": "7c32e970-f9cb-48ec-a60b-2dccb0744141",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<Image src=\"/learning/images/courses/variational-algorithm-design/cost-functions/extracted-outputs/7c32e970-f9cb-48ec-a60b-2dccb0744141-0.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "from qiskit import QuantumCircuit\n",
        "from qiskit.quantum_info import SparsePauliOp\n",
        "\n",
        "# The following code will work for any other initial single-qubit state and observable\n",
        "original_circuit = QuantumCircuit(1)\n",
        "original_circuit.h(0)\n",
        "\n",
        "H = SparsePauliOp([\"X\", \"Z\"], [2, -1])\n",
        "\n",
        "aux_circuits = []\n",
        "for pauli in H.paulis:\n",
        "    aux_circ = original_circuit.copy()\n",
        "    aux_circ.barrier()\n",
        "    if str(pauli) == \"X\":\n",
        "        aux_circ.h(0)\n",
        "    elif str(pauli) == \"Y\":\n",
        "        aux_circ.sdg(0)\n",
        "        aux_circ.h(0)\n",
        "    else:\n",
        "        aux_circ.id(0)\n",
        "    aux_circ.measure_all()\n",
        "    aux_circuits.append(aux_circ)\n",
        "\n",
        "original_circuit.draw(\"mpl\")"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 2,
      "id": "ec3cf7af-66b2-4ea9-94d7-6ec6ba2bfc5e",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<Image src=\"/learning/images/courses/variational-algorithm-design/cost-functions/extracted-outputs/ec3cf7af-66b2-4ea9-94d7-6ec6ba2bfc5e-0.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "execution_count": 2,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "# Auxiliary circuit for X\n",
        "aux_circuits[0].draw(\"mpl\")"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 3,
      "id": "678d3bd0-d8fd-4767-b0a6-77cae945810a",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<Image src=\"/learning/images/courses/variational-algorithm-design/cost-functions/extracted-outputs/678d3bd0-d8fd-4767-b0a6-77cae945810a-0.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "execution_count": 3,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "# Auxiliary circuit for Z\n",
        "aux_circuits[1].draw(\"mpl\")"
      ]
    },
    {
      "attachments": {},
      "cell_type": "markdown",
      "id": "beef97f0-c968-4a3f-9b7b-fed39b88cbe3",
      "metadata": {},
      "source": [
        "`Sampler` を使って手動で計算を行い、その結果を `Estimator` で確認することができる：\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "d59dffe0-85cb-4849-8421-03bbcc9668df",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "Sampler results:\n",
            "  >> Expected value of X: 1.00000\n",
            "  >> Expected value of Z: 0.00420\n",
            "  >> Total expected value: 1.99580\n",
            "Estimator results:\n",
            "  >> Expected value of X: 1.00000\n",
            "  >> Expected value of Z: 0.00000\n",
            "  >> Total expected value: 2.00000\n"
          ]
        }
      ],
      "source": [
        "from qiskit.primitives import StatevectorSampler, StatevectorEstimator\n",
        "from qiskit.result import QuasiDistribution\n",
        "import numpy as np\n",
        "\n",
        "\n",
        "## SAMPLER\n",
        "shots = 10000\n",
        "sampler = StatevectorSampler()\n",
        "job = sampler.run(aux_circuits, shots=shots)\n",
        "\n",
        "# Run the sampler job and step through results\n",
        "expvals = []\n",
        "for index, pauli in enumerate(H.paulis):\n",
        "    data_pub = job.result()[index].data\n",
        "    bitstrings = data_pub.meas.get_bitstrings()\n",
        "    counts = data_pub.meas.get_counts()\n",
        "    quasi_dist = QuasiDistribution(\n",
        "        {outcome: freq / shots for outcome, freq in counts.items()}\n",
        "    )\n",
        "\n",
        "    # Use the probabilities and known eigenvalues of Pauli operators to estimate\n",
        "    # the expectation value.\n",
        "    val = 0\n",
        "\n",
        "    if str(pauli) == \"X\":\n",
        "        val += -1 * quasi_dist.get(1, 0)\n",
        "        val += 1 * quasi_dist.get(0, 0)\n",
        "\n",
        "    if str(pauli) == \"Y\":\n",
        "        val += -1 * quasi_dist.get(1, 0)\n",
        "        val += 1 * quasi_dist.get(0, 0)\n",
        "\n",
        "    if str(pauli) == \"Z\":\n",
        "        val += 1 * quasi_dist.get(0, 0)\n",
        "        val += -1 * quasi_dist.get(1, 0)\n",
        "\n",
        "    expvals.append(val)\n",
        "\n",
        "# Print expectation values\n",
        "\n",
        "print(\"Sampler results:\")\n",
        "for pauli, expval in zip(H.paulis, expvals):\n",
        "    print(f\"  >> Expected value of {str(pauli)}: {expval:.5f}\")\n",
        "\n",
        "total_expval = np.sum(H.coeffs * expvals).real\n",
        "print(f\"  >> Total expected value: {total_expval:.5f}\")\n",
        "\n",
        "# Use estimator for comparison\n",
        "observables = [\n",
        "    *H.paulis,\n",
        "    H,\n",
        "]  # Note: run for individual Paulis as well as full observable H\n",
        "\n",
        "estimator = StatevectorEstimator()\n",
        "job = estimator.run([(original_circuit, observables)])\n",
        "estimator_expvals = job.result()[0].data.evs\n",
        "\n",
        "# Print results\n",
        "print(\"Estimator results:\")\n",
        "for obs, expval in zip(observables, estimator_expvals):\n",
        "    if obs is not H:\n",
        "        print(f\"  >> Expected value of {str(obs)}: {expval:.5f}\")\n",
        "    else:\n",
        "        print(f\"  >> Total expected value: {expval:.5f}\")"
      ]
    },
    {
      "attachments": {},
      "cell_type": "markdown",
      "id": "44f13c37-50e3-426c-90cb-f730a81e20d1",
      "metadata": {},
      "source": [
        "<span id=\"mathematical-rigor-optional\" />\n",
        "\n",
        "### 数学的厳密性（任意）\n",
        "\n",
        "$\\hat{H}$, $|\\psi\\rangle = \\sum_\\lambda a_\\lambda |\\lambda\\rangle$ の固有状態の基底に関して $|\\psi\\rangle$ を表現すると、以下のようになる：\n",
        "\n",
        "$$\n",
        "\\begin{aligned}\n",
        "\\langle \\psi | \\hat{H} | \\psi \\rangle\n",
        "& = \\bigg(\\sum_{\\lambda'}a^*_{\\lambda'} \\langle \\lambda'|\\bigg) \\hat{H}\n",
        "  \\bigg(\\sum_{\\lambda} a_\\lambda | \\lambda\\rangle\\bigg)\\\\[1mm]\n",
        "\n",
        "& = \\sum_{\\lambda}\\sum_{\\lambda'} a^*_{\\lambda'}a_{\\lambda}\n",
        "  \\langle \\lambda'|\\hat{H}| \\lambda\\rangle\\\\[1mm]\n",
        "\n",
        "& = \\sum_{\\lambda}\\sum_{\\lambda'} a^*_{\\lambda'}a_{\\lambda} \\lambda\n",
        "\\langle \\lambda'| \\lambda\\rangle\\\\[1mm]\n",
        "\n",
        "& = \\sum_{\\lambda}\\sum_{\\lambda'} a^*_{\\lambda'}a_{\\lambda} \\lambda\n",
        "\\cdot \\delta_{\\lambda, \\lambda'}\\\\[1mm]\n",
        "\n",
        "& = \\sum_\\lambda |a_\\lambda|^2 \\lambda\\\\[1mm]\n",
        "\n",
        "& = \\sum_\\lambda p_\\lambda \\lambda\\\\[1mm]\n",
        "\n",
        "\\end{aligned}\n",
        "$$\n",
        "\n"
      ]
    },
    {
      "attachments": {},
      "cell_type": "markdown",
      "id": "6a3bea3d-a2f6-4033-85f9-9a10c5d5c64c",
      "metadata": {
        "gloss": {
          "hermitian": {
            "text": "A hermitian is a square matrix that is equal to its own conjugate transpose, or a linear operator that is self-adjoint.",
            "title": "Hermitian"
          }
        }
      },
      "source": [
        "目標とする観測値 $\\hat{H}$ の固有値や固有状態がわからないので、まずその対角化を考える必要がある。 $\\hat{H}$ が <DefinitionTooltip definition=\"エルミートとは、それ自身の共役転置と等しい正方行列、または自己共役である線形作用素のことである。\">エルミート</DefinitionTooltip> であることを考えると、 $\\hat{H}=V^\\dagger \\Lambda V,$ $\\Lambda$ が対角固有値行列であるようなユニタリー変換 $V$ が存在するので、 $\\langle j | \\Lambda | k \\rangle = 0$ if $j\\neq k$, and $\\langle j | \\Lambda | j \\rangle = \\lambda_j$.\n",
        "\n",
        "これは期待値が次のように書き換えられることを意味する：\n",
        "\n",
        "$$\n",
        "\\begin{aligned}\n",
        "\\langle\\psi|\\hat{H}|\\psi\\rangle\n",
        "& = \\langle\\psi|V^\\dagger \\Lambda V|\\psi\\rangle\\\\[1mm]\n",
        "\n",
        "& = \\langle\\psi|V^\\dagger \\bigg(\\sum_{j=0}^{2^n-1} |j\\rangle\n",
        "\\langle j|\\bigg) \\Lambda \\bigg(\\sum_{k=0}^{2^n-1} |k\\rangle \\langle k|\\bigg) V|\\psi\\rangle\\\\[1mm]\n",
        "\n",
        "& = \\sum_{j=0}^{2^n-1} \\sum_{k=0}^{2^n-1}\\langle\\psi|V^\\dagger |j\\rangle\n",
        "\\langle j| \\Lambda  |k\\rangle \\langle k| V|\\psi\\rangle\\\\[1mm]\n",
        "\n",
        "& = \\sum_{j=0}^{2^n-1}\\langle\\psi|V^\\dagger |j\\rangle\n",
        "\\langle j| \\Lambda  |j\\rangle \\langle j| V|\\psi\\rangle\\\\[1mm]\n",
        "\n",
        "& = \\sum_{j=0}^{2^n-1}|\\langle j| V|\\psi\\rangle|^2 \\lambda_j\\\\[1mm]\n",
        "\n",
        "\\end{aligned}\n",
        "$$\n",
        "\n",
        "システムが状態 $|\\phi\\rangle = V |\\psi\\rangle$ にある場合、 $| j\\rangle$ を測定する確率は $p_j = |\\langle j|\\phi \\rangle|^2$ であることを考えると、上記の期待値は次のように表すことができる：\n",
        "\n",
        "$$\n",
        "\\langle\\psi|\\hat{H}|\\psi\\rangle =\n",
        "\\sum_{j=0}^{2^n-1} p_j \\lambda_j.\n",
        "$$\n",
        "\n",
        "確率は、 $|\\psi\\rangle$ ではなく、 $V |\\psi\\rangle$ 状態から取られることに注意することが非常に重要である。これが、行列 $V$ が絶対に必要な理由である。\n",
        "\n"
      ]
    },
    {
      "attachments": {},
      "cell_type": "markdown",
      "id": "c21a9a05-6e07-45dc-a090-4414dfdf2521",
      "metadata": {},
      "source": [
        "行列 $V$ と固有値 $\\Lambda$ をどうやって求めるのか、不思議に思うかもしれない。もしすでに固有値がわかっていれば、変分アルゴリズムの目的はこれらの固有値を求めることなので、量子コンピュータを使う必要はないだろう $\\hat{H}$。\n",
        "\n",
        "幸いなことに、これを回避する方法があります。任意の $2^n \\times 2^n$ 行列は、 $n$ のパウリ行列と単位行列の $4^n$ のテンソル積の線形結合として表すことができ、これらはすべてエルミートかつユニタリであり、 $V$ および $\\Lambda$ が既知です。これが、 IBM Quantum が内部で実行している処理であり `Estimator` 、任意のオブジェクト [`Operator`](/docs/api/qiskit/qiskit.quantum_info.Operator) を.に分解しています [`SparsePauliOp`](/docs/api/qiskit/qiskit.quantum_info.SparsePauliOp)。\n",
        "\n",
        "以下は使用可能な演算子である：\n",
        "\n",
        "$$\n",
        "\\begin{array}{c|c|c|c}\n",
        "  \\text{Operator} & \\sigma & V & \\Lambda \\\\[1mm]\n",
        "  \\hline\n",
        "  I & \\sigma_0 = \\begin{pmatrix} 1 & 0 \\\\ 0 & 1 \\end{pmatrix} & V_0 = I & \\Lambda_0 = I = \\begin{pmatrix} 1 & 0 \\\\ 0 & 1 \\end{pmatrix} \\\\[4mm]\n",
        "\n",
        "  X & \\sigma_1 = \\begin{pmatrix} 0 & 1 \\\\ 1 & 0 \\end{pmatrix} & V_1 = H =\\frac{1}{\\sqrt{2}} \\begin{pmatrix} 1 & 1 \\\\ 1 & -1 \\end{pmatrix} & \\Lambda_1 = \\sigma_3 = \\begin{pmatrix} 1 & 0 \\\\ 0 & -1 \\end{pmatrix} \\\\[4mm]\n",
        "\n",
        "  Y & \\sigma_2 = \\begin{pmatrix} 0 & -i \\\\ i & 0 \\end{pmatrix} & V_2 = HS^\\dagger  =\\frac{1}{\\sqrt{2}} \\begin{pmatrix} 1 & 1 \\\\ 1 & -1 \\end{pmatrix}\\cdot  \\begin{pmatrix} 1 & 0 \\\\ 0 & -i \\end{pmatrix} = \\frac{1}{\\sqrt{2}} \\begin{pmatrix} 1 & -i \\\\ 1 & i \\end{pmatrix}\\quad & \\Lambda_2 = \\sigma_3 = \\begin{pmatrix} 1 & 0 \\\\ 0 & -1 \\end{pmatrix} \\\\[4mm]\n",
        "\n",
        "  Z & \\sigma_3 = \\begin{pmatrix} 1 & 0 \\\\ 0 & -1 \\end{pmatrix} & V_3 = I & \\Lambda_3 = \\sigma_3 = \\begin{pmatrix} 1 & 0 \\\\ 0 & -1 \\end{pmatrix}\n",
        "\\end{array}\n",
        "$$\n",
        "\n"
      ]
    },
    {
      "attachments": {},
      "cell_type": "markdown",
      "id": "9e1c0933-5fbe-466d-9114-92d66d21785f",
      "metadata": {},
      "source": [
        "そこで、 $\\hat{H}$、ポーリスとアイデンティティに関して書き直してみよう：\n",
        "\n",
        "$$\n",
        "\\hat{H} =\n",
        "\\sum_{k_{n-1}=0}^3...\n",
        "\\sum_{k_0=0}^3 w_{k_{n-1}...k_0}\n",
        "\\sigma_{k_{n-1}}\\otimes ... \\otimes \\sigma_{k_0} = \\sum_{k=0}^{4^n-1} w_k \\hat{P}_k,\n",
        "$$\n",
        "\n",
        "ここで $k = \\sum_{l=0}^{n-1} 4^l k_l \\equiv k_{n-1}...k_0$ は $k_{n-1},...,k_0\\in \\{0,1,2,3\\}$ （つまりベース $4$ ）、 $\\hat{P}_{k} := \\sigma_{k_{n-1}}\\otimes ... \\otimes \\sigma_{k_0}$ ：\n",
        "\n",
        "$$\n",
        "\\begin{aligned}\n",
        "\\langle\\psi|\\hat{H}|\\psi\\rangle\n",
        "& = \\sum_{k=0}^{4^n-1} w_k\n",
        "\\sum_{j=0}^{2^n-1}|\\langle j| V_k|\\psi\\rangle|^2 \\langle j| \\Lambda_k |j\\rangle \\\\[1mm]\n",
        "\n",
        "& = \\sum_{k=0}^{4^n-1} w_k \\sum_{j=0}^{2^n-1}p_{kj} \\lambda_{kj}, \\\\[1mm]\n",
        "\n",
        "\n",
        "\\end{aligned}\n",
        "$$\n",
        "\n",
        "ここで、 $V_k := V_{k_{n-1}}\\otimes ... \\otimes V_{k_0}$ と $\\Lambda_k := \\Lambda_{k_{n-1}}\\otimes ... \\otimes \\Lambda_{k_0}$ は、次のようなものである： $\\hat{P_k}=V_k^\\dagger \\Lambda_k V_k.$\n",
        "\n"
      ]
    },
    {
      "attachments": {},
      "cell_type": "markdown",
      "id": "42f771a0-486d-4a5f-9df1-a1720d7bf252",
      "metadata": {
        "gloss": {
          "oracle": {
            "text": " A hypothetical device or software component that performs a specific function, but the internal workings of which are unknown. A user is only aware of the inputs and outputs of the black box, and has no knowledge of how the black box processes the inputs to produce the outputs.",
            "title": "Black-box oracle"
          }
        }
      },
      "source": [
        "<span id=\"cost-functions\" />\n",
        "\n",
        "## コスト関数\n",
        "\n",
        "一般に、コスト関数は問題のゴールと、そのゴールに対して試行状態がどの程度うまくいっているかを記述するために使われる。 この定義は、化学、機械学習、金融、最適化など、さまざまな例に適用できる。\n",
        "\n",
        "系の基底状態を見つける簡単な例を考えてみよう。 我々の目的は、エネルギーを表す観測値（ハミルトニアン $\\hat{\\mathcal{H}}$ ）の期待値を最小化することである：\n",
        "\n",
        "$$\n",
        "\\min_{\\vec\\theta} \\langle\\psi(\\vec\\theta)|\\hat{\\mathcal{H}}|\\psi(\\vec\\theta)\\rangle\n",
        "$$\n",
        "\n",
        "`Estimator` を使って期待値を評価し、この値をオプティマイザに渡して最小化することができる。 最適化が成功すれば、最適なパラメータ値のセット $\\vec\\theta^*$ が返され、そこから提案された解の状態 $|\\psi(\\vec\\theta^*)\\rangle$ を構築し、観測された期待値を $C(\\vec\\theta^*)$ として計算することができる。\n",
        "\n",
        "私たちが考えている限られた状態のセットに対してのみ、コスト関数を最小化することができることに注目してほしい。 このことから、2つの可能性が考えられる：\n",
        "\n",
        "* **私たちのアナザッツは、探索空間全体の解の状態を定義していません** ：もしそうであれば、オプティマイザーは解を見つけることができないので、探索空間をより正確に表現できるかもしれない他のアサッツを試してみる必要があります。\n",
        "* **我々のオプティマイザーは、この有効解を見つけることができない** ：最適化はグローバルに定義することもローカルに定義することもできる。 これが何を意味するかは、後のセクションで探ることにしよう。\n",
        "\n",
        "結局のところ、古典的な最適化ループを実行することになるが、コスト関数の評価は量子コンピューターに頼ることになる。 この観点から、最適化を純粋に古典的な取り組みと考えることもできる。そこでは、オプティマイザがコスト関数を評価する必要があるたびに、 <DefinitionTooltip definition=\"特定の機能を果たすが、その内部構造が不明な仮想的な装置またはソフトウェア・コンポーネント。 ユーザーはブラックボックスの入力と出力しか知らず、ブラックボックスがどのように入力を処理して出力を生成するかは知らない。\">ブラックボックス量子オラクル</DefinitionTooltip>。\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "650faaab-b964-4587-a39f-d6cc80b225b2",
      "metadata": {},
      "outputs": [],
      "source": [
        "def cost_func_vqe(params, circuit, hamiltonian, estimator):\n",
        "    \"\"\"Return estimate of energy from estimator\n",
        "\n",
        "    Parameters:\n",
        "        params (ndarray): Array of ansatz parameters\n",
        "        ansatz (QuantumCircuit): Parameterized ansatz circuit\n",
        "        hamiltonian (SparsePauliOp): Operator representation of Hamiltonian\n",
        "        estimator (Estimator): Estimator primitive instance\n",
        "\n",
        "    Returns:\n",
        "        float: Energy estimate\n",
        "    \"\"\"\n",
        "    pub = (circuit, hamiltonian, params)\n",
        "    cost = estimator.run([pub]).result()[0].data.evs\n",
        "    return cost"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "a01a54f2-da16-4008-b422-fa7ded531f67",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<Image src=\"/learning/images/courses/variational-algorithm-design/cost-functions/extracted-outputs/a01a54f2-da16-4008-b422-fa7ded531f67-0.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "execution_count": 6,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "from qiskit.circuit.library import TwoLocal\n",
        "\n",
        "observable = SparsePauliOp.from_list([(\"XX\", 1), (\"YY\", -3)])\n",
        "\n",
        "reference_circuit = QuantumCircuit(2)\n",
        "reference_circuit.x(0)\n",
        "\n",
        "variational_form = TwoLocal(\n",
        "    2,\n",
        "    rotation_blocks=[\"rz\", \"ry\"],\n",
        "    entanglement_blocks=\"cx\",\n",
        "    entanglement=\"linear\",\n",
        "    reps=1,\n",
        ")\n",
        "ansatz = reference_circuit.compose(variational_form)\n",
        "\n",
        "theta_list = (2 * np.pi * np.random.rand(1, 8)).tolist()\n",
        "ansatz.decompose().draw(\"mpl\")"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "7357e05e-f68a-4cd5-bf0d-77eab963a86d",
      "metadata": {},
      "source": [
        "まず、シミュレーター（ StatevectorEstimator ）を使ってこれを実行する。 通常、これはデバッグのために推奨されることだが、我々はデバッグの実行後、すぐに実際の量子ハードウェア上での計算を行う。 最先端のスーパーコンピューティング設備がなければ、もはや古典的なシミュレーションが不可能な問題が増えている。\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 7,
      "id": "883bcb28-15d0-4046-a654-f43d9480a642",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "[-0.58744589]\n"
          ]
        }
      ],
      "source": [
        "estimator = StatevectorEstimator()\n",
        "cost = cost_func_vqe(theta_list, ansatz, observable, estimator)\n",
        "print(cost)"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "1a94eba3-146d-4eee-970d-9a966d1e15f3",
      "metadata": {},
      "source": [
        "それでは、実際の量子コンピュータ上で実行を進めていきます。 構文の変更点にご注意ください。 pass\\_manager に関連する手順については、次の例でさらに詳しく説明します。 変分アルゴリズムにおいて特に重要な手順の一つは、 IBM Quantum Compute Service セッションの利用です。 セッションを開始すると、パラメータが更新されるたびに新しいキューで待機することなく、変分アルゴリズムを複数回実行できるようになります。 待ち時間が長い場合や、反復処理が何度も必要な場合には、これが重要になります。 なお、Open PlanのユーザーはQuantum Computeセッションを利用できません。 セッションにアクセスできない場合は、一度に送信する反復回数を減らし、次回以降の実行で再利用できるよう、最新のパラメータを保存しておくことができます。 反復処理の送信回数が多すぎたり、キューの待ち時間が長すぎたりすると、エラーコード 1217 が発生する場合があります。これは、ジョブの送信間隔が長すぎることを示しています。\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "e4ca4722-46ab-418f-8a1f-740a65e92eb9",
      "metadata": {},
      "outputs": [],
      "source": [
        "# Estimated usage: < 1 min. Benchmarked at 7 seconds on an Eagle processor\n",
        "# Load necessary packages:\n",
        "\n",
        "from qiskit_ibm_runtime import (\n",
        "    QiskitRuntimeService,\n",
        "    Session,\n",
        "    EstimatorOptions,\n",
        "    EstimatorV2 as Estimator,\n",
        ")\n",
        "from qiskit.transpiler.preset_passmanagers import generate_preset_pass_manager\n",
        "\n",
        "# Select the least busy backend:\n",
        "\n",
        "service = QiskitRuntimeService()\n",
        "backend = service.least_busy(\n",
        "    operational=True, min_num_qubits=ansatz.num_qubits, simulator=False\n",
        ")\n",
        "# Or get a specific backend:\n",
        "# backend = service.backend(\"ibm_brisbane\")\n",
        "\n",
        "# Use a pass manager to transpile the circuit and observable for the specific backend being used:\n",
        "\n",
        "pm = generate_preset_pass_manager(backend=backend, optimization_level=1)\n",
        "isa_ansatz = pm.run(ansatz)\n",
        "isa_observable = observable.apply_layout(layout=isa_ansatz.layout)\n",
        "\n",
        "\n",
        "# Set estimator options\n",
        "estimator_options = EstimatorOptions(resilience_level=1, default_shots=10_000)\n",
        "\n",
        "# Open a Quantum Compute session:\n",
        "\n",
        "with Session(backend=backend) as session:\n",
        "    estimator = Estimator(mode=session, options=estimator_options)\n",
        "    cost = cost_func_vqe(theta_list, isa_ansatz, isa_observable, estimator)\n",
        "\n",
        "session.close()\n",
        "print(cost)"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "95dc0e83-46ce-4839-91c3-af550aef9ddf",
      "metadata": {},
      "source": [
        "上記の2つの計算で得られた値は非常に似ていることに注意してほしい。 結果を向上させるテクニックについては、さらに後述する。\n",
        "\n"
      ]
    },
    {
      "attachments": {},
      "cell_type": "markdown",
      "id": "7f3951a3-47ad-4ddb-90a0-2218b1e11d15",
      "metadata": {},
      "source": [
        "<span id=\"example-mapping-to-non-physical-systems\" />\n",
        "\n",
        "### 非物理システムへの例示マッピング\n",
        "\n",
        "最大切断（max-cut）問題は、グラフの頂点を2つの互いに素な集合に分割し、その2つの集合間の辺の数を最大化する組み合わせ最適化問題である。 より形式的に言えば、無向グラフ $G=(V,E)$ （ $V$ を頂点の集合、 $E$ を辺の集合とする）において、最大切断問題とは、頂点を2つの互いに素な部分集合 $S$ と $T$ に分割し、一方の端点が $S$ にあり、もう一方の端点が $T$ にある辺の数を最大化するよう求める問題である。\n",
        "\n",
        "最大カット法は、クラスタリング、ネットワーク設計、相転移など、さまざまな問題の解決に応用することができます。 まずは問題グラフを作成することから始めましょう：\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 16,
      "id": "739ca7a0-fae3-4389-a8de-7ae93c13b9e1",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<Image src=\"/learning/images/courses/variational-algorithm-design/cost-functions/extracted-outputs/739ca7a0-fae3-4389-a8de-7ae93c13b9e1-0.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "metadata": {},
          "output_type": "display_data"
        }
      ],
      "source": [
        "import rustworkx as rx\n",
        "from rustworkx.visualization import mpl_draw\n",
        "\n",
        "n = 4\n",
        "G = rx.PyGraph()\n",
        "G.add_nodes_from(range(n))\n",
        "# The edge syntax is (start, end, weight)\n",
        "edges = [(0, 1, 1.0), (0, 2, 1.0), (0, 3, 1.0), (1, 2, 1.0), (2, 3, 1.0)]\n",
        "G.add_edges_from(edges)\n",
        "\n",
        "mpl_draw(\n",
        "    G, pos=rx.shell_layout(G), with_labels=True, edge_labels=str, node_color=\"#1192E8\"\n",
        ")"
      ]
    },
    {
      "attachments": {},
      "cell_type": "markdown",
      "id": "3246e173-b1a8-48c2-bce8-f80a1524bcfb",
      "metadata": {},
      "source": [
        "この問題は二項最適化問題として表現できる。 各ノード $0 \\leq i < n$、ここで $n$ はグラフのノード数（この場合 $n=4$ ）で、バイナリ変数 $x_i$ を考える。この変数は、ノード $i$ が $1$ とラベル付けするグループの1つであれば値 $1$ を持ち、 $0$ とラベル付けするもう1つのグループであれば値 $0$ を持つ。また、ノード $i$ からノード $j$ に向かう辺の重みを $w_{ij}$ （隣接行列 $w$ の要素 $(i,j)$ ）とする。グラフは無向グラフなので、 $w_{ij}=w_{ji}$。そうすると、我々の問題は次のコスト関数を最大化するものとして定式化できる：\n",
        "\n",
        "$$\n",
        "\\begin{aligned}\n",
        "C(\\vec{x})\n",
        "& =\\sum_{i,j=0}^n w_{ij} x_i(1-x_j)\\\\[1mm]\n",
        "\n",
        "& = \\sum_{i,j=0}^n w_{ij} x_i - \\sum_{i,j=0}^n w_{ij} x_ix_j\\\\[1mm]\n",
        "\n",
        "& = \\sum_{i,j=0}^n w_{ij} x_i - \\sum_{i=0}^n \\sum_{j=0}^i 2w_{ij} x_ix_j\n",
        "\\end{aligned}\n",
        "$$\n",
        "\n",
        "量子コンピュータでこの問題を解くために、コスト関数を観測可能なものの期待値として表現する。 しかし、Qiskitがネイティブに認める観測量はパウリ作用素で構成され、その固有値は $0$ と $1$ ではなく $1$ と $-1$ です。そのため、次のように変数を変更します：\n",
        "\n",
        "ここで $\\vec{x}=(x_0,x_1,\\cdots ,x_{n-1})$。隣接行列 $w$ を使えば、すべてのエッジの重みに簡単にアクセスできる。 これを用いてコスト関数を求める：\n",
        "\n",
        "$$\n",
        "z_i = 1-2x_i \\rightarrow x_i = \\frac{1-z_i}{2}\n",
        "$$\n",
        "\n",
        "ということを意味している：\n",
        "\n",
        "$$\n",
        "\\begin{array}{lcl} x_i=0 & \\rightarrow & z_i=1 \\\\ x_i=1 & \\rightarrow & z_i=-1.\\end{array}\n",
        "$$\n",
        "\n",
        "つまり、最大化したい新しいコスト関数は次のようになる：\n",
        "\n",
        "$$\n",
        "\\begin{aligned}\n",
        "C(\\vec{z})\n",
        "& = \\sum_{i,j=0}^n w_{ij} \\bigg(\\frac{1-z_i}{2}\\bigg)\\bigg(1-\\frac{1-z_j}{2}\\bigg)\\\\[1mm]\n",
        "\n",
        "& = \\sum_{i,j=0}^n \\frac{w_{ij}}{4} - \\sum_{i,j=0}^n \\frac{w_{ij}}{4} z_iz_j\\\\[1mm]\n",
        "\n",
        "& = \\sum_{i=0}^n \\sum_{j=0}^i \\frac{w_{ij}}{2} -  \\sum_{i=0}^n \\sum_{j=0}^i \\frac{w_{ij}}{2} z_iz_j\n",
        "\\end{aligned}\n",
        "$$\n",
        "\n",
        "さらに、量子コンピュータの自然な傾向として、極大値ではなく極小値（通常は最低エネルギー）を見つけるので、 $C(\\vec{z})$ を最大化するのではなく、最小化することになる：\n",
        "\n",
        "$$\n",
        "-C(\\vec{z}) =  \\sum_{i=0}^n \\sum_{j=0}^i \\frac{w_{ij}}{2} z_iz_j -  \\sum_{i=0}^n \\sum_{j=0}^i \\frac{w_{ij}}{2}\n",
        "$$\n",
        "\n",
        "さて、最小化すべきコスト関数があり、その変数は値 $-1$ と $1$ を持つことができるので、次のようにパウリ $Z$ と類推することができる：\n",
        "\n",
        "$$\n",
        "z_i \\equiv Z_i = \\overbrace{I}^{n-1}\\otimes ... \\otimes \\overbrace{Z}^{i} \\otimes ... \\otimes \\overbrace{I}^{0}\n",
        "$$\n",
        "\n",
        "言い換えれば、変数 $z_i$ は、量子ビット $i$ に作用する $Z$ ゲートと等価になる。さらに\n",
        "\n",
        "$$\n",
        "Z_i|x_{n-1}\\cdots x_0\\rangle = z_i|x_{n-1}\\cdots x_0\\rangle \\rightarrow \\langle x_{n-1}\\cdots x_0 |Z_i|x_{n-1}\\cdots x_0\\rangle = z_i\n",
        "$$\n",
        "\n",
        "となると、これから考えるのは観測値である：\n",
        "\n",
        "$$\n",
        "\\hat{H} = \\sum_{i=0}^n \\sum_{j=0}^i \\frac{w_{ij}}{2} Z_iZ_j\n",
        "$$\n",
        "\n",
        "これに独立項を後から加えることになる：\n",
        "\n",
        "$$\n",
        "\\texttt{offset} = - \\sum_{i=0}^n \\sum_{j=0}^i \\frac{w_{ij}}{2}\n",
        "$$\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "83c86ba1-8b9d-4222-bb7e-637e6f29e5cd",
      "metadata": {},
      "source": [
        "この演算子は、エッジで結ばれたノード上のZ演算子を持つ項の線形結合である（0番目の量子ビットが最も右にあることを思い出してほしい）： $IIZZ + IZIZ + IZZI + ZIIZ + ZZII$.いったん演算子が構築されれば、QAOAアルゴリズムのansatzは、Qiskit回路ライブラリの `QAOAAnsatz` 回路を使うことで簡単に構築できます。\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 17,
      "id": "29398315-3baf-4363-88fc-69b6438e4afa",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<Image src=\"/learning/images/courses/variational-algorithm-design/cost-functions/extracted-outputs/29398315-3baf-4363-88fc-69b6438e4afa-0.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "execution_count": 17,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "from qiskit.circuit.library import QAOAAnsatz\n",
        "from qiskit.quantum_info import SparsePauliOp\n",
        "\n",
        "hamiltonian = SparsePauliOp.from_list(\n",
        "    [(\"IIZZ\", 1), (\"IZIZ\", 1), (\"IZZI\", 1), (\"ZIIZ\", 1), (\"ZZII\", 1)]\n",
        ")\n",
        "\n",
        "\n",
        "ansatz = QAOAAnsatz(hamiltonian, reps=2)\n",
        "# Draw\n",
        "ansatz.decompose(reps=3).draw(\"mpl\")"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 18,
      "id": "91d02379-9da6-426b-a5f0-d1fb75a891ee",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "Offset: -2.5\n"
          ]
        }
      ],
      "source": [
        "# Sum the weights, and divide by 2\n",
        "\n",
        "offset = -sum(edge[2] for edge in edges) / 2\n",
        "print(f\"\"\"Offset: {offset}\"\"\")"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "84a98a08-00e4-4b05-a3f0-de29a7e73a60",
      "metadata": {},
      "source": [
        "IBM Quantum 推定器は、ハミルトニアンとパラメータ化されたアンザッツを直接受け取り、必要なエネルギーを返すため、QAOAインスタンスのコスト関数は非常に単純です：\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 19,
      "id": "73ac80dd-87cf-4a43-b19b-e89a4782a44a",
      "metadata": {},
      "outputs": [],
      "source": [
        "def cost_func(params, ansatz, hamiltonian, estimator):\n",
        "    \"\"\"Return estimate of energy from estimator\n",
        "\n",
        "    Parameters:\n",
        "        params (ndarray): Array of ansatz parameters\n",
        "        ansatz (QuantumCircuit): Parameterized ansatz circuit\n",
        "        hamiltonian (SparsePauliOp): Operator representation of Hamiltonian\n",
        "        estimator (Estimator): Estimator primitive instance\n",
        "\n",
        "    Returns:\n",
        "        float: Energy estimate\n",
        "    \"\"\"\n",
        "    pub = (ansatz, hamiltonian, params)\n",
        "    cost = estimator.run([pub]).result()[0].data.evs\n",
        "    #    cost = estimator.run(ansatz, hamiltonian, parameter_values=params).result().values[0]\n",
        "    return cost"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 20,
      "id": "fc6af87b-a838-43b8-96ce-0af790fe0172",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "1.473098768180865\n"
          ]
        }
      ],
      "source": [
        "import numpy as np\n",
        "\n",
        "x0 = 2 * np.pi * np.random.rand(ansatz.num_parameters)\n",
        "\n",
        "estimator = StatevectorEstimator()\n",
        "cost = cost_func_vqe(x0, ansatz, hamiltonian, estimator)\n",
        "print(cost)"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "389b7e86-cd61-4184-96c3-ae91b8ad59f5",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "1.1120776913677988\n"
          ]
        }
      ],
      "source": [
        "# Estimated usage: < 1 min, benchmarked at 6 seconds on ibm_osaka, 5-23-24\n",
        "# Load some necessary packages:\n",
        "\n",
        "from qiskit_ibm_runtime import QiskitRuntimeService\n",
        "from qiskit_ibm_runtime import Session, EstimatorV2 as Estimator\n",
        "\n",
        "# Select the least busy backend:\n",
        "\n",
        "backend = service.least_busy(\n",
        "    operational=True, min_num_qubits=ansatz.num_qubits, simulator=False\n",
        ")\n",
        "\n",
        "# Or get a specific backend:\n",
        "# backend = service.backend(\"ibm_brisbane\")\n",
        "\n",
        "# Use a pass manager to transpile the circuit and observable for the specific backend being used:\n",
        "\n",
        "pm = generate_preset_pass_manager(backend=backend, optimization_level=1)\n",
        "isa_ansatz = pm.run(ansatz)\n",
        "isa_hamiltonian = hamiltonian.apply_layout(layout=isa_ansatz.layout)\n",
        "\n",
        "# Set estimator options\n",
        "estimator_options = EstimatorOptions(resilience_level=1, default_shots=10_000)\n",
        "\n",
        "# Open a Quantum Compute session:\n",
        "\n",
        "with Session(backend=backend) as session:\n",
        "    estimator = Estimator(mode=session, options=estimator_options)\n",
        "    cost = cost_func_vqe(x0, isa_ansatz, isa_hamiltonian, estimator)\n",
        "\n",
        "# Close session after done\n",
        "session.close()\n",
        "print(cost)"
      ]
    },
    {
      "attachments": {},
      "cell_type": "markdown",
      "id": "16c94186-366c-4ac4-8745-4e7da283f8da",
      "metadata": {},
      "source": [
        "アプリケーションでこの例を再び取り上げ、オプティマイザを活用して探索空間を反復する方法を探ります。 一般的に言えば、これには以下が含まれる：\n",
        "\n",
        "* オプティマイザを活用して最適なパラメータを見つける\n",
        "* 最適なパラメータをアサッツに結合して固有値を求める\n",
        "* 固有値を問題定義に置き換える\n",
        "\n"
      ]
    },
    {
      "attachments": {},
      "cell_type": "markdown",
      "id": "d14d5800-24c1-4e4b-b692-9bdb9ef4440f",
      "metadata": {},
      "source": [
        "<span id=\"measurement-strategy-speed-versus-accuracy\" />\n",
        "\n",
        "## 測定戦略：速度対精度\n",
        "\n",
        "前述したように、私たちはノイズの多い量子コンピュータを*ブラックボックスのオラクルとして使って*います。ノイズは取得した値を非決定論的なものにし、ランダムな揺らぎをもたらします。 これは、量子の有用性を徐々に探求し、量子の優位性へと前進していく中で、私たちが取り組まなければならない一般的な問題である：\n",
        "\n",
        "![シミュレーション・コストが回路の複雑さによってどのように変化するかを示すグラフ。 古典的なコンピュータを使えば、指数関数的に成長する。 量子エラーの緩和を使えば、それが有利になるクロスオーバーがあるはずだ。 量子エラー訂正は、シミュレーション・コストをリニアに増加させることが可能であり、確実にアドバンテージにつながる。](https://quantum.cloud.ibm.com/learning/images/courses/variational-algorithm-design/cost-functions/cost-function-path-to-quantum-advantage.svg)\n",
        "\n",
        "IBM Quantum プリミティブのエラー抑制およびエラー緩和オプションを活用することで、ノイズに対処し、現在の量子コンピュータの有用性を最大限に引き出すことができます。\n",
        "\n"
      ]
    },
    {
      "attachments": {},
      "cell_type": "markdown",
      "id": "f23f0d82-d4f9-4485-aad3-cd2f8fd19b4f",
      "metadata": {
        "gloss": {
          "overhead": {
            "text": "Extra costs introduced by new techniques, relative to a base implementation.",
            "title": "Overhead"
          }
        }
      },
      "source": [
        "<span id=\"error-suppression\" />\n",
        "\n",
        "### エラー抑制\n",
        "\n",
        "[エラー抑制](/docs/guides/error-mitigation-and-suppression-techniques)とは、エラーを最小限に抑えるために、コンパイル時に回路を最適化および変換する手法を指します。 これは基本的なエラー処理の手法であり、通常、全体の実行時間に <DefinitionTooltip definition=\"基本的な実装に対して、新しい技術によってもたらされる余分なコスト。\">オーバーヘッド</DefinitionTooltip> 程度の処理オーバーヘッドが生じます。 このオーバーヘッドには、量子ハードウェア上で実行するために回路をトランスパイルする以下の処理が含まれます：\n",
        "\n",
        "* 量子システムで利用可能なネイティブゲートを使って回路を表現する\n",
        "* 仮想量子ビットを物理量子ビットにマッピングする\n",
        "* 接続要件に基づくSWAPの追加\n",
        "* 1Q と 2Q ゲートの最適化\n",
        "* アイドル量子ビットに動的デカップリングを追加してデコヒーレンスの影響を防ぐ。\n",
        "\n",
        "プリミティブでは、 `optimization_level` オプションを設定し、高度なトランスパイルオプションを選択することで、エラー抑制技術を使用することができます。 後のコースでは、結果を向上させるためのさまざまな回路構成方法について掘り下げていきますが、ほとんどの場合、 `optimization_level=3` を設定することをお勧めします。\n",
        "\n",
        "ここでは、単純な理想的動作をする回路例を見て、トランスパイルプロセスにおける最適化の増加の価値を可視化する。\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 24,
      "id": "9e0bf552-32b0-477e-9ac3-4ab643c30623",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<Image src=\"/learning/images/courses/variational-algorithm-design/cost-functions/extracted-outputs/9e0bf552-32b0-477e-9ac3-4ab643c30623-0.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "execution_count": 24,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "from qiskit.circuit import Parameter, QuantumCircuit\n",
        "from qiskit.quantum_info import SparsePauliOp\n",
        "\n",
        "theta = Parameter(\"theta\")\n",
        "\n",
        "qc = QuantumCircuit(2)\n",
        "qc.x(1)\n",
        "qc.h(0)\n",
        "qc.cp(theta, 0, 1)\n",
        "qc.h(0)\n",
        "observables = SparsePauliOp.from_list([(\"ZZ\", 1)])\n",
        "\n",
        "qc.draw(\"mpl\")"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "1c2b0408-e004-4a04-8aa5-cf519744082b",
      "metadata": {},
      "source": [
        "上記の回路は、 $[0,2\\pi]$ のような適切な区間に位相を挿入すれば、与えられた観測値の正弦波の期待値を得ることができる。\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 25,
      "id": "99b23f88-ddcb-45dc-a86d-3d48ff990319",
      "metadata": {},
      "outputs": [],
      "source": [
        "## Setup phases\n",
        "import numpy as np\n",
        "\n",
        "phases = np.linspace(0, 2 * np.pi, 50)\n",
        "\n",
        "# phases need to be expressed as a list of lists in order to work\n",
        "individual_phases = [[phase] for phase in phases]"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "ca040383-9c8c-4a38-8e40-bad1b26c6085",
      "metadata": {},
      "source": [
        "シミュレーターを使って、最適化されたトランスパレーションの有用性を示すことができる。 エラー緩和の有用性を実証するために、実際のハードウェアを使用することについては後述する。 QiskitRuntimeService、実際のバックエンド（この場合はibm\\_brisbane）を取得し、 AerSimulator、そのバックエンド（ノイズの挙動を含む）をシミュレートする。\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "6f0e6f32-02f7-471f-a9f3-f30d22f8cca4",
      "metadata": {},
      "outputs": [],
      "source": [
        "from qiskit_ibm_runtime import QiskitRuntimeService\n",
        "from qiskit_aer import AerSimulator\n",
        "\n",
        "# get a real backend from the runtime service\n",
        "service = QiskitRuntimeService()\n",
        "backend = service.backend(\"ibm_brisbane\")\n",
        "\n",
        "# generate a simulator that mimics the real quantum system with the latest calibration results\n",
        "backend_sim = AerSimulator.from_backend(backend)"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "38df43e8-b11e-4671-b8fb-7a2eb74f648a",
      "metadata": {},
      "source": [
        "これで、パスマネージャーを使用して、回路をバックエンドの「命令セットアーキテクチャ（ISA）」にトランスパイルすることができます。 これは、 IBM Quantum Compute Serviceにおける新しい要件です。バックエンドに送信されるすべての回路は、そのバックエンドのターゲットの制約に準拠している必要があります。つまり、バックエンドのISA（そのデバイスが理解・実行できる命令セット）に基づいて記述されている必要があります。 これらの目標制約は、デバイスのネイティブ基底ゲート、量子ビット間の接続性、および（該当する場合）パルスやその他の命令のタイミング仕様といった要因によって定義されます。\n",
        "\n",
        "今回のケースでは、最適化レベルを0に設定した場合と、3に設定した場合の2回行う。 毎回、Estimatorプリミティブを使用して、異なる位相の値における観測値の期待値を推定する。\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "4dc699cd-0bb4-4b48-adcc-0bbe99218a26",
      "metadata": {},
      "outputs": [],
      "source": [
        "# Import estimator and specify that we are using the simulated backend:\n",
        "\n",
        "from qiskit_ibm_runtime import EstimatorV2 as Estimator\n",
        "\n",
        "estimator = Estimator(mode=backend_sim)\n",
        "\n",
        "circuit = qc"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "7990eb62-879d-4beb-b452-f3d86b164d11",
      "metadata": {},
      "outputs": [],
      "source": [
        "# Use a pass manager to transpile the circuit and observable for the backend being simulated.\n",
        "# Start with no optimization:\n",
        "\n",
        "from qiskit.transpiler.preset_passmanagers import generate_preset_pass_manager\n",
        "\n",
        "pm = generate_preset_pass_manager(backend=backend_sim, optimization_level=0)\n",
        "isa_circuit = pm.run(circuit)\n",
        "isa_observables = observables.apply_layout(layout=isa_circuit.layout)\n",
        "\n",
        "noisy_exp_values = []\n",
        "pub = (isa_circuit, isa_observables, [individual_phases])\n",
        "cost = estimator.run([pub]).result()[0].data.evs\n",
        "noisy_exp_values = cost[0]\n",
        "\n",
        "# Repeat above steps, but now with optimization = 3:\n",
        "\n",
        "exp_values_with_opt_es = []\n",
        "pm = generate_preset_pass_manager(backend=backend_sim, optimization_level=3)\n",
        "isa_circuit = pm.run(circuit)\n",
        "isa_observables = observables.apply_layout(layout=isa_circuit.layout)\n",
        "\n",
        "pub = (isa_circuit, isa_observables, [individual_phases])\n",
        "cost = estimator.run([pub]).result()[0].data.evs\n",
        "exp_values_with_opt_es = cost[0]"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "0cc8d4ea-81ef-4146-b8ed-9c7edae72be3",
      "metadata": {},
      "source": [
        "最後に結果をプロットしてみると、最適化なしでも計算の精度はかなり良かったが、最適化をレベル3に上げることで確実に向上していることがわかる。 より深く、より複雑な回路では、最適化レベル0と3の差はより大きくなる可能性が高いことに注意されたい。 これは、おもちゃの模型として使われる非常に単純な回路である。\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 29,
      "id": "f3d3f805-f8d0-474d-9a88-2d1f164639b0",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<Image src=\"/learning/images/courses/variational-algorithm-design/cost-functions/extracted-outputs/f3d3f805-f8d0-474d-9a88-2d1f164639b0-0.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "metadata": {},
          "output_type": "display_data"
        }
      ],
      "source": [
        "import matplotlib.pyplot as plt\n",
        "\n",
        "plt.plot(phases, noisy_exp_values, \"o\", label=\"opt=0\")\n",
        "plt.plot(phases, exp_values_with_opt_es, \"o\", label=\"opt=3\")\n",
        "plt.plot(phases, 2 * np.sin(phases / 2) ** 2 - 1, label=\"ideal\")\n",
        "plt.ylabel(\"Expectation\")\n",
        "plt.legend()\n",
        "plt.show()"
      ]
    },
    {
      "attachments": {},
      "cell_type": "markdown",
      "id": "2394d082-2278-48cf-95b0-3363ed723ec1",
      "metadata": {
        "gloss": {
          "bias": {
            "text": "A systematic drift in the measured quantities, usually caused by errors.",
            "title": "Bias"
          }
        }
      },
      "source": [
        "<span id=\"error-mitigation\" />\n",
        "\n",
        "### エラー軽減\n",
        "\n",
        "[エラー緩和](/docs/guides/error-mitigation-and-suppression-techniques)とは、実行時にデバイスのノイズをモデル化することで、ユーザーが回路エラーを低減できるようにする手法を指します。 通常、これに伴い、モデルの学習に関連する量子事前処理のオーバーヘッドと、生成されたモデルを用いて生データの誤差を軽減するための古典的後処理のオーバーヘッドが発生する。\n",
        "\n",
        "IBM Quantum プリミティブの オプション `resilience_level` は、エラーに対する耐性をどの程度設定するかを指定します。 レベルが高いほど、量子サンプリングのオーバーヘッドにより処理時間は長くなりますが、より正確な結果が得られます。 レジリエンスレベルを使用することで、プリミティブクエリにエラー軽減を適用する際の、コストと精度のバランスを調整することができます。\n",
        "\n",
        "誤差を軽減する技術を導入する場合、結果の <DefinitionTooltip definition=\"通常は誤差によって引き起こされる、測定量の系統的なドリフト。\">バイアス</DefinitionTooltip>、以前の、軽減されていないバイアスに比べて減少することが期待される。 場合によっては、バイアスが消えることさえある。 しかし、これには代償が伴う。 推定量のバイアスを減らすと、統計的なばらつきが大きくなる（つまり分散が大きくなる）。 これは、バイアスを減らすために必要な以上のオーバーヘッドをもたらすので、デフォルトでは行われない。 以下の例のように、 options.executions.shots で回路あたりのショット数を調整することで、この動作に簡単にオプトインすることができる。\n",
        "\n",
        "![/var バイアスのトレードオフのように、分布が広がったり狭まったりすることを示す図。](https://quantum.cloud.ibm.com/learning/images/courses/variational-algorithm-design/cost-functions/cost-function-bias-variance-trade-off.svg)\n",
        "\n",
        "このコースでは、 IBM Quantum のプリミティブが実行できるエラー軽減機能を、詳細な実装内容に踏み込むことなく概観するために、これらのエラー軽減モデルについて大まかに解説します。\n",
        "\n",
        "<span id=\"twirled-readout-error-extinction-t-rex\" />\n",
        "\n",
        "### ツイールド読み出しエラー消去（T-REx）\n",
        "\n",
        "Twirled Readout Error Extinction（T-REx）は、量子測定の過程で発生するノイズを低減するために、パウリ・ツワーリングとして知られる技術を使用する。 このテクニックは、特定のノイズの形を想定していないため、非常に一般的で効果的である。\n",
        "\n",
        "全体のワークフロー\n",
        "\n",
        "1. ランダムなビット反転でゼロ状態のデータを取得（測定前のパウリX）\n",
        "2. ランダム化されたビット反転（測定前のパウリX）により、希望する（ノイズの多い）状態のデータを取得する\n",
        "3. 各データセットについて特殊関数を計算し、除算する。\n",
        "\n",
        " \n",
        "\n",
        "![T-REXの測定・校正回路図。](https://quantum.cloud.ibm.com/learning/images/courses/variational-algorithm-design/cost-functions/cost-function-trex-data-collection.svg)\n",
        "\n",
        "これは `options.resilience_level = 1` で設定できる。\n",
        "\n",
        "<span id=\"zero-noise-extrapolation\" />\n",
        "\n",
        "### ゼロノイズ外挿\n",
        "\n",
        "ゼロノイズ外挿（ZNE）は、まず目的の量子状態を準備する回路のノイズを増幅し、いくつかの異なるノイズレベルの測定値を得て、それらの測定値を用いてノイズのない結果を推測することで機能する。\n",
        "\n",
        "全体のワークフロー\n",
        "\n",
        "1. 複数のノイズファクターに対して回路ノイズを増幅\n",
        "2. すべてのノイズ増幅回路を動かす\n",
        "3. ゼロノイズ限界まで外挿する\n",
        "\n",
        " \n",
        "\n",
        "![ZNEのステップを示す図。 ノイズはさまざまな要因によって人為的に増幅される。 その後、ノイズがゼロのときの値を外挿する。](https://quantum.cloud.ibm.com/learning/images/courses/variational-algorithm-design/cost-functions/cost-function-zne-stages.svg)\n",
        "\n",
        "これは次のように設定 `options.resilience_level = 2`できます。 さまざまな `noise_factors`、 `noise_amplifiers`、および を検討することで `extrapolators`、これをさらに最適化することは可能ですが、これは本コースの範囲外となります。 [ここで説明している](/docs/guides/error-mitigation-and-suppression-techniques)これらのオプションを、ぜひ試してみてください。\n",
        "\n",
        "各手法には、それぞれ関連するオーバーヘッドがある。必要な量子計算の回数（時間）と結果の精度とのトレードオフである：\n",
        "\n",
        "$$\n",
        "\\begin{array}{c|c|c|c}\n",
        "  \\text{Methods} & R=1 \\text{, T-REx} & R=2 \\text{, ZNE} \\\\[1mm]\n",
        "  \\hline\n",
        "  \\text{Assumptions} & \\text{None} & \\text{Ability to scale noise} \\\\[1mm]\n",
        "  \\text{Qubit overhead} & 1 & 1 \\\\[1mm]\n",
        "  \\text{Sampling overhead} & 2 & N_{\\text{noise-factors}} \\\\[1mm]\n",
        "  \\text{Bias} & 0 & \\mathcal{O}(\\lambda^{N_{\\text{noise-factors}}}) \\\\[1mm]\n",
        "\\end{array}\n",
        "$$\n",
        "\n"
      ]
    },
    {
      "attachments": {},
      "cell_type": "markdown",
      "id": "8b46120f-5312-4450-bf51-13be198428fa",
      "metadata": {},
      "source": [
        "<span id=\"using-the-options-in-quantum-compute-for-mitigation-and-suppression\" />\n",
        "\n",
        "### Quantum Compute のオプションを活用したリスク軽減と抑制\n",
        "\n",
        "IBM Quantum Compute Service でエラーの軽減および抑制機能を使用しながら、期待値を計算する方法をご紹介します。 以前とまったく同じ回路と観測変数を活用できますが、今回は最適化レベルをレベル2に固定したまま、使用している*レジリエンス*やエラー軽減手法を調整します。 このエラー軽減処理は、最適化ループ全体を通じて複数回行われます。\n",
        "\n",
        "エラー緩和はシミュレーターでは利用できないので、この部分は実際のハードウェアで実行する。\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "57a6b723-6e73-4693-95bf-f0782a8eb854",
      "metadata": {},
      "outputs": [],
      "source": [
        "# Estimated usage: 8 minutes, benchmarked on an Eagle processor, 5-23-24\n",
        "\n",
        "from qiskit_ibm_runtime import QiskitRuntimeService\n",
        "from qiskit_ibm_runtime import (\n",
        "    Session,\n",
        "    EstimatorOptions,\n",
        "    EstimatorV2 as Estimator,\n",
        ")\n",
        "\n",
        "# We select the least busy backend\n",
        "\n",
        "# Select the least busy backend\n",
        "# backend = service.least_busy(\n",
        "#    operational=True, min_num_qubits=ansatz.num_qubits, simulator=False\n",
        "# )\n",
        "\n",
        "# Or use a specific backend\n",
        "backend = service.backend(\"ibm_brisbane\")\n",
        "\n",
        "# Initialize some variables to save the results from different runs:\n",
        "\n",
        "exp_values_with_em0_es = []\n",
        "exp_values_with_em1_es = []\n",
        "exp_values_with_em2_es = []\n",
        "\n",
        "# Use a pass manager to optimize the circuit and observables for the backend chosen:\n",
        "\n",
        "pm = generate_preset_pass_manager(backend=backend, optimization_level=2)\n",
        "isa_circuit = pm.run(circuit)\n",
        "isa_observables = observables.apply_layout(layout=isa_circuit.layout)\n",
        "\n",
        "# Open a session and run with no error mitigation:\n",
        "\n",
        "estimator_options = EstimatorOptions(resilience_level=0, default_shots=10_000)\n",
        "\n",
        "with Session(backend=backend) as session:\n",
        "    estimator = Estimator(mode=session, options=estimator_options)\n",
        "\n",
        "    pub = (isa_circuit, isa_observables, [individual_phases])\n",
        "    cost = estimator.run([pub]).result()[0].data.evs\n",
        "\n",
        "session.close()\n",
        "\n",
        "exp_values_with_em0_es = cost[0]\n",
        "\n",
        "# Open a session and run with resilience = 1:\n",
        "\n",
        "estimator_options = EstimatorOptions(resilience_level=1, default_shots=10_000)\n",
        "\n",
        "with Session(backend=backend) as session:\n",
        "    estimator = Estimator(mode=session, options=estimator_options)\n",
        "\n",
        "    pub = (isa_circuit, isa_observables, [individual_phases])\n",
        "    cost = estimator.run([pub]).result()[0].data.evs\n",
        "\n",
        "session.close()\n",
        "\n",
        "exp_values_with_em1_es = cost[0]\n",
        "\n",
        "# Open a session and run with resilience = 2:\n",
        "\n",
        "estimator_options = EstimatorOptions(resilience_level=2, default_shots=10_000)\n",
        "\n",
        "with Session(backend=backend) as session:\n",
        "    estimator = Estimator(mode=session, options=estimator_options)\n",
        "\n",
        "    pub = (isa_circuit, isa_observables, [individual_phases])\n",
        "    cost = estimator.run([pub]).result()[0].data.evs\n",
        "\n",
        "session.close()\n",
        "\n",
        "exp_values_with_em2_es = cost[0]"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "48215ea6-3045-4880-8671-265e2fb33e5e",
      "metadata": {},
      "source": [
        "前回と同様に、3段階の誤差軽減を行った場合の期待値を位相角の関数としてプロットすることができる。 非常に難しいことだが、エラーを軽減することで結果がわずかに改善されることがわかる。 この効果も、より深く複雑な回路ではより顕著になる。\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 93,
      "id": "474f1a1a-ee90-468d-9390-fdb455aeb142",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<Image src=\"/learning/images/courses/variational-algorithm-design/cost-functions/extracted-outputs/474f1a1a-ee90-468d-9390-fdb455aeb142-0.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "metadata": {},
          "output_type": "display_data"
        }
      ],
      "source": [
        "import matplotlib.pyplot as plt\n",
        "\n",
        "plt.plot(phases, exp_values_with_em0_es, \"o\", label=\"unmitigated\")\n",
        "plt.plot(phases, exp_values_with_em1_es, \"o\", label=\"resil = 1\")\n",
        "plt.plot(phases, exp_values_with_em2_es, \"o\", label=\"resil = 2\")\n",
        "plt.plot(phases, 2 * np.sin(phases / 2) ** 2 - 1, label=\"ideal\")\n",
        "plt.ylabel(\"Expectation\")\n",
        "plt.legend()\n",
        "plt.show()"
      ]
    },
    {
      "attachments": {},
      "cell_type": "markdown",
      "id": "1e683c07-96f3-47d5-8981-8d3aeb8be81f",
      "metadata": {},
      "source": [
        "<span id=\"summary\" />\n",
        "\n",
        "## サマリー\n",
        "\n",
        "このレッスンでは、コスト関数の作成方法を学びました：\n",
        "\n",
        "* コスト関数を作成する\n",
        "* IBM Quantum のプリミティブを活用してノイズを低減・抑制する方法\n",
        "* スピードと精度を最適化する測定戦略の立て方\n",
        "\n",
        "これがハイレベルな変分ワークロードだ：\n",
        "\n",
        "![参照状態と変分状態を準備するユニタリーを備えた量子回路を示す図。 これらはコスト関数の評価に使われる。](https://quantum.cloud.ibm.com/learning/images/courses/variational-algorithm-design/cost-functions/cost-function-circuit.svg)\n",
        "\n",
        "私たちのコスト関数は、最適化ループの各反復中に実行される。 次のレッスンでは、古典的なオプティマイザが、新しいパラメータを選択するために、コスト関数の評価をどのように利用するかを探ります。\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 9,
      "id": "2751c16d-a9c1-407b-ab88-a9dcf768bc2e",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "1.1.0\n",
            "0.23.0\n"
          ]
        }
      ],
      "source": [
        "import qiskit\n",
        "import qiskit_ibm_runtime\n",
        "\n",
        "print(qiskit.version.get_version_info())\n",
        "print(qiskit_ibm_runtime.version.get_version_info())"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "id": "a1b8767d",
      "source": "© IBM Corp., 2017-2026"
    }
  ],
  "metadata": {
    "kernelspec": {
      "display_name": "Python 3",
      "language": "python",
      "name": "python3"
    },
    "language_info": {
      "codemirror_mode": {
        "name": "ipython",
        "version": 3
      },
      "file_extension": ".py",
      "mimetype": "text/x-python",
      "name": "python",
      "nbconvert_exporter": "python",
      "pygments_lexer": "ipython3",
      "version": "3"
    }
  },
  "nbformat": 4,
  "nbformat_minor": 2
}