AIComputing101
October 15, 2025 Quantum Computing Dr. Stephen Shao Qiskit Quantum

IBM Qiskit: Circuit Design, Simulation, and Hybrid Quantum-Classical Computing

IBM Qiskit Architecture and Quantum Circuit Design

The quantum-computing-101 repository has been updated to focus on IBM's Qiskit ecosystem, the leading open-source framework for quantum computing. This guide explores Qiskit's architecture, circuit design principles, simulation capabilities through Qiskit Aer, and the critical role of hybrid quantum-classical computing in addressing current quantum technology limitations.

Understanding Qiskit Architecture

Qiskit is a comprehensive software stack designed to work with quantum hardware while abstracting many of the low-level complexities. Its modular architecture consists of four primary components:

  • Qiskit Terra: The foundation layer for composing quantum circuits and working with quantum programs
  • Qiskit Aer: High-performance simulators with noise models for testing quantum circuits
  • Qiskit Ignis: Tools for quantum hardware characterization, verification, and error mitigation
  • Qiskit Aqua: Domain-specific applications and algorithms for quantum computing

This modular approach allows developers to work at different abstraction levels, from direct quantum circuit manipulation to high-level algorithm implementation.

Qiskit Circuit Design Fundamentals

At the core of quantum computing is the quantum circuit – a sequence of quantum gates applied to quantum bits (qubits). Qiskit provides an intuitive interface for creating and manipulating these circuits.

Basic Circuit Construction

from qiskit import QuantumCircuit, execute, Aer
from qiskit.visualization import plot_histogram
import matplotlib.pyplot as plt

# Create a quantum circuit with 2 qubits and 2 classical bits
qc = QuantumCircuit(2, 2)

# Add a Hadamard gate to the first qubit - puts it into superposition
qc.h(0)

# Add a controlled-X (CNOT) gate between qubit 0 and 1
qc.cx(0, 1)

# Measure the qubits and store results in classical bits
qc.measure([0, 1], [0, 1])

# Draw the circuit
qc.draw(output='mpl')
plt.show()

# Execute on a simulator
simulator = Aer.get_backend('qasm_simulator')
result = execute(qc, simulator, shots=1024).result()
counts = result.get_counts(qc)

# Plot results
plot_histogram(counts)
plt.show()

This simple circuit creates an entangled state between two qubits, demonstrating one of the fundamental phenomena of quantum mechanics that powers quantum computing's potential advantages.

Advanced Circuit Design Patterns

Complex quantum algorithms often use repeating patterns and modular components. Qiskit supports circuit composition and reuse:

def create_quantum_adder(n):
    """Create a quantum circuit that adds 1 to an n-qubit number"""
    adder = QuantumCircuit(n+1, name="Adder +1")
    
    # Apply X gate to the least significant bit
    adder.x(0)
    
    # Create carry chain with controlled-X gates
    for i in range(n-1):
        adder.cx(i, i+1)
        
    # Return as a subcircuit that can be embedded in larger circuits
    return adder.to_instruction()

# Create a 3-qubit adder circuit
adder = create_quantum_adder(3)

# Create main circuit with 4 qubits (3 data + 1 carry) and 4 classical bits
main_circuit = QuantumCircuit(4, 4)

# Initialize input state to |011⟩
main_circuit.x(1)
main_circuit.x(2)

# Add the adder subcircuit
main_circuit.append(adder, [0, 1, 2, 3])

# Measure all qubits
main_circuit.measure(range(4), range(4))

# Draw the full circuit
main_circuit.draw(output='mpl')
plt.show()

Qiskit Aer: Powerful Quantum Simulation

Qiskit Aer provides state-of-the-art simulation capabilities that are essential for quantum algorithm development, especially given the current limitations of physical quantum hardware.

Choosing the Right Simulator

Aer offers multiple simulator backends optimized for different use cases:

from qiskit import Aer

# List all available Aer backends
for backend in Aer.backends():
    print(backend.name())

# 1. Statevector simulator - for full state representation (small circuits)
statevector_sim = Aer.get_backend('statevector_simulator')

# 2. QASM simulator - for sampling results like real quantum hardware
qasm_sim = Aer.get_backend('qasm_simulator')

