{
  "cells": [
    {
      "cell_type": "markdown",
      "id": "2abbf9e4",
      "metadata": {},
      "source": [
        "---\n",
        "title: \"Estimativa de fase quântica com o Q-CTRL ( Qiskit Functions )\"\n",
        "description: \"Implemente o algoritmo de estimativa de fase quântica em 35 qubits usando a função Q-CTRL Qiskit\"\n",
        "---\n",
        "\n",
        "{/* cspell:ignore eigenphase topk ylab boxstyle fontsize */}\n",
        "\n",
        "<span id=\"quantum-phase-estimation-with-q-ctrls-qiskit-functions\" />\n",
        "\n",
        "# Estimativa de fase quântica com o Q-CTRL ( Qiskit Functions )\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "4170a8f8",
      "metadata": {},
      "source": [
        "*Estimativa de uso: 40 segundos em um processador Heron r2. (OBSERVAÇÃO: essa é apenas uma estimativa. Seu tempo de execução pode variar)*\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "b2f4a24e",
      "metadata": {},
      "source": [
        "<span id=\"background\" />\n",
        "\n",
        "## Segundo plano\n",
        "\n",
        "A estimativa de fase quântica (QPE) é um algoritmo fundamental na computação quântica que forma a base de muitas aplicações importantes, como o algoritmo de Shor, a estimativa de energia do estado fundamental da química quântica e os problemas de valor próprio.  O QPE estima a fase $\\varphi$ associada a um estado próprio de um operador unitário, codificado na relação\n",
        "\n",
        "$U \\lvert \\varphi \\rangle = e^{2\\pi i \\varphi} \\lvert \\varphi \\rangle,$\n",
        "\n",
        "e o determina com uma precisão de $\\epsilon = O(1/2^m)$ usando $m$ contando qubits [\\[1\\]](#references). Ao preparar esses qubits em superposição, aplicar potências controladas de $U$ e, em seguida, usar a Transformada Quântica de Fourier (QFT) inversa para extrair a fase em resultados de medição codificados em binário, a QPE produz uma distribuição de probabilidade com pico em cadeias de bits cujas frações binárias se aproximam de $\\varphi$. No caso ideal, o resultado de medição mais provável corresponde diretamente à expansão binária da fase, enquanto a probabilidade de outros resultados diminui rapidamente com o número de qubits de contagem. No entanto, a execução de circuitos QPE profundos no hardware apresenta desafios: o grande número de qubits e as operações de emaranhamento tornam o algoritmo altamente sensível à decoerência e aos erros de porta. Isso resulta em distribuições ampliadas e deslocadas de cadeias de bits, mascarando a verdadeira fase própria. Como consequência, a cadeia de bits com a maior probabilidade pode não corresponder mais à expansão binária correta de $\\varphi$.\n",
        "\n",
        "Neste tutorial, apresentamos uma implementação do algoritmo QPE usando as ferramentas de gerenciamento de desempenho e supressão de erros Fire Opal da Q-CTRL, oferecidas como uma função Qiskit (consulte a [documentação do Fire Opal](/docs/guides/q-ctrl-performance-management) ). O Fire Opal aplica automaticamente otimizações avançadas, incluindo desacoplamento dinâmico, melhorias no layout de qubit e técnicas de supressão de erros, resultando em resultados de maior fidelidade. Esses aprimoramentos aproximam as distribuições de strings de bits do hardware daquelas obtidas em simulações sem ruído, de modo que você possa identificar com segurança a fase própria correta, mesmo sob os efeitos do ruído.\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "5019f20e",
      "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 v1.4 ou posterior, com suporte [para visualização](/docs/api/qiskit/visualization)\n",
        "* Qiskit Runtime v0.40 ou posterior (`pip install qiskit-ibm-runtime`)\n",
        "* Qiskit Functions Catalog v0.9.0 (`pip install qiskit-ibm-catalog`)\n",
        "* Fire Opal SDK v9.0.2 ou posterior (`pip install fire-opal`)\n",
        "* Q-CTRL Visualizer v8.0.2 ou posterior (`pip install qctrl-visualizer`)\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "360f9871",
      "metadata": {},
      "source": [
        "<span id=\"setup\" />\n",
        "\n",
        "## Instalação\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "46eddb0f",
      "metadata": {},
      "source": [
        "Primeiro, autentique-se usando sua [chave de API IBM Quantum](http://quantum.cloud.ibm.com/). Em seguida, selecione a função do Qiskit da seguinte maneira. (Este código pressupõe que você já tenha [salvo sua conta](/docs/guides/functions-get-started#install-qiskit-functions-catalog-client) no seu ambiente local.)\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 5,
      "id": "39896f05",
      "metadata": {},
      "outputs": [],
      "source": [
        "from qiskit import QuantumCircuit\n",
        "\n",
        "import numpy as np\n",
        "import matplotlib.pyplot as plt\n",
        "import qiskit\n",
        "from qiskit import qasm2\n",
        "from qiskit_aer import AerSimulator\n",
        "from qiskit_ibm_runtime import QiskitRuntimeService\n",
        "from qiskit_ibm_runtime import SamplerV2 as Sampler\n",
        "from qiskit.transpiler.preset_passmanagers import generate_preset_pass_manager\n",
        "import qctrlvisualizer as qv\n",
        "from qiskit_ibm_catalog import QiskitFunctionsCatalog\n",
        "\n",
        "plt.style.use(qv.get_qctrl_style())"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "9abf8775",
      "metadata": {},
      "outputs": [],
      "source": [
        "catalog = QiskitFunctionsCatalog(channel=\"ibm_quantum_platform\")\n",
        "\n",
        "# Access Function\n",
        "perf_mgmt = catalog.load(\"q-ctrl/performance-management\")"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "6337a6c2",
      "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",
        "Neste tutorial, ilustramos o QPE para recuperar a fase própria de um unitário de um único qubit conhecido. A unitária cuja fase queremos estimar é a porta de fase de um único qubit aplicada ao qubit de destino:\n",
        "\n",
        "$$\n",
        "U(\\theta)=\n",
        "\\begin{pmatrix}\n",
        "1 & 0\\\\[2pt]\n",
        "0 & e^{i\\theta}\n",
        "\\end{pmatrix}\n",
        "= e^{i\\theta\\,|1\\rangle\\!\\langle 1|}.\n",
        "$$\n",
        "\n",
        "Preparamos seu estado próprio $|\\psi\\rangle=|1\\rangle$. Como $|1\\rangle$ é um vetor próprio de $U(\\theta)$ com valor próprio $e^{i\\theta}$, a fase própria a ser estimada é:\n",
        "\n",
        "$$\n",
        "\\varphi = \\frac{\\theta}{2\\pi} \\pmod{1}\n",
        "$$\n",
        "\n",
        "Definimos $\\theta=\\tfrac{1}{6}\\cdot 2\\pi$, de modo que a fase da verdade fundamental é $\\varphi=1/6$. O circuito QPE implementa as potências controladas $U^{2^k}$ aplicando rotações de fase controladas com ângulos $\\theta\\cdot2^k$ e, em seguida, aplica a QFT inversa ao registro de contagem e a mede. As cadeias de bits resultantes se concentram na representação binária de $1/6$.\n",
        "\n",
        "O circuito usa $m$ qubits de contagem (para definir a precisão da estimativa) mais um qubit de destino. Começamos definindo os blocos de construção necessários para implementar o QPE: a Transformada Quântica de Fourier (QFT) e seu inverso, funções utilitárias para mapear entre frações decimais e binárias da fase própria e auxiliares para normalizar contagens brutas em probabilidades para comparar resultados de simulação e hardware.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 7,
      "id": "4c5cd3d4",
      "metadata": {},
      "outputs": [],
      "source": [
        "def inverse_quantum_fourier_transform(quantum_circuit, number_of_qubits):\n",
        "    \"\"\"\n",
        "    Apply an inverse Quantum Fourier Transform the first `number_of_qubits` qubits in the\n",
        "    `quantum_circuit`.\n",
        "    \"\"\"\n",
        "    for qubit in range(number_of_qubits // 2):\n",
        "        quantum_circuit.swap(qubit, number_of_qubits - qubit - 1)\n",
        "    for j in range(number_of_qubits):\n",
        "        for m in range(j):\n",
        "            quantum_circuit.cp(-np.pi / float(2 ** (j - m)), m, j)\n",
        "        quantum_circuit.h(j)\n",
        "    return quantum_circuit"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 8,
      "id": "6d56f133",
      "metadata": {},
      "outputs": [],
      "source": [
        "def bitstring_count_to_probabilities(data, shot_count):\n",
        "    \"\"\"\n",
        "    This function turns an unsorted dictionary of bitstring counts into a sorted dictionary\n",
        "    of probabilities.\n",
        "    \"\"\"\n",
        "    # Turn the bitstring counts into probabilities.\n",
        "    probabilities = {\n",
        "        bitstring: bitstring_count / shot_count\n",
        "        for bitstring, bitstring_count in data.items()\n",
        "    }\n",
        "\n",
        "    sorted_probabilities = dict(\n",
        "        sorted(probabilities.items(), key=lambda x: x[1], reverse=True)\n",
        "    )\n",
        "\n",
        "    return sorted_probabilities"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "d33b21fd",
      "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",
        "Construímos o circuito QPE preparando os qubits de contagem em superposição, aplicando rotações de fase controladas para codificar a fase própria de destino e finalizando com um QFT inverso antes da medição.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 9,
      "id": "79d62a79",
      "metadata": {},
      "outputs": [],
      "source": [
        "def quantum_phase_estimation_benchmark_circuit(\n",
        "    number_of_counting_qubits, phase\n",
        "):\n",
        "    \"\"\"\n",
        "    Create the circuit for quantum phase estimation.\n",
        "\n",
        "    Parameters\n",
        "    ----------\n",
        "    number_of_counting_qubits : The number of qubits in the circuit.\n",
        "    phase : The desired phase.\n",
        "\n",
        "    Returns\n",
        "    -------\n",
        "    QuantumCircuit\n",
        "        The quantum phase estimation circuit for `number_of_counting_qubits` qubits.\n",
        "    \"\"\"\n",
        "    qc = QuantumCircuit(\n",
        "        number_of_counting_qubits + 1, number_of_counting_qubits\n",
        "    )\n",
        "    target = number_of_counting_qubits\n",
        "\n",
        "    # |1> eigenstate for the single-qubit phase gate\n",
        "    qc.x(target)\n",
        "\n",
        "    # Hadamards on counting register\n",
        "    for q in range(number_of_counting_qubits):\n",
        "        qc.h(q)\n",
        "\n",
        "    # ONE controlled phase per counting qubit: cp(phase * 2**k)\n",
        "    for k in range(number_of_counting_qubits):\n",
        "        qc.cp(phase * (1 << k), k, target)\n",
        "\n",
        "    qc.barrier()\n",
        "\n",
        "    # Inverse QFT on counting register\n",
        "    inverse_quantum_fourier_transform(qc, number_of_counting_qubits)\n",
        "\n",
        "    qc.barrier()\n",
        "    for q in range(number_of_counting_qubits):\n",
        "        qc.measure(q, q)\n",
        "    return qc"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "0e550ad5",
      "metadata": {},
      "source": [
        "<span id=\"step-3-execute-using-qiskit-primitives\" />\n",
        "\n",
        "## Passo 3: Execute usando Qiskit primitives\n",
        "\n",
        "Definimos o número de disparos e qubits para o experimento e codificamos a fase de destino $\\varphi = 1/6$ usando $m$ dígitos binários. Com esses parâmetros, criamos o circuito QPE que será executado na simulação, no hardware padrão e nos back-ends aprimorados do Fire Opal.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 10,
      "id": "19e6dd45",
      "metadata": {},
      "outputs": [],
      "source": [
        "shot_count = 10000\n",
        "num_qubits = 35\n",
        "phase = (1 / 6) * 2 * np.pi\n",
        "circuits_quantum_phase_estimation = (\n",
        "    quantum_phase_estimation_benchmark_circuit(\n",
        "        number_of_counting_qubits=num_qubits, phase=phase\n",
        "    )\n",
        ")"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "6c53f759",
      "metadata": {},
      "source": [
        "<span id=\"run-mps-simulation\" />\n",
        "\n",
        "### Executar simulação MPS\n",
        "\n",
        "Primeiro, geramos uma distribuição de referência usando o simulador `matrix_product_state` e convertemos as contagens em probabilidades normalizadas para comparação posterior com os resultados do hardware.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 11,
      "id": "1fabc3a2",
      "metadata": {},
      "outputs": [],
      "source": [
        "# Run the algorithm on the IBM Aer simulator.\n",
        "aer_simulator = AerSimulator(method=\"matrix_product_state\")\n",
        "\n",
        "# Transpile the circuits for the simulator.\n",
        "transpiled_circuits = qiskit.transpile(\n",
        "    circuits_quantum_phase_estimation, aer_simulator\n",
        ")"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 12,
      "id": "99eca1f1",
      "metadata": {},
      "outputs": [],
      "source": [
        "simulated_result = (\n",
        "    aer_simulator.run(transpiled_circuits, shots=shot_count)\n",
        "    .result()\n",
        "    .get_counts()\n",
        ")"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 13,
      "id": "263624e9",
      "metadata": {},
      "outputs": [],
      "source": [
        "simulated_result_probabilities = []\n",
        "\n",
        "simulated_result_probabilities.append(\n",
        "    bitstring_count_to_probabilities(\n",
        "        simulated_result,\n",
        "        shot_count=shot_count,\n",
        "    )\n",
        ")"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "df203619",
      "metadata": {},
      "source": [
        "<span id=\"run-on-hardware\" />\n",
        "\n",
        "### Executar no hardware\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "41bf548b",
      "metadata": {},
      "outputs": [],
      "source": [
        "service = QiskitRuntimeService()\n",
        "backend = service.least_busy(operational=True, simulator=False)\n",
        "\n",
        "pm = generate_preset_pass_manager(backend=backend, optimization_level=3)\n",
        "isa_circuits = pm.run(circuits_quantum_phase_estimation)"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 15,
      "id": "b2bdb8b8",
      "metadata": {},
      "outputs": [],
      "source": [
        "# Run the algorithm with IBM default.\n",
        "sampler = Sampler(backend)\n",
        "\n",
        "# Run all circuits using Qiskit Runtime.\n",
        "ibm_default_job = sampler.run([isa_circuits], shots=shot_count)"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "945967d0",
      "metadata": {},
      "source": [
        "<span id=\"run-on-hardware-with-fire-opal\" />\n",
        "\n",
        "### Execute em hardware com Fire Opal\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "ca892a3c",
      "metadata": {},
      "outputs": [],
      "source": [
        "# Run the circuit using Sampler\n",
        "fire_opal_job = perf_mgmt.run(\n",
        "    primitive=\"sampler\",\n",
        "    pubs=[qasm2.dumps(circuits_quantum_phase_estimation)],\n",
        "    backend_name=backend.name,\n",
        "    options={\"default_shots\": shot_count},\n",
        ")"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "000a119c",
      "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"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "dff71917",
      "metadata": {},
      "outputs": [],
      "source": [
        "# Retrieve results.\n",
        "ibm_default_result = ibm_default_job.result()\n",
        "ibm_default_probabilities = []\n",
        "\n",
        "for idx, pub_result in enumerate(ibm_default_result):\n",
        "    ibm_default_probabilities.append(\n",
        "        bitstring_count_to_probabilities(\n",
        "            pub_result.data.c0.get_counts(),\n",
        "            shot_count=shot_count,\n",
        "        )\n",
        "    )"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "be4e50e5",
      "metadata": {},
      "outputs": [],
      "source": [
        "fire_opal_result = fire_opal_job.result()\n",
        "\n",
        "fire_opal_probabilities = []\n",
        "for idx, pub_result in enumerate(fire_opal_result):\n",
        "    fire_opal_probabilities.append(\n",
        "        bitstring_count_to_probabilities(\n",
        "            pub_result.data.c0.get_counts(),\n",
        "            shot_count=shot_count,\n",
        "        )\n",
        "    )"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 16,
      "id": "c0134366",
      "metadata": {},
      "outputs": [],
      "source": [
        "data = {\n",
        "    \"simulation\": simulated_result_probabilities,\n",
        "    \"default\": ibm_default_probabilities,\n",
        "    \"fire_opal\": fire_opal_probabilities,\n",
        "}"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 21,
      "id": "a6dc6744",
      "metadata": {},
      "outputs": [],
      "source": [
        "def plot_distributions(\n",
        "    data,\n",
        "    number_of_counting_qubits,\n",
        "    top_k=None,\n",
        "    by=\"prob\",\n",
        "    shot_count=None,\n",
        "):\n",
        "    def nrm(d):\n",
        "        s = sum(d.values())\n",
        "        return {k: (v / s if s else 0.0) for k, v in d.items()}\n",
        "\n",
        "    def as_float(d):\n",
        "        return {k: float(v) for k, v in d.items()}\n",
        "\n",
        "    def to_space(d):\n",
        "        if by == \"prob\":\n",
        "            return nrm(as_float(d))\n",
        "        else:\n",
        "            if shot_count and 0.99 <= sum(d.values()) <= 1.01:\n",
        "                return {\n",
        "                    k: v * float(shot_count) for k, v in as_float(d).items()\n",
        "                }\n",
        "            else:\n",
        "                return as_float(d)\n",
        "\n",
        "    def topk(d, k):\n",
        "        items = sorted(d.items(), key=lambda kv: kv[1], reverse=True)\n",
        "        return items[: (k or len(d))]\n",
        "\n",
        "    phase = \"1/6\"\n",
        "\n",
        "    sim = to_space(data[\"simulation\"])\n",
        "    dft = to_space(data[\"default\"])\n",
        "    qct = to_space(data[\"fire_opal\"])\n",
        "\n",
        "    correct = max(sim, key=sim.get) if sim else None\n",
        "    print(\"Correct result:\", correct)\n",
        "\n",
        "    sim_items = topk(sim, top_k)\n",
        "    dft_items = topk(dft, top_k)\n",
        "    qct_items = topk(qct, top_k)\n",
        "\n",
        "    sim_keys, y_sim = zip(*sim_items) if sim_items else ([], [])\n",
        "    dft_keys, y_dft = zip(*dft_items) if dft_items else ([], [])\n",
        "    qct_keys, y_qct = zip(*qct_items) if qct_items else ([], [])\n",
        "\n",
        "    fig, axes = plt.subplots(3, 1, layout=\"constrained\")\n",
        "    ylab = \"Probabilities\"\n",
        "\n",
        "    def panel(ax, keys, ys, title, color):\n",
        "        x = np.arange(len(keys))\n",
        "        bars = ax.bar(x, ys, color=color)\n",
        "        ax.set_title(title)\n",
        "        ax.set_ylabel(ylab)\n",
        "        ax.set_xticks(x)\n",
        "        ax.set_xticklabels(keys, rotation=90)\n",
        "        ax.set_xlabel(\"Bitstrings\")\n",
        "        if correct in keys:\n",
        "            i = keys.index(correct)\n",
        "            bars[i].set_edgecolor(\"black\")\n",
        "            bars[i].set_linewidth(2)\n",
        "        return max(ys, default=0.0)\n",
        "\n",
        "    c_sim, c_dft, c_qct = (\n",
        "        qv.QCTRL_STYLE_COLORS[5],\n",
        "        qv.QCTRL_STYLE_COLORS[1],\n",
        "        qv.QCTRL_STYLE_COLORS[0],\n",
        "    )\n",
        "    m1 = panel(axes[0], list(sim_keys), list(y_sim), \"Simulation\", c_sim)\n",
        "    m2 = panel(axes[1], list(dft_keys), list(y_dft), \"Default\", c_dft)\n",
        "    m3 = panel(axes[2], list(qct_keys), list(y_qct), \"Q-CTRL\", c_qct)\n",
        "\n",
        "    for ax, m in zip(axes, (m1, m2, m3)):\n",
        "        ax.set_ylim(0, 1.05 * (m or 1.0))\n",
        "\n",
        "    for ax in axes:\n",
        "        ax.label_outer()\n",
        "    fig.suptitle(\n",
        "        rf\"{number_of_counting_qubits} counting qubits, $2\\pi\\varphi$={phase}\"\n",
        "    )\n",
        "    fig.set_size_inches(20, 10)\n",
        "    plt.show()"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 22,
      "id": "593334d2",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "Correct result: 00101010101010101010101010101010101\n"
          ]
        },
        {
          "data": {
            "text/plain": [
              "<Image src=\"/docs/images/tutorials/quantum-phase-estimation-qctrl/extracted-outputs/593334d2-1.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "metadata": {},
          "output_type": "display_data"
        }
      ],
      "source": [
        "experiment_index = 0\n",
        "phase_index = 0\n",
        "\n",
        "distributions = {\n",
        "    \"simulation\": data[\"simulation\"][phase_index],\n",
        "    \"default\": data[\"default\"][phase_index],\n",
        "    \"fire_opal\": data[\"fire_opal\"][phase_index],\n",
        "}\n",
        "\n",
        "plot_distributions(\n",
        "    distributions, num_qubits, top_k=100, by=\"prob\", shot_count=shot_count\n",
        ")"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "a5199fb3",
      "metadata": {},
      "source": [
        "A simulação define a linha de base para a fase própria correta. As execuções de hardware padrão mostram ruído que obscurece esse resultado, pois o ruído espalha a probabilidade por muitas cadeias de bits incorretas. Com o Q-CTRL Performance Management, a distribuição se torna mais nítida e o resultado correto é recuperado, permitindo um QPE confiável nessa escala.\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "c72c6bb0",
      "metadata": {},
      "source": [
        "<span id=\"references\" />\n",
        "\n",
        "## Referências\n",
        "\n",
        "\\[1] Aula 7: [Estimativa de fase e fatoração](/learning/courses/fundamentals-of-quantum-algorithms/phase-estimation-and-factoring/introduction). IBM Quantum Learning - Fundamentos de algoritmos quânticos. Recuperado em 3 de outubro de 2025.\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "4760c8b9",
      "metadata": {},
      "source": [
        "<span id=\"tutorial-survey\" />\n",
        "\n",
        "## Pesquisa tutorial\n",
        "\n",
        "Reserve um minuto para fazer comentários sobre este tutorial. Suas percepções nos ajudarão a melhorar nossas ofertas de conteúdo e a experiência do usuário.\n",
        "\n",
        "[Link para a pesquisa](https://your.feedback.ibm.com/jfe/form/SV_3BLFkNVEuh0QBWm)\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"
    },
    "hours": 1,
    "qpuSeconds": 40
  },
  "nbformat": 4,
  "nbformat_minor": 5
}