{
  "cells": [
    {
      "cell_type": "markdown",
      "id": "meta-header",
      "metadata": {},
      "source": [
        "---\n",
        "title: \"Introdução ao transpilador com tecnologia de IA do Qiskit\"\n",
        "description: \"Saiba como o transpiler baseado em IA se compara à transpilagem padrão que utiliza circuitos espelho.\"\n",
        "---\n",
        "\n",
        "{/* cspell:ignore fontsize fontweight steelblue AITI */}\n",
        "\n",
        "<span id=\"qiskit-ai-powered-transpiler-introduction\" />\n",
        "\n",
        "# Introdução ao transpilador com tecnologia de IA do Qiskit\n",
        "\n",
        "*Estimativa de tempo de uso: 5 minutos no Heron d IBM (OBSERVAÇÃO: trata-se apenas de uma estimativa.) (O tempo de execução pode variar.)*\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "learning-outcomes",
      "metadata": {},
      "source": [
        "<span id=\"learning-outcomes\" />\n",
        "\n",
        "## Resultados do aprendizado\n",
        "\n",
        "Ao concluir este tutorial, os usuários deverão compreender:\n",
        "\n",
        "* Como usar o transpiler baseado em IA (`generate_ai_pass_manager`) como um substituto direto do transpiler padrão\n",
        "* Como o transpiler baseado em IA se compara ao transpiler padrão em termos de profundidade de dois qubits, número de portas e tempo de transpilagem\n",
        "* Como usar circuitos espelho para avaliar a qualidade da transpilagem por meio da execução em hardware\n",
        "\n",
        "<span id=\"prerequisites\" />\n",
        "\n",
        "## Pré-requisitos\n",
        "\n",
        "Sugerimos que os usuários estejam familiarizados com os seguintes tópicos antes de seguir com este tutorial:\n",
        "\n",
        "* [Circuitos de transpilação](/docs/guides/transpile)\n",
        "* [Configurar gerenciadores de passagem predefinidos](/docs/guides/transpile-with-pass-managers)\n",
        "* [O transpiler baseado em IA é aprovado](/docs/guides/ai-transpiler-passes)\n",
        "\n",
        "<span id=\"background\" />\n",
        "\n",
        "## Segundo plano\n",
        "\n",
        "**O transpiler** do Qiskit, equipado com inteligência artificial, introduz etapas de transpilagem baseadas em aprendizado de máquina que podem produzir circuitos mais curtos e mais eficientes em termos de hardware do que os métodos heurísticos tradicionais, como o SABRE. Circuitos mais curtos acumulam menos ruído, o que melhora diretamente a qualidade dos resultados em hardware quântico real.\n",
        "\n",
        "Neste tutorial, comparamos duas estratégias de transpilagem:\n",
        "\n",
        "| Estratégia | API                                                                            |\n",
        "| ---------- | ------------------------------------------------------------------------------ |\n",
        "| **Padrão** | `generate_preset_pass_manager(optimization_level=3, ...)`                      |\n",
        "| **IA**     | `generate_ai_pass_manager(optimization_level=1, ai_optimization_level=3, ...)` |\n",
        "\n",
        "Medimos três métricas para cada estratégia: **profundidade do portão de dois qubits**, **número total de portões** e **tempo de execução da transpilacão**.\n",
        "\n",
        "<span id=\"ai-powered-transpiler-benchmarks\" />\n",
        "\n",
        "### Tests de desempenho de transpiladores baseados em IA\n",
        "\n",
        "Em testes comparativos, o transpiler baseado em IA produziu consistentemente circuitos mais simples e de melhor qualidade em comparação com o transpiler padrão do Qiskit. Para esses testes, utilizamos a estratégia padrão do gerenciador de passagens do Qiskit, configurada com [`generate_preset_pass_manager`](/docs/api/qiskit/qiskit.transpiler.generate_preset_pass_manager). Embora essa estratégia padrão seja frequentemente eficaz, ela pode apresentar dificuldades com circuitos maiores ou mais complexos. Em contrapartida, os passes baseados em IA alcançaram uma redução média de 24% no número de portas de dois qubits e uma redução de 36% na profundidade do circuito para circuitos grandes (mais de 100 qubits) ao serem transpilados para a topologia “heavy-hex” do hardware d IBM Quantum®. Para obter mais informações sobre esses benchmarks, consulte este [blog](https://www.ibm.com/quantum/blog/qiskit-performance).\n",
        "\n",
        "![Testes de desempenho de transpiladores baseados em IA](https://quantum.cloud.ibm.com/docs/images/tutorials/ai-transpiler-introduction/ai-transpiler-benchmarks.avif)\n",
        "\n",
        "Este tutorial aborda os principais benefícios das etapas de IA e como elas se comparam aos métodos tradicionais.\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "requirements",
      "metadata": {},
      "source": [
        "<span id=\"requirements\" />\n",
        "\n",
        "## Requisitos\n",
        "\n",
        "Antes de iniciar este tutorial, certifique-se de ter os seguintes itens instalados:\n",
        "\n",
        "* Qiskit SDK v2.0 ou versão posterior, com suporte [à visualização](/docs/api/qiskit/visualization)\n",
        "* Qiskit Runtime `pip install qiskit-ibm-runtime`v0.22 ou posterior\n",
        "* Transpilador do Qiskit IBM com modo local de IA (`pip install 'qiskit-ibm-transpiler[ai-local-mode]'`)\n",
        "* Qiskit Aer (`pip install qiskit-aer`)\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "setup-header",
      "metadata": {},
      "source": [
        "<span id=\"setup\" />\n",
        "\n",
        "## Instalação\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "setup-code",
      "metadata": {},
      "outputs": [],
      "source": [
        "from qiskit import QuantumCircuit\n",
        "from qiskit.circuit.random import random_circuit\n",
        "from qiskit.transpiler import generate_preset_pass_manager\n",
        "from qiskit_ibm_runtime import QiskitRuntimeService, SamplerV2\n",
        "from qiskit_ibm_transpiler import generate_ai_pass_manager\n",
        "from qiskit_aer import AerSimulator\n",
        "from qiskit_aer.noise import NoiseModel, depolarizing_error\n",
        "import matplotlib.pyplot as plt\n",
        "from statistics import mean, stdev\n",
        "import time\n",
        "import logging\n",
        "\n",
        "seed = 42\n",
        "\n",
        "\n",
        "def transpile_with_metrics(pass_manager, circuit):\n",
        "    \"\"\"Transpile a circuit and return the result along with key metrics.\"\"\"\n",
        "    start = time.time()\n",
        "    qc_out = pass_manager.run(circuit)\n",
        "    elapsed = time.time() - start\n",
        "\n",
        "    depth_2q = qc_out.depth(lambda x: x.operation.num_qubits == 2)\n",
        "    gate_count = qc_out.size()\n",
        "\n",
        "    return qc_out, {\n",
        "        \"depth_2q\": depth_2q,\n",
        "        \"gate_count\": gate_count,\n",
        "        \"time_s\": round(elapsed, 3),\n",
        "    }\n",
        "\n",
        "\n",
        "def remap_to_contiguous(tqc):\n",
        "    \"\"\"Remap a transpiled circuit to use contiguous qubit indices.\n",
        "\n",
        "    Transpiled circuits target specific physical qubits (e.g., qubit 45, 67)\n",
        "    on a large backend. This remaps them to 0, 1, 2, ... so Aer only\n",
        "    simulates the active qubits.\"\"\"\n",
        "    active = sorted(\n",
        "        {tqc.find_bit(q).index for inst in tqc.data for q in inst.qubits}\n",
        "    )\n",
        "    qubit_map = {old: new for new, old in enumerate(active)}\n",
        "    new_qc = QuantumCircuit(len(active))\n",
        "    for inst in tqc.data:\n",
        "        old_indices = [tqc.find_bit(q).index for q in inst.qubits]\n",
        "        new_qc.append(inst.operation, [qubit_map[i] for i in old_indices])\n",
        "    return new_qc\n",
        "\n",
        "\n",
        "def build_mirror_circuit(tqc, simulate=True):\n",
        "    \"\"\"Build a mirror circuit: U followed by U-dagger, with measurements.\n",
        "\n",
        "    The expected output is always |0...0>, so measuring the survival\n",
        "    probability reveals how much noise each transpilation strategy adds.\n",
        "\n",
        "    Args:\n",
        "        tqc: A transpiled circuit.\n",
        "        simulate: If True (default), remap to contiguous qubits so Aer\n",
        "            only simulates the active qubits. If False, keep the full\n",
        "            physical layout for hardware execution.\"\"\"\n",
        "    if simulate:\n",
        "        tqc = remap_to_contiguous(tqc)\n",
        "    mirror = tqc.compose(tqc.inverse())\n",
        "    mirror.measure_all()\n",
        "    return mirror\n",
        "\n",
        "\n",
        "def print_summary(results):\n",
        "    \"\"\"Print a summary of each metric as mean +/- stdev across all circuits,\n",
        "    along with the mean percentage improvement of AI over Default.\"\"\"\n",
        "    metrics = [\n",
        "        (\"Depth 2Q\", \"Depth 2Q (Default)\", \"Depth 2Q (AI)\"),\n",
        "        (\"Gate Count\", \"Gate Count (Default)\", \"Gate Count (AI)\"),\n",
        "        (\"Time (s)\", \"Time (Default)\", \"Time (AI)\"),\n",
        "    ]\n",
        "    header = (\n",
        "        f\"{'Metric':<12}{'Default (mean +/- std)':>24}\"\n",
        "        f\"{'AI (mean +/- std)':>22}{'AI % improvement':>22}\"\n",
        "    )\n",
        "    print(header)\n",
        "    print(\"-\" * len(header))\n",
        "    for label, col_def, col_ai in metrics:\n",
        "        defaults = [r[col_def] for r in results]\n",
        "        ais = [r[col_ai] for r in results]\n",
        "        pct = [(d - a) / d * 100 for d, a in zip(defaults, ais)]\n",
        "        default_str = f\"{mean(defaults):.1f} +/- {stdev(defaults):.1f}\"\n",
        "        ai_str = f\"{mean(ais):.1f} +/- {stdev(ais):.1f}\"\n",
        "        pct_str = f\"{mean(pct):+.1f}% +/- {stdev(pct):.1f}%\"\n",
        "        print(f\"{label:<12}{default_str:>24}{ai_str:>22}{pct_str:>22}\")\n",
        "\n",
        "\n",
        "def plot_metrics_and_pct(results, title_prefix):\n",
        "    \"\"\"Plot metric comparisons and percentage improvement of AI over Default.\"\"\"\n",
        "    qubits = [r[\"Qubits\"] for r in results]\n",
        "    metrics = [\n",
        "        (\"Depth 2Q (Default)\", \"Depth 2Q (AI)\", \"Two-Qubit Depth\"),\n",
        "        (\"Gate Count (Default)\", \"Gate Count (AI)\", \"Gate Count\"),\n",
        "        (\"Time (Default)\", \"Time (AI)\", \"Transpilation Time\"),\n",
        "    ]\n",
        "\n",
        "    # Row 1: raw metric comparison\n",
        "    fig, axs = plt.subplots(1, 3, figsize=(21, 5))\n",
        "    fig.suptitle(\n",
        "        f\"{title_prefix}: Metric Comparison\",\n",
        "        fontsize=15,\n",
        "        fontweight=\"bold\",\n",
        "        y=1.02,\n",
        "    )\n",
        "    for ax, (col_def, col_ai, label) in zip(axs, metrics):\n",
        "        ax.plot(qubits, [r[col_def] for r in results], \"o-\", label=\"Default\")\n",
        "        ax.plot(qubits, [r[col_ai] for r in results], \"s-\", label=\"AI\")\n",
        "        ax.set_title(label)\n",
        "        ax.set_xlabel(\"Number of Qubits\")\n",
        "        ax.set_ylabel(label)\n",
        "        ax.legend()\n",
        "    plt.tight_layout()\n",
        "    plt.show()\n",
        "\n",
        "    # Row 2: percentage improvement\n",
        "    fig, axs = plt.subplots(1, 3, figsize=(21, 5))\n",
        "    fig.suptitle(\n",
        "        f\"{title_prefix}: % Improvement of AI over Default\",\n",
        "        fontsize=15,\n",
        "        fontweight=\"bold\",\n",
        "        y=1.02,\n",
        "    )\n",
        "    for ax, (col_def, col_ai, label) in zip(axs, metrics):\n",
        "        pct = [(r[col_def] - r[col_ai]) / r[col_def] * 100 for r in results]\n",
        "        ax.axhline(\n",
        "            0, color=\"#1f77b4\", linewidth=2, label=\"Default (baseline)\"\n",
        "        )\n",
        "        ax.plot(qubits, pct, \"s-\", color=\"#ff7f0e\", label=\"AI\")\n",
        "        ax.fill_between(qubits, 0, pct, alpha=0.15, color=\"#ff7f0e\")\n",
        "        ax.set_title(label)\n",
        "        ax.set_xlabel(\"Number of Qubits\")\n",
        "        ax.set_ylabel(\"% Improvement\")\n",
        "        ax.legend()\n",
        "    plt.tight_layout()\n",
        "    plt.show()\n",
        "\n",
        "\n",
        "# Suppress verbose AI-powered transpiler logs\n",
        "logging.getLogger(\n",
        "    \"qiskit_ibm_transpiler.wrappers.ai_local_synthesis\"\n",
        ").setLevel(logging.WARNING)"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "sim-header",
      "metadata": {},
      "source": [
        "<span id=\"small-scale-simulator-example\" />\n",
        "\n",
        "## Exemplo de simulador em pequena escala\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "sim-step1-header",
      "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",
        "Geramos 20 circuitos aleatórios com profundidade 4, nos quais o número de qubits varia de seis a 25. Esses circuitos servirão como nossos casos de teste para comparar estratégias de transpilagem.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 2,
      "id": "sim-step1-code",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "Created 20 circuits with qubit counts from 6 to 25\n"
          ]
        },
        {
          "data": {
            "text/plain": [
              "<Image src=\"/docs/images/tutorials/ai-transpiler-introduction/extracted-outputs/sim-step1-code-1.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "execution_count": 2,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "num_circuits_sim = 20\n",
        "depth_sim = 4\n",
        "qubit_range_sim = list(range(6, 26))\n",
        "\n",
        "circuits_sim = [\n",
        "    # We have only two qubit gates, as those test how well the\n",
        "    # transpiler can optimize the circuit.\n",
        "    random_circuit(\n",
        "        num_qubits=n,\n",
        "        depth=depth_sim,\n",
        "        max_operands=2,\n",
        "        num_operand_distribution={2: 1},\n",
        "        seed=seed + i,\n",
        "    )\n",
        "    for i, n in enumerate(qubit_range_sim)\n",
        "]\n",
        "\n",
        "print(\n",
        "    f\"Created {len(circuits_sim)} circuits with qubit counts \"\n",
        "    f\"from {qubit_range_sim[0]} to {qubit_range_sim[-1]}\"\n",
        ")\n",
        "circuits_sim[0].draw(output=\"mpl\", fold=-1)"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "sim-step2-header",
      "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",
        "Criamos o gerenciador de passes padrão (SABRE) para o backend escolhido. Ambas as estratégias de transpilagem têm como alvo o mapa de acoplamento completo do backend. A simulação local continua sendo viável porque a etapa de simulação utiliza `remap_to_contiguous` para reclassificar cada circuito transpilado de modo a incluir apenas seus qubits ativos; assim, o Aer simula apenas esses qubits, em vez de todo o dispositivo.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "sim-step2-backend",
      "metadata": {},
      "outputs": [],
      "source": [
        "service = QiskitRuntimeService()\n",
        "backend = service.least_busy(\n",
        "    min_num_qubits=100, operational=True, simulator=False\n",
        ")\n",
        "\n",
        "\n",
        "pm_default_sim = generate_preset_pass_manager(\n",
        "    optimization_level=3,\n",
        "    backend=backend,\n",
        "    seed_transpiler=seed,\n",
        ")"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 4,
      "id": "sim-step2-transpile",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "application/vnd.jupyter.widget-view+json": {
              "model_id": "bc06de12e386408abf67166416c2d1a0",
              "version_major": 2,
              "version_minor": 0
            },
            "text/plain": [
              "Fetching 4 files:   0%|          | 0/4 [00:00<?, ?it/s]"
            ]
          },
          "metadata": {},
          "output_type": "display_data"
        },
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "Metric        Default (mean +/- std)     AI (mean +/- std)      AI % improvement\n",
            "--------------------------------------------------------------------------------\n",
            "Depth 2Q               33.0 +/- 12.9          26.4 +/- 8.0      +15.8% +/- 17.6%\n",
            "Gate Count           522.0 +/- 266.0       560.5 +/- 279.1        -9.0% +/- 9.0%\n",
            "Time (s)                 0.0 +/- 0.0           0.2 +/- 0.1    -893.6% +/- 362.9%\n"
          ]
        }
      ],
      "source": [
        "results_sim = []\n",
        "\n",
        "for i, qc in enumerate(circuits_sim):\n",
        "    n = qubit_range_sim[i]\n",
        "\n",
        "    qc_default, m_default = transpile_with_metrics(pm_default_sim, qc)\n",
        "\n",
        "    # Create a fresh AI pass manager each iteration to avoid stale layout state\n",
        "    pm_ai = generate_ai_pass_manager(\n",
        "        optimization_level=1,\n",
        "        ai_optimization_level=3,\n",
        "        backend=backend,\n",
        "    )\n",
        "    qc_ai, m_ai = transpile_with_metrics(pm_ai, qc)\n",
        "\n",
        "    results_sim.append(\n",
        "        {\n",
        "            \"Qubits\": n,\n",
        "            \"Depth 2Q (Default)\": m_default[\"depth_2q\"],\n",
        "            \"Depth 2Q (AI)\": m_ai[\"depth_2q\"],\n",
        "            \"Gate Count (Default)\": m_default[\"gate_count\"],\n",
        "            \"Gate Count (AI)\": m_ai[\"gate_count\"],\n",
        "            \"Time (Default)\": m_default[\"time_s\"],\n",
        "            \"Time (AI)\": m_ai[\"time_s\"],\n",
        "        }\n",
        "    )\n",
        "\n",
        "print_summary(results_sim)"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "sim-step2-table-note",
      "metadata": {},
      "source": [
        "A tabela resumida mostra a média e o desvio-padrão de cada métrica em todos os 20 circuitos, juntamente com a porcentagem média de melhoria do transpiler baseado em IA em relação ao padrão. Valores positivos indicam que o transpiler baseado em IA produziu melhores resultados; valores negativos indicam que o padrão foi melhor.\n",
        "\n",
        "Nesse exemplo em pequena escala, o transpiler baseado em IA alcança, em média, uma profundidade de dois qubits cerca de 16% menor, mas ao custo de um aumento de aproximadamente 9% no número de portas. Isso destaca um compromisso fundamental na escolha entre as duas estratégias: o transpiler baseado em IA prioriza a redução da profundidade (menos camadas sequenciais de portas de dois qubits), enquanto o transpiler padrão (SABRE) prioriza a minimização do número total de portas (menos inserções de SWAP). Dependendo da sua aplicação, uma métrica pode ser mais importante do que a outra.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 5,
      "id": "sim-step2-plot",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<Image src=\"/docs/images/tutorials/ai-transpiler-introduction/extracted-outputs/sim-step2-plot-0.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "metadata": {},
          "output_type": "display_data"
        },
        {
          "data": {
            "text/plain": [
              "<Image src=\"/docs/images/tutorials/ai-transpiler-introduction/extracted-outputs/sim-step2-plot-1.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "metadata": {},
          "output_type": "display_data"
        }
      ],
      "source": [
        "plot_metrics_and_pct(results_sim, \"Small-Scale Random Circuits\")"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "sim-step2-analysis",
      "metadata": {},
      "source": [
        "**Profundidade de dois qubits:** O transpiler baseado em IA geralmente produz circuitos com menor profundidade de dois qubits. A profundidade é uma das principais métricas para as quais o modelo de roteamento de IA foi treinado para otimizar, e a melhoria é visível na maioria dos tamanhos de circuitos, embora o SABRE consiga igualar ou superar esse desempenho em circuitos específicos.\n",
        "\n",
        "**Contagem de portas:** Os resultados estão bastante equilibrados nessa escala, com a SABRE apresentando uma ligeira vantagem no geral. A heurística de roteamento do SABRE foi projetada para minimizar o número de portas SWAP inseridas, o que reduz diretamente o número de portas. Em circuitos de tamanho reduzido, a diferença é modesta.\n",
        "\n",
        "**Tempo de transpilação:** o tempo de execução do SABRE é praticamente constante, independentemente do número de qubits; portanto, o tamanho do circuito tem pouco efeito sobre o tempo de transpilação nessa escala. A lógica central de roteamento do SABRE é altamente otimizada (implementada em grande parte em Rust). O transpiler baseado em IA leva um tempo visivelmente maior e sua duração varia de acordo com o tamanho do circuito, embora os tempos absolutos continuem razoáveis para uso interativo.\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "sim-step3-header",
      "metadata": {},
      "source": [
        "<span id=\"step-3-execute-using-qiskit-primitives\" />\n",
        "\n",
        "### Passo 3: Execute usando Qiskit primitives\n",
        "\n",
        "Para avaliar o impacto da transpilação na fidelidade do circuito, construa circuitos espelho a partir do caso de 10 qubits e execute-os no simulador Aer com um modelo simples de ruído. A saída esperada de um circuito espelho é sempre a sequência de bits composta inteiramente por zeros; portanto, a probabilidade de se medir um $|0\\rangle^{\\otimes n}$ a demonstra o grau de preservação da fidelidade por cada estratégia de transpilagem.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 6,
      "id": "sim-step3-code",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "Default: depth 84, gates 280\n",
            "AI:      depth 91, gates 343\n"
          ]
        }
      ],
      "source": [
        "# Use the 10-qubit circuit (index where qubits == 10)\n",
        "idx_10q = qubit_range_sim.index(10)\n",
        "\n",
        "qc_10q = circuits_sim[idx_10q]\n",
        "qc_default_10q, _ = transpile_with_metrics(pm_default_sim, qc_10q)\n",
        "\n",
        "pm_ai = generate_ai_pass_manager(\n",
        "    optimization_level=1,\n",
        "    ai_optimization_level=3,\n",
        "    backend=backend,\n",
        ")\n",
        "qc_ai_10q, _ = transpile_with_metrics(pm_ai, qc_10q)\n",
        "\n",
        "tqc_methods = {\n",
        "    \"Default\": qc_default_10q,\n",
        "    \"AI\": qc_ai_10q,\n",
        "}\n",
        "\n",
        "print(\n",
        "    f\"Default: depth {qc_default_10q.depth()}, gates {qc_default_10q.size()}\"\n",
        ")\n",
        "print(f\"AI:      depth {qc_ai_10q.depth()}, gates {qc_ai_10q.size()}\")"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 7,
      "id": "sim-step3-run",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "Default   P(|00...0>) = 0.8460  (8460/10000)\n",
            "AI        P(|00...0>) = 0.8121  (8121/10000)\n"
          ]
        }
      ],
      "source": [
        "# Build a simple depolarizing noise model\n",
        "noise_model = NoiseModel()\n",
        "noise_model.add_all_qubit_quantum_error(\n",
        "    depolarizing_error(0.001, 1),\n",
        "    [\"sx\", \"x\", \"rz\"],  # ~0.1% per 1Q gate\n",
        ")\n",
        "noise_model.add_all_qubit_quantum_error(\n",
        "    depolarizing_error(0.01, 2),\n",
        "    [\"cx\", \"ecr\"],  # ~1% per 2Q gate\n",
        ")\n",
        "\n",
        "aer_sim = AerSimulator(noise_model=noise_model)\n",
        "\n",
        "shots = 10000\n",
        "survival_probs = {}\n",
        "\n",
        "for method, tqc in tqc_methods.items():\n",
        "    mirror = build_mirror_circuit(tqc, simulate=True)\n",
        "\n",
        "    sampler = SamplerV2(mode=aer_sim)\n",
        "    job = sampler.run([mirror], shots=shots)\n",
        "    counts = job.result()[0].data.meas.get_counts()\n",
        "\n",
        "    all_zeros = \"0\" * mirror.num_qubits\n",
        "    survival = counts.get(all_zeros, 0) / shots\n",
        "    survival_probs[method] = survival\n",
        "    print(\n",
        "        f\"{method:8s}  P(|00...0>) = {survival:.4f}  \"\n",
        "        f\"({counts.get(all_zeros, 0)}/{shots})\"\n",
        "    )"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "sim-step3-analysis",
      "metadata": {},
      "source": [
        "Executamos ambos os circuitos de espelho no simulador Aer, utilizando um modelo simples de ruído despolarizante. A probabilidade de sobrevivência, definida como a fração de tentativas que retornam a sequência de bits composta inteiramente por zeros, quantifica a quantidade de ruído que cada estratégia de transpilação introduz.\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "sim-step4-header",
      "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",
        "Calculamos a probabilidade de se obter a sequência de bits composta inteiramente por zeros em ambas as execuções. Uma probabilidade de sobrevivência mais alta indica maior fidelidade, o que significa que a transpilacão introduziu menos ruído. O gráfico abaixo mostra o complemento, 1 - P(|0...0>), de modo que uma barra mais baixa indica maior fidelidade e pequenas diferenças no erro ficam mais fáceis de perceber.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 8,
      "id": "sim-step4-code",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<Image src=\"/docs/images/tutorials/ai-transpiler-introduction/extracted-outputs/sim-step4-code-0.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "metadata": {},
          "output_type": "display_data"
        }
      ],
      "source": [
        "# Plot 1 - P(|0...0>), the probability of an erroneous (non-zero) outcome.\n",
        "# A lower bar means the transpilation introduced less noise.\n",
        "error_probs = {method: 1 - p for method, p in survival_probs.items()}\n",
        "\n",
        "fig, ax = plt.subplots(figsize=(6, 4))\n",
        "ax.bar(\n",
        "    error_probs.keys(),\n",
        "    error_probs.values(),\n",
        "    color=[\"steelblue\", \"coral\"],\n",
        ")\n",
        "ax.set_ylabel(\"1 - P(|0...0>)\")\n",
        "ax.set_title(\"Mirror Circuit Error (10-qubit, Aer Simulator)\")\n",
        "ax.set_ylim(0, 1)\n",
        "plt.tight_layout()\n",
        "plt.show()"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "sim-step4-analysis",
      "metadata": {},
      "source": [
        "Nesse caso, o transpiler padrão gerou um circuito mais simples e menor para essa instância específica de 10 qubits; portanto, espera-se que ele apresente maior fidelidade. Os resultados por circuito variam: como mostra a tabela resumida acima, a vantagem do transpiler baseado em IA está na menor profundidade média de dois qubits, e não em cada circuito individualmente. A estratégia que proporciona maior fidelidade depende da magnitude da diferença em cada métrica, das características de ruído do hardware e da estrutura do circuito. De acordo com um modelo uniforme de ruído despolarizante, o número total de portas costuma ter um impacto mais direto no erro acumulado do que apenas a profundidade.\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "hw-header",
      "metadata": {},
      "source": [
        "<span id=\"large-scale-hardware-example\" />\n",
        "\n",
        "## Exemplo de hardware em grande escala\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "hw-steps-header",
      "metadata": {},
      "source": [
        "<span id=\"steps-1-4\" />\n",
        "\n",
        "### Etapas 1 a 4\n",
        "\n",
        "Aqui, todos esses detalhes são reunidos em um fluxo de trabalho claro em escala maior, que é então executado em hardware quântico real.\n",
        "\n",
        "O código abaixo gera 25 circuitos aleatórios com profundidade 8, nos quais o número de qubits varia de 26 a 50. Esses circuitos são então transpilados com ambas as estratégias, e as mesmas métricas são coletadas. Em seguida, construímos circuitos espelhados a partir do caso de 26 qubits e os enviamos para o backend real.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 9,
      "id": "hw-step1",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "Created 25 circuits with qubit counts from 26 to 50\n"
          ]
        }
      ],
      "source": [
        "# -------------------------Step 1-------------------------\n",
        "num_circuits_hw = 25\n",
        "depth_hw = 8\n",
        "qubit_range_hw = list(range(26, 51))\n",
        "\n",
        "circuits_hw = [\n",
        "    # We have only two qubit gates, as those test how well the\n",
        "    # transpiler can optimize the circuit.\n",
        "    random_circuit(\n",
        "        num_qubits=n,\n",
        "        depth=depth_hw,\n",
        "        max_operands=2,\n",
        "        num_operand_distribution={2: 1},\n",
        "        seed=seed + i,\n",
        "    )\n",
        "    for i, n in enumerate(qubit_range_hw)\n",
        "]\n",
        "\n",
        "print(\n",
        "    f\"Created {len(circuits_hw)} circuits with qubit counts \"\n",
        "    f\"from {qubit_range_hw[0]} to {qubit_range_hw[-1]}\"\n",
        ")"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 10,
      "id": "hw-step2",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "Metric        Default (mean +/- std)     AI (mean +/- std)      AI % improvement\n",
            "--------------------------------------------------------------------------------\n",
            "Depth 2Q              217.4 +/- 50.4        191.0 +/- 35.6      +10.9% +/- 10.7%\n",
            "Gate Count         4513.3 +/- 1394.3     5227.1 +/- 1536.4       -16.4% +/- 5.8%\n",
            "Time (s)                 0.1 +/- 0.0           3.5 +/- 1.5   -3588.2% +/- 643.6%\n"
          ]
        }
      ],
      "source": [
        "# -------------------------Step 2-------------------------\n",
        "pm_default = generate_preset_pass_manager(\n",
        "    optimization_level=3,\n",
        "    backend=backend,\n",
        "    seed_transpiler=seed,\n",
        ")\n",
        "\n",
        "results_hw = []\n",
        "\n",
        "for i, qc in enumerate(circuits_hw):\n",
        "    n = qubit_range_hw[i]\n",
        "\n",
        "    qc_default, m_default = transpile_with_metrics(pm_default, qc)\n",
        "\n",
        "    # Create a fresh AI pass manager each iteration to avoid stale layout state\n",
        "    pm_ai = generate_ai_pass_manager(\n",
        "        optimization_level=1,\n",
        "        ai_optimization_level=3,\n",
        "        backend=backend,\n",
        "    )\n",
        "    qc_ai, m_ai = transpile_with_metrics(pm_ai, qc)\n",
        "\n",
        "    results_hw.append(\n",
        "        {\n",
        "            \"Qubits\": n,\n",
        "            \"Depth 2Q (Default)\": m_default[\"depth_2q\"],\n",
        "            \"Depth 2Q (AI)\": m_ai[\"depth_2q\"],\n",
        "            \"Gate Count (Default)\": m_default[\"gate_count\"],\n",
        "            \"Gate Count (AI)\": m_ai[\"gate_count\"],\n",
        "            \"Time (Default)\": m_default[\"time_s\"],\n",
        "            \"Time (AI)\": m_ai[\"time_s\"],\n",
        "        }\n",
        "    )\n",
        "\n",
        "print_summary(results_hw)"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 11,
      "id": "hw-step2-plot",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<Image src=\"/docs/images/tutorials/ai-transpiler-introduction/extracted-outputs/hw-step2-plot-0.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "metadata": {},
          "output_type": "display_data"
        },
        {
          "data": {
            "text/plain": [
              "<Image src=\"/docs/images/tutorials/ai-transpiler-introduction/extracted-outputs/hw-step2-plot-1.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "metadata": {},
          "output_type": "display_data"
        }
      ],
      "source": [
        "plot_metrics_and_pct(results_hw, \"Large-Scale Random Circuits\")"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 12,
      "id": "hw-step3",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "Mirror circuit (Default): depth 1577, gates 9672\n",
            "Mirror circuit (AI):      depth 1235, gates 11092\n",
            "Job submitted: d8gt7vm6983c73dqbg0g\n"
          ]
        }
      ],
      "source": [
        "# -------------------------Step 3-------------------------\n",
        "# Build mirror circuits from the 26-qubit case\n",
        "idx_26q = qubit_range_hw.index(26)\n",
        "\n",
        "qc_26q = circuits_hw[idx_26q]\n",
        "qc_default_26q, _ = transpile_with_metrics(pm_default, qc_26q)\n",
        "\n",
        "pm_ai = generate_ai_pass_manager(\n",
        "    optimization_level=1,\n",
        "    ai_optimization_level=3,\n",
        "    backend=backend,\n",
        ")\n",
        "qc_ai_26q, _ = transpile_with_metrics(pm_ai, qc_26q)\n",
        "\n",
        "mirror_default_hw = build_mirror_circuit(qc_default_26q, simulate=False)\n",
        "mirror_ai_hw = build_mirror_circuit(qc_ai_26q, simulate=False)\n",
        "\n",
        "# Re-transpile to basis gates (the inverse can introduce gates like sxdg)\n",
        "pm_basis = generate_preset_pass_manager(\n",
        "    optimization_level=0,\n",
        "    backend=backend,\n",
        ")\n",
        "mirror_default_hw = pm_basis.run(mirror_default_hw)\n",
        "mirror_ai_hw = pm_basis.run(mirror_ai_hw)\n",
        "\n",
        "print(\n",
        "    f\"Mirror circuit (Default): depth {mirror_default_hw.depth()}, \"\n",
        "    f\"gates {mirror_default_hw.size()}\"\n",
        ")\n",
        "print(\n",
        "    f\"Mirror circuit (AI):      depth {mirror_ai_hw.depth()}, \"\n",
        "    f\"gates {mirror_ai_hw.size()}\"\n",
        ")\n",
        "\n",
        "# Submit to real hardware\n",
        "sampler_hw = SamplerV2(mode=backend)\n",
        "sampler_hw.options.environment.job_tags = [\"TUT_AITI\"]\n",
        "\n",
        "shots_hw = 500000\n",
        "job_hw = sampler_hw.run([mirror_default_hw, mirror_ai_hw], shots=shots_hw)\n",
        "print(f\"Job submitted: {job_hw.job_id()}\")"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 13,
      "id": "hw-step4",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "Default   P(|00...0>) = 0.0005  (239/500000)\n",
            "AI        P(|00...0>) = 0.0050  (2516/500000)\n"
          ]
        },
        {
          "data": {
            "text/plain": [
              "<Image src=\"/docs/images/tutorials/ai-transpiler-introduction/extracted-outputs/hw-step4-1.avif\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "metadata": {},
          "output_type": "display_data"
        }
      ],
      "source": [
        "# -------------------------Step 4-------------------------\n",
        "result_hw = job_hw.result()\n",
        "\n",
        "survival_probs_hw = {}\n",
        "for i, method in enumerate([\"Default\", \"AI\"]):\n",
        "    counts = result_hw[i].data.meas.get_counts()\n",
        "    mirror = [mirror_default_hw, mirror_ai_hw][i]\n",
        "    all_zeros = \"0\" * mirror.num_qubits\n",
        "    survival = counts.get(all_zeros, 0) / shots_hw\n",
        "    survival_probs_hw[method] = survival\n",
        "    print(\n",
        "        f\"{method:8s}  P(|00...0>) = {survival:.4f}  \"\n",
        "        f\"({counts.get(all_zeros, 0)}/{shots_hw})\"\n",
        "    )\n",
        "\n",
        "# Plot 1 - P(|0...0>), the probability of an erroneous (non-zero) outcome.\n",
        "# A lower bar means the transpilation introduced less noise.\n",
        "error_probs_hw = {method: 1 - p for method, p in survival_probs_hw.items()}\n",
        "\n",
        "fig, ax = plt.subplots(figsize=(6, 4))\n",
        "ax.bar(\n",
        "    error_probs_hw.keys(),\n",
        "    error_probs_hw.values(),\n",
        "    color=[\"steelblue\", \"coral\"],\n",
        ")\n",
        "ax.set_ylabel(\"1 - P(|0...0>)\")\n",
        "ax.set_title(f\"Mirror Circuit Error (26-qubit, {backend.name})\")\n",
        "ax.set_ylim(0, 1)\n",
        "plt.tight_layout()\n",
        "plt.show()"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "hw-analysis",
      "metadata": {},
      "source": [
        "<span id=\"analysis-of-results\" />\n",
        "\n",
        "### Análise dos resultados\n",
        "\n",
        "Os resultados em grande escala reforçam as tendências observadas no exemplo em pequena escala, agora em uma escala mais exigente.\n",
        "\n",
        "**Profundidade de dois qubits:** O transpiler baseado em IA continua a apresentar uma profundidade de dois qubits visivelmente menor em toda a gama de tamanhos de circuitos. A otimização da profundidade é um dos principais objetivos para os quais o modelo de roteamento baseado em IA foi treinado, e a vantagem é mais evidente em sistemas com um número maior de qubits, nos quais o problema de roteamento se torna mais complexo para os métodos heurísticos.\n",
        "\n",
        "**Número de portas:** O transpiler padrão (SABRE) produz consistentemente circuitos com menos portas em todos os tamanhos de circuito nessa faixa. A heurística do SABRE foi projetada especificamente para minimizar o número de portas lógicas e, nessa escala, a vantagem é clara e uniforme.\n",
        "\n",
        "**Tempo de transpilação:** A diferença no tempo de transpilação aumenta em escalas maiores. O SABRE permanece praticamente constante, enquanto o tempo de execução do transpiler baseado em IA cresce de forma mais acentuada. Apesar disso, o tempo de execução do transpiler baseado em IA continua sendo viável para a maioria dos fluxos de trabalho.\n",
        "\n",
        "**Fidelidade do circuito espelho:** Ambos os métodos produzem probabilidades de sobrevivência bem abaixo de 1% nessa escala, deixando pouco sinal utilizável. Com um número total de portas em torno de 10.000 e profundidades de dois qubits superiores a 1.000, o ruído despolarizador acumulado ao longo do circuito de espelhos suprime a maior parte do sinal. Isso destaca uma limitação fundamental da abordagem do circuito espelho: embora seja simples e não exija simulação clássica, ela não se adapta bem a circuitos grandes ou profundos, nos quais ambos os métodos são levados para perto do nível de ruído e o pequeno sinal remanescente é dominado pelo erro acumulado.\n",
        "\n",
        "Embora esses resultados ressaltem a eficácia do transpiler baseado em IA, é importante observar suas limitações. Atualmente, o método de síntese por IA está disponível apenas para determinados mapas de acoplamento, o que pode limitar sua aplicabilidade mais ampla. Essa restrição deve ser levada em conta ao avaliar seu uso em diferentes cenários.\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "next-steps",
      "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 material a seguir:\n",
        "\n",
        "  * [Otimizações de transpilação com o SABRE](/docs/tutorials/transpilation-optimizations-with-sabre)\n",
        "  * [Métodos de compilação para circuitos de simulação hamiltonianos](/docs/tutorials/compilation-methods-for-hamiltonian-simulation-circuits)\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": 300
  },
  "nbformat": 4,
  "nbformat_minor": 5
}