IBM Qiskit — Programming Quantum Computers in Python
In this tutorial, you'll learn about IBM Qiskit. We cover key concepts, practical examples, and best practices to help you understand and apply this topic effectively.
IBM Qiskit is an open-source Python framework for programming quantum computers, providing tools to build, simulate, and execute quantum circuits on IBM's cloud-accessible quantum processors.
What You'll Learn
By the end of this tutorial, you will install Qiskit, build quantum circuits, run simulations, execute on real quantum hardware (if you have IBM Quantum access), implement Grover Search and Bell state circuits, and use Qiskit's visualization tools.
Why It Matters
Qiskit is the most widely used Quantum Computing framework with over 1 million downloads monthly. IBM provides free cloud access to quantum hardware with up to 127 qubits. Learning Qiskit gives you hands-on experience with real quantum computers.
Real-World Use
Researchers at MIT used Qiskit to simulate quantum chemistry for battery materials. JPMorgan Chase uses Qiskit for quantum finance algorithms. IBM's Qiskit Patterns methodology is used across industry for quantum application development.
Learning Path
flowchart LR
A[Quantum Cryptography] --> B[IBM Qiskit]
B --> C[Google Cirq]
C --> D[Microsoft Q#]
B --> E{You Are Here}
style E fill:#f90,color:#fff
Prerequisites: Understand quantum circuits and quantum gates. Proficiency in Python is required.
Installing Qiskit
# Install Qiskit
pip install qiskit qiskit-aer qiskit-ibm-runtime
# Verify installation
python -c "import qiskit; print(qiskit.__version__)"
# Expected: 1.x.x
Your First Qiskit Circuit
# first_qiskit.py
from qiskit import QuantumCircuit
from qiskit_aer import AerSimulator
# Create a quantum circuit with 2 qubits and 2 classical bits
qc = QuantumCircuit(2, 2)
# Apply a Hadamard gate to create superposition on qubit 0
qc.h(0)
# Apply CNOT: entangle qubit 0 and qubit 1
qc.cx(0, 1)
# Measure both qubits
qc.measure([0, 1], [0, 1])
# Print the circuit
print("=== Quantum Circuit ===")
print(qc.draw())
# Simulate
simulator = AerSimulator()
result = simulator.run(qc, shots=4096).result()
counts = result.get_counts()
print(f"\nMeasurement results: {counts}")
Expected output:
=== Quantum Circuit ===
┌───┐ ┌─┐
q_0: ┤ H ├──■──┤M├───
└───┘┌─┴─┐└╥┘┌─┐
q_1: ─────┤ X ├─╫─┤M├
└───┘ ║ └╥┘
c: 2/═══════════╩══╩═
0 1
Measurement results: {'00': 2048, '11': 2048}
Building More Complex Circuits
# complex_circuit.py
from qiskit import QuantumCircuit
from qiskit_aer import AerSimulator
import numpy as np
def create_ghz_state(n_qubits):
"""Create an n-qubit GHZ state."""
qc = QuantumCircuit(n_qubits, n_qubits)
# Hadamard on first qubit
qc.h(0)
# Cascade of CNOTs
for i in range(n_qubits - 1):
qc.cx(i, i + 1)
# Measure all qubits
qc.measure(range(n_qubits), range(n_qubits))
return qc
def create_random_circuit(n_qubits, depth):
"""Create a random quantum circuit."""
qc = QuantumCircuit(n_qubits, n_qubits)
gates = ['h', 'x', 'y', 'z', 't', 's']
for _ in range(depth):
for q in range(n_qubits):
gate = np.random.choice(gates)
getattr(qc, gate)(q)
# Add some entanglement
if n_qubits > 1:
control = np.random.randint(0, n_qubits - 1)
target = np.random.randint(control + 1, n_qubits)
qc.cx(control, target)
qc.measure(range(n_qubits), range(n_qubits))
return qc
# Create and simulate GHZ state
print("=== 4-Qubit GHZ State ===")
ghz = create_ghz_state(4)
print(ghz.draw())
simulator = AerSimulator()
result = simulator.run(ghz, shots=4096).result()
counts = result.get_counts()
print(f"\nResults: {counts}")
print(f"Only |0000⟩ and |1111⟩ should appear")
# Create and simulate random circuit
print("\n=== Random 3-Qubit Circuit ===")
random_qc = create_random_circuit(3, 5)
print(random_qc.draw())
result = simulator.run(random_qc, shots=4096).result()
counts = result.get_counts()
print(f"\nResults: {counts}")
Expected output:
=== 4-Qubit GHZ State ===
┌───┐ ┌─┐
q_0: ┤ H ├──■──────■──────■───────┤M├───
└───┘┌─┴─┐ │ │ └╥┘┌─┐
q_1: ─────┤ X ├──■──┼──────┼────────╫─┤M├
└───┘┌─┴─┐│ │ ║ └╥┘
q_2: ──────────┤ X ├┼──■───┼────────╫──╫─
└───┘│┌─┴─┐ │ ║ ║
q_3: ───────────────┤ X ├─■─────────╫──╫─
└───┘ ║ ║
c: 4/═══════════════════════════════╩══╩═
0 3
Results: {'0000': 2056, '1111': 2040}
Qiskit with Classical Logic
# qiskit_classical.py
from qiskit import QuantumCircuit
from qiskit_aer import AerSimulator
from qiskit.circuit import ClassicalRegister, QuantumRegister
# Build a circuit with classical control
qr = QuantumRegister(3, 'q')
cr = ClassicalRegister(3, 'c')
qc = QuantumCircuit(qr, cr)
# Create Bell pair
qc.h(0)
qc.cx(0, 1)
# Measure qubits 0 and 1
qc.measure(0, 0)
qc.measure(1, 1)
# Apply X on qubit 2 conditioned on measurement results
qc.x(2).c_if(cr, 0b10) # If result = 2 (binary 10), flip q2
qc.measure(2, 2)
print("=== Circuit with Classical Control ===")
print(qc.draw())
simulator = AerSimulator()
result = simulator.run(qc, shots=4096).result()
counts = result.get_counts()
print(f"\nResults: {counts}")
Expected output:
=== Circuit with Classical Control ===
┌───┐ ┌─┐ ┌─┐
q_0: ┤ H ├──■──┤M├──────┤M├
└───┘┌─┴─┐└╥┘┌─┐ └╥┘
q_1: ─────┤ X ├─╫─┤M├────╫─
└───┘ ║ └╥┘ ║
q_2: ───────────╫──╫─────╫─
║ ║ ┌───╖
┌───┐ ║ ║ └─╫─╢
c: 3/═══════════╩══╩═══╩══
0 1 2
Results: {'000': 1024, '010': 1024, '101': 1024, '111': 1024}
Visualizing Results
# qiskit_visualization.py
from qiskit import QuantumCircuit
from qiskit_aer import AerSimulator
from qiskit.visualization import plot_histogram, plot_bloch_vector
# Create a superposition circuit
qc = QuantumCircuit(1, 1)
qc.h(0)
qc.measure(0, 0)
# Simulate
simulator = AerSimulator()
result = simulator.run(qc, shots=4096).result()
counts = result.get_counts()
print("=== Visualization ===")
print(f"Counts: {counts}")
# Histogram (would display in Jupyter)
# plot_histogram(counts)
# Bloch sphere representation
import numpy as np
# For the state after H|0⟩ = |+⟩
bloch_vector = [1, 0, 0] # +X direction
print(f"\nBloch vector for |+⟩: {bloch_vector}")
print(f"Plotting shows qubit on +X axis of Bloch sphere")
Expected output:
=== Visualization ===
Counts: {'0': 2048, '1': 2048}
Bloch vector for |+⟩: [1, 0, 0]
Plotting shows qubit on +X axis of Bloch sphere
Running on Real Hardware
# qiskit_real_hardware.py
from qiskit import QuantumCircuit
from qiskit_ibm_runtime import QiskitRuntimeService, Sampler
# Uncomment and add your IBM Quantum API token
# service = QiskitRuntimeService(channel="ibm_quantum",
# token="YOUR_IBM_QUANTUM_TOKEN")
# List available backends
# backends = service.backends()
# print("Available backends:")
# for backend in backends:
# print(f" {backend.name}: {backend.status().pending_jobs} jobs queued")
# Create a simple circuit
qc = QuantumCircuit(2, 2)
qc.h(0)
qc.cx(0, 1)
qc.measure_all()
print("=== Running on IBM Quantum Hardware ===")
print("Circuit ready for execution:")
print(qc.draw())
# To run on real hardware (requires IBM Quantum account):
# backend = service.least_busy(operational=True, simulator=False)
# sampler = Sampler(backend=backend)
# job = sampler.run([qc], shots=4096)
# print(f"Job ID: {job.job_id()}")
# result = job.result()
# print(f"Counts: {result.quasi_dists[0]}")
print("\nNote: Uncomment the IBM Quantum code and add your API token")
print("to run on real quantum hardware.")
Grover Search with Qiskit
# grover_qiskit.py
from qiskit import QuantumCircuit
from qiskit_aer import AerSimulator
from qiskit.circuit.library import GroverOperator, MCMT, ZGate
import numpy as np
def grover_circuit(n_qubits, target):
"""Build a Grover search circuit."""
from qiskit.circuit.library import Diagonal
# Create oracle that marks target
oracle = QuantumCircuit(n_qubits)
# Mark target by flipping its phase
oracle.diag([1 if i != target else -1 for i in range(2**n_qubits)])
oracle.name = "Oracle"
# Grover operator
grover_op = GroverOperator(oracle)
# Full circuit
qc = QuantumCircuit(n_qubits, n_qubits)
# Initial superposition
qc.h(range(n_qubits))
# Grover iterations
num_iterations = int(np.floor(np.pi / 4 * np.sqrt(2**n_qubits)))
qc.compose(grover_op.repeat(num_iterations), inplace=True)
# Measure
qc.measure(range(n_qubits), range(n_qubits))
return qc
# Find target 5 in 3-qubit search space
print("=== Grover Search with Qiskit ===")
target = 5
qc = grover_circuit(3, target)
simulator = AerSimulator()
result = simulator.run(qc, shots=4096).result()
counts = result.get_counts()
# Find most common result
most_common = max(counts, key=counts.get)
print(f"Most common result: {most_common}")
print(f"Target (binary): {format(target, '03b')}")
print(f"Match: {most_common == format(target, '03b')}")
print(f"\nCounts: {counts}")
Expected output:
=== Grover Search with Qiskit ===
Most common result: 101
Target (binary): 101
Match: True
Counts: {'101': 3892, '000': 68, '010': 52, ...}
Qiskit Transpilation
Qiskit automatically optimizes circuits for specific hardware backends:
# qiskit_transpile.py
from qiskit import QuantumCircuit
from qiskit.compiler import transpile
from qiskit_aer import AerSimulator
# Create a circuit using arbitrary gates
qc = QuantumCircuit(3, 3)
qc.h(0)
qc.cx(0, 1)
qc.ccx(0, 1, 2) # Toffoli gate
qc.measure_all()
print("=== Transpilation ===")
print("Original circuit:")
print(qc.draw())
# Transpile for a specific backend
# Uses basis gates: cx, id, rz, sx, x
simulator = AerSimulator()
transpiled = transpile(qc, simulator, optimization_level=3)
print(f"\nTranspiled circuit ({transpiled.depth()} depth, "
f"{transpiled.size()} gates):")
print(transpiled.draw())
# Verify functional equivalence
original_counts = simulator.run(qc, shots=1024).result().get_counts()
transpiled_counts = simulator.run(transpiled, shots=1024).result().get_counts()
print(f"\nOriginal results: {original_counts}")
print(f"Transpiled results: {transpiled_counts}")
print(f"Equivalent: {original_counts == transpiled_counts}")
Expected output:
=== Transpilation ===
Original circuit:
┌───┐ ┌───┐ ░ ┌─┐
q_0: ┤ H ├──■──┤ T ├─░─┤M├------
└───┘┌─┴─┐├───┤ ░ └╥┘┌─┐
q_1: ─────┤ X ├┤ T ├─░──╫─┤M├─
└───┘└───┘ ░ ║ └╥┘┌─┐
q_2: ────────────────░──╫──╫─┤M├
░ ║ ║ └╥┘
c: 3/═══════════════════╩══╩══╩═
0 1 2
Common Mistakes
1. Forgetting to Import Modules
Qiskit has many submodules. Forgetting from qiskit_aer import AerSimulator or from qiskit_ibm_runtime import QiskitRuntimeService causes import errors.
2. Using Incorrect Gate Names
Qiskit uses specific gate method names: qc.h(0) not qc.hadamard(0). Check the API documentation for correct method names.
3. Misunderstanding Measurement
Calling qc.measure_all() adds measurement to all qubits and creates classical registers automatically. Using qc.measure() requires specifying qubit and classical bit indices.
4. Forgetting to Simulate
A QuantumCircuit object is just a description. To get results, you must run it through a simulator or backend using backend.run(qc).result().
5. Ignoring Hardware Constraints
Real hardware has limited connectivity (two-qubit gates only on connected qubits). Transpilation handles this, but deep circuits may have high error rates.
Practice Questions
1. How do you create a QuantumCircuit in Qiskit?
qc = QuantumCircuit(n_qubits, n_classical_bits) creates a circuit. Gates are added using methods like qc.h(0), qc.cx(0, 1), and qc.measure_all().
2. What is the difference between AerSimulator and real hardware execution?
AerSimulator runs perfect simulations on classical hardware. Real hardware executes on quantum processors with noise, decoherence, and limited connectivity.
3. How does Qiskit handle circuit optimization?
Qiskit's transpiler (transpile function) optimizes circuits by merging gates, decomposing into native gates, and routing qubits to satisfy hardware connectivity constraints.
4. What is the Qiskit Runtime service?
IBM Quantum's execution environment that handles job scheduling, error mitigation, and result retrieval. It replaces the older IBM Q Experience API.
5. How do you visualize circuit results in Qiskit?
Using plot_histogram(counts) for measurement distributions, plot_bloch_vector() for single-qubit states, and circuit.draw() for circuit diagrams.
Challenge: Quantum Teleportation in Qiskit
Implement the quantum teleportation protocol in Qiskit:
def quantum_teleportation_qiskit():
"""Implement quantum teleportation using Qiskit."""
from qiskit import QuantumCircuit
from qiskit_aer import AerSimulator
qc = QuantumCircuit(3, 2)
# Step 1: Create Bell pair between Alice (q1) and Bob (q2)
# Step 2: Prepare message state on q0
# Step 3: Apply teleportation operations
# Step 4: Measure and apply corrections
# Your implementation here
return qc
Real-World Task: Quantum Chemistry with Qiskit
Use Qiskit Nature to compute the ground state energy of a hydrogen molecule:
# Requires: pip install qiskit-nature
from qiskit_nature.second_q.drivers import PySCFDriver
from qiskit_nature.second_q.mappers import ParityMapper
from qiskit_nature.second_q.algorithms import GroundStateEigensolver
from qiskit_algorithms import VQE
from qiskit_algorithms.optimizers import SLSQP
from qiskit.circuit.library import TwoLocal
driver = PySCFDriver(atom='H 0 0 0; H 0 0 0.735')
problem = driver.run()
# ... build VQE circuit and compute energy
This is the workflow used by quantum chemists to simulate molecular properties on quantum computers.
FAQ
Try It Yourself
Install Qiskit and run the Bell state circuit. Modify it to create a 5-qubit GHZ state. Experiment with different gates and measure how the output distribution changes. Try the transpiler with different optimization levels.
What's Next
You now know how to program quantum computers with IBM Qiskit. Next, you will learn Google Cirq and Microsoft Q# for alternative quantum programming frameworks.
Built by the developers of Doda Browser, DodaZIP, and Durga Antivirus Pro. Last updated: 2026-06-21.
Built by the developers of DodaTech
Doda Browser, DodaZIP & Durga Antivirus Pro