# 3. Unitary simulator - for calculating circuit unitary matrix
unitary_sim = Aer.get_backend('unitary_simulator')

# 4. Pulse simulator - for low-level hardware pulse simulation
pulse_sim = Aer.get_backend('pulse_simulator')

Noise Modeling for Realistic Simulation

One of Aer's most powerful features is its ability to simulate noise, critical for developing error mitigation strategies:

from qiskit.providers.aer.noise import NoiseModel
from qiskit.providers.aer.noise.errors import depolarizing_error, thermal_relaxation_error

# Create a noise model
noise_model = NoiseModel()

# Add depolarizing error to Hadamard gates
error = depolarizing_error(0.01, 1)
noise_model.add_all_qubit_quantum_error(error, ['h'])

# Add thermal relaxation error to measurement
t1 = 50.0  # T1 relaxation time in microseconds
t2 = 70.0  # T2 relaxation time in microseconds
error_meas = thermal_relaxation_error(t1, t2, 0.1)
noise_model.add_all_qubit_quantum_error(error_meas, ['measure'])

# Use the noise model in simulation
result_noisy = execute(
    qc,  # Our quantum circuit from earlier
    Aer.get_backend('qasm_simulator'),
    noise_model=noise_model,
    shots=1024
).result()

# Compare with ideal results
counts_noisy = result_noisy.get_counts()
plot_histogram([counts, counts_noisy], legend=['Ideal', 'With Noise'])
plt.show()

For more accurate noise modeling, Qiskit can even import noise profiles from real IBM quantum hardware:

from qiskit import IBMQ

# Load IBM Quantum account
IBMQ.load_account()
provider = IBMQ.get_provider(hub='ibm-q')

# Get noise model from a real quantum device
device = provider.get_backend('ibm_brisbane')  # 127-qubit processor
noise_model = NoiseModel.from_backend(device)

# Get coupling map and basis gates from the real device
coupling_map = device.configuration().coupling_map
basis_gates = noise_model.basis_gates

# Simulate using the real device's noise profile
result = execute(
    qc,
    Aer.get_backend('qasm_simulator'),
    coupling_map=coupling_map,
    basis_gates=basis_gates,
    noise_model=noise_model
).result()

Hybrid Quantum-Classical Computing

Current quantum hardware (NISQ devices) has limited qubit counts and high error rates, making pure quantum algorithms impractical for most real-world problems. Hybrid quantum-classical approaches address these limitations by combining quantum processing with classical computing.

Variational Quantum Algorithms

Variational algorithms like VQE (Variational Quantum Eigensolver) and QAOA (Quantum Approximate Optimization Algorithm) use this hybrid approach:

from qiskit.algorithms import VQE
from qiskit.algorithms.optimizers import SPSA
from qiskit.circuit.library import TwoLocal
from qiskit.opflow import Z, I

# Define a Hamiltonian (problem to solve)
# For example, H2 molecule Hamiltonian simplified
hamiltonian = (0.5 * Z ^ Z) + (0.3 * Z ^ I) + (0.3 * I ^ Z)

# Create a quantum ansatz (parameterized circuit)
ansatz = TwoLocal(
    num_qubits=2,
    rotation_blocks=['ry', 'rz'],
    entanglement_blocks='cz',
    entanglement='linear',
    reps=2
)

# Classical optimizer
optimizer = SPSA(maxiter=100)

# Create VQE instance
vqe = VQE(
    ansatz=ansatz,
    optimizer=optimizer,
    quantum_instance=Aer.get_backend('qasm_simulator')
)

# Run VQE - hybrid quantum-classical process
result = vqe.compute_minimum_eigenvalue(operator=hamiltonian)
print(f"Ground state energy: {result.eigenvalue.real}")
print(f"Optimized parameters: {result.optimal_parameters}")

Quantum Machine Learning with Hybrid Approaches

Hybrid techniques are particularly powerful in quantum machine learning:

from qiskit_machine_learning.algorithms import VQC
from qiskit_machine_learning.datasets import ad_hoc_data
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import MinMaxScaler

# Generate sample data
X, y, _, _ = ad_hoc_data(
    training_size=100,
    test_size=50,
    n=2,  # 2 qubits
    gap=0.3,
    one_hot=False
)

