Skip to content

This is the IBM lab repo of quantum progamming course(CS238) taught by professor Jens Palsberg in UCLA

Notifications You must be signed in to change notification settings

yezhuoyang/QuantumLab

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

78 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

QuantumLab

This is the lab repository for the Quantum Programming course (CS238) taught by Professor Jens Palsberg in the Fall 2025 quarter in UCLA.
In this lab, you will gain hands-on experience with quantum programming using Qiskit.

You will:

  • Learn how to create and compile quantum circuits with Qiskit.
  • Learn how to run and debug circuits using simulation.
  • Become familiar with quantum gates, the Quantum Fourier Transform (QFT), Quantum Phase Estimation (QPE), and Shor’s Algorithm.
  • Learn how to simulate your algorithms on noisy backends and fake quantum computers provided by Qiskit.

Repository Structure

The repository is organized into the following folders and files:

  • Figure/
    Contains all figures and images used in the README file.

  • Labs/
    Includes the three Jupyter notebooks(Lab1:QuantumCircuit.ipynb, Lab2:PhaseEstimation.ipynb, Lab3:ShorsAlg.ipynb) that you are required to complete as part of the lab assignments.

  • test/
    Stores all test scripts used to automatically verify your implementations.

  • util/
    Provides helper code, such as utilities for constructing noise models and fake backends. These codes are reused in the noisy simulation.

Environment set up

The installation process has been tested with Python 3.11.
If you encounter issues, please downgrade to Python 3.11:

👉 Download Python 3.11

It is recommended to use a lightweight virtual environment to avoid dependency conflicts.

First, install virtualenv:

python -m pip install --user virtualenv
python -m virtualenv --help

You can visit the document page of virtualenv to get more detailed explanation of how this works: Documentation of virtualenv

Next, create a new virtual enviroment using virtualenv under the same directory.

python -m venv ./IBMLabVenv

You will notice that a new folder IBMLabVenv/ appear in the same directory of this IBMlab. This folder store all information of python package and compiled library that you might need later.

You can visit the document page of venv command to get more detailed explanation of how this works: Documentation of venv

After create the virtual enviroment, you can activate it by running the following instruction:

.\IBMLabVenv\Scripts\activate

Install all required package by:

pip install -r requirements.txt 

Run Jupyter note book

First activate your virtual environment, then start the jupyter notebook:

jupyter notebook

Basic of qiskit

In this section, we will explore the key Qiskit interfaces relevant to the homework.
For a better understanding, copy the code snippets into a Jupyter notebook and experiment with them on your own.

Circuit construction and visualization

To initialize a quantum circuit in Qiskit, import the package and use the QuantumCircuit class:

from qiskit import QuantumCircuit
qc=QuantumCircuit(3,2) # Initialize a circuit with 3 qubits and 2 classical bits

You can add quantum gates to the circuit directly with built-in methods:

qc.x(0) #Add PauliX gate to qubit 0
qc.h(1) #Add Hadamard gate to qubit 1
qc.cx(0,1) #Add a CNOT gate to qubit 0,1 controlled by qubit 0

Alternatively, you can use the append method:

from qiskit.circuit.library import XGate,HGate,CXGate
qc.append(XGate(),[0]) #Add PauliX gate to qubit 0
qc.append(HGate,[1]) #Add Hadamard gate to qubit 1
qc.append(CXGate(),[0,1]) #Add a CNOT gate to qubit 0,1 controlled by qubit 0

You can also append a small user-defined subcircuit to a larger circuit:

from qiskit import QuantumCircuit
qc=QuantumCircuit(3,2) # Initialize a circuit with 3 qubits and 2 classical bits
qc.h(0)
qc.h(1)
qc.h(2)
qc.barrier()
subqc=QuantumCircuit(2,0,name="subqc") # Initialize your subcircuit. You can label it a new name
subqc.cx(1,0)
subqc.h(1)
subqc.y(0)
subqc.cx(0,1)
# Append the subcircuit to your original circuit. 
# You should specify where you want to insert you subcircuit on your second parameter.
# Here, the 0th qubit of subqc is mapped to the 1th qubit, the 1th qubit of subqc is mapped to the 2nd qubit
qc.append(subqc,[1,2]) 

Visualization is a useful way to debug your circuit interactively. Qiskit provides a built-in draw method:

qc.draw('mpl')
Example circuit diagram
Figure 1: The output visualization of the defined circuit Example. Qiskit both dipicts quantum registers(q) and classcal registers(c).
Example circuit diagram
Figure 2: A user defined circuit with a sub circuit(subqc) inside. The subqc is seen as a subroutine called by the upper-level circuit. And qiskit will not display the detailed implementation. Such modularization help you better organize a complicatet quantum circuit.

To save the diagram as an image file, include a filename:

qc.draw('mpl',filename='filename.png')

If you want to see the unitary matrix representation of your circuit:

from qiskit.quantum_info import Operator
U = Operator(qc)
print(U.data)

Run simulation and plot results

The QuantumCircuit we created above does not execute automatically.
To run a circuit, you must explicitly simulate it.

A Qiskit circuit consists of both quantum registers and classical registers.
Measurement results are stored in the classical registers.

When running a simulation, don’t forget to add measurement operations:

