Introduction to NoisyCircuits
Library Imports
[1]:
from NoisyCircuits import QuantumCircuit as QC
from NoisyCircuits.utils.CreateNoiseModel import GetNoiseModel, CreateNoiseModel
import pickle
import os
import json
import numpy as np
2026-03-09 13:17:36,117 INFO util.py:154 -- Missing packages: ['ipywidgets']. Run `pip install -U ipywidgets`, then restart the notebook server for rich notebook output.
Setup Input Fields
In the input fields:
token: refers to the IBM API token for accessing IBM Quantum Systems. See IBM Documentation for account creation and token access here.
backend_name: refers to the IBM quantum hardware for which the noise model needs to be built. Currently, the software only supports the IBM Eagle R3 Chip set which have a basis gate set comprising of \(X\), \(\sqrt{X}\), \(R_z(\cdot)\) and \(ECR\). As of 15.08.2025, the backend codenamed “ibm_brisbane” is the only available quantum hardware with the Eagle R3 chip.
num_qubits: the number of qubits in the quantum circuits.
num_cores: the number of cores to run parallel Monte-Carlo Wavefunction (MCWF) Trajectories. (Ensure sufficient resources are available for runs.)
num_trajectories: the number of trajectories for the MCWF method.
threshold: the threshold for filtering out noise data.
jsonize: a boolean variable indicating whether the noise model needs to be jsonized or if the input noise model is already in a json format.
[16]:
api_json = json.load(open(os.path.join(os.path.expanduser("~"), "ibm_api.json"), "r"))
token = api_json["apikey"] # Replace with your Token
service_crn = api_json["service-crn"] # Replace with your Service CRN
backend_name = "ibm_fez"
num_qubits = 2
num_cores = 20
num_trajectories = 20
threshold = 1e-4
noise_model = None
jsonize = True
verbose = True
# Options: "heron", "eagle". Note that "eagle" is now deprecated and only available in simulation mode (i.e., no noise model from hardware).
qpu_type = "heron"
sim_backend = "pennylane" # Choose between "qulacs", "pennylane" and "qiskit"
Getting the Noise Model
Run the code below to obtain the noise model from IBM backend calibration data. This requires a valid IBM Quantum Token as well as a service-crn for available quantum backend instances. If not available, please skip this cell and execute the next cell to utilize the sample noise data.
[3]:
noise_model = GetNoiseModel(backend_name=backend_name, token=token, service_crn=service_crn).get_noise_model()
Warning: Found relaxation time anomaly for qubit 72 with $T_2 \geq 2T_1$. Setting $T_2 = 2T_1$.
Run the code below to use a sample noise model generated from IBM calibration data.
[ ]:
if noise_model is None:
if qpu_type == "eagle":
file_path = "https://raw.githubusercontent.com/Sats2/NoisyCircuits/main/noise_models/Noise_Model_Eagle_QPU.pkl"
noise_model = pickle.load(open(file_path, "rb"))
elif qpu_type == "heron":
file_path = "https://raw.githubusercontent.com/Sats2/NoisyCircuits/main/noise_models/Sample_Noise_Model_Heron_QPU.csv"
noise_model = CreateNoiseModel(calibration_data_file=file_path,
basis_gates=[["x", "sx", "rz", "rx"], ["cz", "rzz"]]).create_noise_model()
else:
raise ValueError("Invalid qpu_type. Choose either 'heron' or 'eagle'.")
Initialize the Circuit Instance
[4]:
nqc = QC(num_qubits=num_qubits,
noise_model=noise_model,
num_cores=num_cores,
backend_qpu_type=qpu_type,
num_trajectories=num_trajectories,
sim_backend=sim_backend,
threshold=threshold,
jsonize=jsonize,
verbose=verbose)
Completed Extraction of Measurement Errors.
Completed Extraction of two-qubit gate Errors.
Starting post-processing on Single Qubit Errors.
Successfully switched backend to pennylane.
Completed post-processing on Single Qubit Errors.
Processing two-qubit gate errors.
Qubit pair (0, 1): 17/48 errors above threshold (31 filtered out)
Qubit pair (1, 0): 17/48 errors above threshold (31 filtered out)
Qubit pair (0, 1): 17/48 errors above threshold (31 filtered out)
Qubit pair (1, 0): 17/48 errors above threshold (31 filtered out)
Two Qubit Gate errors processed.
Building Noise Operators for Two Qubit Gate Errors.
Completed building Noise Operators for Two Qubit Gate Errors.
Extracting Measurement Errors.
Preparing Qubit Connectivity Map for Requested Qubits
Qubit Connectivity Map Prepared.
Returning Single Qubit Error Instructions, Two Qubit Gate Error Instructions, Measurement Errors and Connectivity Map.
2026-03-09 13:18:02,844 INFO worker.py:2007 -- Started a local Ray instance.
/Users/adam-ukj7r05xnu2fywx/miniconda3/envs/NoisyCircuits/lib/python3.10/site-packages/ray/_private/worker.py:2046: FutureWarning: Tip: In future versions of Ray, Ray will no longer override accelerator visible devices env var if num_gpus=0 or num_gpus=None (default). To enable this behavior and turn off this error message, set RAY_ACCEL_ENV_VAR_OVERRIDE_ON_ZERO=0
warnings.warn(
Example Circuit
Example 1: Creating an EPR Pair
First we create an EPR pair generating quantum circuit and execute it as a pure statevector simulation and as a noisy simulation (comparing density matrix and MCWF methods).
[5]:
# Reset the circuit --> Ensure the circuit tape has no prior instructions
nqc.refresh()
[6]:
# Create the EPR Pair Circuit
nqc.H(0)
nqc.CX(0, 1)
[7]:
# Run the circuit with pure state simulation, argument qubits is the measured qubits
nqc.run_pure_state(qubits=[0,1])
[7]:
array([5.00000000e-01, 3.39184123e-33, 3.39184123e-33, 5.00000000e-01])
[8]:
# Run the circuit with density matrix simulation
nqc.run_with_density_matrix(qubits=[0,1])
[8]:
array([0.48472261, 0.03088778, 0.01758682, 0.46680279])
[9]:
# Run with MCWF Simulation
nqc.execute(qubits=[0,1], num_trajectories=100)
[9]:
array([0.48931892, 0.02535658, 0.01266101, 0.4726635 ])
[10]:
# Run with MCWF Simulation
nqc.execute(qubits=[0,1], num_trajectories=1000)
[10]:
array([0.48657377, 0.02858423, 0.0158844 , 0.4689576 ])
For the MCWF method, using more trajectories ensures better convergence to the density matrix result.
Example 2: Qubit Swap
In this example, we see the effect of noise on a qubit swap between two qubits whose states where initialized using angle encoding.
[11]:
# nqc.refresh() resets the quantum circuit to zero gates.
# The argument to the rotation gates are the angle, followed by the qubit index.
nqc.refresh()
nqc.RY(theta=1.2, qubit=0)
nqc.RY(theta=0.5, qubit=1)
nqc.SWAP(qubit1=0, qubit2=1)
[12]:
# Run with pure state simulation
nqc.run_pure_state(qubits=[1])
[12]:
array([0.68117888, 0.31882112])
[13]:
# Run with the density matrix simulation
nqc.run_with_density_matrix(qubits=[1])
[13]:
array([0.66565228, 0.33434772])
[14]:
# Run with MCWF Simulation
nqc.execute(qubits=[1], num_trajectories=500)
[14]:
array([0.66590558, 0.33409442])
Shutdown the Parallel instance
Due to parallel implementation with “ray”, there is a requirement to explicitly shutdown the parallel pool
[15]:
nqc.shutdown()
Download this Notebook - /examples/introduction.ipynb