← Quantum Computing
Quantum Computing

Building Your First Circuit

The QuantumCircuit class in Qiskit lets you imperatively add qubits, bits, and gates to build a quantum program

Source: mortalapps.com
TL;DR
  • The QuantumCircuit class is the primary tool in Qiskit for building quantum programs.
  • Qubits and classical bits in Qiskit are zero-indexed, meaning the first qubit is at index 0.
  • Gates are added to a circuit using imperative methods like qc.h() for Hadamard and qc.cx() for CNOT.
  • Explicitly defining QuantumRegister and ClassicalRegister helps organize complex circuits with multiple registers.
  • Barriers (qc.barrier()) prevent the transpiler from optimizing gates across the barrier and improve visual layout.
  • The qc.measure() method maps quantum states to classical bits, collapsing superpositions into classical data.

Why This Matters

The fundamental unit of execution in quantum computing is the quantum circuit. A quantum circuit is a sequence of quantum gates applied to a set of qubits, followed by measurements that extract classical information. In Qiskit, we construct these circuits programmatically using the QuantumCircuit class. This class provides an intuitive, imperative API for adding qubits, classical registers, and gates to a timeline.

When you build a circuit in Qiskit, you are essentially building a directed acyclic graph (DAG) where the nodes represent quantum operations and the edges represent the flow of quantum and classical information. This programmatic representation is highly flexible, allowing you to use classical control flow (like loops and conditionals) to generate complex, dynamic quantum circuits that would be impossible to draw by hand.

In this topic, you will master the mechanics of the QuantumCircuit class. You will learn how to initialize registers, apply single-qubit and multi-qubit gates, use barriers to organize your circuit's timeline, and add measurement operations. You will write the code to construct a Bell state and understand how Qiskit tracks the state of your qubits as you build your program.

Core Intuition

Think of building a quantum circuit in Qiskit like composing a piece of sheet music. The qubits are the horizontal staves (lines) of the music, and the gates are the musical notes placed on those staves. Time flows from left to right. When you call qc.h(0), you are placing a 'Hadamard note' on the first stave at the current beat. When you call qc.cx(0, 1), you are drawing a chord that connects the first and second staves, requiring them to play in harmony (entanglement).

Another helpful analogy is a physical breadboard used in electronics. The qubits are the copper traces running along the board, and the gates are physical components (resistors, transistors) that you plug into those traces. The classical bits are output wires connected to LEDs that light up at the very end of the circuit to show the final voltage levels. You build the circuit by plugging components in one by one, from input to output.

Barriers in Qiskit act like cardboard dividers placed on your breadboard. They don't change how the electricity flows, but they keep different sections of your circuit organized and prevent the compiler from accidentally mixing up components from different stages of your design. They tell the compiler: 'Finish everything on the left of this line before optimizing anything on the right.'

Visualization

Code-to-Circuit Mapping
Code-to-Circuit Mapping Shows how individual lines of Qiskit code map directly to elements in a quantum circuit diagram.

Technical Explanation

In Qiskit, a QuantumCircuit is initialized by specifying the number of quantum bits (qubits) and classical bits (clbits) it should contain. Qubits are indexed starting from 0. When gates are applied, they modify the state of the specified qubits. Mathematically, applying a gate $U$ to qubit $i$ corresponds to applying the operator $I \otimes \dots \otimes U \otimes \dots \otimes I$ to the joint statevector of the system.

Let's look at the mathematical transformations of a 2-qubit system as we build a Bell state. The system starts in the ground state:

$$\lvert \psi_0 \rangle = \lvert 00 \rangle = \begin{pmatrix} 1 \\ 0 \\ 0 \\ 0 \end{pmatrix}$$

Applying a Hadamard gate to qubit 0, qc.h(0), applies the operator $H \otimes I$:

$$\lvert \psi_1 \rangle = (H \otimes I) \lvert 00 \rangle = \frac{1}{\sqrt{2}}(\lvert 00 \rangle + \lvert 10 \rangle) = \begin{pmatrix} \frac{1}{\sqrt{2}} \\ 0 \\ \frac{1}{\sqrt{2}} \\ 0 \end{pmatrix}$$

Applying a CNOT gate with control 0 and target 1, qc.cx(0, 1), applies the controlled-X operator:

$$\lvert \psi_2 \rangle = \text{CNOT}_{0 \to 1} \lvert \psi_1 \rangle = \frac{1}{\sqrt{2}}(\lvert 00 \rangle + \lvert 11 \rangle) = \begin{pmatrix} \frac{1}{\sqrt{2}} \\ 0 \\ 0 \\ \frac{1}{\sqrt{2}} \end{pmatrix}$$

Here is the complete Qiskit code to construct this circuit, including barriers and explicit register definitions:

PYTHON
from qiskit import QuantumRegister, ClassicalRegister, QuantumCircuit

# Explicitly define registers for clarity
qr = QuantumRegister(2, name="q")
cr = ClassicalRegister(2, name="c")
qc = QuantumCircuit(qr, cr)

# Apply gates
qc.h(qr[0])          # Hadamard on qubit 0
qc.barrier()         # Visual and compilation barrier
qc.cx(qr[0], qr[1])  # CNOT with control qr[0] and target qr[1]
qc.barrier()         # Another barrier before measurement

# Measure qubits into classical bits
qc.measure(qr[0], cr[0])
qc.measure(qr[1], cr[1])

# Print the text representation of the circuit
print(qc.draw('text'))

In this code, we use QuantumRegister and ClassicalRegister explicitly. While QuantumCircuit(2, 2) is a convenient shorthand, explicitly defining registers is highly useful when building complex circuits with multiple distinct registers (e.g., an addressing register and a data register in a QRAM circuit).

Key Takeaways

The QuantumCircuit class is the primary tool in Qiskit for building quantum programs.
Qubits and classical bits in Qiskit are zero-indexed, meaning the first qubit is at index 0.
Gates are added to a circuit using imperative methods like qc.h() for Hadamard and qc.cx() for CNOT.
Explicitly defining QuantumRegister and ClassicalRegister helps organize complex circuits with multiple registers.
Barriers (qc.barrier()) prevent the transpiler from optimizing gates across the barrier and improve visual layout.
The qc.measure() method maps quantum states to classical bits, collapsing superpositions into classical data.