{
  "cells": [
    {
      "cell_type": "markdown",
      "id": "dd701ecc",
      "metadata": {},
      "source": [
        "---\n",
        "title: \"Compilação quântica aproximada para circuitos de evolução temporal\"\n",
        "description: \"Aprenda a usar o AQC-Tensor para compactar circuitos de evolução temporal trotterizados, visando uma execução eficiente em hardware quântico.\"\n",
        "---\n",
        "\n",
        "{/* cspell:ignore circo Néel */}\n",
        "\n",
        "<span id=\"approximate-quantum-compilation-for-time-evolution-circuits\" />\n",
        "\n",
        "# Compilação quântica aproximada para circuitos de evolução temporal\n",
        "\n",
        "*Estimativa de tempo de execução: 15 segundos em um processador Heron (NOTA: Trata-se apenas de uma estimativa. (O tempo de execução pode variar.)*\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "12608301",
      "metadata": {},
      "source": [
        "<span id=\"learning-outcomes\" />\n",
        "\n",
        "## Resultados do aprendizado\n",
        "\n",
        "Ao concluir este tutorial, você deverá compreender as seguintes informações:\n",
        "\n",
        "* Como usar o complemento AQC-Tensor do Qiskit para comprimir circuitos de Trotter profundos em circuitos de ansatz rasos\n",
        "* Como gerar um ansatz parametrizado a partir de um circuito de Trotter e otimizar seus parâmetros utilizando métodos de redes tensoriais (MPS)\n",
        "* Como avaliar a fidelidade de um circuito comprimido em relação à evolução alvo e executá-lo em hardware quântico\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "c3c5992a",
      "metadata": {},
      "source": [
        "<span id=\"prerequisites\" />\n",
        "\n",
        "## Pré-requisitos\n",
        "\n",
        "Recomenda-se que você se familiarize com estes tópicos:\n",
        "\n",
        "* [Noções básicas sobre circuitos quânticos](/learning/courses/basics-of-quantum-information)\n",
        "* [Simulação hamiltoniana e trotterização](/learning/courses/utility-scale-quantum-computing/quantum-simulation)\n",
        "* [Introdução aos primitivos](/docs/guides/primitives)\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "714adc39",
      "metadata": {},
      "source": [
        "<span id=\"background\" />\n",
        "\n",
        "## Segundo plano\n",
        "\n",
        "Este tutorial demonstra como implementar **a Compilação Quântica Aproximada** utilizando redes tensoriais (AQC-Tensor) com o Qiskit para melhorar o desempenho dos circuitos quânticos. O AQC-Tensor comprime circuitos Trotter profundos em circuitos mais simples e mais compatíveis com hardware, mantendo a precisão da simulação.\n",
        "\n",
        "<span id=\"how-aqc-tensor-works\" />\n",
        "\n",
        "### Como funciona o AQC-Tensor\n",
        "\n",
        "Considere simular um hamiltoniano $H$ durante um tempo total de $t$ utilizando $k$ passos de Trotter. O circuito completo de Trotter é:\n",
        "\n",
        "$$\n",
        "U_{\\text{full}} = \\left[U_{\\text{Trotter}}(t/k)\\right]^k\n",
        "$$\n",
        "\n",
        "Uma abordagem simplista utiliza poucos passos de Trotter para manter a profundidade do circuito em um nível razoável, mas isso introduz um erro de Trotter significativo. O AQC-Tensor resolve essa contradição separando a precisão da profundidade:\n",
        "\n",
        "1. **Circuito-alvo (alta precisão, profundo):** Construa um circuito de Trotter com muitos passos — por exemplo, um circuito do tipo “ $10k$ ” — para o mesmo tempo de evolução. Este circuito apresenta um erro de Trotter muito menor, mas é muito complexo para ser implementado em hardware. Como é simulado apenas classicamente como um estado de produto matricial (MPS), a profundidade não é um problema.\n",
        "\n",
        "2. **Circuito de Ansatz (baixa profundidade, parametrizado):** Defina um circuito parametrizado $V(\\theta)$ com a mesma estrutura de um circuito de Trotter de etapa única. Inicialize-o de forma que $V(\\theta_{\\text{init}}) = U_{\\text{Trotter}}(t/k)$, e, em seguida, otimize iterativamente $\\theta$ para que $V(\\theta)$ reproduza o estado-alvo de alta precisão da forma mais fiel possível.\n",
        "\n",
        "O resultado é um circuito que mantém a profundidade de um único passo de Trotter, mas alcança a precisão de muitos, tornando-o viável para hardware quântico no futuro próximo.\n",
        "\n",
        "<span id=\"when-to-use-aqc-tensor\" />\n",
        "\n",
        "### Quando usar o AQC-Tensor\n",
        "\n",
        "O AQC-Tensor é mais eficaz quando:\n",
        "\n",
        "* **A profundidade do circuito excede os tempos de coerência do hardware.** Se uma simulação de Trotter exigir mais etapas de Trotter do que o dispositivo é capaz de suportar, o AQC-Tensor pode comprimir a evolução em um circuito mais simples.\n",
        "* **O entrelaçamento continua sendo tratável no âmbito clássico.** O entrelaçamento total em um estado evoluído no tempo depende principalmente do tempo de evolução $t$, e não do número de passos de Trotter $k$. Isso significa que um circuito alvo com $10k$ passos normalmente não é mais difícil de representar como um MPS do que um com $k$ passos, desde que $t$ seja curto o suficiente para que as dimensões dos elos permaneçam manejáveis.\n",
        "* **Existe uma abordagem natural.** Como o ansatz reflete a estrutura de um circuito de Trotter, ele oferece um ponto de partida com base física e parâmetros iniciais bem definidos, evitando os problemas de convergência que podem afetar ansatzes variacionais arbitrários.\n",
        "\n",
        "Essa abordagem contrasta com a compressão genérica de circuitos: em vez de tentar aproximar um operador unitário arbitrário com menos portas lógicas, o AQC-Tensor mantém a mesma estrutura de portas e otimiza seus parâmetros para reduzir o erro de Trotter. Consulte a [documentação do AQC-Tensor](https://qiskit.github.io/qiskit-addon-aqc-tensor/) para obter mais informações.\n",
        "\n",
        "Este tutorial orienta você por todo o fluxo de trabalho do AQC-Tensor para preparação de estados: definição de um hamiltoniano, geração de circuitos de Trotter, compressão desses circuitos por meio da otimização de redes tensoriais e execução do resultado em um hardware d IBM Quantum®.\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "f8a05291",
      "metadata": {},
      "source": [
        "<span id=\"requirements\" />\n",
        "\n",
        "## Requisitos\n",
        "\n",
        "Antes de iniciar este tutorial, verifique se você tem os seguintes itens instalados:\n",
        "\n",
        "* Qiskit SDK v2.0 ou posterior, com suporte [à visualização](/docs/en/api/qiskit/visualization)\n",
        "* Qiskit Runtime v0.22 ou posterior (`pip install qiskit-ibm-runtime`)\n",
        "* Complemento AQC-Tensor Qiskit (`pip install 'qiskit-addon-aqc-tensor[aer,quimb-jax]'`)\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "f9410d21",
      "metadata": {},
      "source": [
        "<span id=\"setup\" />\n",
        "\n",
        "## Instalação\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 1,
      "id": "ecdb92e0",
      "metadata": {},
      "outputs": [],
      "source": [
        "import numpy as np\n",
        "import quimb.tensor\n",
        "import datetime\n",
        "import matplotlib.pyplot as plt\n",
        "\n",
        "from scipy.linalg import expm\n",
        "from scipy.optimize import OptimizeResult, minimize\n",
        "\n",
        "from qiskit.quantum_info import SparsePauliOp, Pauli\n",
        "from qiskit.transpiler import CouplingMap\n",
        "from qiskit.transpiler.preset_passmanagers import generate_preset_pass_manager\n",
        "from qiskit import QuantumCircuit\n",
        "from qiskit.synthesis import SuzukiTrotter\n",
        "\n",
        "from qiskit_addon_utils.problem_generators import (\n",
        "    generate_time_evolution_circuit,\n",
        ")\n",
        "from qiskit_addon_aqc_tensor.ansatz_generation import (\n",
        "    generate_ansatz_from_circuit,\n",
        ")\n",
        "from qiskit_addon_aqc_tensor.objective import MaximizeStateFidelity\n",
        "from qiskit_addon_aqc_tensor.simulation.quimb import QuimbSimulator\n",
        "from qiskit_addon_aqc_tensor.simulation import tensornetwork_from_circuit\n",
        "from qiskit_addon_aqc_tensor.simulation import compute_overlap\n",
        "\n",
        "from qiskit_ibm_runtime import QiskitRuntimeService\n",
        "from qiskit_ibm_runtime import EstimatorV2 as Estimator\n",
        "from qiskit_ibm_runtime.fake_provider import FakeKyiv\n",
        "\n",
        "from rustworkx.visualization import graphviz_draw"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "6473f943",
      "metadata": {},
      "source": [
        "<span id=\"small-scale-simulator-example\" />\n",
        "\n",
        "## Exemplo de simulador em pequena escala\n",
        "\n",
        "Esta seção utiliza um sistema de 10 locais para ilustrar passo a passo o fluxo de trabalho do AQC-Tensor. Simulamos a dinâmica de uma cadeia de espín XXZ de 10 nós, um modelo amplamente estudado para a análise das interações de espín e das propriedades magnéticas.\n",
        "\n",
        "O hamiltoniano é o seguinte:\n",
        "\n",
        "$$\n",
        "\\hat{\\mathcal{H}}_{XXZ} = \\sum_{i=1}^{L-1} J_{i,(i+1)}\\left(X_i X_{(i+1)}+Y_i Y_{(i+1)}+ 2\\cdot Z_i Z_{(i+1)} \\right) \\, ,\n",
        "$$\n",
        "\n",
        "onde $J_{i,(i+1)}$ é um coeficiente aleatório para a aresta $(i, i+1)$ e $L=10$.\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "6520161e",
      "metadata": {},
      "source": [
        "<span id=\"step-1-map-classical-inputs-to-a-quantum-problem\" />\n",
        "\n",
        "### Passo 1: Mapear entradas clássicas para um problema quântico\n",
        "\n",
        "Nesta etapa, nós:\n",
        "\n",
        "1. Defina o hamiltoniano, o observável e o estado inicial.\n",
        "2. Calcule o valor exato da esperança pelo método clássico para comparação posterior.\n",
        "3. Gere um circuito de Trotter de alta precisão (o alvo do AQC) e comprima-o em um ansatz de baixa profundidade usando o AQC-Tensor.\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "bbeb5729",
      "metadata": {},
      "source": [
        "<span id=\"set-up-the-hamiltonian-observable-and-initial-state\" />\n",
        "\n",
        "#### Definir o hamiltoniano, a observável e o estado inicial\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 2,
      "id": "527dbada",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "Hamiltonian: SparsePauliOp(['IIIIIIIIII', 'IIIIIIIIXX', 'IIIIIIIIYY', 'IIIIIIIIZZ', 'IIIIIIXXII', 'IIIIIIYYII', 'IIIIIIZZII', 'IIIIXXIIII', 'IIIIYYIIII', 'IIIIZZIIII', 'IIXXIIIIII', 'IIYYIIIIII', 'IIZZIIIIII', 'XXIIIIIIII', 'YYIIIIIIII', 'ZZIIIIIIII', 'IIIIIIIXXI', 'IIIIIIIYYI', 'IIIIIIIZZI', 'IIIIIXXIII', 'IIIIIYYIII', 'IIIIIZZIII', 'IIIXXIIIII', 'IIIYYIIIII', 'IIIZZIIIII', 'IXXIIIIIII', 'IYYIIIIIII', 'IZZIIIIIII'],\n",
            "              coeffs=[1.        +0.j, 0.52440675+0.j, 0.52440675+0.j, 1.0488135 +0.j,\n",
            " 0.60759468+0.j, 0.60759468+0.j, 1.21518937+0.j, 0.55138169+0.j,\n",
            " 0.55138169+0.j, 1.10276338+0.j, 0.52244159+0.j, 0.52244159+0.j,\n",
            " 1.04488318+0.j, 0.4618274 +0.j, 0.4618274 +0.j, 0.9236548 +0.j,\n",
            " 0.57294706+0.j, 0.57294706+0.j, 1.14589411+0.j, 0.46879361+0.j,\n",
            " 0.46879361+0.j, 0.93758721+0.j, 0.6958865 +0.j, 0.6958865 +0.j,\n",
            " 1.391773  +0.j, 0.73183138+0.j, 0.73183138+0.j, 1.46366276+0.j])\n",
            "Observable: SparsePauliOp(['IIIIZZIIII'],\n",
            "              coeffs=[1.+0.j])\n"
          ]
        },
        {
          "data": {
            "text/plain": [
              "<Image src=\"/docs/images/tutorials/approximate-quantum-compilation-for-time-evolution/extracted-outputs/527dbada-1.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "execution_count": 2,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "# L is the number of sites in the 1D spin chain\n",
        "L = 10\n",
        "\n",
        "# Generate the coupling map\n",
        "edge_list = [(i - 1, i) for i in range(1, L)]\n",
        "even_edges = edge_list[::2]\n",
        "odd_edges = edge_list[1::2]\n",
        "coupling_map = CouplingMap(edge_list)\n",
        "\n",
        "# Generate random coefficients for our XXZ Hamiltonian\n",
        "np.random.seed(0)\n",
        "Js = np.random.rand(L - 1) + 0.5 * np.ones(L - 1)\n",
        "hamiltonian = SparsePauliOp(Pauli(\"I\" * L))\n",
        "for i, edge in enumerate(even_edges + odd_edges):\n",
        "    hamiltonian += SparsePauliOp.from_sparse_list(\n",
        "        [\n",
        "            (\"XX\", (edge), Js[i] / 2),\n",
        "            (\"YY\", (edge), Js[i] / 2),\n",
        "            (\"ZZ\", (edge), Js[i]),\n",
        "        ],\n",
        "        num_qubits=L,\n",
        "    )\n",
        "\n",
        "# Generate a ZZ observable between the two middle qubits\n",
        "observable = SparsePauliOp.from_sparse_list(\n",
        "    [(\"ZZ\", (L // 2 - 1, L // 2), 1.0)], num_qubits=L\n",
        ")\n",
        "\n",
        "# Generate an initial Néel state |1010101010⟩\n",
        "initial_state_circuit = QuantumCircuit(L)\n",
        "for i in range(L):\n",
        "    if i % 2:\n",
        "        initial_state_circuit.x(i)\n",
        "\n",
        "print(\"Hamiltonian:\", hamiltonian)\n",
        "print(\"Observable:\", observable)\n",
        "graphviz_draw(coupling_map.graph, method=\"circo\")"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "54ad6963",
      "metadata": {},
      "source": [
        "<span id=\"compute-the-exact-expectation-value\" />\n",
        "\n",
        "#### Calcular o valor exato da esperança\n",
        "\n",
        "Para um sistema dessa magnitude, podemos calcular diretamente o valor esperado ao longo do tempo utilizando a exponenciação de matrizes. Isso serve como nossa referência para avaliar a precisão do circuito AQC.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 3,
      "id": "20c70651",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "AQC evolution time: 0.2\n",
            "Subsequent evolution time: 0.066667\n",
            "Total evolution time: 0.266667\n",
            "Exact expectation value: -0.700899\n"
          ]
        }
      ],
      "source": [
        "aqc_evolution_time = 0.2\n",
        "\n",
        "# Each baseline Trotter step covers dt = aqc_evolution_time / 3\n",
        "# The subsequent (uncompressed) step covers 1 additional dt\n",
        "subsequent_evolution_time = aqc_evolution_time / 3\n",
        "total_evolution_time = aqc_evolution_time + subsequent_evolution_time\n",
        "\n",
        "# Compute exact expectation value via matrix exponentiation\n",
        "H_matrix = hamiltonian.to_matrix()\n",
        "U_exact = expm(-1j * H_matrix * total_evolution_time)\n",
        "\n",
        "# Build the initial state vector (Néel state)\n",
        "initial_state_vec = np.zeros(2**L)\n",
        "state_idx = sum(2**i for i in range(L) if i % 2)\n",
        "initial_state_vec[state_idx] = 1.0\n",
        "\n",
        "# Evolve and compute expectation value\n",
        "evolved_state = U_exact @ initial_state_vec\n",
        "obs_matrix = observable.to_matrix()\n",
        "exact_expval = (evolved_state.conj() @ obs_matrix @ evolved_state).real\n",
        "\n",
        "print(f\"AQC evolution time: {aqc_evolution_time}\")\n",
        "print(f\"Subsequent evolution time: {subsequent_evolution_time:.6f}\")\n",
        "print(f\"Total evolution time: {total_evolution_time:.6f}\")\n",
        "print(f\"Exact expectation value: {exact_expval:.6f}\")"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "a93c047c",
      "metadata": {},
      "source": [
        "<span id=\"generate-the-aqc-target-circuit\" />\n",
        "\n",
        "#### Gerar o circuito de referência AQC\n",
        "\n",
        "Vamos agora construir o circuito de Trotter que servirá como alvo do AQC. Este circuito utiliza vários passos de Trotter (32) para garantir alta precisão. Como será simulado apenas de forma clássica como um MPS — e não executado em hardware —, a grande profundidade não é motivo de preocupação.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 4,
      "id": "db66bf00",
      "metadata": {},
      "outputs": [],
      "source": [
        "aqc_target_num_trotter_steps = 32\n",
        "\n",
        "aqc_target_circuit = initial_state_circuit.copy()\n",
        "aqc_target_circuit.compose(\n",
        "    generate_time_evolution_circuit(\n",
        "        hamiltonian,\n",
        "        synthesis=SuzukiTrotter(reps=aqc_target_num_trotter_steps),\n",
        "        time=aqc_evolution_time,\n",
        "    ),\n",
        "    inplace=True,\n",
        ")"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "bce1ef52",
      "metadata": {},
      "source": [
        "<span id=\"generate-an-ansatz-initial-parameters-subsequent-circuit-and-a-baseline-circuit\" />\n",
        "\n",
        "#### Gerar um modelo inicial, parâmetros iniciais, circuito subsequente e um circuito de referência\n",
        "\n",
        "Em seguida, construímos um circuito “bom” com o mesmo tempo de evolução que o alvo do AQC, mas com muito menos passos de Trotter (apenas um). Passamos esse circuito para `generate_ansatz_from_circuit`, que retorna:\n",
        "\n",
        "1. Um circuito **ansatz** geral e parametrizado com a mesma conectividade de dois qubits.\n",
        "2. **Parâmetros iniciais** que reproduzem o circuito de entrada quando inseridos no ansatz.\n",
        "\n",
        "Também construímos:\n",
        "\n",
        "* Um **circuito subsequente** com uma etapa de Trotter que será anexado (sem compactação) após a parte otimizada por AQC, seguindo a abordagem [do tutorial](https://qiskit.github.io/qiskit-addon-aqc-tensor/tutorials/01_initial_state_aqc.html) sobre o estado inicial do AQC-Tensor.\n",
        "* **Um circuito Trotter de referência** que utiliza quatro etapas de Trotter ao longo de todo o tempo de evolução (`aqc_evolution_time + subsequent_evolution_time`). Isso serve como referência: representa o que seria executado em hardware sem AQC. A abordagem AQC (3 etapas comprimidas + 1 etapa não comprimida) alcança maior precisão com menor profundidade.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "78f2665e",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "Target circuit:      depth 384\n",
            "Baseline circuit:    depth 48 (4 Trotter steps, time=0.2667)\n",
            "Subsequent circuit:  depth 12 (1 Trotter step, time=0.0667)\n",
            "Ansatz circuit:      depth 3, with 156 parameters\n"
          ]
        },
        {
          "data": {
            "text/plain": [
              "<Image src=\"/docs/images/tutorials/approximate-quantum-compilation-for-time-evolution/extracted-outputs/78f2665e-1.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "execution_count": 5,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "aqc_ansatz_num_trotter_steps = 1\n",
        "\n",
        "aqc_good_circuit = initial_state_circuit.copy()\n",
        "aqc_good_circuit.compose(\n",
        "    generate_time_evolution_circuit(\n",
        "        hamiltonian,\n",
        "        synthesis=SuzukiTrotter(reps=aqc_ansatz_num_trotter_steps),\n",
        "        time=aqc_evolution_time,\n",
        "    ),\n",
        "    inplace=True,\n",
        ")\n",
        "\n",
        "aqc_ansatz, aqc_initial_parameters = generate_ansatz_from_circuit(\n",
        "    aqc_good_circuit\n",
        ")\n",
        "\n",
        "# Subsequent circuit: 1 non-compressed Trotter step appended after AQC\n",
        "subsequent_num_trotter_steps = 1\n",
        "subsequent_circuit = generate_time_evolution_circuit(\n",
        "    hamiltonian,\n",
        "    synthesis=SuzukiTrotter(reps=subsequent_num_trotter_steps),\n",
        "    time=subsequent_evolution_time,\n",
        ")\n",
        "\n",
        "# Baseline Trotter circuit: 4 Trotter steps over total evolution time, no AQC\n",
        "baseline_num_trotter_steps = 4\n",
        "baseline_circuit = initial_state_circuit.copy()\n",
        "baseline_circuit.compose(\n",
        "    generate_time_evolution_circuit(\n",
        "        hamiltonian,\n",
        "        synthesis=SuzukiTrotter(reps=baseline_num_trotter_steps),\n",
        "        time=total_evolution_time,\n",
        "    ),\n",
        "    inplace=True,\n",
        ")\n",
        "\n",
        "print(\n",
        "    f\"Target circuit:      depth {aqc_target_circuit.depth(lambda x: x.operation.num_qubits == 2)}\"\n",
        ")\n",
        "print(\n",
        "    f\"Baseline circuit:    depth {baseline_circuit.depth(lambda x: x.operation.num_qubits == 2)} ({baseline_num_trotter_steps} Trotter steps, time={total_evolution_time:.4f})\"\n",
        ")\n",
        "print(\n",
        "    f\"Subsequent circuit:  depth {subsequent_circuit.depth(lambda x: x.operation.num_qubits == 2)} ({subsequent_num_trotter_steps} Trotter step, time={subsequent_evolution_time:.4f})\"\n",
        ")\n",
        "print(\n",
        "    f\"Ansatz circuit:      depth {aqc_ansatz.depth(lambda x: x.operation.num_qubits == 2)}, with {len(aqc_initial_parameters)} parameters\"\n",
        ")\n",
        "aqc_ansatz.draw(\"mpl\", fold=-1)"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "be1b4049",
      "metadata": {},
      "source": [
        "<span id=\"set-up-tensor-network-simulation-and-build-the-target-mps\" />\n",
        "\n",
        "#### Configurar a simulação de rede tensorial e construir o MPS alvo\n",
        "\n",
        "Utilizamos o simulador de circuitos [quimb](https://github.com/jcmgray/quimb) matrix-product state (MPS), com o JAX fornecendo diferenciação automática para a otimização baseada em gradientes. Em seguida, construímos uma representação MPS do estado alvo e avaliamos a fidelidade inicial entre o ansatz inicial e o estado alvo. Como a instância do problema é um exemplo relativamente pequeno, a fidelidade inicial é bastante alta.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 6,
      "id": "666fcf42",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "Target MPS maximum bond dimension: 5\n",
            "Starting fidelity: 0.998246\n"
          ]
        }
      ],
      "source": [
        "simulator_settings = QuimbSimulator(\n",
        "    quimb.tensor.CircuitMPS, autodiff_backend=\"jax\"\n",
        ")\n",
        "\n",
        "aqc_target_mps = tensornetwork_from_circuit(\n",
        "    aqc_target_circuit, simulator_settings\n",
        ")\n",
        "print(\"Target MPS maximum bond dimension:\", aqc_target_mps.psi.max_bond())\n",
        "\n",
        "good_mps = tensornetwork_from_circuit(aqc_good_circuit, simulator_settings)\n",
        "starting_fidelity = abs(compute_overlap(good_mps, aqc_target_mps)) ** 2\n",
        "print(f\"Starting fidelity: {starting_fidelity:.6f}\")"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "1f14eb3f",
      "metadata": {},
      "source": [
        "<span id=\"optimize-the-ansatz-parameters\" />\n",
        "\n",
        "#### Otimizar os parâmetros do ansatz\n",
        "\n",
        "Minimizamos a `MaximizeStateFidelity` função de custo utilizando o otimizador L-BFGS-B. O otimizador ajusta iterativamente os parâmetros do ansatz para maximizar a concordância entre o circuito do ansatz e o MPS alvo.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 7,
      "id": "6ad144d6",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "2026-05-18 13:14:49.731596 Intermediate result: Fidelity 0.99952882\n",
            "2026-05-18 13:14:49.734425 Intermediate result: Fidelity 0.99958531\n",
            "2026-05-18 13:14:49.737101 Intermediate result: Fidelity 0.99960093\n",
            "2026-05-18 13:14:49.739813 Intermediate result: Fidelity 0.99961046\n",
            "2026-05-18 13:14:49.742969 Intermediate result: Fidelity 0.99962560\n",
            "2026-05-18 13:14:49.745916 Intermediate result: Fidelity 0.99964395\n",
            "2026-05-18 13:14:49.748615 Intermediate result: Fidelity 0.99968150\n",
            "2026-05-18 13:14:49.753684 Intermediate result: Fidelity 0.99970569\n",
            "2026-05-18 13:14:49.756208 Intermediate result: Fidelity 0.99973788\n",
            "2026-05-18 13:14:49.759067 Intermediate result: Fidelity 0.99975385\n",
            "2026-05-18 13:14:49.762321 Intermediate result: Fidelity 0.99976458\n",
            "2026-05-18 13:14:49.765526 Intermediate result: Fidelity 0.99977661\n",
            "2026-05-18 13:14:49.768496 Intermediate result: Fidelity 0.99978663\n",
            "2026-05-18 13:14:49.771278 Intermediate result: Fidelity 0.99980236\n",
            "2026-05-18 13:14:49.773735 Intermediate result: Fidelity 0.99981607\n",
            "2026-05-18 13:14:49.776339 Intermediate result: Fidelity 0.99982811\n",
            "2026-05-18 13:14:49.779177 Intermediate result: Fidelity 0.99985827\n",
            "2026-05-18 13:14:49.782243 Intermediate result: Fidelity 0.99988354\n",
            "2026-05-18 13:14:49.784904 Intermediate result: Fidelity 0.99991608\n",
            "2026-05-18 13:14:49.787737 Intermediate result: Fidelity 0.99993336\n",
            "2026-05-18 13:14:49.790414 Intermediate result: Fidelity 0.99993956\n",
            "2026-05-18 13:14:49.793029 Intermediate result: Fidelity 0.99994421\n",
            "2026-05-18 13:14:49.795585 Intermediate result: Fidelity 0.99994743\n",
            "2026-05-18 13:14:49.835045 Intermediate result: Fidelity 0.99994791\n",
            "2026-05-18 13:14:49.839786 Intermediate result: Fidelity 0.99994803\n",
            "2026-05-18 13:14:49.842403 Intermediate result: Fidelity 0.99994898\n",
            "2026-05-18 13:14:49.873779 Intermediate result: Fidelity 0.99994898\n",
            "Done after 27 iterations.\n"
          ]
        }
      ],
      "source": [
        "aqc_stopping_fidelity = 1\n",
        "aqc_max_iterations = 500\n",
        "\n",
        "stopping_point = 1.0 - aqc_stopping_fidelity\n",
        "objective = MaximizeStateFidelity(\n",
        "    aqc_target_mps, aqc_ansatz, simulator_settings\n",
        ")\n",
        "\n",
        "\n",
        "def callback(intermediate_result: OptimizeResult):\n",
        "    fidelity = 1 - intermediate_result.fun\n",
        "    print(\n",
        "        f\"{datetime.datetime.now()} Intermediate result: Fidelity {fidelity:.8f}\"\n",
        "    )\n",
        "    if intermediate_result.fun < stopping_point:\n",
        "        raise StopIteration\n",
        "\n",
        "\n",
        "result = minimize(\n",
        "    objective,\n",
        "    aqc_initial_parameters,\n",
        "    method=\"L-BFGS-B\",\n",
        "    jac=True,\n",
        "    options={\"maxiter\": aqc_max_iterations},\n",
        "    callback=callback,\n",
        ")\n",
        "if result.status not in (0, 1, 99):\n",
        "    raise RuntimeError(\n",
        "        f\"Optimization failed: {result.message} (status={result.status})\"\n",
        "    )\n",
        "\n",
        "print(f\"Done after {result.nit} iterations.\")\n",
        "aqc_final_parameters = result.x"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "ea5b484a",
      "metadata": {},
      "source": [
        "<span id=\"assemble-the-final-aqc-circuit\" />\n",
        "\n",
        "#### Montar o circuito AQC final\n",
        "\n",
        "Com os parâmetros otimizados em mãos, os associamos ao ansatz e, em seguida, acrescentamos o passo de Trotter subsequente (não comprimido). O circuito resultante tem a profundidade de um único passo de Trotter comprimido mais um passo não comprimido, mas a parte comprimida aproxima-se da precisão de 32 passos de Trotter.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 8,
      "id": "e09e40de",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<Image src=\"/docs/images/tutorials/approximate-quantum-compilation-for-time-evolution/extracted-outputs/e09e40de-0.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "execution_count": 8,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "aqc_final_circuit = aqc_ansatz.assign_parameters(aqc_final_parameters)\n",
        "aqc_final_circuit.compose(subsequent_circuit, inplace=True)\n",
        "aqc_final_circuit.draw(\"mpl\", fold=-1)"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "047511db",
      "metadata": {},
      "source": [
        "<span id=\"step-2-optimize-problem-for-quantum-hardware-execution\" />\n",
        "\n",
        "### Etapa 2: Otimizar o problema para execução em hardware quântico\n",
        "\n",
        "Para este exemplo em pequena escala, usamos um backend simulado (`FakeKyiv`) para simular a execução em hardware localmente. Compilamos tanto o circuito otimizado para AQC (`aqc_final_circuit`) quanto o circuito Trotter de referência (`baseline_circuit`, quatro etapas de Trotter ao longo de todo o tempo de evolução, sem AQC) para a arquitetura do conjunto de instruções (ISA) do backend, com `optimization_level=3` para reduzir ainda mais a profundidade do circuito.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 9,
      "id": "9e7556dd",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "AQC circuit depth: 15\n",
            "Baseline Trotter circuit depth: 27\n"
          ]
        }
      ],
      "source": [
        "backend = FakeKyiv()\n",
        "\n",
        "pass_manager = generate_preset_pass_manager(\n",
        "    backend=backend, optimization_level=3\n",
        ")\n",
        "\n",
        "# Transpile the AQC-optimized circuit (compressed + subsequent step)\n",
        "isa_circuit = pass_manager.run(aqc_final_circuit)\n",
        "isa_observable = observable.apply_layout(isa_circuit.layout)\n",
        "print(\n",
        "    \"AQC circuit depth:\",\n",
        "    isa_circuit.depth(lambda x: x.operation.num_qubits == 2),\n",
        ")\n",
        "\n",
        "# Transpile the baseline Trotter circuit (no AQC optimization)\n",
        "isa_baseline_circuit = pass_manager.run(baseline_circuit)\n",
        "isa_baseline_observable = observable.apply_layout(isa_baseline_circuit.layout)\n",
        "print(\n",
        "    \"Baseline Trotter circuit depth:\",\n",
        "    isa_baseline_circuit.depth(lambda x: x.operation.num_qubits == 2),\n",
        ")"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "60aec566",
      "metadata": {},
      "source": [
        "<span id=\"step-3-execute-using-qiskit-primitives\" />\n",
        "\n",
        "### Passo 3: Execute usando Qiskit primitives\n",
        "\n",
        "Utilizamos a [`EstimatorV2`](/docs/api/qiskit-ibm-runtime/estimator-v2) primitiva com o backend simulado para executar tanto o circuito otimizado por AQC quanto o circuito Trotter de referência, medindo a observável ZZ para cada um deles.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 10,
      "id": "241e24f2",
      "metadata": {},
      "outputs": [],
      "source": [
        "estimator = Estimator(backend)\n",
        "\n",
        "# Run both circuits\n",
        "aqc_result = estimator.run([(isa_circuit, isa_observable)]).result()\n",
        "baseline_result = estimator.run(\n",
        "    [(isa_baseline_circuit, isa_baseline_observable)]\n",
        ").result()"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "0b980055",
      "metadata": {},
      "source": [
        "<span id=\"step-4-post-process-and-return-result-in-desired-classical-format\" />\n",
        "\n",
        "### Etapa 4: Pós-processamento e retorno do resultado no formato clássico desejado\n",
        "\n",
        "Extraímos os valores esperados de ambas as execuções e os comparamos com o resultado exato. O circuito Trotter de referência mostra o que obteríamos sem o AQC na mesma profundidade do circuito, enquanto o circuito AQC demonstra a melhoria resultante da otimização por rede tensorial.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 11,
      "id": "af07a1d9",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "Exact:              -0.7009\n",
            "Baseline Trotter:   -0.5400, |Δ| = 0.1609  (depth 27, 4 steps)\n",
            "AQC (3+1):          -0.5728, |Δ| = 0.1281  (depth 15, compressed+subsequent)\n"
          ]
        }
      ],
      "source": [
        "aqc_expval = aqc_result[0].data.evs.tolist()\n",
        "baseline_expval = baseline_result[0].data.evs.tolist()\n",
        "\n",
        "print(f\"Exact:              {exact_expval:.4f}\")\n",
        "print(\n",
        "    f\"Baseline Trotter:   {baseline_expval:.4f}, |\\u0394| = {np.abs(exact_expval - baseline_expval):.4f}  (depth {isa_baseline_circuit.depth(lambda x: x.operation.num_qubits == 2)}, {baseline_num_trotter_steps} steps)\"\n",
        ")\n",
        "print(\n",
        "    f\"AQC (3+1):          {aqc_expval:.4f}, |\\u0394| = {np.abs(exact_expval - aqc_expval):.4f}  (depth {isa_circuit.depth(lambda x: x.operation.num_qubits == 2)}, compressed+subsequent)\"\n",
        ")"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 12,
      "id": "77c39ba8",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<Image src=\"/docs/images/tutorials/approximate-quantum-compilation-for-time-evolution/extracted-outputs/77c39ba8-0.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "metadata": {},
          "output_type": "display_data"
        }
      ],
      "source": [
        "plt.style.use(\"seaborn-v0_8\")\n",
        "\n",
        "labels = [\n",
        "    f\"Baseline Trotter\\n({baseline_num_trotter_steps} steps, depth {isa_baseline_circuit.depth(lambda x: x.operation.num_qubits == 2)})\",\n",
        "    f\"AQC (3+1)\\n(depth {isa_circuit.depth(lambda x: x.operation.num_qubits == 2)})\",\n",
        "]\n",
        "values = [baseline_expval, aqc_expval]\n",
        "colors = [\"tab:orange\", \"tab:blue\"]\n",
        "\n",
        "plt.figure(figsize=(8, 5))\n",
        "bars = plt.bar(labels, values, color=colors, width=0.5)\n",
        "plt.axhline(\n",
        "    y=exact_expval,\n",
        "    color=\"tab:green\",\n",
        "    linestyle=\"--\",\n",
        "    linewidth=2,\n",
        "    label=f\"Exact ({exact_expval:.4f})\",\n",
        ")\n",
        "plt.ylabel(\"Expected Value\")\n",
        "plt.title(\n",
        "    \"AQC-Tensor (3 compressed + 1 uncompressed) vs Baseline Trotter (10-site XXZ)\"\n",
        ")\n",
        "plt.legend()\n",
        "for bar in bars:\n",
        "    y_val = bar.get_height()\n",
        "    plt.text(\n",
        "        bar.get_x() + bar.get_width() / 2.0,\n",
        "        y_val,\n",
        "        f\"{y_val:.4f}\",\n",
        "        ha=\"center\",\n",
        "        va=\"bottom\" if y_val >= 0 else \"top\",\n",
        "    )\n",
        "plt.axhline(y=0, color=\"black\", linewidth=0.3)\n",
        "plt.tight_layout()\n",
        "plt.show()"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "37062efa",
      "metadata": {},
      "source": [
        "<span id=\"large-scale-hardware-example\" />\n",
        "\n",
        "## Exemplo de hardware em grande escala\n",
        "\n",
        "Agora, ampliamos para um modelo XXZ de 50 nós para demonstrar o AQC-Tensor em um problema de dimensão mais realista. O fluxo de trabalho é o mesmo do exemplo em pequena escala: comprimimos três passos de Trotter por meio do AQC e acrescentamos um passo não comprimido.\n",
        "\n",
        "Para um sistema dessa magnitude, a exponenciação de matrizes é inviável (dimensões $2^{50}$ ), por isso calculamos o valor esperado de referência diretamente a partir de um MPS de alta precisão evoluído durante todo o tempo.\n",
        "\n",
        "<span id=\"steps-1–4-combined\" />\n",
        "\n",
        "### Etapas 1 a 4 combinadas\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 13,
      "id": "b6c0f26a",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "Target circuit:  depth 385\n",
            "Ansatz circuit:  depth 7, with 816 parameters\n",
            "Subsequent circuit: depth 12\n",
            "Baseline circuit:   depth 49 (4 steps, time=0.2667)\n",
            "Target MPS maximum bond dimension: 5\n",
            "Reference expectation value (from MPS): -0.738669\n",
            "2026-05-18 13:02:11.219150 Intermediate result: Fidelity 0.99795732\n",
            "2026-05-18 13:02:11.232256 Intermediate result: Fidelity 0.99822481\n",
            "2026-05-18 13:02:11.245160 Intermediate result: Fidelity 0.99829520\n",
            "2026-05-18 13:02:11.257765 Intermediate result: Fidelity 0.99832379\n",
            "2026-05-18 13:02:11.270280 Intermediate result: Fidelity 0.99836416\n",
            "2026-05-18 13:02:11.284116 Intermediate result: Fidelity 0.99840073\n",
            "2026-05-18 13:02:11.296856 Intermediate result: Fidelity 0.99846863\n",
            "2026-05-18 13:02:11.309602 Intermediate result: Fidelity 0.99865244\n",
            "2026-05-18 13:02:11.322012 Intermediate result: Fidelity 0.99872665\n",
            "2026-05-18 13:02:11.334195 Intermediate result: Fidelity 0.99892335\n",
            "2026-05-18 13:02:11.346570 Intermediate result: Fidelity 0.99901045\n",
            "2026-05-18 13:02:11.359202 Intermediate result: Fidelity 0.99907181\n",
            "2026-05-18 13:02:11.371511 Intermediate result: Fidelity 0.99911125\n",
            "2026-05-18 13:02:11.383870 Intermediate result: Fidelity 0.99918585\n",
            "2026-05-18 13:02:11.396184 Intermediate result: Fidelity 0.99921504\n",
            "2026-05-18 13:02:11.408543 Intermediate result: Fidelity 0.99924936\n",
            "2026-05-18 13:02:11.422557 Intermediate result: Fidelity 0.99929226\n",
            "2026-05-18 13:02:11.436275 Intermediate result: Fidelity 0.99933099\n",
            "2026-05-18 13:02:11.449511 Intermediate result: Fidelity 0.99935792\n",
            "2026-05-18 13:02:11.462093 Intermediate result: Fidelity 0.99937925\n",
            "2026-05-18 13:02:11.475783 Intermediate result: Fidelity 0.99940690\n",
            "2026-05-18 13:02:11.490254 Intermediate result: Fidelity 0.99944409\n",
            "2026-05-18 13:02:11.503292 Intermediate result: Fidelity 0.99946840\n",
            "2026-05-18 13:02:11.516064 Intermediate result: Fidelity 0.99949378\n",
            "2026-05-18 13:02:11.532861 Intermediate result: Fidelity 0.99951380\n",
            "2026-05-18 13:02:11.546182 Intermediate result: Fidelity 0.99955313\n",
            "2026-05-18 13:02:11.559168 Intermediate result: Fidelity 0.99955707\n",
            "2026-05-18 13:02:11.571753 Intermediate result: Fidelity 0.99959306\n",
            "2026-05-18 13:02:11.584257 Intermediate result: Fidelity 0.99960486\n",
            "2026-05-18 13:02:11.597610 Intermediate result: Fidelity 0.99961714\n",
            "2026-05-18 13:02:11.610106 Intermediate result: Fidelity 0.99962953\n",
            "2026-05-18 13:02:11.622515 Intermediate result: Fidelity 0.99963525\n",
            "2026-05-18 13:02:11.635543 Intermediate result: Fidelity 0.99964658\n",
            "2026-05-18 13:02:11.649044 Intermediate result: Fidelity 0.99965027\n",
            "2026-05-18 13:02:11.664148 Intermediate result: Fidelity 0.99965802\n",
            "2026-05-18 13:02:11.678033 Intermediate result: Fidelity 0.99966731\n",
            "2026-05-18 13:02:11.692714 Intermediate result: Fidelity 0.99967780\n",
            "2026-05-18 13:02:11.706753 Intermediate result: Fidelity 0.99968567\n",
            "2026-05-18 13:02:11.720780 Intermediate result: Fidelity 0.99969139\n",
            "2026-05-18 13:02:11.733471 Intermediate result: Fidelity 0.99969628\n",
            "2026-05-18 13:02:11.745998 Intermediate result: Fidelity 0.99970331\n",
            "2026-05-18 13:02:11.758424 Intermediate result: Fidelity 0.99970796\n",
            "2026-05-18 13:02:11.771986 Intermediate result: Fidelity 0.99971165\n",
            "2026-05-18 13:02:11.785841 Intermediate result: Fidelity 0.99971892\n",
            "2026-05-18 13:02:11.799105 Intermediate result: Fidelity 0.99972226\n",
            "2026-05-18 13:02:11.811623 Intermediate result: Fidelity 0.99972441\n",
            "2026-05-18 13:02:11.824114 Intermediate result: Fidelity 0.99972679\n",
            "2026-05-18 13:02:11.837179 Intermediate result: Fidelity 0.99972965\n",
            "2026-05-18 13:02:12.345479 Intermediate result: Fidelity 0.99972965\n",
            "Done after 49 iterations.\n",
            "<IBMBackend('ibm_pittsburgh')>\n",
            "AQC circuit depth: 71\n",
            "Baseline Trotter circuit depth: 111\n",
            "Job ID: d85kc6o0bvlc73d5nhn0\n"
          ]
        }
      ],
      "source": [
        "# -------------------------Step 1-------------------------\n",
        "\n",
        "# Define the 50-site spin chain\n",
        "L = 50\n",
        "edge_list = [(i - 1, i) for i in range(1, L)]\n",
        "even_edges = edge_list[::2]\n",
        "odd_edges = edge_list[1::2]\n",
        "coupling_map = CouplingMap(edge_list)\n",
        "\n",
        "# Random XXZ Hamiltonian\n",
        "np.random.seed(0)\n",
        "Js = np.random.rand(L - 1) + 0.5 * np.ones(L - 1)\n",
        "hamiltonian = SparsePauliOp(Pauli(\"I\" * L))\n",
        "for i, edge in enumerate(even_edges + odd_edges):\n",
        "    hamiltonian += SparsePauliOp.from_sparse_list(\n",
        "        [\n",
        "            (\"XX\", (edge), Js[i] / 2),\n",
        "            (\"YY\", (edge), Js[i] / 2),\n",
        "            (\"ZZ\", (edge), Js[i]),\n",
        "        ],\n",
        "        num_qubits=L,\n",
        "    )\n",
        "\n",
        "observable = SparsePauliOp.from_sparse_list(\n",
        "    [(\"ZZ\", (L // 2 - 1, L // 2), 1.0)], num_qubits=L\n",
        ")\n",
        "\n",
        "# Initial Néel state\n",
        "initial_state_circuit = QuantumCircuit(L)\n",
        "for i in range(L):\n",
        "    if i % 2:\n",
        "        initial_state_circuit.x(i)\n",
        "\n",
        "# Time parameters\n",
        "aqc_evolution_time = 0.2\n",
        "subsequent_evolution_time = aqc_evolution_time / 3\n",
        "total_evolution_time = aqc_evolution_time + subsequent_evolution_time\n",
        "\n",
        "# AQC target circuit (high-accuracy, 32 Trotter steps for AQC portion)\n",
        "aqc_target_num_trotter_steps = 32\n",
        "\n",
        "aqc_target_circuit = initial_state_circuit.copy()\n",
        "aqc_target_circuit.compose(\n",
        "    generate_time_evolution_circuit(\n",
        "        hamiltonian,\n",
        "        synthesis=SuzukiTrotter(reps=aqc_target_num_trotter_steps),\n",
        "        time=aqc_evolution_time,\n",
        "    ),\n",
        "    inplace=True,\n",
        ")\n",
        "\n",
        "# Generate ansatz from 1-step Trotter circuit\n",
        "aqc_good_circuit = initial_state_circuit.copy()\n",
        "aqc_good_circuit.compose(\n",
        "    generate_time_evolution_circuit(\n",
        "        hamiltonian,\n",
        "        synthesis=SuzukiTrotter(reps=1),\n",
        "        time=aqc_evolution_time,\n",
        "    ),\n",
        "    inplace=True,\n",
        ")\n",
        "\n",
        "aqc_ansatz, aqc_initial_parameters = generate_ansatz_from_circuit(\n",
        "    aqc_good_circuit\n",
        ")\n",
        "\n",
        "# Subsequent circuit: 1 non-compressed Trotter step\n",
        "subsequent_circuit = generate_time_evolution_circuit(\n",
        "    hamiltonian,\n",
        "    synthesis=SuzukiTrotter(reps=1),\n",
        "    time=subsequent_evolution_time,\n",
        ")\n",
        "\n",
        "# Baseline Trotter circuit: 4 Trotter steps over total evolution time, no AQC\n",
        "baseline_num_trotter_steps = 4\n",
        "baseline_circuit = initial_state_circuit.copy()\n",
        "baseline_circuit.compose(\n",
        "    generate_time_evolution_circuit(\n",
        "        hamiltonian,\n",
        "        synthesis=SuzukiTrotter(reps=baseline_num_trotter_steps),\n",
        "        time=total_evolution_time,\n",
        "    ),\n",
        "    inplace=True,\n",
        ")\n",
        "print(\n",
        "    f\"Target circuit:  depth {aqc_target_circuit.depth(lambda x: x.operation.num_qubits == 2)}\"\n",
        ")\n",
        "print(\n",
        "    f\"Ansatz circuit:  depth {aqc_ansatz.depth(lambda x: x.operation.num_qubits == 2)}, with {len(aqc_initial_parameters)} parameters\"\n",
        ")\n",
        "print(\n",
        "    f\"Subsequent circuit: depth {subsequent_circuit.depth(lambda x: x.operation.num_qubits == 2)}\"\n",
        ")\n",
        "print(\n",
        "    f\"Baseline circuit:   depth {baseline_circuit.depth(lambda x: x.operation.num_qubits == 2)} ({baseline_num_trotter_steps} steps, time={total_evolution_time:.4f})\"\n",
        ")\n",
        "\n",
        "# Build target MPS and compute reference expectation value\n",
        "simulator_settings = QuimbSimulator(\n",
        "    quimb.tensor.CircuitMPS, autodiff_backend=\"jax\"\n",
        ")\n",
        "aqc_target_mps = tensornetwork_from_circuit(\n",
        "    aqc_target_circuit, simulator_settings\n",
        ")\n",
        "print(\"Target MPS maximum bond dimension:\", aqc_target_mps.psi.max_bond())\n",
        "\n",
        "# For the reference expectation value, we need the full evolution (AQC + subsequent)\n",
        "# Build a high-accuracy full circuit for MPS reference\n",
        "full_target_circuit = initial_state_circuit.copy()\n",
        "full_target_circuit.compose(\n",
        "    generate_time_evolution_circuit(\n",
        "        hamiltonian,\n",
        "        synthesis=SuzukiTrotter(reps=aqc_target_num_trotter_steps),\n",
        "        time=total_evolution_time,\n",
        "    ),\n",
        "    inplace=True,\n",
        ")\n",
        "full_target_mps = tensornetwork_from_circuit(\n",
        "    full_target_circuit, simulator_settings\n",
        ")\n",
        "exact_expval = full_target_mps.local_expectation(\n",
        "    quimb.pauli(\"Z\") & quimb.pauli(\"Z\"), (L // 2 - 1, L // 2)\n",
        ").real.item()\n",
        "print(f\"Reference expectation value (from MPS): {exact_expval:.6f}\")\n",
        "\n",
        "# Optimize ansatz parameters\n",
        "objective = MaximizeStateFidelity(\n",
        "    aqc_target_mps, aqc_ansatz, simulator_settings\n",
        ")\n",
        "\n",
        "\n",
        "def callback(intermediate_result: OptimizeResult):\n",
        "    fidelity = 1 - intermediate_result.fun\n",
        "    print(\n",
        "        f\"{datetime.datetime.now()} Intermediate result: Fidelity {fidelity:.8f}\"\n",
        "    )\n",
        "\n",
        "\n",
        "result = minimize(\n",
        "    objective,\n",
        "    aqc_initial_parameters,\n",
        "    method=\"L-BFGS-B\",\n",
        "    jac=True,\n",
        "    options={\"maxiter\": 500},\n",
        "    callback=callback,\n",
        ")\n",
        "if result.status not in (0, 1, 99):\n",
        "    raise RuntimeError(\n",
        "        f\"Optimization failed: {result.message} (status={result.status})\"\n",
        "    )\n",
        "print(f\"Done after {result.nit} iterations.\")\n",
        "\n",
        "# Assemble the final AQC circuit: optimized ansatz + subsequent Trotter step\n",
        "aqc_final_circuit = aqc_ansatz.assign_parameters(result.x)\n",
        "aqc_final_circuit.compose(subsequent_circuit, inplace=True)\n",
        "\n",
        "# -------------------------Step 2-------------------------\n",
        "\n",
        "service = QiskitRuntimeService()\n",
        "backend = service.least_busy(min_num_qubits=127)\n",
        "print(backend)\n",
        "\n",
        "pass_manager = generate_preset_pass_manager(\n",
        "    backend=backend, optimization_level=3\n",
        ")\n",
        "isa_circuit = pass_manager.run(aqc_final_circuit)\n",
        "isa_observable = observable.apply_layout(isa_circuit.layout)\n",
        "print(\n",
        "    \"AQC circuit depth:\",\n",
        "    isa_circuit.depth(lambda x: x.operation.num_qubits == 2),\n",
        ")\n",
        "\n",
        "# Also transpile the baseline Trotter circuit (4 Trotter steps, no AQC)\n",
        "isa_baseline_circuit = pass_manager.run(baseline_circuit)\n",
        "isa_baseline_observable = observable.apply_layout(isa_baseline_circuit.layout)\n",
        "print(\n",
        "    \"Baseline Trotter circuit depth:\",\n",
        "    isa_baseline_circuit.depth(lambda x: x.operation.num_qubits == 2),\n",
        ")\n",
        "\n",
        "# -------------------------Step 3-------------------------\n",
        "\n",
        "# Submit both circuits in a single job\n",
        "estimator = Estimator(backend)\n",
        "estimator.options.environment.job_tags = [\"TUT_AQCTE\"]\n",
        "\n",
        "job = estimator.run(\n",
        "    [\n",
        "        (isa_circuit, isa_observable),\n",
        "        (isa_baseline_circuit, isa_baseline_observable),\n",
        "    ]\n",
        ")\n",
        "print(\"Job ID:\", job.job_id())"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 15,
      "id": "a4dc23fd-494e-46cb-a8f5-d1cd444b96f4",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "Exact (MPS):        -0.7387\n",
            "Baseline Trotter:   -0.5955, |Δ| = 0.1432\n",
            "AQC (3+1):          -0.6734, |Δ| = 0.0653\n"
          ]
        },
        {
          "data": {
            "text/plain": [
              "<Image src=\"/docs/images/tutorials/approximate-quantum-compilation-for-time-evolution/extracted-outputs/a4dc23fd-494e-46cb-a8f5-d1cd444b96f4-1.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "metadata": {},
          "output_type": "display_data"
        }
      ],
      "source": [
        "# -------------------------Step 4-------------------------\n",
        "\n",
        "hw_results = job.result()\n",
        "aqc_expval = hw_results[0].data.evs.tolist()\n",
        "baseline_expval = hw_results[1].data.evs.tolist()\n",
        "\n",
        "print(f\"Exact (MPS):        {exact_expval:.4f}\")\n",
        "print(\n",
        "    f\"Baseline Trotter:   {baseline_expval:.4f}, |\\u0394| = {np.abs(exact_expval - baseline_expval):.4f}\"\n",
        ")\n",
        "print(\n",
        "    f\"AQC (3+1):          {aqc_expval:.4f}, |\\u0394| = {np.abs(exact_expval - aqc_expval):.4f}\"\n",
        ")\n",
        "\n",
        "labels = [\n",
        "    f\"Baseline Trotter\\n({baseline_num_trotter_steps} steps, depth {isa_baseline_circuit.depth(lambda x: x.operation.num_qubits == 2)})\",\n",
        "    f\"AQC (3+1)\\n(depth {isa_circuit.depth(lambda x: x.operation.num_qubits == 2)})\",\n",
        "]\n",
        "values = [baseline_expval, aqc_expval]\n",
        "colors = [\"tab:orange\", \"tab:blue\"]\n",
        "\n",
        "plt.figure(figsize=(8, 5))\n",
        "bars = plt.bar(labels, values, color=colors, width=0.5)\n",
        "plt.axhline(\n",
        "    y=exact_expval,\n",
        "    color=\"tab:green\",\n",
        "    linestyle=\"--\",\n",
        "    linewidth=2,\n",
        "    label=f\"Exact ({exact_expval:.4f})\",\n",
        ")\n",
        "plt.ylabel(\"Expected Value\")\n",
        "plt.title(\n",
        "    \"AQC-Tensor (3 compressed + 1 uncompressed) vs Baseline Trotter (50-site XXZ)\"\n",
        ")\n",
        "plt.legend()\n",
        "for bar in bars:\n",
        "    y_val = bar.get_height()\n",
        "    plt.text(\n",
        "        bar.get_x() + bar.get_width() / 2.0,\n",
        "        y_val,\n",
        "        f\"{y_val:.4f}\",\n",
        "        ha=\"center\",\n",
        "        va=\"bottom\" if y_val >= 0 else \"top\",\n",
        "    )\n",
        "plt.axhline(y=0, color=\"black\", linewidth=0.3)\n",
        "plt.tight_layout()\n",
        "plt.show()"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "278bc002",
      "metadata": {},
      "source": [
        "<span id=\"next-steps\" />\n",
        "\n",
        "## Próximas etapas\n",
        "\n",
        "<Admonition type=\"tip\" title=\"Recomendações\">\n",
        "  Se você achou este trabalho interessante, talvez se interesse pelo seguinte material:\n",
        "\n",
        "  * [Documentação do complemento AQC-Tensor](https://qiskit.github.io/qiskit-addon-aqc-tensor/) — inclui a técnica **AQC unitária** relacionada, que otimiza circuitos parametrizados para aproximar um operador unitário alvo, em vez de um estado preparado\n",
        "  * [Técnicas de mitigação e supressão de erros](/docs/guides/error-mitigation-and-suppression-techniques)\n",
        "  * [Combinar técnicas de mitigação de erros](/docs/tutorials/combine-error-mitigation-techniques)\n",
        "</Admonition>\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "id": "a1b8767d",
      "source": "© IBM Corp., 2017-2026"
    }
  ],
  "metadata": {
    "description": "Learn how to use AQC-Tensor to compress Trotterized time-evolution circuits for efficient execution on quantum hardware.",
    "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"
    },
    "title": "Approximate quantum compilation for time evolution circuits",
    "hours": 1.5,
    "qpuSeconds": 15
  },
  "nbformat": 4,
  "nbformat_minor": 5
}