{
  "cells": [
    {
      "cell_type": "markdown",
      "id": "710d86a8-3243-4133-b7bc-093306598512",
      "metadata": {},
      "source": [
        "---\n",
        "title: \"Crie uma etapa personalizada do transpiler\"\n",
        "description: \"Aprenda a escrever sua própria passagem de transpiler usando o Qiskit, incluindo a representação do circuito DAG\"\n",
        "---\n",
        "\n",
        "<span id=\"write-a-custom-transpiler-pass\" />\n",
        "\n",
        "# Crie uma etapa personalizada do transpiler\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "5a66bd4b-56b1-4f33-b1bf-b43dbc7c03a7",
      "metadata": {
        "tags": [
          "version-info"
        ]
      },
      "source": [
        "{/*\n",
        "  DO NOT EDIT THIS CELL!!!\n",
        "  This cell's content is generated automatically by a script. Anything you add\n",
        "  here will be removed next time the notebook is run. To add new content, create\n",
        "  a new cell before or after this one.\n",
        "  */}\n",
        "\n",
        "<Accordion>\n",
        "  <AccordionItem title=\"Versões do pacote\">\n",
        "    O código desta página foi desenvolvido usando os seguintes requisitos.\n",
        "    Recomendamos o uso dessas versões ou de versões mais recentes.\n",
        "\n",
        "    ```\n",
        "    qiskit[all]~=2.5.0\n",
        "    ```\n",
        "  </AccordionItem>\n",
        "</Accordion>\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "32806873-3c88-48fc-94ad-9d20e0f378f8",
      "metadata": {},
      "source": [
        "O Qiskit SDK permite que você crie passagens de transpilação personalizadas e as execute no objeto `PassManager` ou as adicione a um `StagedPassManager`. Aqui demonstraremos como escrever uma passagem de transpilador, concentrando-nos na criação de uma passagem que executa [o giro de Pauli](https://arxiv.org/abs/quant-ph/0606161) nas portas quânticas ruidosas em um circuito quântico. Este exemplo usa o DAG, que é o objeto manipulado pelo tipo de passe `TransformationPass` .\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "c49a2046-39b0-4e63-aa63-911845ffd315",
      "metadata": {},
      "source": [
        "<Accordion>\n",
        "  <AccordionItem title=\"Contexto: Representação DAG\">\n",
        "    Antes de criar uma passagem, é importante apresentar a representação interna dos circuitos quânticos no Qiskit, o [gráfico acíclico dirigido (DAG)](../api/qiskit/qiskit.dagcircuit.DAGCircuit) (consulte [este tutorial](https://qiskit.org/ecosystem/rustworkx/tutorial/dags.html) para obter uma visão geral).  Para seguir essas etapas, instale a [biblioteca `graphviz` ](https://graphviz.org/download/) para as funções de plotagem DAG.\n",
        "\n",
        "    No Qiskit, nas etapas de transpilagem, os circuitos são representados usando um DAG.  Em geral, um DAG é composto por *vértices* (também conhecidos como “nós”) e *arestas* direcionadas que conectam pares de vértices em uma orientação específica.  Essa representação é armazenada usando `qiskit.dagcircuit.DAGCircuit` objetos que são compostos por objetos `DagNode` individuais.  A vantagem dessa representação em relação a uma lista pura de portas (ou seja, uma *lista de rede* ) é que o fluxo de informações entre as operações é explícito, facilitando a tomada de decisões de transformação.\n",
        "\n",
        "    Este exemplo ilustra o DAG criando um circuito simples que prepara um estado Bell e aplica uma rotação $R_Z$, dependendo do resultado da medição.\n",
        "\n",
        "    ```python\n",
        "    from qiskit import QuantumRegister, ClassicalRegister, QuantumCircuit\n",
        "    import numpy as np\n",
        "\n",
        "    qr = QuantumRegister(3, 'qr')\n",
        "    cr = ClassicalRegister(3, 'cr')\n",
        "    qc = QuantumCircuit(qr, cr)\n",
        "\n",
        "    qc.h(qr[0])\n",
        "    qc.cx(qr[0], qr[1])\n",
        "    qc.measure(qr[0], cr[0])\n",
        "    with qc.if_test((cr, 2)):\n",
        "        qc.rz(np.pi/2, qr[1])\n",
        "    qc.draw(output='mpl')\n",
        "\n",
        "    ```\n",
        "\n",
        "    ![Circuito que prepara um estado de Bell e aplica uma rotação R\\_Z dependendo do resultado da medição.](https://quantum.cloud.ibm.com/docs/images/guides/custom-transpiler-pass/DAG_circ.avif \"Circuito\")\n",
        "\n",
        "    Use a função `qiskit.tools.visualization.dag_drawer()` para visualizar o DAG desse circuito.  Há três tipos de nós de gráfico: nós de qubit/clbit (verde), nós de operação (azul) e nós de saída (vermelho).  Cada borda indica o fluxo de dados (ou dependência) entre dois nós.\n",
        "\n",
        "    ```python\n",
        "    from qiskit.converters import circuit_to_dag\n",
        "    from qiskit.visualization import dag_drawer\n",
        "\n",
        "    dag = circuit_to_dag(qc)\n",
        "    dag_drawer(dag)\n",
        "    ```\n",
        "\n",
        "    ![O DAG do circuito consiste em nós que são conectados por bordas direcionais. É uma forma visual de representar qubits ou bits clássicos, as operações e a maneira como os dados fluem.](https://quantum.cloud.ibm.com/docs/images/guides/custom-transpiler-pass/DAG.avif \"DAG\")\n",
        "  </AccordionItem>\n",
        "</Accordion>\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "7e2e2bc6-c900-4d3b-a948-3f5d154cdea2",
      "metadata": {},
      "source": [
        "<span id=\"transpiler-passes\" />\n",
        "\n",
        "## Passagens do transpiler\n",
        "\n",
        "As etapas do transpiler [`TransformationPass`](../api/qiskit/qiskit.transpiler.TransformationPass)são classificadas como [`AnalysisPass`](../api/qiskit/qiskit.transpiler.AnalysisPass) ou. As passagens, em geral, funcionam com o [DAG](../api/qiskit/qiskit.dagcircuit.DAGCircuit) e o `property_set`, um objeto semelhante a um dicionário para armazenar propriedades determinadas pelas passagens de análise. As etapas de análise funcionam tanto com o DAG quanto com seu `property_set`.  Eles não podem modificar o DAG, mas podem modificar o `property_set`.  Isso contrasta com as etapas de transformação, que modificam o DAG e podem ler (mas não gravar) nele `property_set`.  Por exemplo, as etapas de transformação convertem um circuito para sua [ISA](/docs/guides/transpile#instruction-set-architecture) ou realizam etapas de roteamento para inserir portas SWAP onde necessário.\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "f8ead728-b2b7-47b9-b3b1-f3578b594ffe",
      "metadata": {},
      "source": [
        "<span id=\"create-a-paulitwirl-transpiler-pass\" />\n",
        "\n",
        "## Criar uma passagem `PauliTwirl` do transpiler\n",
        "\n",
        "O exemplo a seguir constrói uma passagem de transpilador que adiciona giros de Pauli. [O giro de Pauli](https://arxiv.org/abs/quant-ph/0606161) é uma estratégia de supressão de erros que randomiza a forma como os qubits experimentam canais ruidosos, que assumimos como portas de dois qubits neste exemplo (porque elas são muito mais propensas a erros do que as portas de um único qubit). Os giros de Pauli não afetam a operação das portas de dois qubits. Eles são escolhidos de forma que aqueles aplicados *antes da* porta de dois qubits (à esquerda) sejam neutralizados por aqueles aplicados *após a* porta de dois qubits (à direita). Nesse sentido, as operações de dois qubits são idênticas, mas a maneira como são realizadas é diferente. Uma vantagem do giro de Pauli é que ele transforma erros coerentes em erros estocásticos, que podem ser melhorados com o aumento da média.\n",
        "\n",
        "As passagens do Transpiler atuam no [DAG](../api/qiskit/qiskit.dagcircuit.DAGCircuit), portanto, o método importante a ser substituído é `.run()`, que recebe o DAG como entrada. A inicialização de pares de Paulis, conforme mostrado, preserva a operação de cada porta de dois qubits. Isso é feito com o método auxiliar `build_twirl_set`, que passa por cada Pauli de dois qubits (conforme obtido em `pauli_basis(2)`) e encontra o outro Pauli que preserva a operação.\n",
        "\n",
        "No DAG, use o método `op_nodes()` para retornar todos os seus nós. O DAG também pode ser usado para coletar execuções, que são sequências de nós que são executadas ininterruptamente em um qubit. Eles podem ser coletados como execuções de um único qubit com `collect_1q_runs`, execuções de dois qubit com `collect_2q_runs` e execuções de nós em que os nomes das instruções estão em uma lista de nomes com `collect_runs`.  O site `DAGCircuit` tem muitos métodos para pesquisar e percorrer um gráfico.  Um método comumente usado é o `topological_op_nodes`, que fornece os nós em uma ordem de dependência. Outros métodos, como o `bfs_successors` , são usados principalmente para determinar como os nós interagem com as operações subsequentes em um DAG.\n",
        "\n",
        "No exemplo, queremos substituir cada nó, que representa uma instrução, por um subcircuito construído como um mini DAG. O mini DAG tem um registro quântico de dois qubits adicionado a ele.  As operações são adicionadas ao mini DAG usando `apply_operation_back`, que coloca o `Instruction` na saída do mini DAG (enquanto `apply_operation_front` o colocaria na entrada do mini DAG). O nó é então substituído pelo mini DAG usando `substitute_node_with_dag`, e o processo continua em cada instância de `CXGate` e `ECRGate` no DAG (correspondente às portas de base de dois qubits nos backends IBM® ).\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 1,
      "id": "80546e59-dcd8-4b61-88b5-00b220409f6d",
      "metadata": {},
      "outputs": [],
      "source": [
        "from qiskit.dagcircuit import DAGCircuit\n",
        "from qiskit.circuit import QuantumCircuit, QuantumRegister, Gate\n",
        "from qiskit.circuit.library import CXGate, ECRGate\n",
        "from qiskit.transpiler import PassManager\n",
        "from qiskit.transpiler.basepasses import TransformationPass\n",
        "from qiskit.quantum_info import Operator, pauli_basis\n",
        "\n",
        "import numpy as np\n",
        "\n",
        "from typing import Iterable, Optional"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 2,
      "id": "6bb6ff72-43dd-4f8c-a67c-b43af2548b2a",
      "metadata": {},
      "outputs": [],
      "source": [
        "class PauliTwirl(TransformationPass):\n",
        "    \"\"\"Add Pauli twirls to two-qubit gates.\"\"\"\n",
        "\n",
        "    def __init__(\n",
        "        self,\n",
        "        gates_to_twirl: Optional[Iterable[Gate]] = None,\n",
        "    ):\n",
        "        \"\"\"\n",
        "        Args:\n",
        "            gates_to_twirl: Names of gates to twirl. The default behavior is to twirl all\n",
        "                two-qubit basis gates, `cx` and `ecr` for IBM backends.\n",
        "        \"\"\"\n",
        "        if gates_to_twirl is None:\n",
        "            gates_to_twirl = [CXGate(), ECRGate()]\n",
        "        self.gates_to_twirl = gates_to_twirl\n",
        "        self.build_twirl_set()\n",
        "        super().__init__()\n",
        "\n",
        "    def build_twirl_set(self):\n",
        "        \"\"\"\n",
        "        Build a set of Paulis to twirl for each gate and store internally as .twirl_set.\n",
        "        \"\"\"\n",
        "        self.twirl_set = {}\n",
        "\n",
        "        # iterate through gates to be twirled\n",
        "        for twirl_gate in self.gates_to_twirl:\n",
        "            twirl_list = []\n",
        "\n",
        "            # iterate through Paulis on left of gate to twirl\n",
        "            for pauli_left in pauli_basis(2):\n",
        "                # iterate through Paulis on right of gate to twirl\n",
        "                for pauli_right in pauli_basis(2):\n",
        "                    # save pairs that produce identical operation as gate to twirl\n",
        "                    if (Operator(pauli_left) @ Operator(twirl_gate)).equiv(\n",
        "                        Operator(twirl_gate) @ pauli_right\n",
        "                    ):\n",
        "                        twirl_list.append((pauli_left, pauli_right))\n",
        "\n",
        "            self.twirl_set[twirl_gate.name] = twirl_list\n",
        "\n",
        "    def run(\n",
        "        self,\n",
        "        dag: DAGCircuit,\n",
        "    ) -> DAGCircuit:\n",
        "        # collect all nodes in DAG and proceed if it is to be twirled\n",
        "        twirling_gate_classes = tuple(\n",
        "            gate.base_class for gate in self.gates_to_twirl\n",
        "        )\n",
        "        for node in dag.op_nodes():\n",
        "            if not isinstance(node.op, twirling_gate_classes):\n",
        "                continue\n",
        "\n",
        "            # random integer to select Pauli twirl pair\n",
        "            pauli_index = np.random.randint(\n",
        "                0, len(self.twirl_set[node.op.name])\n",
        "            )\n",
        "            twirl_pair = self.twirl_set[node.op.name][pauli_index]\n",
        "\n",
        "            # instantiate mini_dag and attach quantum register\n",
        "            mini_dag = DAGCircuit()\n",
        "            register = QuantumRegister(2)\n",
        "            mini_dag.add_qreg(register)\n",
        "\n",
        "            # apply left Pauli, gate to twirl, and right Pauli to empty mini-DAG\n",
        "            mini_dag.apply_operation_back(\n",
        "                twirl_pair[0].to_instruction(), [register[0], register[1]]\n",
        "            )\n",
        "            mini_dag.apply_operation_back(node.op, [register[0], register[1]])\n",
        "            mini_dag.apply_operation_back(\n",
        "                twirl_pair[1].to_instruction(), [register[0], register[1]]\n",
        "            )\n",
        "\n",
        "            # substitute gate to twirl node with twirling mini-DAG\n",
        "            dag.substitute_node_with_dag(node, mini_dag)\n",
        "\n",
        "        return dag"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "da136beb-d1b2-4f68-8274-386e80a49860",
      "metadata": {},
      "source": [
        "<span id=\"use-the-paulitwirl-transpiler-pass\" />\n",
        "\n",
        "## Use a passagem `PauliTwirl` do transpiler\n",
        "\n",
        "O código a seguir usa o pass criado acima para transpilá-lo. Considere um circuito simples com `cx` portas `ecr` e.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 3,
      "id": "9123905d-b4cb-4ae9-9695-4ad77e70bdab",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<Image src=\"/docs/images/guides/custom-transpiler-pass/extracted-outputs/9123905d-b4cb-4ae9-9695-4ad77e70bdab-0.svg\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "execution_count": 3,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "qc = QuantumCircuit(3)\n",
        "qc.cx(0, 1)\n",
        "qc.ecr(1, 2)\n",
        "qc.ecr(1, 0)\n",
        "qc.cx(2, 1)\n",
        "qc.draw(\"mpl\")"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "f112c2af-c99a-4733-8118-4786e2dfdfd3",
      "metadata": {},
      "source": [
        "Para aplicar o passe personalizado, crie um gerenciador de passes usando o passe `PauliTwirl` e execute-o em 50 circuitos.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 4,
      "id": "ea884cd2-2446-4b2d-a0f7-82ef574b11ee",
      "metadata": {},
      "outputs": [],
      "source": [
        "pm = PassManager([PauliTwirl()])\n",
        "twirled_qcs = [pm.run(qc) for _ in range(50)]"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "3d4d921e-1a43-4f9a-bc30-6c64092d8f6b",
      "metadata": {},
      "source": [
        "Cada porta de dois qubits está agora imprensada entre duas Paulis.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 5,
      "id": "e2515cf3-f8d9-4281-9673-d5a955d7aab9",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "<Image src=\"/docs/images/guides/custom-transpiler-pass/extracted-outputs/e2515cf3-f8d9-4281-9673-d5a955d7aab9-0.svg\" alt=\"Output of the previous code cell\" />"
            ]
          },
          "execution_count": 5,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "twirled_qcs[-1].draw(\"mpl\")"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "41cccfba-8b65-401c-9d30-66396a3fe3a1",
      "metadata": {},
      "source": [
        "Os operadores são os mesmos se `Operator` de `qiskit.quantum_info` for usado:\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 6,
      "id": "0f8b4ca1-4205-4b71-941d-0852eebbe917",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "np.True_"
            ]
          },
          "execution_count": 6,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "np.all([Operator(twirled_qc).equiv(qc) for twirled_qc in twirled_qcs])"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "0d680854-13f8-4ccd-9be1-595edb4f942c",
      "metadata": {},
      "source": [
        "<span id=\"next-steps\" />\n",
        "\n",
        "## Próximas etapas\n",
        "\n",
        "<Admonition type=\"tip\" title=\"Recomendações\">\n",
        "  * Para saber como usar a função `generate_preset_passmanager` em vez de escrever seus próprios passes, comece com o tópico [Definições padrão de transpilação e opções de configuração](defaults-and-configuration-options).\n",
        "  * Experimente o guia [Comparar configurações do transpiler](/docs/guides/circuit-transpilation-settings).\n",
        "  * Consulte a [documentação da API do transpiler](/docs/api/qiskit/transpiler).\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"
    }
  },
  "nbformat": 4,
  "nbformat_minor": 2
}