{
  "cells": [
    {
      "cell_type": "markdown",
      "id": "frontmatter",
      "metadata": {},
      "source": [
        "---\n",
        "title: \"Compreender as opções de camada aberta versus camada fechada e o efeito na construção do subespaço\"\n",
        "description: \"Compreender as opções de camada aberta versus camada fechada e o efeito na construção do subespaço para a versão mais recente da diagonalização quântica baseada em amostras (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",
        "# Compreender as opções de camada aberta versus camada fechada e o efeito na construção do subespaço\n",
        "\n",
        "Neste guia, mostraremos como escolher as dimensões do subespaço no `qiskit_addon_sqd` pacote para realizar o pós-processamento de amostras quânticas utilizando [a técnica de recuperação de configuração autoconsistente](https://arxiv.org/abs/2405.05068).\n",
        "\n",
        "Mais importante ainda, este guia também destaca algumas diferenças no comportamento da construção do subespaço quando executada nos `open_shell = False` modos ou `open_shell = True` :\n",
        "\n",
        "* `open_shell = False` só funciona quando o número de elétrons em aceleração e desaceleração é o mesmo.\n",
        "\n",
        "* `open_shell = True` deve ser utilizado quando o número de elétrons em aceleração e desaceleração for diferente. Também pode ser usado quando o número de elétrons em estado de aceleração e desaceleração é o mesmo. No entanto, neste último caso, há uma diferença nos tamanhos dos subespaços gerados entre `open_shell = False` e `open_shell = True`, conforme discutido neste guia.\n",
        "\n",
        "**NOTA:** Algumas das manipulações da configuração eletrônica (sequência de bits) neste pacote têm como objetivo preservar a simetria total de spin $S^2$. Os solucionadores padrão de Interação de Configuração Selecionada (SCI) não conseguem impor exatamente a conservação d $S^2$. Consequentemente, eles fazem isso, aproximadamente, por meio de um multiplicador de Lagrange.\n",
        "\n",
        "A escolha das configurações eletrônicas inseridas no solucionador de estados próprios também pode ter um forte efeito na conservação do spin. Por exemplo, em um sistema (2 elétrons, 2 orbitais), é possível amostrar a configuração $|1001\\rangle$ (que possui uma única excitação de spin-up sobre o estado RHF $|0101\\rangle$ ), que é uma combinação linear dos estados singletos e tripletos de camada aberta, respectivamente $(|1001\\rangle ± |0110\\rangle) /\\sqrt{2}$. Se a configuração |0110⟩ não for amostrada, não é possível construir nenhuma função própria do spin total, o que leva à contaminação ou redundância de spin (a configuração |1001⟩ está envolvida em um cálculo de CI, mas possui coeficiente 0 no vetor CI). Como uma única amostra $|1001\\rangle$ é gerada no computador quântico, é assim que o `sqd` pacote lida com essa situação:\n",
        "\n",
        "* `open_shell = False`:\n",
        "\n",
        "  1. A sequência de bits $1001$ é dividida ao meio, representando as configurações de rotação para cima e para baixo: $10$ (para cima) e $01$ (para baixo).\n",
        "\n",
        "  2. A lista de configurações únicas com polarização de spin foi elaborada: $\\mathcal{U} = [01, 10]$.\n",
        "\n",
        "  3. Em seguida, consideramos todas as combinações possíveis de elementos d $\\mathcal{U}$ es para formar a base: $\\left \\{ |0101\\rangle, |0110\\rangle , |1001\\rangle , |1010\\rangle \\right \\}$, que contém os estados singlete e triplete.\n",
        "\n",
        "* `open_shell = True`:\n",
        "\n",
        "  1. Ao contrário do que `open_shell = False` ocorre nesse caso, não combinamos as metades da sequência de bits para formar a base.\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "a6755afb-ca1e-4473-974b-ba89acc8abce",
      "metadata": {},
      "source": [
        "<span id=\"closed-shell\" />\n",
        "\n",
        "### De estrutura fechada\n",
        "\n",
        "Este exemplo mostra como as cadeias de bits são manipuladas em um sistema (2 elétrons, 4 orbitais).\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": [
        "Especifique manualmente um dicionário de resultados de medição:\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": [
        "Transforme as contagens `dict` em uma matriz de sequência de bits e em um array de probabilidades para o pós-processamento:\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": [
        "Selecionar uma subamostra de um único lote com tamanho igual a dois:\n",
        "\n",
        "* `n_batches = 1`: Número de lotes de configurações utilizados pelas diferentes chamadas ao solucionador de estados próprios\n",
        "* `samples_per_batch = 2`: Número de configurações únicas a serem incluídas em cada lote\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": [
        "Obter a representação decimal das sequências de bits de spin-up e spin-down utilizadas pelo solucionador de estados próprios.\n",
        "\n",
        "O primeiro elemento da tupla corresponde à representação decimal das configurações de spin para cima, enquanto o segundo elemento da tupla corresponde à representação decimal das configurações de spin para baixo:\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": [
        "Observe que, embora o número de amostras por lote seja dois, e as sequências de bits amostradas sejam: $00010010$ e $01001000$, são geradas quatro configurações eletrônicas por espécie de spin. Nesse caso, o conjunto de configurações únicas com polarização de spin é dado por:\n",
        "\n",
        "$$\n",
        "\\mathcal{U} = \\{ 0001, 0010, 0100, 1000 \\}\n",
        "$$\n",
        "\n",
        "cuja representação decimal em base-10 é\n",
        "\n",
        "$$\n",
        "\\mathcal{U}_{10} = \\{ 1, 2, 4, 8 \\}\n",
        "$$\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "03b32ed5",
      "metadata": {},
      "source": [
        "Base do subespaço:\n",
        "\n",
        "O solucionador de estados próprios considera todos os pares possíveis de sequências de bits com spin para cima e spin para baixo para construir a base $\\mathcal{B}$ do subespaço:\n",
        "\n",
        "* Elemento 1: $|00010001\\rangle$\n",
        "\n",
        "* Elemento 2: $|00010010\\rangle$\n",
        "\n",
        "* Elemento 3: $|00010100\\rangle$\n",
        "\n",
        "* Elemento 4: $|00011000\\rangle$\n",
        "\n",
        "* Elemento 5: $|00100001\\rangle$\n",
        "\n",
        "* Elemento 6: $|00100010\\rangle$\n",
        "\n",
        "* Elemento 7: $|00100100\\rangle$\n",
        "\n",
        "* Elemento 8: $|00101000\\rangle$\n",
        "\n",
        "* Elemento 9: $|01000001\\rangle$\n",
        "\n",
        "* Elemento 10: $|01000010\\rangle$\n",
        "\n",
        "* Elemento 11: $|01000100\\rangle$\n",
        "\n",
        "* Elemento 12: $|01001000\\rangle$\n",
        "\n",
        "* Elemento 13: $|10000001\\rangle$\n",
        "\n",
        "* Elemento 14: $|10000010\\rangle$\n",
        "\n",
        "* Elemento 15: $|10000100\\rangle$\n",
        "\n",
        "* Elemento 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": [
        "**A dimensão do subespaço é limitada superiormente por** : $2 \\cdot$ (`samples_per_batch`) $^2$.\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "9412e52b",
      "metadata": {},
      "source": [
        "<span id=\"open-shell\" />\n",
        "\n",
        "### Concha aberta\n",
        "\n",
        "Este exemplo mostra como as cadeias de bits são manipuladas em um sistema (2 elétrons, 4 orbitais).\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": [
        "Especifique manualmente um dicionário de resultados de medição:\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": [
        "Transforme as contagens `dict` em uma matriz de sequência de bits e em um array de probabilidades para o pós-processamento:\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": [
        "Selecionar uma subamostra de um único lote com tamanho igual a dois:\n",
        "\n",
        "* `n_batches = 1`: Número de lotes de configurações utilizados pelas diferentes chamadas ao solucionador de estados próprios\n",
        "* `samples_per_batch = 2`: Número de configurações únicas a serem incluídas em cada lote\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": [
        "Obter a representação decimal das sequências de bits de spin-up e spin-down utilizadas pelo solucionador de estados próprios.\n",
        "\n",
        "O primeiro elemento da tupla corresponde à representação decimal das configurações de spin para cima, enquanto o segundo elemento da tupla corresponde à representação decimal das configurações de spin para baixo:\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": [
        "Se especificarmos que `open_shell = True`, não incluiremos todas as meias-cadeias de bits únicas como configurações “spin-up” e “spin-down”, resultando assim em uma base menor do que quando especificamos `open_shell = False`.\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "e1959b72",
      "metadata": {},
      "source": [
        "Base do subespaço:\n",
        "\n",
        "O solucionador de estados próprios considera todos os pares possíveis de sequências de bits com spin para cima e spin para baixo para construir a base $\\mathcal{B}$ do subespaço:\n",
        "\n",
        "* Elemento 1: $|00010010\\rangle$\n",
        "\n",
        "* Elemento 2: $|00011000\\rangle$\n",
        "\n",
        "* Elemento 3: $|01000010\\rangle$\n",
        "\n",
        "* Elemento 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": [
        "**A dimensão do subespaço é limitada superiormente por** : (`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
}