{
  "cells": [
    {
      "cell_type": "markdown",
      "id": "f502c3c3-d0be-4be4-afab-2d569f171f98",
      "metadata": {},
      "source": [
        "---\n",
        "title: \"ハミルトンズ\"\n",
        "description: \"量子化学アプリケーションのためのハミルトニアンの構築とマッピングについて概説する。 カスタムのJordan-Wignerマッパーを使用し、 PySCF を活用する。\"\n",
        "---\n",
        "\n",
        "{/* cspell:ignore pxxr prqs nelecas Lipinska mcscf chmax Dmax vmax ecore ncas Excp disp antisymmetry Coov irrep IIZZ ZZII workstreams openfermion webkitallowfullscreen allowfullscreen frameborder referrerpolicy Kassal Tranter Ardle Seeley */}\n",
        "\n",
        "<span id=\"hamiltonians-for-quantum-chemistry\" />\n",
        "\n",
        "# 量子化学のためのハミルトニアン\n",
        "\n",
        "まず、VQEにおいてハミルトニアンが果たす役割について簡単に説明しよう。\n",
        "\n",
        "<span id=\"the-hamiltonian-in-vqe-overview\" />\n",
        "\n",
        "## VQE のハミルトニアン概要\n",
        "\n",
        "ビクトリア・リピンスカ博士が、ハミルトニアンと、量子コンピューティングで使用するためのハミルトニアンのマッピング方法について解説する。\n",
        "\n",
        "<IBMVideo id=\"132414924\" title=\"ビクトリア・リピンスカは、ハミルトニアンとは何か、そしてVQEでどのように使われているのかを思い出させてくれる。 特に、区別できないフェルミオンのハミルトニアンを、量子ビットのハミルトニアンにマッピングする必要性について述べている。\" />\n",
        "\n",
        "<span id=\"references\" />\n",
        "\n",
        "### 参照\n",
        "\n",
        "上記のビデオでは以下の記事が参照されている。\n",
        "\n",
        "* [「フェルミオンシミュレーションのための量子アルゴリズム」、オルティスら](https://arxiv.org/pdf/cond-mat/0012334.pdf)\n",
        "* [量子コンピュータを用いた化学のシミュレーション、Kassalら](https://arxiv.org/pdf/1007.2648.pdf)\n",
        "* [「量子化学の量子シミュレーションにおけるブラヴィー・キタエフ変換とジョーダン・ウィグナー変換の比較」、トランター他](https://pubs.acs.org/doi/full/10.1021/acs.jctc.8b00450)\n",
        "* [『量子コンピューティング時代の量子化学』、Caoほか](https://arxiv.org/pdf/1812.09976.pdf)\n",
        "* [量子計算化学、 McArdle, ほか](https://arxiv.org/pdf/1808.10402.pdf)。\n",
        "* [電子構造の量子計算のためのブラヴィー・キタエフ変換、シーリーら](https://arxiv.org/pdf/1208.5986.pdf)。\n",
        "\n",
        "<span id=\"preparing-hamiltonians-for-quantum-chemistry\" />\n",
        "\n",
        "## 量子化学のためのハミルトニアンの準備\n",
        "\n",
        "量子コンピュータを化学の問題に応用するための最初のステップは、対象となる系のハミルトニアンを定義することである。 ここでは、量子化学のハミルトニアンに関する議論に限定する。ハミルトニアンは、同一のフェルミオン系に特有の写像を必要とするからである。\n",
        "\n",
        "量子化学の研究者であれば、分子をモデリングするためのお気に入りのソフトウェアをすでにお持ちで、目的の系を記述するハミルトニアンを生成できることだろう。 ここでは、 PySCF, numpyとQiskitのみで構築されたコードを使用する。 しかし、ハミルトニアンの調製プロセスは、パッケージ化された溶液にも適用される。 既存のワークフローとの統合を容易にするため、「サードパーティソフトウェア」のサブセクションでその一部を説明している。\n",
        "\n",
        "IBM Quantum® QPUで使用する量子化学ハミルトニアンの生成には、以下の手順が必要です：\n",
        "\n",
        "1. 分子を定義する（形状、スピン、活性空間など）\n",
        "2. フェルミオンのハミルトニアン（生成・消滅演算子）を生成する\n",
        "3. フェルミオンのハミルトニアンからボソニック作用素への写像（この文脈ではパウリ作用素を使う）\n",
        "4. サードパーティソフトウェアを使用する場合：生成ソフトウェアとQiskitの間の構文の不一致を処理する\n",
        "\n",
        "フェルミオンのハミルトニアンはフェルミオンの作用素で書かれ、特に電子が区別できないフェルミオンであることを考慮している。 つまり、区別可能なボソニック量子ビットとはまったく異なる統計に従うということだ。 それゆえ、マッピング・プロセスが必要なのだ。\n",
        "\n",
        "これらのプロセスをすでにご存知の方は、このセクションを読み飛ばしてもいいだろう。\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "28e3a254-be8c-4bca-a467-3a92d0ddb1ae",
      "metadata": {},
      "source": [
        "目標：\n",
        "\n",
        "最終的な目標は、次のような形のハミルトニアンを得ることである：\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 1,
      "id": "b802fd0d-40d5-45f1-9cdc-4ae4c5914d82",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "[(1, 'XX'), (1, 'YY'), (1, 'ZZ')]\n"
          ]
        }
      ],
      "source": [
        "H = [(1, \"XX\"), (1, \"YY\"), (1, \"ZZ\")]\n",
        "print(H)"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "dac88e28-2554-4370-90c8-06c4e1042255",
      "metadata": {},
      "source": [
        "それとも\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 2,
      "id": "3375bd43-b53d-479e-93f5-7ec37d9e6a34",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "SparsePauliOp(['XX', 'YY', 'ZZ'],\n",
            "              coeffs=[1.+0.j, 1.+0.j, 1.+0.j])\n"
          ]
        }
      ],
      "source": [
        "from qiskit.quantum_info import SparsePauliOp\n",
        "\n",
        "H = SparsePauliOp([\"XX\", \"YY\", \"ZZ\"], coeffs=[1.0 + 0.0j, 1.0 + 0.0j, 1.0 + 0.0j])\n",
        "print(H)"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "f92e93d1-270d-4c0c-a3bb-353b790222a7",
      "metadata": {},
      "source": [
        "まずはいくつかのパッケージをインポートすることから始めよう：\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 3,
      "id": "f8833e31-77e6-446b-9d3c-1e394fbe1661",
      "metadata": {},
      "outputs": [],
      "source": [
        "import numpy as np\n",
        "from pyscf import ao2mo, gto, mcscf, scf"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "88603887-e5bc-4905-b8e6-ee78b8473d7d",
      "metadata": {},
      "source": [
        "1. 分子を定義する\n",
        "\n",
        "ここでは対象分子の属性を指定する。 この例では、二原子水素を選びました（結果のハミルトニアンが表示するのに十分短いからです）。\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "2d55595c-45f2-4e90-a3d1-22b6ee51ccc6",
      "metadata": {},
      "source": [
        "Python を基盤とする「Simulations of Chemistry Framework」（ [PySCF](https://pyscf.org/) ）には、量子計算に適した分子ハミルトニアンを生成することなどに利用できる、幅広い電子構造モジュールが収録されています。 『 [PySCF クイックスタートガイド](https://pyscf.org/quickstart.html) 』は、すべての変数や機能について詳しく解説した、非常に役立つ資料です。 多くの方にとっては既にご存じのことかと思いますので、ここではごく簡単な概要のみをご紹介します。 これらについてより詳しく知りたい方は、 [PySCF](https://pyscf.org/) をご覧ください。\n",
        "要約すると：\n",
        "\n",
        "**距離は**二原子分子に使うこともできるし、単に各原子のデカルト座標を指定することもできる。 距離の単位はオングストローム。\n",
        "\n",
        "**gtoは**ガウシアンタイプの軌道を生成する。\n",
        "\n",
        "**basisとは**、分子軌道をモデル化するために使われる関数のこと。 ここで' sto-6g ' は一般的な最小基底で、6つのプリミティブなガウス軌道を用いてスレーター型軌道をフィッティングするために名付けられた。\n",
        "\n",
        "**spin** 不対電子の数を示す整数値 ( $2S$ と等しい)。ソフトウェアによっては多重度を代わりに使うものもあるので注意( $2S+1$ )。\n",
        "\n",
        "分子の**電荷**。\n",
        "\n",
        "**symmetry** - 分子の点対称グループ。文字列で指定するか、\"symmetry = True \"を設定することで自動的に検出される。 ここで \"Dooh \"は、同じ原子種を2つ持つ二原子分子に適した対称基である。\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 4,
      "id": "dc4d672b-e73a-4822-b158-b17736d9a197",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<pyscf.gto.mole.Mole at 0x7fc718f07610>"
            ]
          },
          "execution_count": 4,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "distance = 0.735\n",
        "a = distance / 2\n",
        "mol = gto.Mole()\n",
        "mol.build(\n",
        "    verbose=0,\n",
        "    atom=[\n",
        "        [\"H\", (0, 0, -a)],\n",
        "        [\"H\", (0, 0, a)],\n",
        "    ],\n",
        "    basis=\"sto-6g\",\n",
        "    spin=0,\n",
        "    charge=0,\n",
        "    symmetry=\"Dooh\",\n",
        ")"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "2da25c9c-f517-497d-8668-70629e817e3a",
      "metadata": {},
      "source": [
        "全エネルギー（電子エネルギーだけでなく核反発エネルギーも含む）、全電子軌道エネルギー、または電子軌道のある部分集合のエネルギー（相補的な部分集合は凍結）を記述できることに留意してほしい。 $\\text{H}_2$ の場合、以下の異なるエネルギーに注目し、全エネルギーから核反発エネルギーを差し引いたものが、実際には電子エネルギーになることに注意されたい：\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 5,
      "id": "a22e88c6-ef7d-4089-9461-28ed70ebae13",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "0.7199689944489797 -1.8455976628764188 -1.125628668427439 -1.8455976628764188\n"
          ]
        }
      ],
      "source": [
        "mf = scf.RHF(mol)\n",
        "mf.scf()\n",
        "\n",
        "print(\n",
        "    mf.energy_nuc(),\n",
        "    mf.energy_elec()[0],\n",
        "    mf.energy_tot(),\n",
        "    mf.energy_tot() - mol.energy_nuc(),\n",
        ")"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 6,
      "id": "7e1a23ba-d2ac-4961-8c29-8be7e1163c9e",
      "metadata": {},
      "outputs": [],
      "source": [
        "active_space = range(mol.nelectron // 2 - 1, mol.nelectron // 2 + 1)"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "5ee2e242-6508-4a0d-87a7-b7faa897f36d",
      "metadata": {},
      "source": [
        "2. フェルミオンのハミルトニアンを生成する\n",
        "\n",
        "**scfとは**、自己無撞着場法の広範な範囲を指す。\n",
        "\n",
        "**mfの** **rhf** = scf.RHF (mol)は、Restricted Hartree Fock計算を使用するソルバーである。 この核（以下E）は、核反発と分子軌道を含む全エネルギーである。\n",
        "\n",
        "**mcscfは**マルチ・コンフィギュレーション自己無撞着フィールド・パッケージである。\n",
        "\n",
        "**ao2mo** は原子軌道から分子軌道への変換である。\n",
        "\n",
        "また、以下の変数も使用する：\n",
        "\n",
        "**ncas** ：完全な活性空間の軌道数\n",
        "\n",
        "**nelecas** ：完全な活性空間の電子数\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 7,
      "id": "e58fe57a-8135-429d-bd53-2ad4f0a93806",
      "metadata": {},
      "outputs": [],
      "source": [
        "E1 = mf.kernel()\n",
        "mx = mcscf.CASCI(mf, ncas=2, nelecas=(1, 1))\n",
        "mo = mx.sort_mo(active_space, base=0)\n",
        "E2 = mx.kernel(mo)[:2]"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "d77b6abe-a0c3-467e-9551-14bdad6b0fd0",
      "metadata": {},
      "source": [
        "我々はハミルトニアンを求めており、これはしばしば電子コアのエネルギー（ecore、最小化には関与しない）、単電子演算子（ h1e ）、および2電子エネルギー（ h2e ）に分けられる。 以下の最後の2行に、これらが明示的に抜粋されている。\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 8,
      "id": "1025a53a-7414-47f3-9b78-10acb03615d4",
      "metadata": {},
      "outputs": [],
      "source": [
        "h1e, ecore = mx.get_h1eff()\n",
        "h2e = ao2mo.restore(1, mx.get_h2eff(), mx.ncas)"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "928d72cf-212f-4f85-9d81-a7ffb33d6db8",
      "metadata": {},
      "source": [
        "これらのハミルトニアンは現在、フェルミオンの（生成と消滅）作用素であり、（区別できない）フェルミオンの系に適用され、交換のもとでは反対称性を持つ。 この結果、区別可能な系やボソニック系とは異なる静力学が適用されることになる。 IBM Quantum QPUで計算を実行するには、エネルギーを記述するボソニック演算子が必要である。 このような写像の結果は、慣例的にパウリ作用素で書かれる。パウリ作用素はエルミートでユニタリーだからだ。 使えるマッピングはいくつかある。 最も単純なもののひとつに、Jordan Wigner変換がある。\n",
        "\n",
        "3. ハミルトニアンのマッピング\n",
        "\n",
        "化学的ハミルトニアンを量子コンピュータで実行するのに適したものにマッピングするためのツールはたくさんある。 ここでは、 PySCF, numpyとQiskitのみを使用して、Jordan Wignerマッピングを直接実装します。 他の解決策に関するシンタックスの考慮点については後述する。\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "f90c2756-8155-4417-89e9-f248ae76895c",
      "metadata": {},
      "source": [
        "コレスキー関数は、ハミルトニアンの2電子項の低ランク分解を得るのに役立つ。\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 9,
      "id": "af2deda9-75e3-464f-a4e3-489e00631e92",
      "metadata": {},
      "outputs": [],
      "source": [
        "def cholesky(V, eps):\n",
        "    # see https://arxiv.org/pdf/1711.02242.pdf section B2\n",
        "    # see https://arxiv.org/abs/1808.02625\n",
        "    # see https://arxiv.org/abs/2104.08957\n",
        "    no = V.shape[0]\n",
        "    chmax, ng = 20 * no, 0\n",
        "    W = V.reshape(no**2, no**2)\n",
        "    L = np.zeros((no**2, chmax))\n",
        "    Dmax = np.diagonal(W).copy()\n",
        "    nu_max = np.argmax(Dmax)\n",
        "    vmax = Dmax[nu_max]\n",
        "    while vmax > eps:\n",
        "        L[:, ng] = W[:, nu_max]\n",
        "        if ng > 0:\n",
        "            L[:, ng] -= np.dot(L[:, 0:ng], (L.T)[0:ng, nu_max])\n",
        "        L[:, ng] /= np.sqrt(vmax)\n",
        "        Dmax[: no**2] -= L[: no**2, ng] ** 2\n",
        "        ng += 1\n",
        "        nu_max = np.argmax(Dmax)\n",
        "        vmax = Dmax[nu_max]\n",
        "    L = L[:, :ng].reshape((no, no, ng))\n",
        "    print(\n",
        "        \"accuracy of Cholesky decomposition \",\n",
        "        np.abs(np.einsum(\"prg,qsg->prqs\", L, L) - V).max(),\n",
        "    )\n",
        "    return L, ng"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "a6fae700-aac9-445d-97f5-4274ede58428",
      "metadata": {},
      "source": [
        "関数 `identity` と `creators_destructors` は、フェルミオンのハミルトニアンにおける生成と消滅の作用素をパウリ作用素に置き換えている。 `creators_destructors` は、ヨルダン-ウィグナー写像を用いている。\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "b6c0a6a7-94e8-448d-b911-858bc79e6242",
      "metadata": {},
      "outputs": [],
      "source": [
        "def identity(n):\n",
        "    return SparsePauliOp.from_list([(\"I\" * n, 1)])\n",
        "\n",
        "\n",
        "def creators_destructors(n, mapping=\"jordan_wigner\"):\n",
        "    c_list = []\n",
        "    if mapping == \"jordan_wigner\":\n",
        "        for p in range(n):\n",
        "            if p == 0:\n",
        "                ell, r = \"I\" * (n - 1), \"\"\n",
        "            elif p == n - 1:\n",
        "                ell, r = \"\", \"Z\" * (n - 1)\n",
        "            else:\n",
        "                ell, r = \"I\" * (n - p - 1), \"Z\" * p\n",
        "            cp = SparsePauliOp.from_list([(ell + \"X\" + r, 0.5), (ell + \"Y\" + r, -0.5j)])\n",
        "            c_list.append(cp)\n",
        "    else:\n",
        "        raise ValueError(\"Unsupported mapping.\")\n",
        "    d_list = [cp.adjoint() for cp in c_list]\n",
        "    return c_list, d_list"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "04d51259-2188-4c62-9171-c78f74873dd8",
      "metadata": {},
      "source": [
        "最後に、 `build_hamiltonian` は、 `cholesky`、 `identity`、 `creators_destructors` 関数を用いて、量子コンピューター上で実行するのに適した最終的なハミルトニアンを作成する。\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 11,
      "id": "6eeb704d-202c-4c54-8f1a-a2d98f99342e",
      "metadata": {},
      "outputs": [],
      "source": [
        "def build_hamiltonian(ecore: float, h1e: np.ndarray, h2e: np.ndarray) -> SparsePauliOp:\n",
        "    ncas, _ = h1e.shape\n",
        "\n",
        "    C, D = creators_destructors(2 * ncas, mapping=\"jordan_wigner\")\n",
        "    Exc = []\n",
        "    for p in range(ncas):\n",
        "        Excp = [C[p] @ D[p] + C[ncas + p] @ D[ncas + p]]\n",
        "        for r in range(p + 1, ncas):\n",
        "            Excp.append(\n",
        "                C[p] @ D[r]\n",
        "                + C[ncas + p] @ D[ncas + r]\n",
        "                + C[r] @ D[p]\n",
        "                + C[ncas + r] @ D[ncas + p]\n",
        "            )\n",
        "        Exc.append(Excp)\n",
        "\n",
        "    # low-rank decomposition of the Hamiltonian\n",
        "    Lop, ng = cholesky(h2e, 1e-6)\n",
        "    t1e = h1e - 0.5 * np.einsum(\"pxxr->pr\", h2e)\n",
        "\n",
        "    H = ecore * identity(2 * ncas)\n",
        "    # one-body term\n",
        "    for p in range(ncas):\n",
        "        for r in range(p, ncas):\n",
        "            H += t1e[p, r] * Exc[p][r - p]\n",
        "    # two-body term\n",
        "    for g in range(ng):\n",
        "        Lg = 0 * identity(2 * ncas)\n",
        "        for p in range(ncas):\n",
        "            for r in range(p, ncas):\n",
        "                Lg += Lop[p, r, g] * Exc[p][r - p]\n",
        "        H += 0.5 * Lg @ Lg\n",
        "\n",
        "    return H.chop().simplify()"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "1912f38d-73ee-4d9f-a89b-a3f08b7f65a0",
      "metadata": {},
      "source": [
        "最後に、 `build_hamiltonian` 、Jordan-Wigner変換を用いてパウリ演算子から量子ビット・ハミルトニアンを構築する。 これは、我々が使用したコレスキー分解の精度も示している。\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 12,
      "id": "4e951f66-6632-4f07-973e-6c505a1b7a87",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "accuracy of Cholesky decomposition  2.220446049250313e-16\n",
            "SparsePauliOp(['IIII', 'IIIZ', 'IZII', 'IIZI', 'ZIII', 'IZIZ', 'IIZZ', 'ZIIZ', 'IZZI', 'ZZII', 'ZIZI', 'YYYY', 'XXYY', 'YYXX', 'XXXX'],\n",
            "              coeffs=[-0.09820182+0.j, -0.1740751 +0.j, -0.1740751 +0.j,  0.2242933 +0.j,\n",
            "  0.2242933 +0.j,  0.16891402+0.j,  0.1210099 +0.j,  0.16631441+0.j,\n",
            "  0.16631441+0.j,  0.1210099 +0.j,  0.17504456+0.j,  0.04530451+0.j,\n",
            "  0.04530451+0.j,  0.04530451+0.j,  0.04530451+0.j])\n"
          ]
        }
      ],
      "source": [
        "H = build_hamiltonian(ecore, h1e, h2e)\n",
        "print(H)"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "b211c7f6-7ef4-444d-84f9-bfe4b80dda5a",
      "metadata": {},
      "source": [
        "この[分子ノートブック例では](https://ibm.ent.box.com/public/static/59c2kjqefvjy5wy5lct099thr4y0ry8c.zip)、さまざまな複雑さの分子のセットアップとハミルトニアンを示しています。少し修正すれば、ほとんどの低分子を調べることができるでしょう。\n",
        "\n",
        "分子のフェルミオン作用素を構成する際に考慮すべき2つの重要なポイントについて簡単に触れておこう。 分子の種類が変われば、対称性も変わる。 同様に、円筒対称の\" A1 \"のように、様々な対称性を持つ軌道の数も変化する。 これらの変化は、ここにあるように LiH, ：\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 13,
      "id": "400658f1-ce74-460d-8bd6-f78c715982e1",
      "metadata": {},
      "outputs": [],
      "source": [
        "distance = 1.56\n",
        "mol = gto.Mole()\n",
        "mol.build(\n",
        "    verbose=0,\n",
        "    atom=[[\"Li\", (0, 0, 0)], [\"H\", (0, 0, distance)]],\n",
        "    basis=\"sto-6g\",\n",
        "    spin=0,\n",
        "    charge=0,\n",
        "    symmetry=\"Coov\",\n",
        ")\n",
        "mf = scf.RHF(mol)\n",
        "E1 = mf.kernel()\n",
        "\n",
        "# %% ----------------------------------------------------------------------------------------------\n",
        "\n",
        "mx = mcscf.CASCI(mf, ncas=5, nelecas=(1, 1))\n",
        "cas_space_symmetry = {\"A1\": 3, \"E1x\": 1, \"E1y\": 1}\n",
        "mo = mcscf.sort_mo_by_irrep(mx, mf.mo_coeff, cas_space_symmetry)\n",
        "E2 = mx.kernel(mo)[:2]\n",
        "h1e, ecore = mx.get_h1eff()\n",
        "h2e = ao2mo.restore(1, mx.get_h2eff(), mx.ncas)"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "a7c91a40-c0ee-47ab-a33f-9adfd9f2bd18",
      "metadata": {},
      "source": [
        "また、最終的に得られるハミルトニアンの直感をすぐに失ってしまうことも注目に値する。 LiH （ヨルダン・ウィグナー・マッパーを使用）のハミルトニアンは、すでに276項で構成されている。\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 14,
      "id": "d3269648-538e-41a5-b343-f75e3ffadb28",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "accuracy of Cholesky decomposition  1.1102230246251565e-16\n"
          ]
        },
        {
          "data": {
            "text/plain": [
              "276"
            ]
          },
          "execution_count": 14,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "len(build_hamiltonian(ecore, h1e, h2e))"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "aee74cff-d3b4-46db-b511-e4f9686b56de",
      "metadata": {},
      "source": [
        "対称性に疑問がある場合は、 `symmetry = True` と `verbose = 4` を設定することで、分子の対称性情報を生成することもできる：\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 15,
      "id": "29fa8e0b-9481-4ab6-841d-e2ba0a076986",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "System: uname_result(system='Linux', node='IBM-R912JTRT', release='5.10.102.1-microsoft-standard-WSL2', version='#1 SMP Wed Mar 2 00:30:59 UTC 2022', machine='x86_64')  Threads 16\n",
            "Python 3.11.12 (main, May 16 2025, 02:33:32) [GCC 11.4.0]\n",
            "numpy 2.3.1  scipy 1.16.0  h5py 3.14.0\n",
            "Date: Mon Jun 30 12:56:55 2025\n",
            "PySCF version 2.9.0\n",
            "PySCF path  /home/porter284/.pyenv/versions/3.11.12/lib/python3.11/site-packages/pyscf\n",
            "\n",
            "[CONFIG] conf_file None\n",
            "[INPUT] verbose = 4\n",
            "[INPUT] num. atoms = 2\n",
            "[INPUT] num. electrons = 4\n",
            "[INPUT] charge = 0\n",
            "[INPUT] spin (= nelec alpha-beta = 2S) = 0\n",
            "[INPUT] symmetry True subgroup None\n",
            "[INPUT] Mole.unit = angstrom\n",
            "[INPUT] Symbol           X                Y                Z      unit          X                Y                Z       unit  Magmom\n",
            "[INPUT]  1 Li     0.000000000000   0.000000000000   0.000000000000 AA    0.000000000000   0.000000000000   0.000000000000 Bohr   0.0\n",
            "[INPUT]  2 H      0.000000000000   0.000000000000   1.560000000000 AA    0.000000000000   0.000000000000   2.947972754321 Bohr   0.0\n",
            "\n",
            "nuclear repulsion = 1.01764848253846\n",
            "point group symmetry = Coov\n",
            "symmetry origin: [0.         0.         0.73699319]\n",
            "symmetry axis x: [1. 0. 0.]\n",
            "symmetry axis y: [0. 1. 0.]\n",
            "symmetry axis z: [0. 0. 1.]\n",
            "num. orbitals of irrep A1 = 4\n",
            "num. orbitals of irrep E1x = 1\n",
            "num. orbitals of irrep E1y = 1\n",
            "number of shells = 4\n",
            "number of NR pGTOs = 36\n",
            "number of NR cGTOs = 6\n",
            "basis = sto-6g\n",
            "ecp = {}\n",
            "CPU time:         9.85\n"
          ]
        },
        {
          "data": {
            "text/plain": [
              "<pyscf.gto.mole.Mole at 0x7fc719f94850>"
            ]
          },
          "execution_count": 15,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "distance = 1.56\n",
        "mol = gto.Mole()\n",
        "mol.build(\n",
        "    verbose=4,\n",
        "    atom=[[\"Li\", (0, 0, 0)], [\"H\", (0, 0, distance)]],\n",
        "    basis=\"sto-6g\",\n",
        "    spin=0,\n",
        "    charge=0,\n",
        "    symmetry=True,\n",
        ")"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "18c6b81d-cb14-479f-888c-3d598473d7da",
      "metadata": {},
      "source": [
        "他の有用な情報の中で、これは `point group symmetry = Coov` 、またそれぞれの既約表現における軌道の数を返す。\n",
        "\n",
        "```\n",
        "point group symmetry = Coov\n",
        "num. orbitals of irrep A1 = 4\n",
        "num. orbitals of irrep E1x = 1\n",
        "num. orbitals of irrep E1y = 1\n",
        "number of shells = 4\n",
        "```\n",
        "\n",
        "これは、必ずしもアクティブスペースに含ませたい軌道の数を教えてくれるわけではないが、どのような軌道が存在し、それらの対称性を確認するのに役立つ。\n",
        "\n",
        "対称性と軌道を指定することはしばしば役に立つが、含める軌道の数を指定することもできる。 エテンの場合を考えてみよう。 `verbose = 4` を使えば、様々な軌道の対称性を印刷することができる：\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 16,
      "id": "555442e7-e883-4465-9278-5312cd8d1fd0",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "System: uname_result(system='Linux', node='IBM-R912JTRT', release='5.10.102.1-microsoft-standard-WSL2', version='#1 SMP Wed Mar 2 00:30:59 UTC 2022', machine='x86_64')  Threads 16\n",
            "Python 3.11.12 (main, May 16 2025, 02:33:32) [GCC 11.4.0]\n",
            "numpy 2.3.1  scipy 1.16.0  h5py 3.14.0\n",
            "Date: Mon Jun 30 12:57:07 2025\n",
            "PySCF version 2.9.0\n",
            "PySCF path  /home/porter284/.pyenv/versions/3.11.12/lib/python3.11/site-packages/pyscf\n",
            "\n",
            "[CONFIG] conf_file None\n",
            "[INPUT] verbose = 4\n",
            "[INPUT] num. atoms = 6\n",
            "[INPUT] num. electrons = 16\n",
            "[INPUT] charge = 0\n",
            "[INPUT] spin (= nelec alpha-beta = 2S) = 0\n",
            "[INPUT] symmetry True subgroup None\n",
            "[INPUT] Mole.unit = angstrom\n",
            "[INPUT] Symbol           X                Y                Z      unit          X                Y                Z       unit  Magmom\n",
            "[INPUT]  1 C      0.000000000000   0.000000000000   1.000000000000 AA    0.000000000000   0.000000000000   1.889726124565 Bohr   0.0\n",
            "[INPUT]  2 C      0.000000000000   0.000000000000  -1.000000000000 AA    0.000000000000   0.000000000000  -1.889726124565 Bohr   0.0\n",
            "[INPUT]  3 H      0.000000000000   1.000000000000   1.000000000000 AA    0.000000000000   1.889726124565   1.889726124565 Bohr   0.0\n",
            "[INPUT]  4 H      0.000000000000  -1.000000000000   1.000000000000 AA    0.000000000000  -1.889726124565   1.889726124565 Bohr   0.0\n",
            "[INPUT]  5 H      0.000000000000   1.000000000000  -1.000000000000 AA    0.000000000000   1.889726124565  -1.889726124565 Bohr   0.0\n",
            "[INPUT]  6 H      0.000000000000  -1.000000000000  -1.000000000000 AA    0.000000000000  -1.889726124565  -1.889726124565 Bohr   0.0\n",
            "\n",
            "nuclear repulsion = 29.3377079104231\n",
            "point group symmetry = D2h\n",
            "symmetry origin: [0. 0. 0.]\n",
            "symmetry axis x: [0. 1. 0.]\n",
            "symmetry axis y: [1. 0. 0.]\n",
            "symmetry axis z: [-0. -0. -1.]\n",
            "num. orbitals of irrep Ag = 4\n",
            "num. orbitals of irrep B2g = 2\n",
            "num. orbitals of irrep B3g = 1\n",
            "num. orbitals of irrep B1u = 4\n",
            "num. orbitals of irrep B2u = 1\n",
            "num. orbitals of irrep B3u = 2\n",
            "number of shells = 10\n",
            "number of NR pGTOs = 84\n",
            "number of NR cGTOs = 14\n",
            "basis = sto-6g\n",
            "ecp = {}\n",
            "CPU time:         9.92\n"
          ]
        },
        {
          "data": {
            "text/plain": [
              "<pyscf.gto.mole.Mole at 0x7fc719fa9290>"
            ]
          },
          "execution_count": 16,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "# Replace these variables with correct distances:\n",
        "a = 1\n",
        "b = 1\n",
        "c = 1\n",
        "\n",
        "# Build\n",
        "mol = gto.Mole()\n",
        "mol.build(\n",
        "    verbose=4,\n",
        "    atom=[\n",
        "        [\"C\", (0, 0, a)],\n",
        "        [\"C\", (0, 0, -a)],\n",
        "        [\"H\", (0, c, b)],\n",
        "        [\"H\", (0, -c, b)],\n",
        "        [\"H\", (0, c, -b)],\n",
        "        [\"H\", (0, -c, -b)],\n",
        "    ],\n",
        "    basis=\"sto-6g\",\n",
        "    spin=0,\n",
        "    charge=0,\n",
        "    symmetry=True,\n",
        ")"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "7bd49628-dab3-4a1d-800b-32bc107cf242",
      "metadata": {},
      "source": [
        "となる：\n",
        "\n",
        "イレップの軌道数 Ag = 4\n",
        "\n",
        "イレップの軌道数 B2g = 2\n",
        "\n",
        "イレップの軌道数 B3g = 1\n",
        "\n",
        "イレップの軌道数 B1u = 4\n",
        "\n",
        "イレップの軌道数 B2u = 1\n",
        "\n",
        "イレップの軌道数 B3u = 2\n",
        "\n",
        "しかし、対称性によってすべての軌道を指定するのではなく、単純にこう書くことができる：\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 17,
      "id": "55448849-e0a0-489b-9edb-86bad0dad75b",
      "metadata": {},
      "outputs": [],
      "source": [
        "active_space = range(mol.nelectron // 2 - 2, mol.nelectron // 2 + 2)"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "160aa2e7-2d7e-4de9-8069-7acdd9f824e2",
      "metadata": {},
      "source": [
        "このアプローチでは、充填準位に近い複数の軌道（原子価軌道と非占有軌道）を取る。 ここでは、5つの軌道が活性空間に含まれるように選択されている（6番目から10番目）。\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 18,
      "id": "e8b42f17-9d8a-4564-8c6c-b1d0130690fb",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "6 10\n"
          ]
        }
      ],
      "source": [
        "print(\n",
        "    mol.nelectron // 2 - 2,\n",
        "    mol.nelectron // 2 + 2,\n",
        ")"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "0b5b7cc0-0520-4626-8ffb-684f9154cb1c",
      "metadata": {},
      "source": [
        "4. サード・パーティー・ソフトウェア\n",
        "\n",
        "量子化学用に開発されたソフトウェアパッケージはいくつかあり、複数のマッパーやアクティブスペースを制限するツールを提供しているものもある。 上記の手順は一般的なものであり、サードパーティのソフトウェアにも適用されます。 しかし、この他のソフトウェアはQiskitが受け付けない形式のハミルトニアンを返すかもしれません。 例えば、ハミルトニアンを返すソフトウェアもある：\n",
        "\n",
        "`H = -0.042 [] + -0.045 [X0 X1 Y2 Y3] + ... + 0.178 [Z0] + ... + 0.176 [Z2 Z3] + -0.243 [Z3]`\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "8fa9546f-1cb2-4e4d-816f-8ee630b7e133",
      "metadata": {},
      "source": [
        "特に、ゲートに番号が振られていることと、同一性演算子が示されていないことに注意されたい。 これはQiskitで使われているハミルトニアンとは対照的で、 `ZZII` （量子ビット0と1は同一作用素によって、量子ビット2と3はZ作用素によって作用され、量子ビット0が最も右側に来るように並べられている）として `[Z2 Z3]` 。\n",
        "\n",
        "既存のワークストリームに対応するため、以下のコードブロックは一方の構文から他方の構文に変換する。 関数 `convert_openfermion_to_qiskit` は、 OpenFermion またはTangeloで生成されたハミルトニアン（および利用可能なマッパーを使用してすでにパウリ演算子にマッピングされている）、および分子に必要な量子ビット数を引数にとります。\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 19,
      "id": "435e8271-b48e-4e89-9166-91c9cc6f4563",
      "metadata": {},
      "outputs": [],
      "source": [
        "from openfermion import QubitOperator\n",
        "from qiskit.quantum_info import SparsePauliOp\n",
        "\n",
        "\n",
        "def convert_openfermion_to_qiskit(\n",
        "    openfermion_operator: QubitOperator, num_qubits: int\n",
        ") -> SparsePauliOp:\n",
        "    terms = openfermion_operator.terms\n",
        "\n",
        "    labels = []\n",
        "    coefficients = []\n",
        "\n",
        "    for term, constant in terms.items():\n",
        "        # Default set to identity\n",
        "        operator = list(\"I\" * num_qubits)\n",
        "\n",
        "        # Iterate through PauliSum and replace I with Pauli\n",
        "        for index, pauli in term:\n",
        "            operator[index] = pauli\n",
        "        label = \"\".join(operator)\n",
        "        labels.append(label)\n",
        "        coefficients.append(constant)\n",
        "\n",
        "    return SparsePauliOp(labels, coefficients)"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "0fe58207-451d-4bfa-8f2d-8969b1a48cfa",
      "metadata": {},
      "source": [
        "さらに、 [この Python ノートブックには](https://ibm.ent.box.com/s/fh3xele1e7k0nrgd1imivvq52hy3wz9c)、上記の変換を含め、ハミルトニアンを他のソフトウェアワークフローからQiskitに移行するための完全なサンプルコードが含まれています。\n",
        "\n",
        "これで、 IBM® 量子コンピュータで量子化学計算を行うために必要なハミルトニアンを得るためのツールが揃ったことになる。\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"
    }
  },
  "nbformat": 4,
  "nbformat_minor": 2
}