{
  "cells": [
    {
      "cell_type": "markdown",
      "id": "frontmatter",
      "metadata": {},
      "source": [
        "---\n",
        "title: \"Comprendre les options « à couche ouverte » et « à couche fermée », ainsi que leur incidence sur la construction des sous-espaces\"\n",
        "description: \"Comprendre les options « à couche ouverte » et « à couche fermée », ainsi que leur incidence sur la construction des sous-espaces dans la dernière version de la méthode de diagonalisation quantique basée sur des échantillons (SQD)\"\n",
        "---\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "72420c62-2716-4f64-ad5b-73394b481cc1",
      "metadata": {},
      "source": [
        "<span id=\"understand-open-shell-versus-closed-shell-options-and-the-effect-on-subspace-construction\" />\n",
        "\n",
        "# Comprendre les options « à couche ouverte » et « à couche fermée », ainsi que leur incidence sur la construction des sous-espaces\n",
        "\n",
        "Dans ce guide, nous allons vous montrer comment choisir les dimensions du sous-espace dans le `qiskit_addon_sqd` package afin de post-traiter des échantillons quantiques à l'aide de [la technique de récupération de configuration auto-cohérente](https://arxiv.org/abs/2405.05068).\n",
        "\n",
        "Mais surtout, ce guide met également en évidence certaines différences de comportement dans la construction du sous-espace lorsque l'on utilise les `open_shell = False` modes ou `open_shell = True` :\n",
        "\n",
        "* `open_shell = False` ne fonctionne que lorsque le nombre d'électrons en phase de montée en vitesse et en phase de ralentissement est identique.\n",
        "\n",
        "* `open_shell = True` doit être utilisé lorsque le nombre d'électrons en phase d'accélération et de décélération est différent. On peut également l'utiliser lorsque le nombre d'électrons en phase d'accélération et de décélération est identique. Toutefois, dans ce dernier cas, il existe une différence entre les dimensions des sous-espaces générés par `open_shell = False` et `open_shell = True`, comme l'explique ce guide.\n",
        "\n",
        "**REMARQUE :** Certaines des manipulations de configuration électronique (chaîne de bits) effectuées dans ce progiciel ont pour objectif de préserver la symétrie de spin totale $S^2$. Les solveurs standard d’interaction de configuration sélectionnée (SCI) ne permettent pas d’imposer exactement la conservation de l’ $S^2$. Par conséquent, ils procèdent approximativement à l'aide d'un multiplicateur de Lagrange.\n",
        "\n",
        "Le choix des configurations électroniques introduites dans le solveur d'états propres peut également avoir une forte incidence sur la conservation du spin. Par exemple, dans un système (à 2 électrons, 2 orbitales), on peut échantillonner la configuration $|1001\\rangle$ (présentant une seule excitation de spin vers le haut par rapport à l’état RHF $|0101\\rangle$ ), qui est une combinaison linéaire des états singulet et triplet à couche ouverte, respectivement $(|1001\\rangle ± |0110\\rangle) /\\sqrt{2}$. Si la configuration |0110⟩ n’est pas échantillonnée, il n’est possible de construire aucune fonction propre du spin total, ce qui entraîne une contamination ou une redondance de spin (la configuration |1001⟩ est impliquée dans un calcul CI, mais son coefficient est égal à 0 dans le vecteur CI). Étant donné qu’un seul échantillon $|1001\\rangle$ est généré dans l’ordinateur quantique, voici comment le `sqd` module gère cette situation :\n",
        "\n",
        "* `open_shell = False`:\n",
        "\n",
        "  1. La chaîne de bits « $1001$ » est divisée en deux parties, représentant respectivement les configurations « spin-up » et « spin-down » : $10$ (up) et $01$ (down).\n",
        "\n",
        "  2. La liste des configurations uniques à polarisation de spin a été établie : $\\mathcal{U} = [01, 10]$.\n",
        "\n",
        "  3. Nous examinons ensuite toutes les combinaisons possibles d'éléments d' $\\mathcal{U}$ s pour former la base : $\\left \\{ |0101\\rangle, |0110\\rangle , |1001\\rangle , |1010\\rangle \\right \\}$, qui contient les états singulet et triplet.\n",
        "\n",
        "* `open_shell = True`:\n",
        "\n",
        "  1. Contrairement à ce qui se passe `open_shell = False` dans ce cas, nous ne combinons pas les deux moitiés de la chaîne de bits pour former la base.\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "a6755afb-ca1e-4473-974b-ba89acc8abce",
      "metadata": {},
      "source": [
        "<span id=\"closed-shell\" />\n",
        "\n",
        "### À coque fermée\n",
        "\n",
        "Cet exemple montre comment les chaînes de bits sont manipulées dans un système (à 2 électrons et 4 orbitales).\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 1,
      "id": "677f54ac-b4ed-47e3-b5ba-5366d3a520f9",
      "metadata": {},
      "outputs": [],
      "source": [
        "# Specify molecule properties\n",
        "num_orbitals = 4\n",
        "num_elec_a = num_elec_b = 1\n",
        "open_shell = False"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "c58e988c-a109-44cd-a975-9df43250c318",
      "metadata": {},
      "source": [
        "Définissez manuellement un dictionnaire de résultats de mesure :\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 2,
      "id": "e9506e0b-ed64-48bb-a97a-ef851b604af1",
      "metadata": {},
      "outputs": [],
      "source": [
        "counts_dict = {\n",
        "    \"00010010\": 1 / 2.0 - 0.01,\n",
        "    \"01001000\": 1 / 2.0 - 0.01,\n",
        "    \"00010001\": 0.02,\n",
        "}"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "851bc98e-9c08-4e78-9472-36301abc11d8",
      "metadata": {},
      "source": [
        "Convertissez les nombres d'occurrences `dict` en une matrice de chaînes de bits et en un tableau de probabilités en vue du post-traitement :\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 3,
      "id": "7a102a7f-aae6-4583-ab82-ae40fcb5496a",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "[[False False False  True False False  True False]\n",
            " [False  True False False  True False False False]\n",
            " [False False False  True False False False  True]]\n",
            "[0.49 0.49 0.02]\n"
          ]
        }
      ],
      "source": [
        "from qiskit_addon_sqd.counts import counts_to_arrays\n",
        "\n",
        "# Convert counts into bitstring and probability arrays\n",
        "bitstring_matrix_full, probs_arr_full = counts_to_arrays(counts_dict)\n",
        "print(bitstring_matrix_full)\n",
        "print(probs_arr_full)"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "eb704101-0fe8-4d12-b572-b1d844e35a90",
      "metadata": {},
      "source": [
        "Prélever un sous-échantillon d'un seul lot de taille deux :\n",
        "\n",
        "* `n_batches = 1`: Nombre de lots de configurations utilisés par les différents appels au solveur d'états propres\n",
        "* `samples_per_batch = 2`: Nombre de configurations uniques à inclure dans chaque lot\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 4,
      "id": "fe60aee2",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "[[False False False  True False False  True False]\n",
            " [False  True False False  True False False False]]\n"
          ]
        }
      ],
      "source": [
        "from qiskit_addon_sqd.subsampling import postselect_and_subsample\n",
        "\n",
        "n_batches = 1\n",
        "samples_per_batch = 2\n",
        "\n",
        "# seed for random number generator\n",
        "rand_seed = 48\n",
        "\n",
        "# Generate the batches\n",
        "batches = postselect_and_subsample(\n",
        "    bitstring_matrix_full,\n",
        "    probs_arr_full,\n",
        "    hamming_right=num_elec_a,\n",
        "    hamming_left=num_elec_b,\n",
        "    samples_per_batch=samples_per_batch,\n",
        "    num_batches=n_batches,\n",
        "    rand_seed=rand_seed,\n",
        ")\n",
        "\n",
        "print(batches[0])"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "93a6d05a",
      "metadata": {},
      "source": [
        "Obtenir la représentation décimale des chaînes de bits « spin-up » et « spin-down » utilisées par le solveur d'états propres.\n",
        "\n",
        "Le premier élément du tuple correspond à la représentation décimale des configurations de spin vers le haut, tandis que le deuxième élément du tuple correspond à la représentation décimale des configurations de spin vers le bas :\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 5,
      "id": "ef90e039",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "(array([1, 2, 4, 8], dtype=int64), array([1, 2, 4, 8], dtype=int64))\n"
          ]
        }
      ],
      "source": [
        "from qiskit_addon_sqd.fermion import bitstring_matrix_to_ci_strs\n",
        "\n",
        "ci_strs = bitstring_matrix_to_ci_strs(batches[0], open_shell=open_shell)\n",
        "print(ci_strs)"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "70d7883c",
      "metadata": {},
      "source": [
        "Il convient de noter que, bien que le nombre d'échantillons par lot soit de deux et que les chaînes de bits échantillonnées soient : $00010010$ et $01001000$, quatre configurations électroniques sont générées par espèce de spin. Dans ce cas, l'ensemble des configurations uniques à polarisation de spin est donné par :\n",
        "\n",
        "$$\n",
        "\\mathcal{U} = \\{ 0001, 0010, 0100, 1000 \\}\n",
        "$$\n",
        "\n",
        "dont la représentation décimale base-10 est\n",
        "\n",
        "$$\n",
        "\\mathcal{U}_{10} = \\{ 1, 2, 4, 8 \\}\n",
        "$$\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "03b32ed5",
      "metadata": {},
      "source": [
        "Base du sous-espace :\n",
        "\n",
        "Le solveur d'états propres prend en compte toutes les paires possibles de chaînes de bits « spin-up » et « spin-down » pour construire la base $\\mathcal{B}$ du sous-espace :\n",
        "\n",
        "* Élément 1 : $|00010001\\rangle$\n",
        "\n",
        "* Élément 2 : $|00010010\\rangle$\n",
        "\n",
        "* Élément 3 : $|00010100\\rangle$\n",
        "\n",
        "* Élément 4 : $|00011000\\rangle$\n",
        "\n",
        "* Élément 5 : $|00100001\\rangle$\n",
        "\n",
        "* Élément 6 : $|00100010\\rangle$\n",
        "\n",
        "* Élément 7 : $|00100100\\rangle$\n",
        "\n",
        "* Élément 8 : $|00101000\\rangle$\n",
        "\n",
        "* Élément 9 : $|01000001\\rangle$\n",
        "\n",
        "* Élément 10 : $|01000010\\rangle$\n",
        "\n",
        "* Élément 11 : $|01000100\\rangle$\n",
        "\n",
        "* Élément 12 : $|01001000\\rangle$\n",
        "\n",
        "* Élément 13 : $|10000001\\rangle$\n",
        "\n",
        "* Élément 14 : $|10000010\\rangle$\n",
        "\n",
        "* Élément 15 : $|10000100\\rangle$\n",
        "\n",
        "* Élément 16 : $|10001000\\rangle$\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 6,
      "id": "11c924ee",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "Basis elements of the subspace:\n",
            "|00010001>\n",
            "|00010010>\n",
            "|00010100>\n",
            "|00011000>\n",
            "|00100001>\n",
            "|00100010>\n",
            "|00100100>\n",
            "|00101000>\n",
            "|01000001>\n",
            "|01000010>\n",
            "|01000100>\n",
            "|01001000>\n",
            "|10000001>\n",
            "|10000010>\n",
            "|10000100>\n",
            "|10001000>\n"
          ]
        }
      ],
      "source": [
        "ci_strs_up, ci_strs_dn = ci_strs\n",
        "\n",
        "print(\"Basis elements of the subspace:\")\n",
        "\n",
        "for ci_str_up in ci_strs_up:\n",
        "    for ci_str_dn in ci_strs_dn:\n",
        "        format_name = \"{0:0\" + str(num_orbitals) + \"b}\"\n",
        "        print(\n",
        "            \"|\"\n",
        "            + format_name.format(ci_str_up)\n",
        "            + format_name.format(ci_str_dn)\n",
        "            + \">\"\n",
        "        )"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "aa43a4fc",
      "metadata": {},
      "source": [
        "**La dimension du sous-espace est bornée supérieurement par** : $2 \\cdot$ (`samples_per_batch`) $^2$.\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "9412e52b",
      "metadata": {},
      "source": [
        "<span id=\"open-shell\" />\n",
        "\n",
        "### À coque ouverte\n",
        "\n",
        "Cet exemple montre comment les chaînes de bits sont manipulées dans un système (à 2 électrons et 4 orbitales).\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 7,
      "id": "9b515b8a",
      "metadata": {},
      "outputs": [],
      "source": [
        "# Specify molecule properties\n",
        "num_orbitals = 4\n",
        "num_elec_a = num_elec_b = 1\n",
        "open_shell = True"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "9ef78560",
      "metadata": {},
      "source": [
        "Définissez manuellement un dictionnaire de résultats de mesure :\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 8,
      "id": "06b2185a",
      "metadata": {},
      "outputs": [],
      "source": [
        "counts_dict = {\n",
        "    \"00010010\": 1 / 2.0 - 0.01,\n",
        "    \"01001000\": 1 / 2.0 - 0.01,\n",
        "    \"00010001\": 0.02,\n",
        "}"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "08b32957",
      "metadata": {},
      "source": [
        "Convertissez les nombres d'occurrences `dict` en une matrice de chaînes de bits et en un tableau de probabilités en vue du post-traitement :\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 9,
      "id": "90561893",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "[[False False False  True False False  True False]\n",
            " [False  True False False  True False False False]\n",
            " [False False False  True False False False  True]]\n",
            "[0.49 0.49 0.02]\n"
          ]
        }
      ],
      "source": [
        "# Convert counts into bitstring and probability arrays\n",
        "bitstring_matrix_full, probs_arr_full = counts_to_arrays(counts_dict)\n",
        "print(bitstring_matrix_full)\n",
        "print(probs_arr_full)"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "416bfb6c",
      "metadata": {},
      "source": [
        "Prélever un sous-échantillon d'un seul lot de taille deux :\n",
        "\n",
        "* `n_batches = 1`: Nombre de lots de configurations utilisés par les différents appels au solveur d'états propres\n",
        "* `samples_per_batch = 2`: Nombre de configurations uniques à inclure dans chaque lot\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 10,
      "id": "cf4fe11d",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "[[False False False  True False False  True False]\n",
            " [False  True False False  True False False False]]\n"
          ]
        }
      ],
      "source": [
        "n_batches = 1\n",
        "samples_per_batch = 2\n",
        "\n",
        "# seed for random number generator\n",
        "rand_seed = 48\n",
        "\n",
        "# Generate the batches\n",
        "batches = postselect_and_subsample(\n",
        "    bitstring_matrix_full,\n",
        "    probs_arr_full,\n",
        "    hamming_right=num_elec_a,\n",
        "    hamming_left=num_elec_b,\n",
        "    samples_per_batch=samples_per_batch,\n",
        "    num_batches=n_batches,\n",
        "    rand_seed=rand_seed,\n",
        ")\n",
        "\n",
        "print(batches[0])"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "54d699ca",
      "metadata": {},
      "source": [
        "Obtenir la représentation décimale des chaînes de bits « spin-up » et « spin-down » utilisées par le solveur d'états propres.\n",
        "\n",
        "Le premier élément du tuple correspond à la représentation décimale des configurations de spin vers le haut, tandis que le deuxième élément du tuple correspond à la représentation décimale des configurations de spin vers le bas :\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 11,
      "id": "b40b049b",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "(array([2, 8], dtype=int64), array([1, 4], dtype=int64))\n"
          ]
        }
      ],
      "source": [
        "ci_strs = bitstring_matrix_to_ci_strs(batches[0], open_shell=open_shell)\n",
        "print(ci_strs)"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "28921e56",
      "metadata": {},
      "source": [
        "Si l'on spécifie que `open_shell = True`, on n'inclut pas toutes les demi-chaînes de bits uniques en tant que configurations « spin-up » et « spin-down », ce qui donne une base plus restreinte que lorsque l'on spécifie `open_shell = False`.\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "e1959b72",
      "metadata": {},
      "source": [
        "Base du sous-espace :\n",
        "\n",
        "Le solveur d'états propres prend en compte toutes les paires possibles de chaînes de bits « spin-up » et « spin-down » pour construire la base $\\mathcal{B}$ du sous-espace :\n",
        "\n",
        "* Élément 1 : $|00010010\\rangle$\n",
        "\n",
        "* Élément 2 : $|00011000\\rangle$\n",
        "\n",
        "* Élément 3 : $|01000010\\rangle$\n",
        "\n",
        "* Élément 4 : $|01001000\\rangle$\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 12,
      "id": "a550aba2",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "Basis elements of the subspace:\n",
            "|00100001>\n",
            "|00100100>\n",
            "|10000001>\n",
            "|10000100>\n"
          ]
        }
      ],
      "source": [
        "ci_strs_up, ci_strs_dn = ci_strs\n",
        "\n",
        "print(\"Basis elements of the subspace:\")\n",
        "\n",
        "for ci_str_up in ci_strs_up:\n",
        "    for ci_str_dn in ci_strs_dn:\n",
        "        format_name = \"{0:0\" + str(num_orbitals) + \"b}\"\n",
        "        print(\n",
        "            \"|\"\n",
        "            + format_name.format(ci_str_up)\n",
        "            + format_name.format(ci_str_dn)\n",
        "            + \">\"\n",
        "        )"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "7317bc49",
      "metadata": {},
      "source": [
        "**La dimension du sous-espace est bornée supérieurement par** : (`samples_per_batch`) $^2$.\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": 5
}