Writing a Custom Transpiler Pass — Your First Plugin
Extend Qiskit by writing a simple pass that removes redundant gates
The Qiskit transpiler is the engine that transforms your quantum circuit into something that can run on real hardware. But did you know you can write your own transpiler passes? In this article, we will build a custom pass that removes redundant gates from a quantum circuit. Think of it as a code optimiser for quantum programs.
We will use Jupyter Notebook (or Google Colab) with a Python virtual environment. Let us get started.
Setting Up Your Environment
First, create a virtual environment and install the required packages. Open your terminal and run:
For Windows:
python -m venv medium_quantum_venv
medium_quantum_venv\Scripts\activateFor macOS/Linux:
python3 -m venv medium_quantum_venv
source medium_quantum_venv/bin/activateNow install the required packages:
pip install qiskit==2.5.0 qiskit-aer jupyterLaunch Jupyter Notebook:
jupyter notebookWhat We Will Build
We will create a custom transpiler pass called RemoveRedundantGates. This pass will scan a quantum circuit and remove consecutive gates that cancel each other out. For example, two consecutive Hadamard gates (H H) are redundant because H * H = I (identity). Similarly, two consecutive X gates cancel each other.
Get Rahul Tech Articles’s stories in your inbox
Join Medium for free to get updates from this writer.
The pass will inherit from Qiskit’s TransformationPass and operate on the DAG (Directed Acyclic Graph) representation of the circuit.
Importing the Required Libraries
Create a new cell in your Jupyter Notebook and run the following imports:
from qiskit import QuantumCircuit
from qiskit.transpiler import PassManager, TransformationPass
from qiskit.dagcircuit import DAGCircuit
from qiskit_aer import AerSimulatorWriting the Custom Pass
Now we will define our custom pass class. The pass overrides the run method, which receives a DAGCircuit object. We will iterate through the nodes and remove redundant patterns.
class RemoveRedundantGates(TransformationPass):
def run(self, dag):
nodes = list(dag.op_nodes())
i = 0
while i < len(nodes) - 1:
node1 = nodes[i]
node2 = nodes[i + 1]
if (node1.op.name == node2.op.name and
node1.op.name in ['h', 'x', 'y', 'z'] and
node1.qargs == node2.qargs):
dag.remove_op_node(node1)
dag.remove_op_node(node2)
i += 2
else:
i += 1
return dagWhat this does: It looks for two consecutive gates of the same type (H, X, Y, or Z) acting on the same qubit and removes both. Since two identical self-inverse gates in a row equal the identity operation, removing them is safe.
Creating a Test Circuit
Let us build a circuit with some redundant gates to test our pass.
qc = QuantumCircuit(2)
qc.h(0)
qc.h(0) # Redundant: two H gates cancel
qc.x(1)
qc.x(1) # Redundant: two X gates cancel
qc.cx(0, 1)
qc.h(0)
qc.measure_all()
print("Original circuit:")
qc.draw('mpl')Expected Output:
The circuit drawing will show two consecutive H gates on qubit 0, two consecutive X gates on qubit 1, a CNOT gate, and one H gate on qubit 0 before measurement.
Applying the Custom Pass
Now we will create a PassManager and add our custom pass to it. Then we run the pass on our circuit.
pm = PassManager()
pm.append(RemoveRedundantGates())
optimized_qc = pm.run(qc)
print("Optimized circuit:")
optimized_qc.draw('mpl')Expected Output:
The optimised circuit will show only the CNOT gate, the single H gate on qubit 0, and the measurements. The two H gates on qubit 0 and the two X gates on qubit 1 have been removed.
Verifying with Simulation
To confirm that both circuits produce the same results, we can simulate them using AerSimulator.
sim = AerSimulator()
# Transpile both circuits for the simulator
t_qc = qc.copy()
t_opt = optimized_qc.copy()
# Run simulations
result_original = sim.run(t_qc, shots=1024).result()
result_optimized = sim.run(t_opt, shots=1024).result()
counts_original = result_original.get_counts()
counts_optimized = result_optimized.get_counts()
print("Original circuit counts:", counts_original)
print("Optimized circuit counts:", counts_optimized)Expected Output:
Both circuits produce identical measurement outcomes, proving that our pass correctly removed the redundant gates without changing the circuit’s behaviour.
Where to Put This Code
You can keep all the code in a single Jupyter Notebook cell or split it across multiple cells for better readability. If you want to reuse this pass in other projects, save it as a Python file (for example, my_passes.py) and import it:
from my_passes import RemoveRedundantGatesGitHub Repository
You can find the complete Jupyter Notebook for this article at:
Conclusion
Writing a custom transpiler pass in Qiskit is straightforward. By subclassing TransformationPass and implementing the run method, you can create powerful optimisations tailored to your specific needs. We built a simple pass that removes redundant self-inverse gates, reducing circuit depth without affecting the final results. This is just the beginning. You can extend this concept to build more sophisticated passes that merge gates, optimise rotations, or even perform error mitigation.
The Qiskit transpiler is a flexible tool. With custom passes, you have the power to shape your quantum circuits exactly the way you want.







