{
  "cells": [
    {
      "cell_type": "markdown",
      "id": "6581d769-6f75-4b26-90e3-39c28f22a74c",
      "metadata": {},
      "source": [
        "---\n",
        "title: \"Solucionador de autovalores quânticos variacionais\"\n",
        "description: \"Esta introdução ao VQE aborda seus componentes, uma implementação básica e discute quais fatores determinam sua eficiência e utilidade.\"\n",
        "---\n",
        "\n",
        "{/* cspell:ignore ansä IIIZ IZII IIZI ZIII IZIZ IIZZ ZIIZ IZZI ZZII ZIZI XXYY YYXX ansätze ansatze infty IZZX XIYX ZZXZ ZZZX IIXX IIXZ IZXZ IXXZ XZXZ ZIXZ */}\n",
        "\n",
        "<span id=\"the-variational-quantum-eigensolver-vqe\" />\n",
        "\n",
        "# O solucionador de autovalores quânticos variacionais (VQE)\n",
        "\n",
        "Esta lição apresentará o eigensolver quântico variacional, explicará sua importância como um algoritmo fundamental na computação quântica e também explorará seus pontos fortes e fracos. É provável que a VQE por si só, sem métodos de aumento, não seja suficiente para as modernas computações quânticas em escala de utilidade. No entanto, ele é importante como um método híbrido clássico-quântico arquetípico, pois é uma base importante sobre a qual muitos algoritmos mais avançados são desenvolvidos.\n",
        "\n",
        "Este vídeo apresenta uma visão geral do VQE e dos fatores que afetam sua eficiência. O texto abaixo acrescenta mais detalhes e implementa o VQE usando o Qiskit.\n",
        "\n",
        "<IBMVideo id=\"134325519\" title=\"Neste vídeo, Chris Porter descreve os principais componentes do eigensolver quântico variacional. Isso inclui o Hamiltoniano, o ansatz, um otimizador clássico e um estimador. Ele também discute quais fatores afetam a eficiência do VQE.\" />\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "21115450-3f01-4e19-860d-48e31f401b1f",
      "metadata": {},
      "source": [
        "<span id=\"1-what-is-vqe\" />\n",
        "\n",
        "## 1. O que é VQE?\n",
        "\n",
        "O solucionador de valores próprios quântico variacional é um algoritmo que utiliza a computação clássica e a computação quântica em conjunto para realizar uma tarefa. O cálculo do VQE é composto por quatro elementos principais:\n",
        "\n",
        "* **Um operador** : Geralmente um Hamiltoniano, que chamaremos de $H$, que descreve uma propriedade do seu sistema que você deseja otimizar. Outra forma de dizer isso é que você está buscando o vetor próprio desse operador que corresponde ao valor próprio mínimo. Geralmente chamamos esse vetor próprio de \"estado fundamental\".\n",
        "* **Um \"ansatz\"** (palavra alemã que significa \"abordagem\"): trata-se de um circuito quântico que prepara um estado quântico que se aproxima do vetor próprio que você está buscando. Na verdade, o ansatz é uma família de circuitos quânticos, porque algumas das portas no ansatz são parametrizadas, ou seja, elas recebem um parâmetro que podemos variar. Essa família de circuitos quânticos pode preparar uma família de estados quânticos que se aproximam do estado fundamental.\n",
        "* **Um estimador** : um meio de estimar o valor esperado do operador $H$ sobre o estado quântico variacional atual. Às vezes, o que realmente nos interessa é simplesmente esse valor esperado, ao qual chamamos de função de custo. Às vezes, nos interessamos por uma função mais complexa que ainda assim pode ser escrita a partir de um ou mais valores esperados.\n",
        "* **Um otimizador clássico** : um algoritmo que varia os parâmetros para tentar minimizar a função de custo.\n",
        "\n",
        "Vamos examinar cada um desses componentes mais detalhadamente.\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "7dbd605e-a440-446b-bc05-e2e301796bf2",
      "metadata": {},
      "source": [
        "<span id=\"11-the-operator-hamiltonian\" />\n",
        "\n",
        "### 1.1 O operador (Hamiltoniano)\n",
        "\n",
        "No centro de um problema de VQE está um operador que descreve um sistema de interesse. Vamos supor aqui que o menor valor próprio e o vetor próprio correspondente desse operador sejam úteis para alguma finalidade científica ou comercial. Os exemplos podem incluir um Hamiltoniano químico que descreve uma molécula, de modo que o menor valor próprio do operador corresponda à energia do estado fundamental da molécula, e o estado próprio correspondente descreva a geometria ou a configuração eletrônica da molécula. Ou o operador poderia descrever um custo de um determinado processo a ser otimizado, e os estados próprios poderiam corresponder a rotas ou práticas. Em alguns campos, como o da física, um \"Hamiltoniano\" quase sempre se refere a um operador que descreve a energia de um sistema físico. Mas, na computação quântica, é comum ver operadores quânticos que descrevem um problema comercial ou logístico também chamados de \"Hamiltoniano\". Adotaremos essa convenção aqui.\n",
        "\n",
        "![Uma imagem de orbitais atômicos e uma imagem de uma rede com vários nós e conexões entre eles.](https://quantum.cloud.ibm.com/learning/images/courses/quantum-diagonalization-algorithms/vqe/vqe-fig1.avif)\n",
        "\n",
        "O mapeamento de um problema físico ou de otimização para qubits geralmente é uma tarefa não trivial, mas esses detalhes não são o foco deste curso. Uma discussão geral sobre o mapeamento de um problema para um operador quântico pode ser encontrada em [Quantum computing in practice (Computação quântica na prática](/learning/courses/quantum-computing-in-practice) ). Uma análise mais detalhada do mapeamento de problemas químicos em operadores quânticos pode ser encontrada em [Quantum Chemistry with VQE](/learning/courses/quantum-chem-with-vqe).\n",
        "\n",
        "Para fins deste curso, assumiremos que a forma do Hamiltoniano é conhecida. Por exemplo, um hamiltoniano para uma molécula simples de hidrogênio (sob certas suposições de espaço ativo e usando o mapeador Jordan-Wigner) é:\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 2,
      "id": "89b425d8-f54f-4f98-996e-c303f77edb25",
      "metadata": {},
      "outputs": [],
      "source": [
        "from qiskit.quantum_info import SparsePauliOp\n",
        "\n",
        "hamiltonian = SparsePauliOp(\n",
        "    [\n",
        "        \"IIII\",\n",
        "        \"IIIZ\",\n",
        "        \"IZII\",\n",
        "        \"IIZI\",\n",
        "        \"ZIII\",\n",
        "        \"IZIZ\",\n",
        "        \"IIZZ\",\n",
        "        \"ZIIZ\",\n",
        "        \"IZZI\",\n",
        "        \"ZZII\",\n",
        "        \"ZIZI\",\n",
        "        \"YYYY\",\n",
        "        \"XXYY\",\n",
        "        \"YYXX\",\n",
        "        \"XXXX\",\n",
        "    ],\n",
        "    coeffs=[\n",
        "        -0.09820182 + 0.0j,\n",
        "        -0.1740751 + 0.0j,\n",
        "        -0.1740751 + 0.0j,\n",
        "        0.2242933 + 0.0j,\n",
        "        0.2242933 + 0.0j,\n",
        "        0.16891402 + 0.0j,\n",
        "        0.1210099 + 0.0j,\n",
        "        0.16631441 + 0.0j,\n",
        "        0.16631441 + 0.0j,\n",
        "        0.1210099 + 0.0j,\n",
        "        0.17504456 + 0.0j,\n",
        "        0.04530451 + 0.0j,\n",
        "        0.04530451 + 0.0j,\n",
        "        0.04530451 + 0.0j,\n",
        "        0.04530451 + 0.0j,\n",
        "    ],\n",
        ")"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "14c20ee9-51ad-4cc9-be36-7a33fae6c56a",
      "metadata": {},
      "source": [
        "Observe que, no hamiltoniano acima, há termos como `ZZII` e `YYYY` que não se comunicam entre si. Ou seja, para avaliar `ZZII`, precisaríamos medir o operador Pauli Z no qubit 3 (entre outras medições). Mas para avaliar `YYYY`, precisamos medir o operador Pauli Y no mesmo qubit, o qubit 3. Há uma relação de incerteza entre os operadores Y e Z no mesmo qubit; não podemos medir esses dois operadores ao mesmo tempo. Voltaremos a esse ponto a seguir e, de fato, ao longo do curso.\n",
        "O Hamiltoniano acima é um operador de matriz $16\\times 16$. Não é difícil diagonalizar o operador para encontrar seu valor próprio de energia mais baixo.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 3,
      "id": "9703b61e-ff90-4e94-8999-242d0c6766c0",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "The ground state energy is  -1.1459778447627311 hartrees\n"
          ]
        }
      ],
      "source": [
        "import numpy as np\n",
        "\n",
        "A = np.array(hamiltonian)\n",
        "eigenvalues, eigenvectors = np.linalg.eigh(A)\n",
        "print(\"The ground state energy is \", min(eigenvalues), \"hartrees\")"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "01a76c42-29e7-455a-acd6-55490f36121b",
      "metadata": {},
      "source": [
        "Os eigensolvers clássicos de força bruta não podem ser dimensionados para descrever as energias ou as geometrias de sistemas muito grandes de átomos, como medicamentos ou proteínas. O VQE é uma das primeiras tentativas de aproveitar a computação quântica para esse problema.\n",
        "\n",
        "Nesta lição, encontraremos hamiltonianos muito maiores do que os anteriores. Mas seria um desperdício forçar os limites do que o VQE pode fazer, antes de apresentarmos algumas das ferramentas mais avançadas que podem aumentar ou substituir o VQE, mais adiante neste curso.\n",
        "\n",
        "<span id=\"12-ansatz\" />\n",
        "\n",
        "### 1.2 Ansatz\n",
        "\n",
        "A palavra \"ansatz\" significa \"abordagem\" em alemão. O plural correto em alemão é \"ansätze\", embora seja comum ver \"ansatzes\" ou \"ansatze\". No contexto da VQE, um ansatz é o circuito quântico que você usa para criar uma função de onda multiqubit que mais se aproxima do estado fundamental do sistema que você está estudando e que, portanto, produz o menor valor de expectativa do seu operador. Esse circuito quântico conterá parâmetros variacionais (geralmente reunidos no vetor de variáveis $\\vec{\\theta}$ ).\n",
        "\n",
        "![Uma imagem de um circuito quântico com parâmetros variacionais identificados como “theta”.](https://quantum.cloud.ibm.com/learning/images/courses/quantum-diagonalization-algorithms/vqe/vqe-fig2.avif)\n",
        "\n",
        "Um conjunto inicial de valores $\\vec{\\theta_0}$ dos parâmetros variacionais é escolhido. Chamaremos a operação unitária do ansatz no circuito de $U_{\\text{var}}(\\vec{\\theta_0})$. Por padrão, todos os qubits nos computadores quânticos IBM® são inicializados no estado $|0\\rangle$. Quando o circuito for executado, o estado dos qubits será\n",
        "\n",
        "$$\n",
        "|\\psi(\\vec{\\theta_0})\\rangle=U_{\\text{var}}(\\vec{\\theta_0})|0\\rangle^{\\otimes N}\n",
        "$$\n",
        "\n",
        "Se tudo o que precisássemos fosse a energia mais baixa (usando a linguagem dos sistemas físicos), poderíamos estimar isso simplesmente medindo a energia várias vezes e pegando a mais baixa. Mas, normalmente, também queremos a configuração que produz a energia ou o valor próprio mais baixo. Portanto, a próxima etapa é a estimativa do valor de expectativa do Hamiltoniano, que é realizada por meio de medições quânticas. Há muita coisa envolvida nisso. Mas podemos entender esse processo qualitativamente observando que a probabilidade $P_j$ de medir uma energia $E_j$ (novamente usando a linguagem dos sistemas físicos) está relacionada ao valor de expectativa por:\n",
        "\n",
        "$$\n",
        "\\langle \\psi(\\vec{\\theta_0}) |H|\\psi (\\vec{\\theta_0}) \\rangle\n",
        "$$\n",
        "\n",
        "A probabilidade $P_j$ também está relacionada à sobreposição entre o estado próprio $|\\phi_j\\rangle$ e o estado atual do sistema $|\\psi(\\vec{\\theta_0})\\rangle$ :\n",
        "\n",
        "$$\n",
        "P_j=|\\langle \\phi_j|\\psi(\\vec{\\theta_0})\\rangle|^2 = |\\langle \\phi_j|U_{\\text{var}}(\\vec{\\theta_0})|0\\rangle^{\\otimes N}|^2\n",
        "$$\n",
        "\n",
        "Portanto, ao fazer muitas medições dos operadores Pauli que compõem nosso Hamiltoniano, podemos estimar o valor de expectativa do Hamiltoniano no estado atual do sistema $|\\psi(\\vec{\\theta_0})\\rangle$. A próxima etapa é variar os parâmetros $\\vec{\\theta}$ e tentar se aproximar mais do estado de energia mais baixa (solo) do sistema. Por causa dos parâmetros variacionais no ansatz, às vezes se ouve falar em **forma variacional**.\n",
        "\n",
        "Antes de passarmos para esse processo de variação, observe que muitas vezes é útil iniciar seu estado a partir de um estado de \"boa estimativa\". Talvez você saiba o suficiente sobre o sistema para fazer uma estimativa inicial melhor do que $|0\\rangle^{\\otimes N}$. Por exemplo, é comum inicializar os qubits no estado Hartree-Fock em aplicações químicas. Essa estimativa inicial, que não contém nenhum parâmetro de variação, é chamada de **estado de referência**. Vamos chamar o circuito quântico usado para criar o estado de referência de $U_{ref}$. Sempre que for importante distinguir o estado de referência do restante do ansatz, use: $U_{\\text{ansatz}}(\\vec{\\theta}) =U_{\\text{var}}(\\vec{\\theta})U_{\\text{ref}}.$ Equivalentemente\n",
        "\n",
        "$$\n",
        "\\begin{aligned}\n",
        "|\\psi_{\\text{ref}}\\rangle&=U_{\\text{ref}}|0\\rangle^{\\otimes N}\\\\\n",
        "|\\psi_{\\text{ansatz}}(\\vec{\\theta})\\rangle&=U_{var}(\\vec{\\theta})|\\psi_{\\text{ref}}\\rangle = U_{\\text{var}}(\\vec{\\theta})U_{\\text{ref}}|0\\rangle^{\\otimes N}.\n",
        "\\end{aligned}\n",
        "$$\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "b7f66a1f-93cb-47ee-81c3-6fbf62392003",
      "metadata": {},
      "source": [
        "<span id=\"13-estimator\" />\n",
        "\n",
        "### 1.3 Estimador\n",
        "\n",
        "Precisamos de uma maneira de estimar o valor de expectativa do nosso Hamiltoniano em um estado variacional específico $|\\psi(\\vec{\\theta})\\rangle$. Se pudéssemos medir diretamente o operador inteiro $H$, isso seria tão simples quanto fazer muitas medições (digamos $N$ ) e calcular a média dos valores medidos:\n",
        "\n",
        "$$\n",
        "\\langle \\psi(\\vec{\\theta})|H|\\psi(\\vec{\\theta})\\rangle _N \\approx \\frac{1}{N}\\sum_{j=1}^N {E_j}\n",
        "$$\n",
        "\n",
        "Aqui, o símbolo $\\approx$ nos lembra que esse valor de expectativa só seria precisamente correto no limite como $N\\rightarrow \\infty$. Mas com milhares de medições feitas em um circuito, o erro de amostragem do valor esperado é bastante baixo. Há outras considerações, como o ruído, que se tornam um problema para cálculos muito precisos.\n",
        "\n",
        "No entanto, geralmente não é possível medir $H$ de uma só vez. $H$ pode conter vários operadores Pauli X, Y e Z não comutáveis. Portanto, o Hamiltoniano deve ser dividido em grupos de operadores que podem ser medidos simultaneamente, e cada um desses grupos deve ser estimado separadamente, e os resultados combinados para obter um valor de expectativa. Voltaremos a esse assunto com mais detalhes na próxima lição, quando discutirmos o escalonamento das abordagens clássica e quântica. Essa complexidade na medição é um dos motivos pelos quais precisamos de um código altamente eficiente para realizar essa estimativa. Nesta lição e nas seguintes, usaremos o Qiskit Runtime primitive Estimator para essa finalidade.\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "8b68d38e-80ad-4e02-815f-576806ec3e1c",
      "metadata": {},
      "source": [
        "<span id=\"14-classical-optimizers\" />\n",
        "\n",
        "### 1.4 Otimizadores clássicos\n",
        "\n",
        "Um otimizador clássico é qualquer algoritmo clássico projetado para encontrar extremos de uma função de destino (normalmente um mínimo). Eles pesquisam o espaço de parâmetros possíveis em busca de um conjunto que minimize alguma função de interesse. Eles podem ser amplamente categorizados em métodos baseados em gradiente, que utilizam informações de gradiente, e métodos sem gradiente, que operam como otimizadores de caixa preta. A escolha do otimizador clássico pode afetar significativamente o desempenho de um algoritmo, especialmente na presença de ruído no hardware quântico. Os otimizadores populares nesse campo incluem Adam, AMSGrad e SPSA, que apresentaram resultados promissores em ambientes ruidosos. Os otimizadores mais tradicionais incluem COBYLA e SLSQP.\n",
        "\n",
        "Um fluxo de trabalho comum (demonstrado na Seção 3.3 ) é usar um desses algoritmos como o método dentro de um minimizador, como a função `minimize` do scipy. Recebe como argumentos:\n",
        "\n",
        "* Alguma função a ser minimizada. Geralmente, esse é o valor esperado de energia. No entanto, elas são geralmente chamadas de \"funções de custo\".\n",
        "* Um conjunto de parâmetros a partir do qual se inicia a pesquisa. Frequentemente chamado de $x_0$ ou $\\theta_0$.\n",
        "* Argumentos, incluindo os argumentos da função de custo. Na computação quântica com o Qiskit, esses argumentos incluirão o ansatz, o hamiltoniano e a primitiva Estimator, que será abordada mais detalhadamente na próxima subseção.\n",
        "* Um \"método\" de minimização. Isso se refere ao algoritmo específico usado para pesquisar o espaço de parâmetros. É aqui que especificaríamos, por exemplo, COBYLA ou SLSQP.\n",
        "* Opções. As opções disponíveis podem variar de acordo com o método. Mas um exemplo que praticamente todos os métodos incluiriam é o número máximo de iterações do otimizador antes de encerrar a pesquisa: 'maxiter'.\n",
        "\n",
        "![Uma imagem que mostra uma linha curva representando a energia, com vários pontos nos quais o valor está sendo testado para encontrar o mínimo.](https://quantum.cloud.ibm.com/learning/images/courses/quantum-diagonalization-algorithms/vqe/vqe-fig3.avif)\n",
        "\n",
        "Em cada etapa iterativa, o valor esperado do Hamiltoniano é estimado por meio de várias medições. Essa energia estimada é retornada pela função de custo, e o minimizador atualiza as informações que possui sobre o cenário de energia. O que o otimizador faz exatamente para escolher a próxima etapa varia de método para método. Alguns usam gradientes e selecionam a direção da descida mais íngreme. Outros podem levar em conta o ruído e exigir que o custo diminua em uma grande margem antes de aceitar que a energia real diminua nessa direção.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 4,
      "id": "9e0642f5-8127-4647-b3f2-deceff0651ec",
      "metadata": {},
      "outputs": [],
      "source": [
        "# Example syntax for minimization\n",
        "# from scipy.optimize import minimize\n",
        "# res = minimize(cost_func, x0, args=(ansatz, hamiltonian, estimator), method=\"cobyla\",\n",
        "# options={'maxiter': 200})"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "5bbcff76-ea91-4fb6-acca-35e9e6675ed1",
      "metadata": {},
      "source": [
        "<span id=\"15-the-variational-principle\" />\n",
        "\n",
        "### 1.5 O princípio variacional\n",
        "\n",
        "Nesse contexto, o princípio variacional é muito importante; ele afirma que nenhuma função de onda variacional pode gerar um valor de expectativa de energia (ou custo) menor do que o gerado pela função de onda do estado fundamental. Matematicamente,\n",
        "\n",
        "$$\n",
        "E_\\text{var}=\\langle \\psi_\\text{var}|H|\\psi_\\text{var}\\rangle \\geq E_\\text{min}=\\langle \\psi_\\text{0}|H|\\psi_\\text{0}\\rangle\n",
        "$$\n",
        "\n",
        "Isso é fácil de verificar se observarmos que o conjunto de todos os estados próprios $\\{|\\psi_0\\rangle, |\\psi_1\\rangle, |\\psi_2\\rangle, ...|\\psi_n \\rangle\\}$ de $H$ forma uma base completa para o espaço de Hilbert. Em outras palavras, qualquer estado e, em particular, $|\\psi_\\text{var}\\rangle$ pode ser escrito como uma soma ponderada (normalizada) desses estados próprios de $H$ :\n",
        "\n",
        "$$\n",
        "|\\psi_\\text{var}\\rangle=\\sum_{i=0}^n c_i |\\psi_i\\rangle\n",
        "$$\n",
        "\n",
        "em que $c_i$ são constantes a serem determinadas e $\\sum_{i=0} |c_i|^2 = 1$. Deixamos isso como um exercício para o leitor. Mas observe a implicação: o estado variacional que produz o valor de expectativa de energia mais baixo *é* a melhor estimativa do verdadeiro estado fundamental.\n",
        "\n",
        "<span id=\"check-your-understanding\" />\n",
        "\n",
        "#### Verifique sua compreensão\n",
        "\n",
        "Verifique matematicamente que $E_\\text{var}\\geq E_0$ para qualquer estado variacional $|\\psi_\\text{var}\\rangle$.\n",
        "\n",
        "<Accordion>\n",
        "  <AccordionItem title=\"Resposta\">\n",
        "    Usando a expansão dada do estado variacional em termos dos estados próprios de energia,\n",
        "\n",
        "    $$\n",
        "    |\\psi_\\text{var}\\rangle=\\sum_{i=0}^n c_i |\\psi_i\\rangle,\n",
        "    $$\n",
        "\n",
        "    podemos escrever o valor de expectativa da energia variacional como\n",
        "\n",
        "    $$\n",
        "    \\begin{aligned}\n",
        "    E_\\text{var}&=\\langle \\psi_\\text{var}|H|\\psi_\\text{var}\\rangle =\\left(\\sum_{i=0}^n c^*_i \\langle \\psi_i|\\right)H\\left(\\sum_{j=0}^n c_j |\\psi_j\\rangle\\right)\\\\\n",
        "    &=\\left(\\sum_{i=0}^n c^*_i \\langle \\psi_i|\\right)\\left(\\sum_{j=0}^n c_j E_j|\\psi_j\\rangle\\right)\\\\\n",
        "    &=\\sum_{i,j=0}^n c^*_i c_j E_j \\langle \\psi_i|\\psi_j\\rangle\\\\\n",
        "    &=\\sum_{i,j=0}^n c^*_i c_j E_j \\delta_{i,j}\\\\\n",
        "    &=\\sum_{i=0}^n |c_i|^2 E_i.\n",
        "    \\end{aligned}\n",
        "    $$\n",
        "\n",
        "    Para todos os coeficientes $0\\leq|c_i|^2\\leq 1$. Portanto, podemos escrever\n",
        "\n",
        "    $$\n",
        "    \\begin{aligned}\n",
        "    E_\\text{var}&=\\sum_{i=0}^n |c_i|^2 E_i\\geq \\sum_{i=0}^n |c_i|^2 E_0 = E_0 \\sum_{i=0}^n |c_i|^2 = E_0(1) \\\\\n",
        "    E_\\text{var}&\\geq E_0\n",
        "    \\end{aligned}\n",
        "    $$\n",
        "  </AccordionItem>\n",
        "</Accordion>\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "4d14d6df-7320-4f57-bc62-fbee4041957b",
      "metadata": {},
      "source": [
        "<span id=\"2-comparison-with-classical-workflow\" />\n",
        "\n",
        "## 2. Comparação com o fluxo de trabalho clássico\n",
        "\n",
        "Digamos que estejamos interessados em uma matriz com N linhas e N colunas. Suponha que sua matriz seja tão grande que a diagonalização exata não seja uma opção. Suponha ainda que você saiba o suficiente sobre o seu problema para poder fazer algumas suposições sobre a estrutura geral do estado próprio alvo e queira sondar estados semelhantes à sua suposição inicial para ver se o custo/energia pode ser reduzido ainda mais. Essa é uma abordagem variacional e é um método usado quando a diagonalização exata não é uma opção.\n",
        "\n",
        "<span id=\"21-classical-workflow\" />\n",
        "\n",
        "### 2.1 Fluxo de trabalho clássico\n",
        "\n",
        "Usando um computador clássico, isso funcionaria da seguinte forma:\n",
        "\n",
        "* Faça uma suposição de estado, com alguns parâmetros $\\vec{\\theta}_i$ que você irá variar: $|\\psi(\\vec{\\theta}_i)\\rangle$. Embora esse palpite inicial possa ser aleatório, isso não é aconselhável. Queremos usar o conhecimento do problema em questão para adaptar nossa suposição o máximo possível.\n",
        "* Calcule o valor esperado do operador com o sistema nesse estado: $\\langle\\psi(\\vec{\\theta}_i)|H|\\psi(\\vec{\\theta}_i)\\rangle$\n",
        "* Altere os parâmetros de variação e repita: $\\vec{\\theta}_i\\rightarrow \\vec{\\theta}_{i+1}$.\n",
        "* Use as informações acumuladas sobre o cenário de possíveis estados em seu subespaço variacional para fazer suposições cada vez melhores e se aproximar do estado-alvo. O princípio variacional garante que nosso estado variacional não pode produzir um valor próprio menor do que o do estado fundamental alvo. Portanto, quanto menor for o valor de expectativa, melhor será a nossa aproximação do estado fundamental:\n",
        "\n",
        "$$\n",
        "\\min_{\\vec{\\theta}} \\{ E_{\\text{var},i} = \\langle\\psi(\\vec{\\theta_i})|H|\\psi(\\vec{\\theta_i})\\rangle \\} \\geq E_0\n",
        "$$\n",
        "\n",
        "Vamos examinar a dificuldade de cada etapa dessa abordagem. Definir ou atualizar parâmetros é computacionalmente fácil; a dificuldade está em selecionar parâmetros iniciais úteis e fisicamente motivados. Usar as informações acumuladas de iterações anteriores para atualizar os parâmetros de forma que você se aproxime do estado fundamental não é algo trivial. Mas existem algoritmos clássicos de otimização que fazem isso de forma bastante eficiente. Essa otimização clássica só é cara porque pode exigir muitas iterações; no pior dos casos, o número de iterações pode aumentar exponencialmente com N. A etapa individual mais cara do ponto de vista computacional é, quase certamente, o cálculo do valor de expectativa de sua matriz usando um determinado estado $|\\psi(\\vec{\\theta_i})\\rangle$ : $\\langle\\psi(\\vec{\\theta_i})|H|\\psi(\\vec{\\theta_i})\\rangle.$\n",
        "\n",
        "A matriz $N\\times N$ deve atuar sobre o vetor de elementos $N$, o que corresponde a: $O(N^2)$ operações de multiplicação no pior caso. Isso deve ser feito a cada iteração de parâmetros. Para matrizes extremamente grandes, isso tem um alto custo computacional.\n",
        "\n",
        "<span id=\"22-quantum-workflow-and-commuting-pauli-groups\" />\n",
        "\n",
        "### 2.2 Fluxo de trabalho quântico e grupos de Pauli de comutação\n",
        "\n",
        "Agora imagine relegar essa parte do cálculo a um computador quântico. Em vez de calcular esse valor de expectativa, você o estima preparando o estado $|\\psi(\\vec{\\theta_i})\\rangle$ no computador quântico usando seu ansatz variacional e, em seguida, fazendo medições.\n",
        "\n",
        "Isso pode parecer mais fácil do que é. $H$ geralmente não é fácil de medir. Por exemplo, ele poderia ser composto de muitos operadores Pauli X, Y e Z não comutáveis. Mas $H$ **pode** ser escrito como uma combinação linear de termos, $h_\\alpha$, cada um dos quais é facilmente mensurável (por exemplo, operadores Pauli ou grupos de operadores Pauli comutadores de qubit-wise).\n",
        "O valor esperado de $H$ em algum estado $|\\Psi\\rangle$ é a soma ponderada dos valores esperados dos termos constituintes $h_\\alpha$. Essa expressão é válida para qualquer estado $|\\Psi⟩$, mas a usaremos especificamente com nossos estados variacionais $|\\psi(\\theta_i)\\rangle$.\n",
        "\n",
        "$$\n",
        "H = \\sum_{\\alpha = 1}^T{c_\\alpha h_\\alpha}\n",
        "$$\n",
        "\n",
        "em que $h_\\alpha$ é uma cadeia de Pauli como `IZZX…XIYX`, ou várias dessas cadeias que se comunicam entre si. Portanto, uma descrição do valor de expectativa que se aproxima mais das realidades de medição em computadores quânticos é\n",
        "\n",
        "$$\n",
        "\\langle \\Psi |H|\\Psi \\rangle =\\sum_{\\alpha} c_\\alpha \\langle \\Psi | h_\\alpha|\\Psi \\rangle.\n",
        "$$\n",
        "\n",
        "E no contexto de nossa função de onda variacional:\n",
        "\n",
        "$$\n",
        "\\langle \\psi(\\vec{\\theta}_i) |H|\\psi(\\vec{\\theta}_i) \\rangle =\\sum_{\\alpha} c_\\alpha \\langle \\psi(\\vec{\\theta}_i) | h_\\alpha|\\psi(\\vec{\\theta}_i) \\rangle\n",
        "$$\n",
        "\n",
        "Cada um dos termos $h_\\alpha$ pode ser medido $M$ vezes, produzindo amostras de medição $s_{\\alpha j}$ com $j=1…M$ e retorna um valor de expectativa $\\mu_\\alpha$ e um desvio padrão $\\sigma_\\alpha$. Podemos somar esses termos e propagar os erros por meio da soma para obter um valor de expectativa geral $\\mu$ e um desvio padrão $\\sigma$.\n",
        "\n",
        "$$\n",
        "\\begin{aligned}\n",
        "\\langle \\psi(\\vec{\\theta}_i) |h_\\alpha|\\psi(\\vec{\\theta}_i) \\rangle &\\simeq \\mu _\\alpha \\pm \\frac{\\sigma_\\alpha}{\\sqrt{M}} &\\qquad \\mu_\\alpha &=\\frac{1}{M}\\sum_j s_{\\alpha,j} &\\qquad \\sigma^2_\\alpha &=\\frac{1}{M-1}\\sum_j (s_{\\alpha,j}-\\mu_\\alpha)^2\\\\\n",
        "\n",
        "\\langle \\psi(\\vec{\\theta}_i) |H|\\psi(\\vec{\\theta}_i) \\rangle &\\simeq \\mu  \\pm \\sigma &\\qquad \\mu &= \\sum_\\alpha c_\\alpha \\mu_\\alpha &\\qquad \\sigma^2&=\\sum_\\alpha c^2_\\alpha \\frac{\\sigma^2_\\alpha }{M}\n",
        "\n",
        "\\end{aligned}\n",
        "$$\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "ab02194a-bb0e-4bbc-81e1-c5f8f9582d9b",
      "metadata": {},
      "source": [
        "Isso não requer multiplicação em larga escala, nem qualquer processo que necessariamente seja escalonado como $N^2$. Em vez disso, são necessárias várias medições no computador quântico. Se você não precisar de muitos deles, essa abordagem pode ser eficiente. E essa é a parte quântica do VQE.\n",
        "\n",
        "Mas vamos falar sobre os motivos pelos quais isso pode não ser eficiente. Um motivo para muitas medições é reduzir a incerteza estatística em suas estimativas, para cálculos de altíssima precisão. Outro motivo é o número de cadeias de Pauli necessárias para abranger toda a sua matriz. Como as matrizes de Pauli (mais a identidade: X, Y, Z e I) abrangem o espaço de todos os operadores de uma determinada dimensão, temos a garantia de que podemos escrever nossa matriz de interesse como uma soma ponderada de operadores de Pauli, como fizemos anteriormente.\n",
        "\n",
        "$$\n",
        "H = \\sum_{\\alpha = 1}^T{c_\\alpha h_\\alpha}\n",
        "$$\n",
        "\n",
        "em que $h_\\alpha$ é uma cadeia de Pauli que atua em todos os qubits que descrevem seu sistema, como `IZZX…XIYX`, ou várias dessas cadeias que se comunicam entre si. Lembre-se de que o Qiskit usa notação *little endian*, na qual o operador $n^\\text{th}$ Pauli da direita atua no $n^\\text{th}$ qubit. Portanto, podemos medir nosso operador medindo uma série de operadores Pauli.\n",
        "\n",
        "Mas não podemos medir todos esses operadores de Pauli simultaneamente. Os operadores de Pauli (exceto o I) não comutam entre si se estiverem associados ao mesmo qubit. Por exemplo, podemos medir `IZIZ` e `ZZXZ` simultaneamente, pois podemos medir I e Z simultaneamente para o terceiro qubit, e podemos determinar I e X simultaneamente para o primeiro qubit. Mas não podemos medir `ZZZZ` e `ZZZX` simultaneamente, porque Z e X não comutam, e ambos atuam no qubit de ordem 0. Os leitores mais experientes talvez se lembrem de que dois conjuntos de operadores de Pauli podem comutar entre si, mesmo que as medições de cada qubit individual não comutem. O estimador pressupõe medições de Pauli por produto tensorial (por meio de rotações de base), correspondentes a operadores de agrupamento que comutam em cada qubit. Portanto, para estimar simultaneamente duas cadeias (A e B) de operadores de Pauli usando o Estimator, os operadores de Pauli de cada qubit em A e B devem comutar. Isso significa que também não podemos medir `ZZZZ` e `ZZXX` simultaneamente.\n",
        "\n",
        "![Uma tabela com diferentes cordas de Pauli, algumas das quais comutam e outras não.](https://quantum.cloud.ibm.com/learning/images/courses/quantum-diagonalization-algorithms/vqe/vqe-fig4.avif)\n",
        "\n",
        "Assim, decompomos nossa matriz $H$ em uma soma de Paulis atuando em diferentes qubits. Alguns elementos dessa soma podem ser medidos de uma só vez; chamamos isso de um *grupo de Paulis comutantes*. Dependendo do número de termos que não estejam em trânsito, podemos precisar de muitos desses grupos. Chame o número de tais grupos de cadeias de Pauli comutantes de $N_\\text{GCP}$. Se $N_\\text{GCP}$ for pequeno, isso pode funcionar bem. Se o site $H$ tiver milhões de grupos, isso não será útil.\n",
        "\n",
        "Os processos necessários para a estimativa do valor esperado estão reunidos na primitiva do `Qiskit Runtime` chamada `Estimator`. Para saber mais sobre o Estimator, consulte a [referência da API](/docs/api/qiskit-ibm-runtime/estimator-v2) na documentação do IBM Quantum®. É possível simplesmente usar o Estimator diretamente, mas ele retorna muito mais do que apenas o autovalor de menor energia. Por exemplo, ele também retorna informações sobre o erro padrão do conjunto. Assim, no contexto dos problemas de minimização, é comum encontrar o estimador dentro de uma função de custo. Para saber mais sobre as entradas e saídas do Estimator, consulte este [guia](/docs/guides/primitive-input-output#pubs) na documentação do IBM Quantum.\n",
        "\n",
        "Você registra o valor da expectativa (ou a função de custo) para o conjunto de parâmetros $\\vec{\\theta_i}$ usados em seu estado e, em seguida, atualiza os parâmetros. Com o tempo, você poderia usar os valores de expectativa ou os valores da função de custo estimados para aproximar um gradiente da sua função de custo no subespaço de estados amostrados pelo seu ansatz. Existem otimizadores clássicos baseados em gradiente e sem gradiente. Ambos sofrem com possíveis problemas de treinabilidade, como múltiplos mínimos locais e grandes regiões do espaço de parâmetros com gradiente quase nulo, chamadas de *platôs estéreis*.\n",
        "\n",
        "![Duas imagens de uma reta curva com um valor mínimo. Em um deles, os pontos são verificados aleatoriamente na busca pelo mínimo; no outro, estima-se um gradiente traçando uma linha entre dois pontos adjacentes.](https://quantum.cloud.ibm.com/learning/images/courses/quantum-diagonalization-algorithms/vqe/vqe-fig5.avif)\n",
        "\n",
        "<span id=\"23-factors-that-determine-computational-cost\" />\n",
        "\n",
        "### 2.3 Fatores que determinam o custo computacional\n",
        "\n",
        "O VQE não resolverá todos os seus problemas mais difíceis de química quântica. Nº Mas ser melhor em todos os cálculos não é o objetivo. Mudamos o que determina o custo computacional.\n",
        "\n",
        "![Uma tabela comparativa entre as abordagens variacionais clássicas e quânticas. Ambos exigem boas estimativas iniciais. Classicamente, o custo varia proporcionalmente ao quadrado da dimensão da matriz, e na abordagem quântica depende do número de grupos de operadores de Pauli comutativos que você possui.](https://quantum.cloud.ibm.com/learning/images/courses/quantum-diagonalization-algorithms/vqe/vqe-fig6.avif)\n",
        "\n",
        "Passamos de um processo cuja complexidade depende apenas da dimensão da matriz para um processo que depende da precisão necessária e do número de operadores Pauli não comutáveis que compõem a matriz. O último bit não tem análogo na computação clássica.\n",
        "\n",
        "Com base nessas dependências, esse processo pode ser útil para matrizes esparsas ou matrizes que envolvam poucas cadeias de Pauli não comutantes. Esse é o caso dos sistemas de spins que interagem, por exemplo. Para matrizes densas, isso pode ser menos útil. Sabemos, por exemplo, que os sistemas químicos geralmente têm hamiltonianos que envolvem centenas, milhares e até milhões de cadeias de Pauli. Foi feito um trabalho interessante para reduzir esse número de termos. Mas os sistemas químicos podem ser mais adequados a alguns dos outros algoritmos que discutiremos neste curso.\n",
        "\n",
        "<span id=\"check-your-understanding\" />\n",
        "\n",
        "#### Verifique sua compreensão\n",
        "\n",
        "Considere um Hamiltoniano em quatro qubits que contenha os termos:\n",
        "\n",
        "`IIXX`, `IIXZ`, `IIZZ`, `IZXZ`, `IXXZ`, `ZZXZ`, `XZXZ`, `ZIXZ`, `ZZZZ`, `XXXX`\n",
        "\n",
        "Você deseja classificar esses termos em grupos de modo que todos os termos em um grupo possam ser medidos simultaneamente. Qual é o menor número de grupos que você pode formar de modo que todos os termos sejam contabilizados?\n",
        "\n",
        "<Accordion>\n",
        "  <AccordionItem title=\"Resposta\">\n",
        "    Isso pode ser feito em 4 grupos. Observe que essas soluções geralmente não são únicas.\n",
        "\n",
        "    `IIXX`, `XXXX`, `IIZZ`, `ZZZZ`\n",
        "\n",
        "    `IIXZ`, `IZXZ`, `ZIXZ`, `ZZXZ`\n",
        "\n",
        "    `IXXZ`\n",
        "\n",
        "    `XZXZ`\n",
        "  </AccordionItem>\n",
        "</Accordion>\n",
        "\n",
        "O que você acha que costuma dificultar a química quântica com VQE: o número de termos no hamiltoniano ou encontrar um bom ansatz?\n",
        "\n",
        "<Accordion>\n",
        "  <AccordionItem title=\"Resposta\">\n",
        "    Acontece que existem ansätze que são altamente otimizadas para contextos químicos. O número de termos no Hamiltoniano e, portanto, o número de medições necessárias normalmente causam mais problemas.\n",
        "  </AccordionItem>\n",
        "</Accordion>\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "a9a687e3-ae98-49f7-9b5a-0a2700ecd278",
      "metadata": {},
      "source": [
        "<span id=\"3-example-hamiltonian\" />\n",
        "\n",
        "## 3. Exemplo de Hamiltoniano\n",
        "\n",
        "Vamos colocar esse algoritmo em prática usando uma pequena matriz hamiltoniana para que possamos ver o que está acontecendo em cada etapa. Empregaremos a estrutura de padrões Qiskit:\n",
        "\n",
        "* **Etapa 1** : mapear o problema para circuitos e operadores quânticos - **Etapa 2** : otimizar para o hardware de destino - **Etapa 3** : executar no hardware de destino - **Etapa 4** : resultados do pós-processamento\n",
        "\n",
        "<span id=\"31-step-1-map-the-problem-to-quantum-circuits-and-operators\" />\n",
        "\n",
        "### 3.1 Passo 1: Mapear o problema para circuitos e operadores quânticos\n",
        "\n",
        "Usaremos o que foi definido acima no contexto da química. Começamos com algumas importações gerais.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 5,
      "id": "acb6fb0c-4b8c-4ab3-b632-ed201e99b45f",
      "metadata": {},
      "outputs": [],
      "source": [
        "# General imports\n",
        "import numpy as np\n",
        "\n",
        "# SciPy minimizer routine\n",
        "from scipy.optimize import minimize\n",
        "\n",
        "# Plotting functions\n",
        "import matplotlib.pyplot as plt"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "a713b494-ab7a-49c6-845c-db728c4635eb",
      "metadata": {},
      "source": [
        "Novamente, presumimos que o Hamiltoniano de interesse seja conhecido. Usaremos um Hamiltoniano extremamente pequeno aqui, porque outros métodos discutidos neste curso serão mais eficientes na solução de problemas maiores.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 6,
      "id": "0908f251-58af-49f9-98a8-af98110f6c15",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "The ground state energy is  -0.702930394459531\n"
          ]
        }
      ],
      "source": [
        "from qiskit.quantum_info import SparsePauliOp\n",
        "import numpy as np\n",
        "\n",
        "hamiltonian = SparsePauliOp.from_list(\n",
        "    [(\"YZ\", 0.3980), (\"ZI\", -0.3980), (\"ZZ\", -0.0113), (\"XX\", 0.1810)]\n",
        ")\n",
        "\n",
        "A = np.array(hamiltonian)\n",
        "eigenvalues, eigenvectors = np.linalg.eigh(A)\n",
        "print(\"The ground state energy is \", min(eigenvalues))"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "75bf2097-1a9c-48d5-8eff-393e0c9eb2f9",
      "metadata": {},
      "source": [
        "Há muitas opções de ansatz pré-fabricados em Qiskit. Usaremos o site `efficient_su2`.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "84d6380e-8ee8-4340-a416-c07900fe4c5b",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "This circuit has  4 parameters\n"
          ]
        },
        {
          "data": {
            "text/plain": [
              "<Image src=\"/learning/images/courses/quantum-diagonalization-algorithms/vqe/extracted-outputs/84d6380e-8ee8-4340-a416-c07900fe4c5b-1.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "execution_count": 2,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "# Pre-defined ansatz circuit and operator class for Hamiltonian\n",
        "from qiskit.circuit.library import efficient_su2\n",
        "\n",
        "# Note that it is more common to place initial 'h' gates outside the ansatz.\n",
        "# Here we specifically wanted this layer structure.\n",
        "ansatz = efficient_su2(\n",
        "    hamiltonian.num_qubits, su2_gates=[\"h\", \"rz\", \"y\"], entanglement=\"circular\", reps=1\n",
        ")\n",
        "\n",
        "num_params = ansatz.num_parameters\n",
        "print(\"This circuit has \", num_params, \"parameters\")\n",
        "\n",
        "ansatz.decompose().draw(\"mpl\", style=\"iqp\")"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "15394107-6589-4d06-b611-8fa641784b33",
      "metadata": {},
      "source": [
        "Diferentes ansätze terão diferentes estruturas de emaranhamento e diferentes portas de rotação. O que é mostrado aqui usa portas CNOT para entrelaçamento e portas Y e portas RZ parametrizadas para rotações. Observe o tamanho desse espaço de parâmetros; isso significa que devemos minimizar a função de custo em 4 variáveis (os parâmetros para as portas RZ). Isso pode ser ampliado, mas não indefinidamente. A execução de um problema semelhante em 4 qubits, usando o padrão de 3 repetições para `efficient_su2` , produz 16 parâmetros de variação.\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "12ee2d18-b4db-4b94-ab19-8a0654ca4b2e",
      "metadata": {},
      "source": [
        "<span id=\"32-step-2-optimize-for-target-hardware\" />\n",
        "\n",
        "### 3.2 Etapa 2: Otimizar para o hardware de destino\n",
        "\n",
        "O ansatz foi escrito usando portas familiares, mas nosso circuito deve ser transpilado para fazer uso das portas básicas que podem ser implementadas em cada computador quântico. Selecionamos o backend menos ocupado.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 17,
      "id": "ba1a1493-e807-44b8-b971-69f098981da2",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "<IBMBackend('ibm_torino')>\n"
          ]
        }
      ],
      "source": [
        "# runtime imports\n",
        "from qiskit_ibm_runtime import QiskitRuntimeService, Session\n",
        "from qiskit_ibm_runtime import EstimatorV2 as Estimator\n",
        "\n",
        "# To run on hardware, select the backend with the fewest number of jobs in the queue\n",
        "service = QiskitRuntimeService()\n",
        "backend = service.least_busy(operational=True, simulator=False)\n",
        "\n",
        "print(backend)"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "84200023-d16f-41d4-9791-c6ef3488da90",
      "metadata": {},
      "source": [
        "Agora podemos transpilar nosso circuito para esse hardware e visualizar nosso ansatz transpilado.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 9,
      "id": "4a1cdcf3-7d94-4a1f-b675-9549bf28d956",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<Image src=\"/learning/images/courses/quantum-diagonalization-algorithms/vqe/extracted-outputs/4a1cdcf3-7d94-4a1f-b675-9549bf28d956-0.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "execution_count": 9,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "from qiskit.transpiler.preset_passmanagers import generate_preset_pass_manager\n",
        "\n",
        "target = backend.target\n",
        "pm = generate_preset_pass_manager(target=target, optimization_level=3)\n",
        "\n",
        "ansatz_isa = pm.run(ansatz)\n",
        "\n",
        "ansatz_isa.draw(output=\"mpl\", idle_wires=False, style=\"iqp\")"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "6066c477-2d43-459f-bfc6-650011279587",
      "metadata": {},
      "source": [
        "Observe que as portas usadas mudaram, e os qubits em nosso circuito abstrato foram mapeados para qubits de números diferentes no computador quântico. Devemos mapear nosso Hamiltoniano de forma idêntica para que nossos resultados sejam significativos.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 10,
      "id": "3543e888-6f84-4f12-88a8-948dec7f3f55",
      "metadata": {},
      "outputs": [],
      "source": [
        "hamiltonian_isa = hamiltonian.apply_layout(layout=ansatz_isa.layout)"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "ba1ae1c5-c26c-42f8-b3af-411970d4d39d",
      "metadata": {},
      "source": [
        "<span id=\"33-step-3-execute-on-target-hardware\" />\n",
        "\n",
        "### 3.3 Etapa 3: Executar no hardware de destino\n",
        "\n",
        "<span id=\"331-reporting-out-values\" />\n",
        "\n",
        "#### 3.3.1 Relatório de valores\n",
        "\n",
        "Definimos aqui uma função de custo que recebe como argumentos as estruturas que construímos nas etapas anteriores: os parâmetros, o ansatz e o hamiltoniano. Ele também utiliza o Estimator, que ainda não definimos. Incluímos código para acompanhar a evolução da nossa função de custo, de modo a podermos verificar o comportamento de convergência.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "bb1d8999-77aa-4c1a-adae-8974eda9e63b",
      "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 (EstimatorV2): Estimator primitive instance\n",
        "        cost_history_dict: Dictionary for storing intermediate results\n",
        "\n",
        "    Returns:\n",
        "        float: Energy estimate\n",
        "    \"\"\"\n",
        "    pub = (ansatz, [hamiltonian], [params])\n",
        "    result = estimator.run(pubs=[pub]).result()\n",
        "    energy = result[0].data.evs[0]\n",
        "\n",
        "    cost_history_dict[\"iters\"] += 1\n",
        "    cost_history_dict[\"prev_vector\"] = params\n",
        "    cost_history_dict[\"cost_history\"].append(energy)\n",
        "    print(f\"Iters. done: {cost_history_dict['iters']} [Current cost: {energy}]\")\n",
        "\n",
        "    return energy\n",
        "\n",
        "\n",
        "cost_history_dict = {\n",
        "    \"prev_vector\": None,\n",
        "    \"iters\": 0,\n",
        "    \"cost_history\": [],\n",
        "}"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "95537d30-ba5d-48ab-bf6a-82edc8f0a348",
      "metadata": {},
      "source": [
        "É altamente vantajoso se você puder escolher os valores dos parâmetros iniciais com base no conhecimento do problema em questão e nas características do estado-alvo. Não faremos suposições sobre esse conhecimento e usaremos valores iniciais aleatórios.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 12,
      "id": "01a5d370-2947-4441-b71b-ffbdeddf52f0",
      "metadata": {},
      "outputs": [],
      "source": [
        "x0 = 2 * np.pi * np.random.random(num_params)"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "8e0d33b8-7f9c-428d-a76d-d832747b8430",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "Iters. done: 1 [Current cost: 0.010575798722044727]\n",
            "Iters. done: 2 [Current cost: 0.004040015974440895]\n",
            "Iters. done: 3 [Current cost: 0.0020213258785942503]\n",
            "Iters. done: 4 [Current cost: 0.18723082446726014]\n",
            "Iters. done: 5 [Current cost: -0.2746792152068885]\n",
            "Iters. done: 6 [Current cost: -0.3094547651648519]\n",
            "Iters. done: 7 [Current cost: -0.05281985428356641]\n",
            "Iters. done: 8 [Current cost: 0.00808560303514377]\n",
            "Iters. done: 9 [Current cost: -0.0014821685303514388]\n",
            "Iters. done: 10 [Current cost: -0.004759824281150161]\n",
            "Iters. done: 11 [Current cost: 0.09942328705995292]\n",
            "Iters. done: 12 [Current cost: 0.01092366214057508]\n",
            "Iters. done: 13 [Current cost: 0.05017497496069776]\n",
            "Iters. done: 14 [Current cost: 0.13028868414310696]\n",
            "Iters. done: 15 [Current cost: 0.013747803514376994]\n",
            "Iters. done: 16 [Current cost: 0.2583072432944498]\n",
            "Iters. done: 17 [Current cost: -0.14422125655131562]\n",
            "Iters. done: 18 [Current cost: -0.0004950150347678081]\n",
            "Iters. done: 19 [Current cost: 0.00681082268370607]\n",
            "Iters. done: 20 [Current cost: -0.0023377795527156544]\n",
            "Iters. done: 21 [Current cost: 0.6027665591169237]\n",
            "Iters. done: 22 [Current cost: 0.00596641373801917]\n",
            "Iters. done: 23 [Current cost: -0.008318769968051117]\n",
            "Iters. done: 24 [Current cost: -0.00026683306709265246]\n",
            "Iters. done: 25 [Current cost: -0.007648222843450479]\n",
            "Iters. done: 26 [Current cost: 0.004121086261980831]\n",
            "Iters. done: 27 [Current cost: -0.004075019968051117]\n",
            "Iters. done: 28 [Current cost: -0.004419369009584665]\n",
            "Iters. done: 29 [Current cost: 0.213185460054037]\n",
            "Iters. done: 30 [Current cost: -0.06505919572162797]\n",
            "Iters. done: 31 [Current cost: -0.5334241316590271]\n",
            "Iters. done: 32 [Current cost: 0.00218370607028754]\n",
            "Iters. done: 33 [Current cost: 0.09579352143666908]\n",
            "Iters. done: 34 [Current cost: -0.009274800319488819]\n",
            "Iters. done: 35 [Current cost: -0.44395141360688106]\n",
            "Iters. done: 36 [Current cost: 0.011747104632587858]\n",
            "Iters. done: 37 [Current cost: -0.003344149361022364]\n",
            "Iters. done: 38 [Current cost: 0.19138183916486304]\n",
            "Iters. done: 39 [Current cost: 0.013513931813145209]\n"
          ]
        }
      ],
      "source": [
        "# This required 13 min, 20 s QPU time on an Eagle processor, 28 min total time.\n",
        "with Session(backend=backend) as session:\n",
        "    estimator = Estimator(mode=session)\n",
        "    estimator.options.default_shots = 10000\n",
        "\n",
        "    res = minimize(\n",
        "        cost_func,\n",
        "        x0,\n",
        "        args=(ansatz_isa, hamiltonian_isa, estimator),\n",
        "        method=\"cobyla\",\n",
        "        options={\"maxiter\": 50},\n",
        "    )"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "fe98bde2-b435-47d1-b227-ee897aa3fe3e",
      "metadata": {},
      "source": [
        "Podemos examinar os resultados brutos.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 14,
      "id": "b1d07809-5f98-4c11-9bf6-fc5b5c5fb47f",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              " message: Return from COBYLA because the trust region radius reaches its lower bound.\n",
              " success: True\n",
              "  status: 0\n",
              "     fun: -0.5334241316590271\n",
              "       x: [ 1.024e+00  6.459e+00  3.625e+00  4.007e+00]\n",
              "    nfev: 39\n",
              "   maxcv: 0.0"
            ]
          },
          "execution_count": 14,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "res"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "80c958e5-f70e-4736-889a-f88a69c50890",
      "metadata": {},
      "source": [
        "<span id=\"34-step-4-post-process-results\" />\n",
        "\n",
        "### 3.4 Etapa 4: Resultados pós-processamento\n",
        "\n",
        "Se o procedimento terminar corretamente, os valores em nosso dicionário deverão ser iguais ao vetor de soluções e ao número total de avaliações de funções, respectivamente. Isso é fácil de verificar:\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 15,
      "id": "e87046c1-bfe9-4bb3-b7fd-1e4da55149fe",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "{'prev_vector': array([1.02397956, 6.45886604, 3.62479262, 4.00744128]),\n",
              " 'iters': 39,\n",
              " 'cost_history': [np.float64(0.010575798722044727),\n",
              "  np.float64(0.004040015974440895),\n",
              "  np.float64(0.0020213258785942503),\n",
              "  np.float64(0.18723082446726014),\n",
              "  np.float64(-0.2746792152068885),\n",
              "  np.float64(-0.3094547651648519),\n",
              "  np.float64(-0.05281985428356641),\n",
              "  np.float64(0.00808560303514377),\n",
              "  np.float64(-0.0014821685303514388),\n",
              "  np.float64(-0.004759824281150161),\n",
              "  np.float64(0.09942328705995292),\n",
              "  np.float64(0.01092366214057508),\n",
              "  np.float64(0.05017497496069776),\n",
              "  np.float64(0.13028868414310696),\n",
              "  np.float64(0.013747803514376994),\n",
              "  np.float64(0.2583072432944498),\n",
              "  np.float64(-0.14422125655131562),\n",
              "  np.float64(-0.0004950150347678081),\n",
              "  np.float64(0.00681082268370607),\n",
              "  np.float64(-0.0023377795527156544),\n",
              "  np.float64(0.6027665591169237),\n",
              "  np.float64(0.00596641373801917),\n",
              "  np.float64(-0.008318769968051117),\n",
              "  np.float64(-0.00026683306709265246),\n",
              "  np.float64(-0.007648222843450479),\n",
              "  np.float64(0.004121086261980831),\n",
              "  np.float64(-0.004075019968051117),\n",
              "  np.float64(-0.004419369009584665),\n",
              "  np.float64(0.213185460054037),\n",
              "  np.float64(-0.06505919572162797),\n",
              "  np.float64(-0.5334241316590271),\n",
              "  np.float64(0.00218370607028754),\n",
              "  np.float64(0.09579352143666908),\n",
              "  np.float64(-0.009274800319488819),\n",
              "  np.float64(-0.44395141360688106),\n",
              "  np.float64(0.011747104632587858),\n",
              "  np.float64(-0.003344149361022364),\n",
              "  np.float64(0.19138183916486304),\n",
              "  np.float64(0.013513931813145209)]}"
            ]
          },
          "execution_count": 15,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "cost_history_dict"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 16,
      "id": "a789373a-8d32-4761-ba21-6b2f98a7ae5a",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<Image src=\"/learning/images/courses/quantum-diagonalization-algorithms/vqe/extracted-outputs/a789373a-8d32-4761-ba21-6b2f98a7ae5a-0.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "metadata": {},
          "output_type": "display_data"
        }
      ],
      "source": [
        "fig, ax = plt.subplots()\n",
        "x = np.linspace(0, 10, 50)\n",
        "\n",
        "# Define the constant function\n",
        "constant = -0.7029\n",
        "y_constant = np.full_like(x, constant)\n",
        "ax.plot(\n",
        "    range(cost_history_dict[\"iters\"]), cost_history_dict[\"cost_history\"], label=\"VQE\"\n",
        ")\n",
        "ax.set_xlabel(\"Iterations\")\n",
        "ax.set_ylabel(\"Cost\")\n",
        "ax.plot(y_constant, label=\"Target\")\n",
        "plt.legend()\n",
        "plt.draw()"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "4be8cb84-ec8c-4c83-880f-b9c296282040",
      "metadata": {},
      "source": [
        "IBM A Quantum tem outras ofertas de aprimoramento de habilidades relacionadas ao VQE. Se você estiver pronto para colocar a VQE em prática, consulte nosso tutorial: [Estimativa de energia do estado fundamental da cadeia de Heisenberg com VQE](/docs/tutorials/spin-chain-vqe). Se quiser obter mais informações sobre a criação de Hamiltonianos moleculares, consulte [esta lição](/learning/courses/quantum-chem-with-vqe/hamiltonian-construction) em nosso curso sobre [Química quântica com o VQE](/learning/courses/quantum-chem-with-vqe). Se você estiver interessado em entender melhor como funcionam os algoritmos variacionais, como o VQE, recomendamos o curso [Variational Algorithm Design](/learning/courses/variational-algorithm-design/optimization-loops).\n",
        "\n",
        "<span id=\"check-your-understanding\" />\n",
        "\n",
        "#### Verifique sua compreensão\n",
        "\n",
        "Nesta seção, calculamos uma energia de estado fundamental a partir de um Hamiltoniano. Se quiséssemos aplicar isso, por exemplo, para determinar a geometria de uma molécula, como poderíamos estender isso?\n",
        "\n",
        "<Accordion>\n",
        "  <AccordionItem title=\"Resposta\">\n",
        "    Precisaríamos introduzir variáveis para o espaçamento interatômico e os ângulos entre as ligações. Precisaríamos variar isso. Para cada variação dessas, produziríamos um novo Hamiltoniano (já que os operadores que descrevem a energia certamente dependem da geometria). Para cada Hamiltoniano produzido e mapeado em qubits, precisaríamos realizar uma otimização como a feita acima. De todos esses muitos problemas de otimização convergentes, a geometria que produzisse a menor energia seria a adotada pela natureza. Isso é um pouco mais complexo do que o mostrado acima. Esse cálculo é feito para a molécula mais simples, $\\text{H}_2$, [aqui](/learning/courses/quantum-chem-with-vqe/geometry).\n",
        "  </AccordionItem>\n",
        "</Accordion>\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "33231f54-a9c1-499c-a4ad-b4404b843909",
      "metadata": {},
      "source": [
        "<span id=\"4-vqes-relationship-to-other-methods\" />\n",
        "\n",
        "## 4. Relação entre o VQE e outros métodos\n",
        "\n",
        "Nesta seção, analisaremos as vantagens e desvantagens da abordagem VQE original e apontaremos suas relações com outros algoritmos mais recentes.\n",
        "\n",
        "<span id=\"41-the-strengths-and-weaknesses-of-vqe\" />\n",
        "\n",
        "### 4.1 Os pontos fortes e fracos do VQE\n",
        "\n",
        "Alguns pontos fortes já foram apontados. Eles incluem:\n",
        "\n",
        "* Adequação ao hardware moderno: Alguns algoritmos quânticos exigem taxas de erro muito menores, aproximando-se da tolerância a falhas em grande escala. A VQE não; ela pode ser implementada nos computadores quânticos atuais.\n",
        "* Circuitos superficiais: A VQE geralmente emprega circuitos quânticos relativamente rasos. Isso torna o VQE menos suscetível a erros de porta acumulados e o torna adequado para muitas técnicas de atenuação de erros. É claro que os circuitos nem sempre são rasos; isso depende do ansatz usado.\n",
        "* Versatilidade: A VQE pode (em princípio) ser aplicada a qualquer problema que possa ser definido como um problema de valor próprio/vetor próprio. Há muitas ressalvas que tornam a VQE impraticável ou desvantajosa para alguns problemas. Algumas delas estão descritas abaixo.\n",
        "\n",
        "Alguns pontos fracos do VQE e problemas para os quais ele não é prático também foram descritos acima. Dentre eles:\n",
        "\n",
        "* Natureza heurística: A VQE não garante a convergência para a energia correta do estado fundamental, pois seu desempenho depende da escolha do ansatz e dos métodos de otimização [\\[1-2\\]](#references). Se for escolhido um ansatz ruim que não tenha o emaranhamento necessário para o estado fundamental desejado, nenhum otimizador clássico poderá alcançar esse estado fundamental.\n",
        "* Parâmetros potencialmente numerosos: Um ansatz muito expressivo pode ter tantos parâmetros que as iterações de minimização consomem muito tempo.\n",
        "* Alto custo computacional: No VQE, o Estimador é utilizado para estimar o valor esperado de cada termo do hamiltoniano. A maioria das funções de Hamilton de interesse terá termos que não podem ser estimados simultaneamente. Isso pode tornar o VQE um método que consome muitos recursos em sistemas de grande porte com hamiltonianos complexos [\\[1\\]](#references).\n",
        "* Efeitos do ruído: Quando o otimizador clássico está buscando um mínimo, os cálculos com ruído podem confundi-lo e afastá-lo do mínimo verdadeiro ou atrasar sua convergência. Uma possível solução para isso é aproveitar as técnicas mais avançadas de atenuação e supressão de erros [\\[2-3\\]](#references) do site IBM.\n",
        "* Platôs estéreis: Essas regiões de gradientes que desaparecem [\\[2-3\\]](#references) existem mesmo na ausência de ruído, mas o ruído as torna mais problemáticas, já que a alteração nos valores de expectativa devido ao ruído pode ser maior do que a alteração dos parâmetros de atualização nessas regiões estéreis.\n",
        "\n",
        "<span id=\"42-relationship-to-other-approaches\" />\n",
        "\n",
        "### 4.2 Relação com outras abordagens\n",
        "\n",
        "<span id=\"adapt-vqe\" />\n",
        "\n",
        "#### Adapt-VQE\n",
        "\n",
        "O algoritmo **ADAPT-VQE** (Adaptive Derivative-Assembled Pseudo-Trotter Variational Quantum Eigensolver) é um aprimoramento do algoritmo VQE original, projetado para aumentar a eficiência, a precisão e a escalabilidade das simulações quânticas, especialmente em química quântica.\n",
        "\n",
        "O algoritmo VQE original descrito ao longo desta lição usa um ansatz fixo e predefinido para aproximar o estado fundamental do sistema. Em nosso caso, usamos `efficient_su2`, com uma única repetição, usando portas de rotação Y e RZ.  Embora os parâmetros nas portas RZ tenham mudado, a estrutura desse ansatz e as portas usadas não mudaram.\n",
        "\n",
        "O ADAPT-VQE aborda as limitações do VQE por meio da construção adaptativa de ansatz. Em vez de começar com um ansatz fixo, o ADAPT-VQE constrói dinamicamente o ansatz de forma iterativa. Em cada etapa, ele seleciona o operador de um conjunto predefinido (como operadores de excitação fermiônica) que tem o maior gradiente em relação à energia. Isso garante que apenas os operadores mais impactantes sejam adicionados, resultando em um ansatz compacto e eficiente [\\[4-6\\]](#references). Essa abordagem pode ter vários efeitos benéficos:\n",
        "\n",
        "1. **Redução da profundidade do circuito** : Ao aumentar o ansatz de forma incremental e se concentrar apenas nos operadores necessários, o ADAPT-VQE minimiza as operações de porta em comparação com as abordagens tradicionais de VQE [\\[5,7\\]](#references).\n",
        "2. **Precisão aprimorada** : A natureza adaptativa permite que o ADAPT-VQE recupere mais energia de correlação em cada etapa, o que o torna particularmente eficaz para sistemas fortemente correlacionados, nos quais o VQE tradicional tem dificuldades [\\[8,9\\]](#references).\n",
        "3. **Escalabilidade e robustez a ruídos** : O ansatz compacto reduz o acúmulo de erros de porta, reduz a sobrecarga computacional e limita o número de parâmetros variacionais que devem ser minimizados.\n",
        "\n",
        "O ADAPT-VQE ainda não é perfeito. Em alguns casos, ele pode ficar preso ou ser retardado por mínimos locais e pode sofrer com o excesso de parametrização. Também pode ser bastante intensivo em termos de recursos, pois exige o cálculo de gradientes e a otimização de parâmetros com muitas estruturas de portas.\n",
        "\n",
        "<span id=\"quantum-phase-estimation-qpe\" />\n",
        "\n",
        "#### Estimativa de fase quântica (QPE)\n",
        "\n",
        "O QPE tem finalidade semelhante ao VQE, mas é muito diferente na implementação. O QPE requer computadores quânticos tolerantes a falhas devido a seus circuitos quânticos geralmente profundos e ao alto nível de coerência que ele exige. Quando o QPE puder ser implementado, ele será mais preciso do que o VQE. Uma maneira de descrever a diferença é por meio da precisão como uma função da profundidade do circuito. O QPE alcança a precisão $\\epsilon$ com profundidades de circuito escalonadas como $O(1/\\epsilon)$ [\\[10\\]](#references). O VQE requer $O(1/\\epsilon^2)$ amostras para atingir a mesma precisão [\\[10,11\\]](#references).\n",
        "\n",
        "<span id=\"krylov-sqd-qsci-and-others-in-this-course\" />\n",
        "\n",
        "#### Krylov, SQD, QSCI e outros neste curso\n",
        "\n",
        "A VQE ajudou a estabelecer algoritmos quânticos que ainda dependem de computadores clássicos, não apenas para operar o computador quântico, mas para partes substanciais do algoritmo. Vários desses algoritmos são o foco do restante deste curso. Aqui, apresentamos uma explicação rápida de alguns deles, simplesmente para compará-los e contrastá-los com o VQE. Eles serão explicados com muito mais detalhes nas lições seguintes.\n",
        "\n",
        "**Diagonalização quântica de Krylov (KQD)**\n",
        "\n",
        "**Os métodos de subespaço de Krylov** são formas de projetar uma matriz em um subespaço para reduzir sua dimensão e torná-la mais gerenciável, mantendo os recursos mais importantes. Um truque desse método é gerar um subespaço que mantenha esses recursos; acontece que a geração desse subespaço está intimamente relacionada a um método bem estabelecido em computadores quânticos chamado **Trotterização**.\n",
        "\n",
        "Existem algumas variantes dos métodos de Krylov quântico, mas, em geral, a abordagem é a seguinte:\n",
        "\n",
        "* Use o computador quântico para gerar um subespaço (o subespaço de Krylov) por meio de Trotterização\n",
        "* Projetar a matriz de interesse nesse subespaço de Krylov\n",
        "* Diagonalize o novo Hamiltoniano projetado usando um computador clássico\n",
        "\n",
        "**Diagonalização quântica baseada em amostragem (SQD)**\n",
        "\n",
        "**A diagonalização quântica baseada em amostragem (SQD)** está relacionada ao método de Krylov, pois também tenta reduzir a dimensão de uma matriz a ser diagonalizada, preservando os principais recursos. O SQD faz isso da seguinte maneira:\n",
        "\n",
        "* Comece com uma estimativa inicial de seu estado fundamental e prepare o sistema nesse estado fundamental.\n",
        "* Use o Sampler para obter amostras das cadeias de bits que compõem esse estado.\n",
        "* Use a coleção de estados da base computacional do amostrador como o subespaço no qual você projeta sua matriz de interesse.\n",
        "* Diagonalize a matriz menor e projetada usando um computador clássico.\n",
        "\n",
        "Isso está relacionado ao VQE no sentido de que ele aproveita a computação clássica e quântica para componentes substanciais do algoritmo. Ambos também compartilham o requisito de prepararmos uma boa estimativa inicial ou ansatz. Mas a distribuição do trabalho entre os computadores clássicos e quânticos no SQD é mais parecida com a do método Krylov.\n",
        "\n",
        "De fato, o método de Krylov e o SQD foram recentemente combinados no método de diagonalização quântica de Krylov baseado em amostragem (SKQD) [\\[12\\]](#references).\n",
        "\n",
        "**Interação de configuração de subespaço quântico**\n",
        "\n",
        "**A Interação de Configuração Selecionada Quântica (QSCI)**[ \\[13\\]](#references) é um algoritmo que produz um estado fundamental aproximado de um Hamiltoniano por meio da amostragem de uma função de onda experimental para identificar os estados de base computacional significativos para gerar um subespaço para uma diagonalização clássica.\n",
        "Tanto o SQD quanto o QSCI usam um computador quântico para construir um subespaço reduzido.  O ponto forte adicional do QSCI está em sua preparação de estado, especialmente no contexto de problemas de química. Ele aproveita várias estratégias, como o uso de estados evoluídos no tempo [\\[14\\]](#references) e um conjunto de respostas inspiradas na química. Ao se concentrar na preparação eficiente do estado, o QSCI reduz os custos computacionais quânticos para Hamiltonianos químicos, mantendo a alta fidelidade e aproveitando a robustez do ruído das técnicas de amostragem de estado quântico [\\[15\\]](#references). O QSCI também oferece uma técnica de construção adaptativa que fornece mais respostas para um resultado melhor.\n",
        "\n",
        "O fluxo de trabalho padrão do QSCI para problemas químicos é o seguinte:\n",
        "\n",
        "* Crie o Hamiltoniano molecular usando o software de sua preferência (como o SciPy ).\n",
        "* Prepare um algoritmo QSCI selecionando um estado inicial adequado e um ansatz inspirado na química com um conjunto pré-selecionado de parâmetros.\n",
        "* Amostragem de estados básicos significativos e diagonalização do Hamiltoniano usando um computador clássico para obter a energia do estado fundamental.\n",
        "* Frequentemente, utiliza-se a recuperação de configuração [\\[16\\]](#references) e a pós-seleção de simetria [\\[15\\]](#references) como técnicas de pós-processamento.\n",
        "* Opcionalmente, o fluxo de trabalho do QSCI adaptável tem um loop de otimização adicional de step2 a step3, usando mais ansätze com estados iniciais aleatórios.\n",
        "\n",
        "<span id=\"check-your-understanding\" />\n",
        "\n",
        "#### Verifique sua compreensão\n",
        "\n",
        "O que o VQE tem em comum com todos os outros métodos listados acima (exceto o QPE, que não é descrito em detalhes)?\n",
        "\n",
        "<Accordion>\n",
        "  <AccordionItem title=\"Resposta\">\n",
        "    Todos envolvem um estado experimental ou uma função de onda de algum tipo. Todos funcionam melhor quando o palpite inicial para esse estado de teste é excelente.\n",
        "\n",
        "    Outra resposta correta é que todas elas são mais fáceis de implementar quando o Hamiltoniano é fácil de medir (pode ser classificado em relativamente poucos grupos de operadores Pauli comutantes).\n",
        "  </AccordionItem>\n",
        "</Accordion>\n",
        "\n",
        "O que o VQE tem em comum com nenhum dos outros métodos listados acima?\n",
        "\n",
        "<Accordion>\n",
        "  <AccordionItem title=\"Resposta\">\n",
        "    Otimizadores clássicos. Nenhum dos outros usa algoritmos de otimização clássicos para selecionar parâmetros de variação.\n",
        "  </AccordionItem>\n",
        "</Accordion>\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "8086b6a5-daf2-457b-bc7a-84db943b333f",
      "metadata": {},
      "source": [
        "<span id=\"references\" />\n",
        "\n",
        "## Referências\n",
        "\n",
        "\\[2] [https://en.wikipedia.org/wiki/Variational\\_quantum\\_eigensolver](https://en.wikipedia.org/wiki/Variational_quantum_eigensolver)\n",
        "\n",
        "\\[3] [https://journals.aps.org/prapplied/abstract/10.1103/PhysRevApplied.19.024047](https://journals.aps.org/prapplied/abstract/10.1103/PhysRevApplied.19.024047)\n",
        "\n",
        "\\[4] [https://arxiv.org/abs/2111.05176](https://arxiv.org/abs/2111.05176)\n",
        "\n",
        "\\[6] [https://inquanto.quantinuum.com/tutorials/InQ\\_tut\\_fe4n2\\_2.html](https://inquanto.quantinuum.com/tutorials/InQ_tut_fe4n2_2.html)\n",
        "\n",
        "\\[7] [https://www.nature.com/articles/s41467-019-10988-2](https://www.nature.com/articles/s41467-019-10988-2)\n",
        "\n",
        "\\[8] [https://arxiv.org/abs/2210.15438](https://arxiv.org/abs/2210.15438)\n",
        "\n",
        "\\[9] [https://journals.aps.org/prresearch/abstract/10.1103/PhysRevResearch.6.013254](https://journals.aps.org/prresearch/abstract/10.1103/PhysRevResearch.6.013254)\n",
        "\n",
        "\\[10] [https://arxiv.org/html/2403.09624v1](https://arxiv.org/html/2403.09624v1)\n",
        "\n",
        "\\[11] [https://www.nature.com/articles/s42005-023-01312-y](https://www.nature.com/articles/s42005-023-01312-y)\n",
        "\n",
        "\\[13] [https://arxiv.org/abs/1802.00171](https://arxiv.org/abs/1802.00171)\n",
        "\n",
        "\\[14] [https://arxiv.org/abs/2103.08505](https://arxiv.org/abs/2103.08505)\n",
        "\n",
        "\\[15] [https://arxiv.org/html/2501.09702v1](https://arxiv.org/html/2501.09702v1)\n",
        "\n",
        "\\[16] [https://quri-sdk.qunasys.com/docs/examples/quri-algo-vm/qsci/](https://quri-sdk.qunasys.com/docs/examples/quri-algo-vm/qsci/)\n",
        "\n",
        "\\[17] [https://arxiv.org/abs/2412.13839](https://arxiv.org/abs/2412.13839)\n",
        "\n",
        "\\[18] [https://arxiv.org/abs/2302.11320v1](https://arxiv.org/abs/2302.11320v1)\n",
        "\n",
        "\\[19] [https://arxiv.org/pdf/2405.05068v1](https://arxiv.org/pdf/2405.05068v1)\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
}