IBM Qiskit Guide — Quantum Programming with Python
In this tutorial, you'll learn about IBM Qiskit Guide. We cover key concepts, practical examples, and best practices to help you understand and apply this topic effectively.
IBM Qiskit is an open-source Quantum Computing SDK that lets you build, simulate, and run quantum circuits on IBM quantum hardware using Python, bridging algorithm design to real device execution.
What You'll Learn
By the end of this tutorial, you will understand how to install Qiskit, build quantum circuits, use simulators (statevector, QASM, stabilizer), transpile circuits for specific backends, run jobs on IBM quantum hardware, and analyze results.
Why It Matters
Qiskit is the most widely used Quantum Computing framework, with over 10 million downloads. It provides access to IBM's fleet of quantum processors via the cloud. Learning Qiskit gives you practical, hands-on experience with real quantum hardware and is the standard entry point for quantum programming.
Real-World Use
Researchers at MIT used Qiskit to simulate molecular ground states with VQE on IBM hardware. JPMorgan Chase uses Qiskit for portfolio optimization research. Qiskit is the primary platform for IBM's quantum education and research initiatives.
Learning Path
flowchart LR
A[IBM Qiskit] --> B[Google Cirq]
A --> C[Microsoft Q#]
A --> D[Quantum Algorithms]
A --> E{You Are Here}
style E fill:#f90,color:#fff
Prerequisites: Python 3.8+ installed. Understand basic quantum circuits and gates. IBM Quantum account recommended for hardware access.
Installation and Setup
# Install Qiskit (run in terminal)
# pip install qiskit qiskit-aer qiskit-ibm-runtime
# qiskit_setup.py
from qiskit import QuantumCircuit
from qiskit_aer import Aer
import numpy as np
print("=== Qiskit Setup ===")
# Create a simple circuit
qc = QuantumCircuit(2, 2) # 2 qubits, 2 classical bits
# Build Bell state
qc.h(0)
qc.cx(0, 1)
# Measure
qc.measure([0, 1], [0, 1])
print("Circuit:")
print(qc.draw())
# Run on simulator
simulator = Aer.get_backend('aer_simulator')
result = simulator.run(qc, shots=1024).result()
counts = result.get_counts()
print(f"\nResults: {counts}")
print(f"Qiskit version: {qc.qasm()[:50]}...")
Expected output (drawing may vary):
=== Qiskit Setup ===
Circuit:
┌───┐ ┌─┐
q_0: ┤ H ├──■──┤M├───
└───┘┌─┴─┐└╥┘┌─┐
q_1: ─────┤ X ├─╫─┤M├
└───┘ ║ └╥┘
c: 2/═══════════╩══╩═
0 1
Results: {'00': 524, '11': 500}
Quantum Circuits with Qiskit
Qiskit provides a comprehensive set of gates and circuit operations.
# qiskit_circuits.py
from qiskit import QuantumCircuit
from qiskit.quantum_info import Statevector, Operator
from qiskit_aer import Aer
import numpy as np
# 1. Basic Gates
print("=== Basic Gates ===")
qc = QuantumCircuit(3)
# Single qubit gates
qc.h(0) # Hadamard
qc.x(1) # Pauli-X
qc.y(1) # Pauli-Y
qc.z(2) # Pauli-Z
qc.s(0) # S gate
qc.t(0) # T gate
qc.rx(np.pi/2, 0) # RX rotation
qc.ry(np.pi/4, 1) # RY rotation
qc.rz(np.pi/8, 2) # RZ rotation
# Two qubit gates
qc.cx(0, 1) # CNOT
qc.cz(0, 2) # CZ
qc.swap(1, 2) # SWAP
# Three qubit gate
qc.ccx(0, 1, 2) # Toffoli (CCNOT)
# Get statevector
state = Statevector.from_instruction(qc)
print(f"State dimension: {len(state)}")
print(f"Circuit depth: {qc.depth()}")
print(f"Circuit size: {qc.size()}")
# 2. Parameterized Circuits
print("\n=== Parameterized Circuit ===")
from qiskit.circuit import Parameter
theta = Parameter('theta')
phi = Parameter('phi')
pqc = QuantumCircuit(2)
pqc.ry(theta, 0)
pqc.ry(phi, 1)
pqc.cx(0, 1)
# Bind parameters
bound = pqc.bind_parameters({theta: np.pi/2, phi: np.pi/4})
print(f"Bound circuit:\n{bound.draw()}")
# 3. Measure in Different Bases
print("\n=== Measurement in X basis ===")
qc_x = QuantumCircuit(1, 1)
qc_x.h(0) # Rotate to X basis
qc_x.measure(0, 0)
sim = Aer.get_backend('aer_simulator')
result = sim.run(qc_x, shots=1024).result()
print(f"X-basis measurement: {result.get_counts()}")
Expected output:
=== Basic Gates ===
State dimension: 8
Circuit depth: 8
Circuit size: 9
=== Parameterized Circuit ===
Bound circuit:
Using Simulators
Qiskit Aer provides multiple simulation methods for different use cases.
# qiskit_simulators.py
from qiskit import QuantumCircuit
from qiskit_aer import Aer
from qiskit.quantum_info import random_unitary
import numpy as np
# Create a test circuit
def create_test_circuit():
qc = QuantumCircuit(3, 3)
qc.h(0)
qc.cx(0, 1)
qc.cx(0, 2)
qc.measure_all()
return qc
qc = create_test_circuit()
# 1. Statevector Simulator (exact)
print("=== Statevector Simulation ===")
sv_sim = Aer.get_backend('aer_simulator')
# Get statevector by not measuring
qc_no_meas = QuantumCircuit(3)
qc_no_meas.h(0)
qc_no_meas.cx(0, 1)
qc_no_meas.cx(0, 2)
result_sv = sv_sim.run(qc_no_meas, shots=1).result()
statevector = result_sv.get_statevector()
print(f"GHZ state vector:\n{statevector}")
# 2. QASM Simulator (probabilistic)
print("\n=== QASM Simulation ===")
result_qasm = sv_sim.run(qc, shots=4096).result()
counts = result_qasm.get_counts()
print(f"Counts: {counts}")
for bits, count in counts.items():
print(f" |{bits}⟩: {count/4096*100:.1f}%")
# 3. Noise Simulation
print("\n=== Noise Simulation ===")
from qiskit_aer.noise import NoiseModel, depolarizing_error
# Create a noise model
noise_model = NoiseModel()
error = depolarizing_error(0.01, 1) # 1% depolarizing error on single qubit gates
noise_model.add_all_qubit_quantum_error(error, ['h', 'cx'])
result_noisy = sv_sim.run(qc, noise_model=noise_model, shots=4096).result()
counts_noisy = result_noisy.get_counts()
print(f"Noisy counts: {counts_noisy}")
for bits, count in counts_noisy.items():
print(f" |{bits}⟩: {count/4096*100:.1f}%")
# 4. Stabilizer Simulator (for Clifford circuits)
print("\n=== Stabilizer Simulation ===")
qc_clifford = QuantumCircuit(100, 100)
for i in range(99):
qc_clifford.h(i)
qc_clifford.cx(i, i + 1)
qc_clifford.measure_all()
# Only run 10 qubits for display
qc_small = QuantumCircuit(10, 10)
for i in range(9):
qc_small.h(i)
qc_small.cx(i, i + 1)
qc_small.measure_all()
stabilizer_sim = Aer.get_backend('aer_simulator_stabilizer')
result_stab = stabilizer_sim.run(qc_small, shots=1024).result()
print(f"Stabilizer simulation (10 qubits) done: {len(result_stab.get_counts())} outcomes")
Expected output:
=== Statevector Simulation ===
GHZ state vector:
[0.70710678+0.j 0.+0.j 0.+0.j 0.+0.j 0.+0.j 0.+0.j 0.+0.j 0.70710678+0.j]
=== QASM Simulation ===
Counts: {'000': 2048, '111': 2048}
|000⟩: 50.0%
|111⟩: 50.0%
Transpilation and Optimization
Qiskit's transpiler converts circuits to match hardware constraints.
# qiskit_transpile.py
from qiskit import QuantumCircuit, transpile
from qiskit.providers.fake_provider import FakeManilaV2
from qiskit_aer import Aer
import numpy as np
# Create a circuit with arbitrary gates
qc = QuantumCircuit(3)
qc.h(0)
qc.rx(np.pi/3, 1)
qc.cx(1, 2)
qc.rz(np.pi/7, 0)
qc.cx(2, 0)
qc.measure_all()
print("=== Transpilation ===")
print("Original circuit:")
print(f" Depth: {qc.depth()}, Gates: {qc.size()}")
print(f" Operations: {qc.count_ops()}")
# Transpile for a specific backend
backend = FakeManilaV2()
transpiled = transpile(qc, backend=backend)
print(f"\nTranspiled for {backend.name}:")
print(f" Depth: {transpiled.depth()}, Gates: {transpiled.size()}")
print(f" Operations: {transpiled.count_ops()}")
# Optimization levels
print(f"\n=== Optimization Levels ===")
for level in range(4):
optimized = transpile(qc, backend=backend, optimization_level=level)
print(f" Level {level}: depth={optimized.depth():3d}, "
f"gates={optimized.size():3d}")
# Custom coupling map
print(f"\n=== Custom Coupling Map ===")
coupling_map = [[0, 1], [1, 2]] # Linear chain
optimized_cm = transpile(qc, coupling_map=coupling_map,
basis_gates=['u1', 'u2', 'u3', 'cx'],
optimization_level=3)
print(f" Depth: {optimized_cm.depth()}, Gates: {optimized_cm.size()}")
Expected output:
=== Transpilation ===
Original circuit:
Depth: 6, Gates: 6
Operations: OrderedDict([('h', 1), ('rx', 1), ('cx', 2), ('rz', 1), ('measure', 3)])
Transpiled for FakeManilaV2:
Depth: 12, Gates: 18
Running on Real Hardware
To run on IBM quantum hardware, you need an IBM Quantum account.
# qiskit_hardware.py
"""
To run on real IBM hardware:
1. Get an API token from https://quantum-computing.ibm.com/
2. Save it: from qiskit_ibm_runtime import QiskitRuntimeService
QiskitRuntimeService.save_account(token='YOUR_TOKEN')
This example shows the workflow (simulated here for testing).
"""
from qiskit import QuantumCircuit
from qiskit_aer import Aer
import numpy as np
# Build a simple Bernstein-Vazirani circuit
def bernstein_vazirani_circuit(hidden_string):
n = len(hidden_string)
qc = QuantumCircuit(n + 1, n)
# Initialize ancilla to |1⟩
qc.x(n)
qc.h(range(n + 1))
# Oracle: apply Z to qubits where hidden string bit is 1
for i, bit in enumerate(hidden_string):
if bit == '1':
qc.cx(i, n)
qc.h(range(n))
qc.measure(range(n), range(n))
return qc
# Test with a hidden string
hidden = '101'
qc_bv = bernstein_vazirani_circuit(hidden)
sim = Aer.get_backend('aer_simulator')
result = sim.run(qc_bv, shots=1024).result()
counts = result.get_counts()
measured = max(counts, key=counts.get)
print("=== Bernstein-Vazirani on Simulator (Hardware Workflow) ===")
print(f"Hidden string: {hidden}")
print(f"Measured: {measured}")
print(f"Correct: {measured == hidden}")
print(f"\nThis same circuit can be sent to IBM hardware via:")
print(" from qiskit_ibm_runtime import QiskitRuntimeService, Sampler")
print(" service = QiskitRuntimeService()")
print(" backend = service.backend('ibm_brisbane')")
print(" sampler = Sampler(backend=backend)")
print(" job = sampler.run([qc_bv])")
Expected output:
=== Bernstein-Vazirani on Simulator (Hardware Workflow) ===
Hidden string: 101
Measured: 101
Correct: True
Common Mistakes
1. Forgetting to Measure
A circuit without measurement runs on simulators but returns no classical output. Always include measurement operations if you want to extract results.
2. Ignoring Hardware Constraints
Not all gates are available on all hardware. Qubit connectivity is limited. Always transpile for the target backend before running on real hardware.
3. Misinterpreting Measurement Order
Qiskit measures qubits in order with the last qubit as the most significant bit (MSB). Qubit 0 maps to the rightmost bit in the classical register.
4. Running Huge Circuits on Statevector Simulator
Statevector simulation requires 2^n complex numbers. For n > 30 qubits, memory exceeds 16 GB. Use QASM or stabilizer simulators for larger circuits.
5. Not Setting Enough Shots
Quantum measurements are probabilistic. With too few shots, the measured distribution may not accurately reflect the true quantum state probabilities.
Practice Questions
1. How do you create a Bell state in Qiskit?
qc = QuantumCircuit(2, 2)
qc.h(0)
qc.cx(0, 1)
qc.measure([0, 1], [0, 1])
2. What is the difference between statevector and QASM simulators?
Statevector computes the exact quantum state (deterministic, single shot). QASM simulates probabilistic measurement outcomes (many shots, statistical results).
3. Why is Transpilation necessary before running on hardware?
Transpilation converts arbitrary gates to the hardware's native gate set, maps logical qubits to physical qubits respecting connectivity constraints, and optimizes the circuit for the target device.
4. How do you add noise to a Qiskit simulation?
Create a NoiseModel object, add error channels (e.g., depolarizing_error), and pass it to the simulator run method.
Challenge: Quantum Volume Circuit
Implement a Qiskit circuit that computes the quantum volume of a given backend. Quantum volume measures the maximum random circuit depth that a device can successfully execute:
def quantum_volume_circuit(n_qubits, depth):
"""
Generate a quantum volume circuit for benchmarking.
Returns: QuantumCircuit for quantum volume testing
"""
pass
Hints: Each layer picks random pairs of qubits, applies a random SU(4) gate to each pair, and all pairs must form a perfect matching.
Real-World Task: VQE for H2 Molecule
Use Qiskit Nature to run a Variational Quantum Eigensolver (VQE) for the hydrogen molecule. Compute the ground state energy curve as a function of bond length and compare with the exact classical result. This is the standard benchmark for quantum chemistry on quantum computers.
FAQ
What's Next
You now know how to program quantum computers with IBM Qiskit. Next, you will explore Google Cirq.
Built by the developers of Doda Browser, DodaZIP, and Durga Antivirus Pro. Last updated: 2026-06-23.
Built by the developers of DodaTech
Doda Browser, DodaZIP & Durga Antivirus Pro