{
  "cells": [
    {
      "cell_type": "markdown",
      "id": "3445b0b5-7f26-4610-8e1b-5112df1fccb0",
      "metadata": {},
      "source": [
        "---\n",
        "title: \"Combinar opções de mitigação de erro com o primitivo Estimator\"\n",
        "description: \"Combine opções de mitigação de erros para experimentos em escala utilitária usando QPUs 100Q+ IBM Quantum e a primitiva Estimator Qiskit Runtime.\"\n",
        "---\n",
        "\n",
        "<span id=\"combine-error-mitigation-options-with-the-estimator-primitive\" />\n",
        "\n",
        "# Combinar opções de mitigação de erro com o primitivo Estimator\n",
        "\n",
        "*Estimativa de tempo de execução: 7 minutos em um processador Heron r2 (NOTA: Trata-se apenas de uma estimativa. (O tempo de execução pode variar.)*\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "39ba4396-9111-4421-9371-542f067bc816",
      "metadata": {},
      "source": [
        "<span id=\"learning-outcomes\" />\n",
        "\n",
        "## Resultados do aprendizado\n",
        "\n",
        "Recomendamos que os usuários estejam familiarizados com os seguintes tópicos antes de seguir com este tutorial:\n",
        "\n",
        "* Os conceitos básicos de desacoplamento dinâmico, mitigação de erros de medição, rotação de portas e extrapolação sem ruído, conforme descrito neste [guia](/docs/guides/error-mitigation-and-suppression-techniques).\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "b27cb482-b77a-4953-a0a4-39df33896d12",
      "metadata": {},
      "source": [
        "<span id=\"prerequisites\" />\n",
        "\n",
        "## Pré-requisitos\n",
        "\n",
        "Após concluir este tutorial, os usuários deverão compreender:\n",
        "\n",
        "* Como as técnicas de mitigação de erros mencionadas acima são implementadas seletivamente no hardware.\n",
        "* Como se comparam em termos de capacidade de atenuar o ruído do hardware.\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "018313d1-d959-4011-81df-59bf7c157470",
      "metadata": {},
      "source": [
        "<span id=\"background\" />\n",
        "\n",
        "## Segundo plano\n",
        "\n",
        "Este tutorial explora as opções de supressão e mitigação de erros disponíveis na primitiva Estimator do Qiskit Runtime. Este tutorial mostra como implementar cada um dos métodos a seguir individualmente:\n",
        "\n",
        "* Desacoplamento dinâmico\n",
        "* Mitigação de erros de medição\n",
        "* Giro do portão\n",
        "* Extrapolação de ruído zero (ZNE)\n",
        "\n",
        "Observe que uma alternativa à implementação dessas técnicas individualmente é implementá-las utilizando um [nível de resiliência](/docs/guides/estimator-noise-management), em que `resilience_level` assume os valores 0, 1, 2:\n",
        "\n",
        "* 0: Nenhuma medida de mitigação foi implementada.\n",
        "* 1: Foi implementada a mitigação de erros de medição.\n",
        "* 2: Foram implementadas a rotação de portas, a mitigação de erros de medição e o ZNE.\n",
        "\n",
        "Neste tutorial, você criará um circuito e um observável e enviará tarefas utilizando a primitiva Estimator com diferentes combinações de configurações de mitigação de erros. Em seguida, você representará graficamente os resultados para observar os efeitos das diversas configurações. A maior parte do tutorial utiliza um circuito de 10 qubits para facilitar a visualização e, no final, você ampliará o fluxo de trabalho para 50 qubits.\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "0f3d3378-8dac-489e-bf6d-292e693ec145",
      "metadata": {},
      "source": [
        "<span id=\"requirements\" />\n",
        "\n",
        "## Requisitos\n",
        "\n",
        "Antes de iniciar este passo a passo, certifique-se de que você tem o seguinte instalado:\n",
        "\n",
        "* Qiskit SDK v2.1 ou posterior, com suporte [para visualização](/docs/api/qiskit/visualization)\n",
        "* Qiskit Runtime v0.40 ou posterior (`pip install qiskit-ibm-runtime`)\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "069658fa-fa45-48b8-ab69-2610228bf6e4",
      "metadata": {},
      "source": [
        "<span id=\"setup\" />\n",
        "\n",
        "## Instalação\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 7,
      "id": "95a72452-e067-4ee5-bcd9-e3bfcf0de208",
      "metadata": {},
      "outputs": [],
      "source": [
        "import matplotlib.pyplot as plt\n",
        "import numpy as np\n",
        "\n",
        "from qiskit.circuit.library import efficient_su2, unitary_overlap\n",
        "from qiskit.quantum_info import SparsePauliOp\n",
        "from qiskit.transpiler.preset_passmanagers import generate_preset_pass_manager\n",
        "\n",
        "from qiskit_ibm_runtime import QiskitRuntimeService\n",
        "from qiskit_ibm_runtime import Batch, EstimatorV2 as Estimator"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "d15c5fde-5046-4d86-86d8-72d1ed748c4e",
      "metadata": {},
      "source": [
        "<span id=\"small-scale-simulator-example\" />\n",
        "\n",
        "## Exemplo de simulador em pequena escala\n",
        "\n",
        "Vamos pular esta etapa, pois a mitigação de erros de tempo de execução não é compatível com simuladores.\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "b2be0539-4f60-46e8-be1f-8869dae30888",
      "metadata": {},
      "source": [
        "<span id=\"hardware-example\" />\n",
        "\n",
        "## Exemplo de hardware\n",
        "\n",
        "<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",
        "Este passo a passo pressupõe que o problema clássico já foi mapeado para o quântico. Comece construindo um circuito e um observável para medir. Embora as técnicas utilizadas aqui se apliquem a muitos tipos diferentes de circuitos, para simplificar, este passo a passo utiliza o [`efficient_su2`](/docs/api/qiskit/qiskit.circuit.library.efficient_su2) circuito incluído na biblioteca de circuitos Qiskit.\n",
        "\n",
        "`efficient_su2` é um circuito quântico parametrizado projetado para ser executado com eficiência em hardware quântico com conectividade limitada de qubits, mantendo-se, ao mesmo tempo, suficientemente expressivo para resolver problemas em áreas de aplicação como otimização e química. É construído alternando camadas de portas de um qubit parametrizadas com uma camada que contém um padrão fixo de portas de dois qubits, por um número determinado de repetições. O padrão das portas de dois qubits pode ser definido pelo usuário. Aqui você pode usar o padrão `pairwise` integrado, pois ele minimiza a profundidade do circuito ao agrupar as portas de dois qubits da forma mais compacta possível. Esse padrão pode ser executado utilizando apenas conectividade linear entre qubits.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 8,
      "id": "24abd7ba-bbb8-443b-9e81-866795d39a6c",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<Image src=\"/docs/images/tutorials/combine-error-mitigation-techniques/extracted-outputs/24abd7ba-bbb8-443b-9e81-866795d39a6c-0.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "execution_count": 8,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "n_qubits = 10\n",
        "reps = 1\n",
        "\n",
        "circuit = efficient_su2(n_qubits, entanglement=\"pairwise\", reps=reps)\n",
        "\n",
        "circuit.decompose().draw(\"mpl\", scale=0.7)"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "34fec53b-a8b2-461b-a20d-e8ad54b992fa",
      "metadata": {},
      "source": [
        "Como nossa observável, vamos considerar o operador de Pauli $Z$ atuando sobre o último qubit, $Z I \\cdots I$.\n",
        "Observe que o fato de o último qubit corresponder ao primeiro elemento dessa sequência se deve ao uso da notação little-endian pelo Qiskit.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 9,
      "id": "9500ba7b-4542-465f-a4e1-60165d6b6d1e",
      "metadata": {},
      "outputs": [],
      "source": [
        "# Z on the last qubit (index -1) with coefficient 1.0\n",
        "observable = SparsePauliOp.from_sparse_list(\n",
        "    [(\"Z\", [-1], 1.0)], num_qubits=n_qubits\n",
        ")"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "46eff743-de9f-4f55-9c47-02c6d6115b80",
      "metadata": {},
      "source": [
        "Nesta altura, você pode prosseguir com a execução do circuito e medir a grandeza observável. No entanto, você também deseja comparar o resultado do dispositivo quântico com a resposta correta — ou seja, o valor teórico da observável, caso o circuito tivesse sido executado sem erros. No caso de circuitos quânticos pequenos, é possível calcular esse valor simulando o circuito em um computador clássico, mas isso não é possível para circuitos maiores, em escala comercial. É possível contornar esse problema com a técnica do \"circuito espelho\" (também conhecida como \"compute-uncompute\"), que é útil para avaliar o desempenho de dispositivos quânticos.\n",
        "\n",
        "<span id=\"mirror-circuit\" />\n",
        "\n",
        "#### Circuito espelho\n",
        "\n",
        "Na técnica do circuito espelho, você concatena o circuito com seu circuito inverso, que é formado pela inversão de cada porta do circuito na ordem inversa. O circuito resultante implementa o operador de identidade, que pode ser trivialmente simulado. Como a estrutura do circuito original é preservada no circuito espelho, a execução do circuito espelho ainda dá uma ideia de como o dispositivo quântico funcionaria no circuito original.\n",
        "\n",
        "A célula de código a seguir atribui parâmetros aleatórios ao seu circuito e, em seguida, constrói o circuito espelho usando a [`unitary_overlap`](/docs/api/qiskit/qiskit.circuit.library.unitary_overlap) classe. Antes de espelhar o circuito, acrescente uma instrução [de barreira](/docs/api/qiskit/circuit#qiskit.circuit.Barrier) a ele para impedir que o transpilador una as duas partes do circuito de cada lado da barreira, resultando em um circuito transpilado sem nenhuma porta lógica.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 10,
      "id": "4dbde811-1ba9-47a8-85a0-dcaff054ed60",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<Image src=\"/docs/images/tutorials/combine-error-mitigation-techniques/extracted-outputs/4dbde811-1ba9-47a8-85a0-dcaff054ed60-0.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "execution_count": 10,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "# Generate random parameters\n",
        "rng = np.random.default_rng(1234)\n",
        "params = rng.uniform(-np.pi, np.pi, size=circuit.num_parameters)\n",
        "\n",
        "# Assign the parameters to the circuit\n",
        "assigned_circuit = circuit.assign_parameters(params)\n",
        "\n",
        "# Add a barrier to prevent circuit optimization of mirrored operators\n",
        "assigned_circuit.barrier()\n",
        "\n",
        "# Construct mirror circuit\n",
        "mirror_circuit = unitary_overlap(assigned_circuit, assigned_circuit)\n",
        "\n",
        "mirror_circuit.decompose().draw(\"mpl\", scale=0.7)"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "a37c97de-c942-4419-9409-5bcaef9c6876",
      "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",
        "Você deve otimizar seu circuito antes de executá-lo no hardware. Esse processo envolve algumas etapas:\n",
        "\n",
        "* Escolha um layout de qubit que mapeie os qubits virtuais de seu circuito para qubits físicos no hardware.\n",
        "* Insira portas de troca conforme necessário para rotear interações entre qubits que não estão conectados.\n",
        "* Traduza as portas em seu circuito para instruções [de arquitetura de conjunto de instruções (ISA)](/docs/guides/transpile#instruction-set-architecture) que possam ser executadas diretamente no hardware.\n",
        "* Realizar otimizações de circuito para minimizar a profundidade do circuito e a contagem de portas.\n",
        "\n",
        "O transpiler integrado ao Qiskit pode realizar todas essas etapas para você. Como este exemplo utiliza um circuito eficiente em termos de hardware, o transpiler deve ser capaz de escolher um layout de qubits que não exija a inserção de portas de troca para o encaminhamento das interações.\n",
        "\n",
        "Você precisa escolher o dispositivo de hardware a ser usado antes de otimizar seu circuito. A célula de código a seguir solicita o dispositivo menos ocupado com pelo menos 127 qubits.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "2c3ea768-0596-4db1-9b51-3ff78ec65818",
      "metadata": {},
      "outputs": [],
      "source": [
        "service = QiskitRuntimeService()\n",
        "backend = service.least_busy(\n",
        "    operational=True, simulator=False, min_num_qubits=127\n",
        ")"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 12,
      "id": "aeaf076c-1c0a-4ec4-af66-49eff621589d",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "<IBMBackend('ibm_fez')>\n"
          ]
        }
      ],
      "source": [
        "print(backend)"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "46280e59-8c9f-4dd9-a365-6a230ceccf42",
      "metadata": {},
      "source": [
        "Você pode compilar seu circuito para o backend de sua escolha criando um gerenciador de etapas e, em seguida, executando-o no circuito. Uma maneira fácil de criar um gerenciador de senhas é usar a [`generate_preset_pass_manager`](/docs/api/qiskit/qiskit.transpiler.generate_preset_pass_manager) função. Consulte [“Transpilação com gerenciadores de passagens”](/docs/guides/transpile-with-pass-managers) para obter uma explicação mais detalhada sobre a transpilação com gerenciadores de passagens.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 13,
      "id": "027e829a-44d3-455e-b2bf-8ce0d7e26b9b",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<Image src=\"/docs/images/tutorials/combine-error-mitigation-techniques/extracted-outputs/027e829a-44d3-455e-b2bf-8ce0d7e26b9b-0.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "execution_count": 13,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "pass_manager = generate_preset_pass_manager(\n",
        "    optimization_level=3, backend=backend, seed_transpiler=1234\n",
        ")\n",
        "isa_circuit = pass_manager.run(mirror_circuit)\n",
        "\n",
        "isa_circuit.draw(\"mpl\", idle_wires=False, scale=0.7, fold=-1)"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "1865671e-2c7a-44dd-8938-fe4637bb5993",
      "metadata": {},
      "source": [
        "O circuito transpilado agora contém apenas instruções ISA. Todas as portas foram decompostas em termos de portas de tipo “ $\\sqrt{X}$ ”, rotações do tipo “ $R_z$ ” e [portas CZ](/docs/api/qiskit/qiskit.circuit.library.CZGate).\n",
        "\n",
        "O processo de transpilação mapeou os qubits virtuais do circuito para qubits físicos no hardware. As informações sobre o layout do qubit são armazenadas no atributo `layout` do circuito transpilado. O observável também foi definido em termos dos qubits virtuais, portanto, você precisa aplicar esse layout ao observável, o que pode ser feito com o método [`apply_layout`](/docs/api/qiskit/qiskit.quantum_info.SparsePauliOp#apply_layout) de `SparsePauliOp`.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 14,
      "id": "12338588-a2d0-4b9c-9e49-e25ec8617b93",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "Original observable:\n",
            "SparsePauliOp(['ZIIIIIIIII'],\n",
            "              coeffs=[1.+0.j])\n",
            "\n",
            "Observable with layout applied:\n",
            "SparsePauliOp(['IIIIIIIIZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII'],\n",
            "              coeffs=[1.+0.j])\n"
          ]
        }
      ],
      "source": [
        "isa_observable = observable.apply_layout(isa_circuit.layout)\n",
        "\n",
        "print(\"Original observable:\")\n",
        "print(observable)\n",
        "print()\n",
        "print(\"Observable with layout applied:\")\n",
        "print(isa_observable)"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "439d4edf-d1ad-49f3-b206-320958be4f82",
      "metadata": {},
      "source": [
        "<span id=\"step-3-execute-using-qiskit-primitives\" />\n",
        "\n",
        "### Passo 3: Execute usando Qiskit primitives\n",
        "\n",
        "Agora você está pronto para executar seu circuito usando o Estimator primitivo.\n",
        "\n",
        "Aqui você enviará cinco trabalhos separados, começando sem supressão ou atenuação de erros e ativando sucessivamente várias opções de supressão e atenuação de erros disponíveis em Qiskit Runtime. Para obter informações sobre as opções, consulte as páginas a seguir:\n",
        "\n",
        "* [Visão geral de todas as opções](/docs/api/qiskit-ibm-runtime/options)\n",
        "* [Desacoplamento dinâmico](/docs/api/qiskit-ibm-runtime/options-dynamical-decoupling-options)\n",
        "* [Resiliência, incluindo mitigação de erros de medição e extrapolação de ruído zero (ZNE)](/docs/api/qiskit-ibm-runtime/options-resilience-options-v2)\n",
        "* [Girando](/docs/api/qiskit-ibm-runtime/options-twirling-options)\n",
        "\n",
        "Como esses trabalhos podem ser executados independentemente uns dos outros, você pode usar [o modo em lote](/docs/guides/run-jobs-batch) para permitir que o Qiskit Runtime otimize o tempo de execução.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "1114d15b-1408-4f4c-a20f-60f0da722325",
      "metadata": {},
      "outputs": [],
      "source": [
        "pub = (isa_circuit, isa_observable)\n",
        "\n",
        "jobs = []\n",
        "\n",
        "with Batch(backend=backend) as batch:\n",
        "    estimator = Estimator(mode=batch)\n",
        "    estimator.options.environment.job_tags = [\n",
        "        \"TUT_CEM_SS\"\n",
        "    ]  # add tag for this small scale job\n",
        "    # Set number of shots\n",
        "    estimator.options.default_shots = 100_000\n",
        "    # Disable runtime compilation and error mitigation\n",
        "    estimator.options.resilience_level = 0\n",
        "\n",
        "    # Run job with no error mitigation\n",
        "    job0 = estimator.run([pub])\n",
        "    jobs.append(job0)\n",
        "\n",
        "    # Add dynamical decoupling (DD)\n",
        "    estimator.options.dynamical_decoupling.enable = True\n",
        "    estimator.options.dynamical_decoupling.sequence_type = \"XpXm\"\n",
        "    job1 = estimator.run([pub])\n",
        "    jobs.append(job1)\n",
        "\n",
        "    # Add readout error mitigation (DD + TREX)\n",
        "    estimator.options.resilience.measure_mitigation = True\n",
        "    job2 = estimator.run([pub])\n",
        "    jobs.append(job2)\n",
        "\n",
        "    # Add gate twirling (DD + TREX + Gate Twirling)\n",
        "    estimator.options.twirling.enable_gates = True\n",
        "    estimator.options.twirling.num_randomizations = \"auto\"\n",
        "    job3 = estimator.run([pub])\n",
        "    jobs.append(job3)\n",
        "\n",
        "    # Add zero-noise extrapolation (DD + TREX + Gate Twirling + ZNE)\n",
        "    estimator.options.resilience.zne_mitigation = True\n",
        "    estimator.options.resilience.zne.noise_factors = (1, 3, 5)\n",
        "    estimator.options.resilience.zne.extrapolator = (\"exponential\", \"linear\")\n",
        "    job4 = estimator.run([pub])\n",
        "    jobs.append(job4)"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "919517c8-6f42-48d9-a976-53c715c00a4b",
      "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",
        "Por fim, você pode analisar os dados. Aqui você recuperará os resultados do trabalho, extrairá deles os valores de expectativa medidos e plotará os valores, incluindo barras de erro de um desvio padrão.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 16,
      "id": "eef38976-0ca2-429a-b2dc-41aac69605f7",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<Image src=\"/docs/images/tutorials/combine-error-mitigation-techniques/extracted-outputs/eef38976-0ca2-429a-b2dc-41aac69605f7-0.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "metadata": {},
          "output_type": "display_data"
        }
      ],
      "source": [
        "# Retrieve the job results\n",
        "results = [job.result() for job in jobs]\n",
        "\n",
        "# Unpack the PUB results (there's only one PUB result in each job result)\n",
        "pub_results = [result[0] for result in results]\n",
        "\n",
        "# Unpack the expectation values and standard errors\n",
        "expectation_vals = np.array(\n",
        "    [float(pub_result.data.evs) for pub_result in pub_results]\n",
        ")\n",
        "standard_errors = np.array(\n",
        "    [float(pub_result.data.stds) for pub_result in pub_results]\n",
        ")\n",
        "\n",
        "# Plot the expectation values\n",
        "fig, ax = plt.subplots()\n",
        "labels = [\"No mitigation\", \"+ DD\", \"+ TREX\", \"+ Twirling\", \"+ ZNE\"]\n",
        "ax.bar(\n",
        "    range(len(labels)),\n",
        "    expectation_vals,\n",
        "    yerr=standard_errors,\n",
        "    label=\"experiment\",\n",
        ")\n",
        "ax.axhline(y=1.0, color=\"gray\", linestyle=\"--\", label=\"ideal\")\n",
        "ax.set_xticks(range(len(labels)))\n",
        "ax.set_xticklabels(labels)\n",
        "ax.set_ylabel(\"Expectation value\")\n",
        "ax.legend(loc=\"upper left\")\n",
        "\n",
        "plt.show()"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "b400eae8-f38c-4566-82fe-0ccc5ee3f05d",
      "metadata": {},
      "source": [
        "Nessa escala pequena, é difícil ver o efeito da maioria das técnicas de atenuação de erros, mas a extrapolação de ruído zero proporciona um aprimoramento perceptível. No entanto, observe que essa melhoria não é gratuita, pois o resultado do ZNE também tem uma barra de erro maior.\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "958a5d23-ea09-4750-827c-e3bf6c3fa3f4",
      "metadata": {},
      "source": [
        "<span id=\"large-scale-hardware-example\" />\n",
        "\n",
        "## Exemplo de hardware em grande escala\n",
        "\n",
        "Ao desenvolver um experimento, é útil começar com um circuito pequeno para facilitar as visualizações e simulações. Agora que você desenvolveu e testou nosso fluxo de trabalho em um circuito de 10 qubits, é possível ampliá-lo para 50 qubits. A seguinte célula de código repete todas as etapas deste passo a passo, mas agora as aplica a um circuito de 50 qubits.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 17,
      "id": "d7d8408b-faf1-4eda-ab9c-bdeaab01ff53",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<Image src=\"/docs/images/tutorials/combine-error-mitigation-techniques/extracted-outputs/d7d8408b-faf1-4eda-ab9c-bdeaab01ff53-0.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "metadata": {},
          "output_type": "display_data"
        }
      ],
      "source": [
        "n_qubits = 50\n",
        "reps = 1\n",
        "\n",
        "# Construct circuit and observable\n",
        "circuit = efficient_su2(n_qubits, entanglement=\"pairwise\", reps=reps)\n",
        "observable = SparsePauliOp.from_sparse_list(\n",
        "    [(\"Z\", [-1], 1.0)], num_qubits=n_qubits\n",
        ")\n",
        "\n",
        "# Assign parameters to circuit\n",
        "params = rng.uniform(-np.pi, np.pi, size=circuit.num_parameters)\n",
        "assigned_circuit = circuit.assign_parameters(params)\n",
        "assigned_circuit.barrier()\n",
        "\n",
        "# Construct mirror circuit\n",
        "mirror_circuit = unitary_overlap(assigned_circuit, assigned_circuit)\n",
        "\n",
        "# Transpile circuit and observable\n",
        "isa_circuit = pass_manager.run(mirror_circuit)\n",
        "isa_observable = observable.apply_layout(isa_circuit.layout)\n",
        "\n",
        "# Run jobs\n",
        "pub = (isa_circuit, isa_observable)\n",
        "\n",
        "jobs = []\n",
        "\n",
        "with Batch(backend=backend) as batch:\n",
        "    estimator = Estimator(mode=batch)\n",
        "    estimator.options.environment.job_tags = [\n",
        "        \"TUT_CEM_LS\"\n",
        "    ]  # add tag for this large scale job\n",
        "    # Set number of shots\n",
        "    estimator.options.default_shots = 100_000\n",
        "    # Disable runtime compilation and error mitigation\n",
        "    estimator.options.resilience_level = 0\n",
        "\n",
        "    # Run job with no error mitigation\n",
        "    job0 = estimator.run([pub])\n",
        "    jobs.append(job0)\n",
        "\n",
        "    # Add dynamical decoupling (DD)\n",
        "    estimator.options.dynamical_decoupling.enable = True\n",
        "    estimator.options.dynamical_decoupling.sequence_type = \"XpXm\"\n",
        "    job1 = estimator.run([pub])\n",
        "    jobs.append(job1)\n",
        "\n",
        "    # Add readout error mitigation (DD + TREX)\n",
        "    estimator.options.resilience.measure_mitigation = True\n",
        "    job2 = estimator.run([pub])\n",
        "    jobs.append(job2)\n",
        "\n",
        "    # Add gate twirling (DD + TREX + Gate Twirling)\n",
        "    estimator.options.twirling.enable_gates = True\n",
        "    estimator.options.twirling.num_randomizations = \"auto\"\n",
        "    job3 = estimator.run([pub])\n",
        "    jobs.append(job3)\n",
        "\n",
        "    # Add zero-noise extrapolation (DD + TREX + Gate Twirling + ZNE)\n",
        "    estimator.options.resilience.zne_mitigation = True\n",
        "    estimator.options.resilience.zne.noise_factors = (1, 3, 5)\n",
        "    estimator.options.resilience.zne.extrapolator = (\"exponential\", \"linear\")\n",
        "    job4 = estimator.run([pub])\n",
        "    jobs.append(job4)\n",
        "\n",
        "# Retrieve the job results\n",
        "results = [job.result() for job in jobs]\n",
        "\n",
        "# Unpack the PUB results (there's only one PUB result in each job result)\n",
        "pub_results = [result[0] for result in results]\n",
        "\n",
        "# Unpack the expectation values and standard errors\n",
        "expectation_vals = np.array(\n",
        "    [float(pub_result.data.evs) for pub_result in pub_results]\n",
        ")\n",
        "standard_errors = np.array(\n",
        "    [float(pub_result.data.stds) for pub_result in pub_results]\n",
        ")\n",
        "\n",
        "# Plot the expectation values\n",
        "fig, ax = plt.subplots()\n",
        "labels = [\"No mitigation\", \"+ DD\", \"+ TREX\", \"+ Twirling\", \"+ ZNE\"]\n",
        "ax.bar(\n",
        "    range(len(labels)),\n",
        "    expectation_vals,\n",
        "    yerr=standard_errors,\n",
        "    label=\"experiment\",\n",
        ")\n",
        "ax.axhline(y=1.0, color=\"gray\", linestyle=\"--\", label=\"ideal\")\n",
        "ax.set_xticks(range(len(labels)))\n",
        "ax.set_xticklabels(labels)\n",
        "ax.set_ylabel(\"Expectation value\")\n",
        "ax.legend(loc=\"upper left\")\n",
        "\n",
        "plt.show()"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "32d9b036-ea0a-4484-b6ee-036ff732026b",
      "metadata": {},
      "source": [
        "Ao comparar os resultados de 50 qubits com os resultados de 10 qubits anteriores, você pode observar o seguinte (seus resultados podem ser diferentes entre as execuções):\n",
        "\n",
        "* Todas as experiências apresentam resultados mais próximos do valor ideal e todas as barras de erro são menores.\n",
        "* A inclusão do desacoplamento dinâmico pode ter prejudicado o desempenho em comparação com o caso sem medidas de mitigação. Isso não é surpreendente, pois o circuito é muito denso. O desacoplamento dinâmico é útil principalmente quando há grandes intervalos no circuito, durante os quais os qubits permanecem inativos, sem que lhes sejam aplicadas portas. Quando essas lacunas não existem, o desacoplamento dinâmico não é eficaz e pode, na verdade, prejudicar o desempenho devido a erros nos próprios pulsos de desacoplamento dinâmico. O circuito de 10 qubits talvez tenha sido pequeno demais para que pudéssemos observar esse efeito.\n",
        "* Com a extrapolação sem ruído, o resultado fica muito próximo do valor ideal. Isso demonstra o poder do ZNE.\n",
        "\n",
        "<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 material a seguir sobre algumas técnicas adicionais de mitigação e supressão de erros que não foram mencionadas neste tutorial:\n",
        "\n",
        "  * [Cancelamento Probabilístico de Erros (PEC)](/docs/guides/error-mitigation-and-suppression-techniques#probabilistic-error-cancellation-pec)\n",
        "  * [Mitigação de medição sem matriz ( M3 )](https://qiskit.github.io/qiskit-addon-mthree/) (consulte também o tutorial “[Mitigação de erros de leitura para a primitiva Sampler usando M3](/docs/tutorials/readout-error-mitigation-sampler/) ”)\n",
        "  * [Conos de luz sombreados](https://qiskit.github.io/qiskit-addon-slc/)\n",
        "  * [Absorção de ruído propagado (PNA)](https://qiskit.github.io/qiskit-addon-pna/)\n",
        "</Admonition>\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": 420
  },
  "nbformat": 4,
  "nbformat_minor": 4
}