Qiskit is IBM's open-source quantum computing framework that enables developers to write quantum programs and run them on real quantum computers. In this guide, we'll explore Qiskit from the ground up and learn how to build practical quantum applications.
What is Qiskit?
Qiskit is a Python SDK for quantum computing that provides:
- Quantum Circuits: Build quantum algorithms with intuitive APIs
- Simulators: Test your quantum programs locally
- Real Hardware: Run on IBM's quantum computers via the cloud
- Algorithms: Pre-built quantum algorithms
- Visualization: Tools for understanding quantum circuits
Setting Up Your Environment
Installation
# Install Qiskit
pip install qiskit
# Install with visualization tools
pip install qiskit[visualization]
# Install for Aer simulator
pip install qiskit-aer
# Install for IBM Quantum provider
pip install qiskit-ibm-runtimePython Environment Setup
# Import Qiskit components
from qiskit import QuantumCircuit, transpile
from qiskit_aer import AerSimulator
from qiskit.visualization import plot_histogram, plot_bloch_multivector
from qiskit_ibm_runtime import QiskitRuntimeService
import numpy as np
# Initialize simulator
simulator = AerSimulator()
print("Qiskit environment ready!")Basic Quantum Circuits
Creating Your First Quantum Circuit
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 Hadamard gate to qubit 0 (creates superposition)
qc.h(0)
# Apply CNOT gate (qubit 0 controls qubit 1)
qc.cx(0, 1)
# Measure qubits
qc.measure([0, 1], [0, 1])
# Visualize circuit
print(qc.draw())
# Output:
# ┌───┐
# q_0: ┤ H ├──■──
# └───┘┌─┴─┐
# q_1: ─────┤ X ├
# └───┘
# c: 2/════════════Running on Simulator
from qiskit_aer import AerSimulator
# Initialize simulator
simulator = AerSimulator()
# Execute circuit
job = simulator.run(qc, shots=1000)
result = job.result()
counts = result.get_counts()
print("Measurement results:", counts)
# Output: {'00': ~50%, '11': ~50%}
# Plot histogram
plot_histogram(counts)Creating Bell States
def create_bell_state():
"""Create an entangled Bell pair"""
qc = QuantumCircuit(2, 2)
# Create superposition
qc.h(0)
# Entangle qubits
qc.cx(0, 1)
# Measure
qc.measure([0, 1], [0, 1])
return qc
# Create and run Bell state circuit
bell_qc = create_bell_state()
result = simulator.run(bell_qc, shots=1000).result()
counts = result.get_counts()
print("Bell state measurements:", counts)
# Should see approximately 50% '00' and 50% '11'
# No '01' or '10' due to entanglementQuantum Gates in Qiskit
Single-Qubit Gates
from qiskit import QuantumCircuit
import numpy as np
# Create circuit with visualization
qc = QuantumCircuit(1)
# Pauli-X gate (quantum NOT)
qc.x(0)
qc.barrier()
# Pauli-Y gate
qc.y(0)
qc.barrier()
# Pauli-Z gate (phase flip)
qc.z(0)
qc.barrier()
# Hadamard gate (superposition)
qc.h(0)
qc.barrier()
# Rotation gates
qc.rx(np.pi/4, 0) # Rotation around X-axis
qc.ry(np.pi/4, 0) # Rotation around Y-axis
qc.rz(np.pi/4, 0) # Rotation around Z-axis
# Phase gates
qc.s(0) # S gate (π/2 phase)
qc.sdg(0) # S-dagger gate
qc.t(0) # T gate (π/4 phase)
qc.tdg(0) # T-dagger gate
print(qc.draw())Multi-Qubit Gates
# Two-qubit gates
qc = QuantumCircuit(2)
# CNOT gate (controlled-X)
qc.cx(0, 1)
qc.barrier()
# CY gate (controlled-Y)
qc.cy(0, 1)
qc.barrier()
# CZ gate (controlled-Z)
qc.cz(0, 1)
qc.barrier()
# SWAP gate
qc.swap(0, 1)
print(qc.draw())Controlled Rotations
# Controlled rotation gates
qc = QuantumCircuit(2)
# Controlled rotation
qc.crx(np.pi/3, 0, 1) # Controlled X-rotation
qc.cry(np.pi/3, 0, 1) # Controlled Y-rotation
qc.crz(np.pi/3, 0, 1) # Controlled Z-rotation
# Controlled-U gate
qc.cu3(np.pi, np.pi/2, np.pi/4, 0, 1) # Controlled U3 rotation
print(qc.draw())Building Quantum Algorithms
Quantum Teleportation
def quantum_teleportation():
"""Implement quantum teleportation protocol"""
# Create circuit: 3 qubits (message, alice, bob), 3 classical bits
qc = QuantumCircuit(3, 3)
# Step 1: Create Bell pair between Alice and Bob
qc.h(1)
qc.cx(1, 2)
qc.barrier()
# Step 2: Alice prepares message (optional state)
qc.ry(np.pi/3, 0) # Prepare arbitrary state
qc.barrier()
# Step 3: Bell measurement
qc.cx(0, 1)
qc.h(0)
qc.measure([0, 1], [0, 1])
qc.barrier()
# Step 4: Classical communication and correction
qc.z(2).c_if(0, 1) # Apply Z if measurement result is 1
qc.x(2).c_if(1, 1) # Apply X if measurement result is 1
return qc
# Run teleportation
teleport_qc = quantum_teleportation()
result = simulator.run(teleport_qc, shots=1000).result()
counts = result.get_counts()
print("Teleportation results:", counts)
# Bob's qubit (qubit 2) should match Alice's messageDeutsch-Jozsa Algorithm
def deutsch_jozsa(oracle):
"""Deutsch-Jozsa algorithm"""
n = oracle.num_qubits - 1
qc = QuantumCircuit(n + 1, n)
# Initialize ancilla qubit to |1⟩
qc.x(n)
qc.h(n)
# Put input qubits in superposition
qc.h(range(n))
# Apply oracle
qc.append(oracle, range(n + 1))
# Apply Hadamard to input qubits
qc.h(range(n))
# Measure
qc.measure(range(n), range(n))
return qc
# Create constant oracle (always returns 0)
def constant_oracle(n):
qc = QuantumCircuit(n + 1)
return qc.to_gate(label="Constant Oracle")
# Create balanced oracle (returns 0 for half inputs, 1 for other half)
def balanced_oracle(n):
qc = QuantumCircuit(n + 1)
qc.cx(0, n) # CNOT with first qubit as control
return qc.to_gate(label="Balanced Oracle")
# Test with 2-qubit input
n = 2
dj_constant = deutsch_jozsa(constant_oracle(n))
dj_balanced = deutsch_jozsa(balanced_oracle(n))
# Run both
result_const = simulator.run(dj_constant, shots=1000).result()
result_bal = simulator.run(dj_balanced, shots=1000).result()
print("Constant function:", result_const.get_counts())
# Should see all measurements as '00' (all zeros)
print("Balanced function:", result_bal.get_counts())
# Should NOT see all measurements as '00'Grover's Search
def grover_search(num_qubits, target_state):
"""Grover's search algorithm"""
qc = QuantumCircuit(num_qubits, num_qubits)
# Initialize to uniform superposition
qc.h(range(num_qubits))
# Number of iterations
iterations = int(np.pi/4 * np.sqrt(2**num_qubits))
for _ in range(iterations):
# Oracle: mark target state
for qubit in range(num_qubits):
if not (target_state >> (num_qubits - 1 - qubit)) & 1:
qc.x(qubit)
# Multi-controlled Z
qc.h(num_qubits - 1)
qc.mcx(list(range(num_qubits - 1)), num_qubits - 1)
qc.h(num_qubits - 1)
# Uncompute
for qubit in range(num_qubits):
if not (target_state >> (num_qubits - 1 - qubit)) & 1:
qc.x(qubit)
qc.barrier()
# Diffusion operator
qc.h(range(num_qubits))
qc.x(range(num_qubits))
qc.h(num_qubits - 1)
qc.mcx(list(range(num_qubits - 1)), num_qubits - 1)
qc.h(num_qubits - 1)
qc.x(range(num_qubits))
qc.h(range(num_qubits))
qc.barrier()
# Measure
qc.measure(range(num_qubits), range(num_qubits))
return qc
# Search for state |111⟩ in 3-qubit system
grover_qc = grover_search(3, 7) # 7 = 111 in binary
result = simulator.run(grover_qc, shots=1000).result()
counts = result.get_counts()
print("Grover search results:", counts)
# Should see high probability for '111'
plot_histogram(counts)Quantum Fourier Transform
def qft(n):
"""Quantum Fourier Transform circuit"""
qc = QuantumCircuit(n)
for qubit in range(n):
# Apply H gate
qc.h(qubit)
# Apply controlled rotations
for other_qubit in range(qubit + 1, n):
angle = np.pi / 2**(other_qubit - qubit)
qc.cp(angle, other_qubit, qubit)
qc.barrier()
# Swap qubits to reverse order
for i in range(n // 2):
qc.swap(i, n - 1 - i)
return qc
# Create QFT circuit
n = 3
qft_circuit = qft(n)
# Visualize
print(qft_circuit.draw())
# Test QFT
qc = QuantumCircuit(n, n)
qc.h(range(n)) # Initialize to uniform superposition
qc.append(qft_circuit.to_gate(), range(n))
qc.measure(range(n), range(n))
result = simulator.run(qc, shots=1000).result()
counts = result.get_counts()
print("QFT results:", counts)Running on Real Quantum Hardware
IBM Quantum Account Setup
from qiskit_ibm_runtime import QiskitRuntimeService
# Save your API token (first time only)
# QiskitRuntimeService.save_account(channel='ibm_quantum', token='YOUR_API_TOKEN')
# Load service
service = QiskitRuntimeService(channel='ibm_quantum')
# List available backends
print("Available backends:")
for backend in service.backends():
print(f" - {backend.name}")Running on Quantum Computer
# Select backend
backend = service.backend('ibmq_manila')
# Create simple circuit
qc = QuantumCircuit(2, 2)
qc.h(0)
qc.cx(0, 1)
qc.measure([0, 1], [0, 1])
# Transpile for backend
from qiskit import transpile
qc_transpiled = transpile(qc, backend=backend)
# Run on real quantum computer
job = backend.run(qc_transpiled, shots=1000)
# Wait for job to complete
result = job.result()
counts = result.get_counts()
print("Real quantum computer results:", counts)
# Compare with simulator
sim_result = simulator.run(qc, shots=1000).result()
sim_counts = sim_result.get_counts()
print("Simulator results:", sim_counts)Monitoring Jobs
# Submit job
job = backend.run(qc_transpiled, shots=1000)
# Check job status
print(f"Job status: {job.status()}")
# Get job ID
job_id = job.job_id()
print(f"Job ID: {job_id}")
# Retrieve job later
retrieved_job = service.job(job_id)
result = retrieved_job.result()Visualizing Quantum States
Bloch Sphere Visualization
from qiskit.visualization import plot_bloch_multivector
# Create state
qc = QuantumCircuit(1)
qc.h(0)
# Get statevector
from qiskit.quantum_info import Statevector
state = Statevector(qc)
# Plot on Bloch sphere
plot_bloch_multivector(state)Circuit Visualization
from qiskit.visualization import circuit_drawer
# Text drawing
print(qc.draw())
# Matplotlib figure
circuit_drawer(qc, output='mpl', style='iqp')
# LaTeX code
qc.draw(output='latex')State Visualization
from qiskit.visualization import plot_state_city, plot_state_histogram
# City plot
plot_state_city(state)
# Histogram
plot_state_histogram(state)Advanced Qiskit Features
Parametrized Circuits
from qiskit.circuit import Parameter
# Create parameter
theta = Parameter('θ')
# Build parametrized circuit
qc = QuantumCircuit(1)
qc.ry(theta, 0)
qc.measure_all()
# Bind parameter
bound_circuit = qc.bind_parameters({theta: np.pi/4})
# Run
result = simulator.run(bound_circuit, shots=1000).result()
counts = result.get_counts()
print("Parametrized circuit results:", counts)Noise Models
from qiskit_aer.noise import NoiseModel
from qiskit_aer.noise.errors import depolarizing_error
# Create noise model
noise_model = NoiseModel()
# Add depolarizing error
error = depolarizing_error(0.01, 1) # 1% error rate
noise_model.add_all_qubit_quantum_error(error, ['h', 'x', 'y', 'z'])
# Run with noise
result_noisy = simulator.run(qc, noise_model=noise_model, shots=1000).result()
counts_noisy = result_noisy.get_counts()
print("Noisy simulation:", counts_noisy)
print("Ideal simulation:", counts)Optimization
# Transpile optimization
qc_optimized = transpile(qc,
backend=backend,
optimization_level=3)
print("Original gates:", qc.count_ops())
print("Optimized gates:", qc_optimized.count_ops())Qiskit Applications
VQE Implementation
from qiskit.algorithms.minimum_eigensolvers import VQE
from qiskit.algorithms.optimizers import COBYLA
from qiskit.primitives import Estimator
from qiskit.circuit.library import TwoLocal
# Define ansatz
ansatz = TwoLocal(2, ['ry', 'rz'], 'cz', reps=2)
# Define optimizer
optimizer = COBYLA(maxiter=100)
# Create VQE
estimator = Estimator()
vqe = VQE(estimator, ansatz, optimizer)
# Define Hamiltonian (simplified)
from qiskit.quantum_info import SparsePauliOp
hamiltonian = SparsePauliOp.from_list([
("II", 1.0),
("IZ", 0.5),
("ZI", -0.5),
("ZZ", 0.3)
])
# Run VQE
result = vqe.compute_minimum_eigenvalue(hamiltonian)
print(f"Ground state energy: {result.eigenvalue.real:.6f}")Best Practices
- 1Always test on simulator first before running on real hardware
- 2Use transpilation to optimize circuits for target hardware
- 3Account for noise in real quantum computers
- 4Use appropriate optimization levels for your needs
- 5Monitor job queue for efficient resource usage
Conclusion
Qiskit makes quantum programming accessible to developers. With its intuitive API, powerful simulators, and access to real quantum hardware, you can start building quantum applications today.
Start with simple circuits, explore pre-built algorithms, and gradually work your way up to more complex quantum programs. The quantum future is waiting, and Qiskit is your gateway to it!