\n ## \n Background: DAG representation\n

\n\n Before building a pass, it is important to introduce the internal representation of quantum circuits in Qiskit, the [directed acyclic graph (DAG)](../api/qiskit/qiskit.dagcircuit.DAGCircuit) (see [this tutorial](https://qiskit.org/ecosystem/rustworkx/tutorial/dags.html) for an overview). To follow these steps, install the [`graphviz` library](https://graphviz.org/download/) for the DAG plotting functions.\n\n In Qiskit, within the transpilation stages, circuits are represented using a DAG. In general, a DAG is composed of *vertices* (also known as \"nodes\") and directed *edges* that connect pairs of vertices in a particular orientation. This representation is stored using `qiskit.dagcircuit.DAGCircuit` objects that are composed of invididual `DagNode` objects. The advantage of this representation over a pure list of gates (that is, a *netlist*) is that the flow of information between operations is explicit, making it easier to make transformation decisions.\n\n This example illustrates the DAG by creating a simple circuit that prepares a Bell state and applies an $R_Z$ rotation, depending on the measurement outcome.\n\n ```python\n\n from qiskit import QuantumRegister, ClassicalRegister, QuantumCircuit\n\n import numpy as np\n\n\n\n qr = QuantumRegister(3, 'qr')\n\n cr = ClassicalRegister(3, 'cr')\n\n qc = QuantumCircuit(qr, cr)\n\n\n\n qc.h(qr[0])\n\n qc.cx(qr[0], qr[1])\n\n qc.measure(qr[0], cr[0])\n\n qc.rz(np.pi/2, qr[1]).c_if(cr, 2)\n\n qc.draw(output='mpl')\n\n\n\n ```\n\n ![The circuit's DAG consists of nodes that are connected by directional edges. It is a visual way to represent qubits or classical bits, the operations, and the way that data flows. ](/images/guides/custom-transpiler-pass/DAG_circ.png \"DAG\")\n\n Use the `qiskit.tools.visualization.dag_drawer()` function to view this circuit's DAG. There are three kinds of graph nodes: qubit/clbit nodes (green), operation nodes (blue), and output nodes (red). Each edge indicates data flow (or dependency) between two nodes.\n\n ```python\n\n from qiskit.converters import circuit_to_dag\n\n from qiskit.tools.visualization import dag_drawer\n\n\n\n dag = circuit_to_dag(qc)\n\n dag_drawer(dag)\n\n ```\n\n ![](/images/guides/custom-transpiler-pass/DAG.png)\n

\n"]},{"cell_type":"markdown","id":"7e2e2bc6-c900-4d3b-a948-3f5d154cdea2","metadata":{},"source":["## Transpiler passes\n\nTranspiler passes are classified either as an [`AnalysisPass`](../api/qiskit/qiskit.transpiler.AnalysisPass) or a [`TransformationPass`](../api/qiskit/qiskit.transpiler.TransformationPass). Passes in general work with the [DAG](../api/qiskit/qiskit.dagcircuit.DAGCircuit) and the `property_set`, a dictionary-like object for storing properties determined by analysis passes. Analysis passes work with both the DAG and its `property_set`. They cannot modify the DAG, but can modify the `property_set`. This contrasts with transformation passes, which do modify the DAG, and can read (but not write to) `property_set`. For example, transformation passes translate a circuit to its [ISA](./transpile#instruction-set-architecture) or perform routing passes to insert SWAP gates where needed.\n"]},{"cell_type":"markdown","id":"f8ead728-b2b7-47b9-b3b1-f3578b594ffe","metadata":{},"source":["## Create a `PauliTwirl` transpiler pass\n\nThe following example constructs a transpiler pass that adds Pauli twirls. [Pauli twirling](https://arxiv.org/abs/quant-ph/0606161) is an error suppression strategy that randomizes how qubits experience noisy channels, which we assume to be two-qubit gates in this example (because they are much more error-prone than single-qubit gates). The Pauli twirls do not affect the two-qubit gates' operation. They are chosen such that those applied *before* the two-qubit gate (to the left) are countered by those applied *after* the two-qubit gate (to the right). In this sense, the two-qubit operations are identical, but the way they are performed is different. One benefit of Pauli twirling is that it turns coherent errors into stochastic errors, which can be improved by averaging more.\n\nTranspiler passes act on the [DAG](../api/qiskit/qiskit.dagcircuit.DAGCircuit), so the important method to override is `.run()`, which takes the DAG as input. Initializing pairs of Paulis as shown preserves the operation of each two-qubit gate. This is done with the helper method `build_twirl_set`, which goes through each two-qubit Pauli (as obtained from `pauli_basis(2)`) and finds the other Pauli that preserves the operation.\n\nFrom the DAG, use the `op_nodes()` method to return all of its nodes. The DAG can also be used to collect runs, which are sequences of nodes that run uninterrupted on a qubit. These can be collected as single-qubit runs with `collect_1q_runs`, two-qubit runs with `collect_2q_runs`, and runs of nodes where the instruction names are in a namelist with `collect_runs`. The `DAGCircuit` has many methods for searching and traversing a graph. One commonly used method is `topological_op_nodes`, which provides the nodes in a dependency ordering. Other methods such as `bfs_successors` are used primarily to determine how nodes interact with subsequent operations on a DAG.\n\nIn the example, we want to replace each node, representing an instruction, with a subcircuit built as a mini DAG. The mini DAG has a two-qubit quantum register added to it. Operations are added to the mini DAG by using `apply_operation_back`, which places the `Instruction` on the mini DAG's output (whereas `apply_operation_front` would place it on the mini DAG's input). The node is then substituted by the mini DAG by using `substitute_node_with_dag`, and the process continues over each instance of `CXGate` and `ECRGate` in the DAG (corresponding to the two-qubit basis gates on IBMÂ® backends).\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","\n"," # iterate through Paulis on right of gate to twirl\n"," for pauli_right in pauli_basis(2):\n","\n"," # save pairs that produce identical operation as gate to twirl\n"," if (Operator(pauli_left) @ Operator(twirl_gate)).equiv(Operator(twirl_gate) @ pauli_right):\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","\n"," # collect all nodes in DAG and proceed if it is to be twirled\n"," twirling_gate_classes = tuple(gate.base_class for gate in self.gates_to_twirl)\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(0, len(self.twirl_set[node.op.name]))\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(twirl_pair[0].to_instruction(), [register[0], register[1]])\n"," mini_dag.apply_operation_back(node.op, [register[0], register[1]])\n"," mini_dag.apply_operation_back(twirl_pair[1].to_instruction(), [register[0], register[1]])\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":["## Use the `PauliTwirl` transpiler pass\n\nThe following code uses the pass created above to transpile a circuit. Consider a simple circuit with `cx`s and `ecr`s.\n"]},{"cell_type":"code","execution_count":3,"id":"9123905d-b4cb-4ae9-9695-4ad77e70bdab","metadata":{},"outputs":[{"data":{"image/svg+xml":[""],"text/plain":["