from qiskit import QuantumCircuit
qc=QuantumCircuit(3,3) # Initialize a circuit with 3 qubits and 2 classical bits
qc.x(0) #Add PauliX gate to qubit 0
qc.h(1) #Add Hadamard gate to qubit 1
qc.cx(0,1) #Add a CNOT gate to qubit 0,1 controlled by qubit 0
qc.cx(2,1) #Add a CNOT gate to qubit 2,1 controlled by qubit 2
qc.barrier()
qc.measure([0,1,2],[0,1,2]) # Add measurement on the computational basis.
qc.draw("mpl")
Circuit with measurements
Figure 3: Adding measurement operations to a quantum circuit. In qiskit, all measurement outcome must be stored in a classical bit(Where the measurement dashboards point to)

To run an ideal (noise-free) simulation and obtain the results, we use the AerSimulator backend.
You can run the following code:

from qiskit_aer import AerSimulator
from qiskit.visualization import plot_histogram
backend = AerSimulator()
job = backend.run(qc, shots=1000) # Run the circuit 1000 times 
output = job.result().get_counts() 
plot_histogram(output) #Plot the result
Simulation result histogram
Figure 4: Ideal simulation result histogram with 1000 shots. X axis stands for the collapsed basis states after measurement. Y asis stands for the frequency, or counts, or the this states. Note that in qiskit, qubits are ordered using little-endian notation, so 001 means q0 collapse to 1, and q1, q2 collapse to 0, 011 means q0,q1 collapse to 1, and q2 collapse to 0.

Simulation with customized noise model

In this part of the lab, you will run your circuit under a noisy simulation.
We use a custom noise model to introduce bit-flip and phase-flip errors at specified probabilities.

Example:

from qiskit_aer import AerSimulator
from qiskit.visualization import plot_histogram
from noisemodel import construct_bitphaseflip_noise_model
backend = AerSimulator()
noise_model=construct_bitphaseflip_noise_model(0.1,0.1,0.1)
job = backend.run(qc, shots=1000,noise_model=noise_model) # Run the circuit 1000 times 
output = job.result().get_counts() 
plot_histogram(output) #Plot the result
Noisy simulation histogram
Figure 5: The simulation result with a customized noise model, with noise strength set as 0.1. Compare with the ideal(noise-free) simulation, there are more unexpected collapsed states, such as 000,101. You can tune up the noise parameter, and see how this distribution varies accordingly.

Simulation on fake provider

In this lab, you are also required to run simulations on an IBM fake provider, which mimics the behavior of a real noisy superconducting quantum computer. Next, transpile the circuit for the backend and run the simulation:

from qiskit import QuantumCircuit, transpile
from qiskit.providers.fake_provider import GenericBackendV2
from qiskit.visualization import plot_histogram
 
# Generate a 20-qubit simulated backend
backend = GenericBackendV2(num_qubits=20)
 

qc=QuantumCircuit(3,3) # Initialize a circuit with 3 qubits and 2 classical bits
qc.x(0) #Add PauliX gate to qubit 0
qc.h(1) #Add Hadamard gate to qubit 1
qc.cx(0,1) #Add a CNOT gate to qubit 0,1 controlled by qubit 0
qc.cx(2,1) #Add a CNOT gate to qubit 2,1 controlled by qubit 2
qc.barrier()
qc.measure([0,1,2],[0,1,2]) # Add measurement on the computational basis.
 
# Transpile the ideal circuit to a circuit that can be directly executed by the backend
transpiled_circuit = transpile(qc, backend)
transpiled_circuit.draw('mpl')
 
# Run the transpiled circuit using the simulated backend
job = backend.run(transpiled_circuit,shots=1000)
counts = job.result().get_counts()
plot_histogram(counts)

The transpiled circuit looks like this:

Transpiled circuit diagram
Figure 6: Transpiled circuit for the fake backend. On the leftside of the figure, q0->0 means q0 is mapped to real physical qubit labelled 0.

You can also visualize how the virtual qubits in your circuit are mapped to the physical qubits of the backend:

from qiskit.visualization import plot_circuit_layout
fig=plot_circuit_layout(transpiled_circuit,backend)   

# Save the figure to a file, e.g., as 'layout.png'
fig.savefig('Figure/layout.png')
Circuit layout mapping
Figure 7: Mapping of virtual qubits to physical qubits. All edges are connection between physical qubits on a real 2d quantum hardware. Two qubit gates are supported between two qubits only if they are connected. The black vertices with indices are mapped, while the rest blue vertices are still free.

The result of the above simulation is:

Noisy simulation histogram
Figure 8: You can also simulation a transpiled circuit on a fakeprovider. This result is more realistic as hardware constraints are considered.

Reference

Here are some relevant references for the lab.

  • Qiskit Documentation
  • Michael A. Nielsen and Isaac L. Chuang, Quantum Computation and Quantum Information, Cambridge University Press, 2010.
  • Qiskit Textbook: Learn Quantum Computation Using Qiskit
  • John Preskill, Lecture Notes for Physics 219: Quantum Computation (Caltech), available online.
  • Gidney, Craig. "How to factor 2048 bit RSA integers with less than a million noisy qubits." arXiv preprint arXiv:2505.15917 (2025).
  • Gidney, Craig, and Martin Ekerå. "How to factor 2048 bit RSA integers in 8 hours using 20 million noisy qubits." Quantum 5 (2021): 433.

About

This is the IBM lab repo of quantum progamming course(CS238) taught by professor Jens Palsberg in UCLA

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published