# Scale data to [0, 2π] for angle encoding
scaler = MinMaxScaler(feature_range=(0, 2 * np.pi))
X_scaled = scaler.fit_transform(X)

# Split into train and test sets
X_train, X_test, y_train, y_test = train_test_split(
    X_scaled, y, test_size=0.2, random_state=42
)

# Create quantum feature map and ansatz
feature_map = TwoLocal(2, ['ry', 'rz'], 'cz', reps=1)
ansatz = TwoLocal(2, ['ry', 'rz'], 'cz', reps=2)

# Create hybrid quantum-classical classifier
vqc = VQC(
    feature_map=feature_map,
    ansatz=ansatz,
    optimizer=SPSA(maxiter=100),
    quantum_instance=Aer.get_backend('qasm_simulator')
)

# Train the model (hybrid process)
vqc.fit(X_train, y_train)

# Evaluate
score = vqc.score(X_test, y_test)
print(f"Test accuracy: {score:.2f}")

Addressing Quantum Computing Challenges

Hybrid approaches help mitigate several key challenges in current quantum computing:

1. Limited Qubit Count

By breaking problems into smaller subproblems processed sequentially on quantum hardware and combined classically, hybrid methods work within the constraints of NISQ devices.

2. High Error Rates

Classical post-processing can mitigate errors through techniques like zero-noise extrapolation and readout error mitigation:

from qiskit.ignis.mitigation.measurement import CompleteMeasFitter

# Create measurement fitter to characterize noise
meas_calibs, state_labels = CompleteMeasFitter.from_backend(device)
meas_fitter = CompleteMeasFitter(meas_calibs, state_labels)

# Get mitigation filter
meas_filter = meas_fitter.filter

# Apply mitigation to results
mitigated_results = meas_filter.apply(result_noisy)
mitigated_counts = mitigated_results.get_counts()

# Compare results
plot_histogram([counts, counts_noisy, mitigated_counts], 
               legend=['Ideal', 'Noisy', 'Mitigated'])
plt.show()

3. Quantum-Classical Communication Overhead

Qiskit's architecture minimizes data transfer between quantum and classical components through optimized circuit batching and result processing.

4. Algorithm Design Complexity

Qiskit's high-level libraries abstract many complexities, allowing developers to focus on problem-solving rather than low-level quantum mechanics.

Production-Grade Quantum Computing with Qiskit

For enterprise applications, Qiskit provides additional tools and best practices:

Circuit Optimization

Reducing circuit depth and gate count is critical for execution on real hardware:

from qiskit.transpiler import PassManager
from qiskit.transpiler.passes import Optimize1qGates, CXCancellation

# Create a pass manager with optimization passes
pm = PassManager([Optimize1qGates(), CXCancellation()])

# Optimize the circuit
optimized_circuit = pm.run(main_circuit)

print(f"Original circuit depth: {main_circuit.depth()}")
print(f"Optimized circuit depth: {optimized_circuit.depth()}")
print(f"Original CNOT count: {main_circuit.count_ops().get('cx', 0)}")
print(f"Optimized CNOT count: {optimized_circuit.count_ops().get('cx', 0)}")

Accessing Real Quantum Hardware

Qiskit seamlessly transitions from simulation to real hardware:

# Get the least busy backend with at least 2 qubits
backends = provider.backends(
    filters=lambda x: x.configuration().n_qubits >= 2 
    and not x.configuration().simulator 
    and x.status().operational==True
)
backend = provider.get_backend('ibm_kyoto')  # 433-qubit processor

# Transpile the circuit for the specific hardware
from qiskit import transpile
transpiled_circuit = transpile(qc, backend, optimization_level=3)

# Execute on real quantum hardware
job = backend.run(transpiled_circuit, shots=1024)

# Monitor job progress
from qiskit.tools.monitor import job_monitor
job_monitor(job)

# Get results
real_results = job.result()
real_counts = real_results.get_counts()

Update your repository with git pull to access the latest Qiskit examples, including advanced hybrid algorithms and noise mitigation techniques. Share your implementations and findings in our discussion forum—we're particularly interested in novel hybrid approaches that address current quantum computing limitations.