Running Multiple Circuits on Hardware

This tutorial shows how a quantum circuit can be run on actual quantum hardware. This requires a valid IBM Quantum Token as well as a service-crn for available quantum backend instances. Please make sure you have sufficient time available to execute the code on the quantum hardware.

Import all Necessary Libraries

[1]:
from NoisyCircuits.QuantumCircuit import QuantumCircuit as nqc
from NoisyCircuits.utils.CreateNoiseModel import GetNoiseModel
from NoisyCircuits.RunOnHardware import RunOnHardware
import os
import numpy as np
import json
import matplotlib.pyplot as plt
2026-03-06 15:48:29,140 INFO util.py:154 -- Missing packages: ['ipywidgets']. Run `pip install -U ipywidgets`, then restart the notebook server for rich notebook output.

Define all Necessary Parameters

[ ]:
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"
shots = 2048
verbose = False
jsonize = True
num_qubits = 2
num_trajectories = 500
qpu = "heron" # Only possible option for IBM backends at the moment
num_cores = 50
sim_backend = "pennylane" # Choose between "pennylane", "qulacs" and "qiskit"

Get the Noise Model

[3]:
noise_model = GetNoiseModel(backend_name, token, service_crn).get_noise_model()
Warning: Found relaxation time anomaly for qubit 72 with $T_2 \geq 2T_1$. Setting $T_2 = 2T_1$.

Build all Quantum Circuits

[4]:
circuit = nqc(num_qubits=num_qubits,
         noise_model=noise_model,
         num_cores=num_cores,
         backend_qpu_type=qpu,
         num_trajectories=num_trajectories,
         sim_backend=sim_backend,
         jsonize=jsonize,
         verbose=verbose)

# List to store all probabilities from Pure State Simulation
probs_pure_list = []
# List to store all probabilities from MCWF Simulations
probs_sim_list = []
Successfully switched backend to pennylane.
2026-03-06 15:48:49,455 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(
[5]:
hardware_runner = RunOnHardware(
    token=token,
    backend=backend_name,
    shots=shots
)
qiskit_runtime_service._discover_account:WARNING:2026-03-06 15:48:50,211: Loading account with the given token. A saved account will not be used.
qiskit_runtime_service.__init__:WARNING:2026-03-06 15:48:53,034: Instance was not set at service instantiation. Free and trial plan instances will be prioritized. Based on the following filters: (tags: None, region: us-east, eu-de), and available plans: (open), the available account instances are: Open_Sys. If you need a specific instance set it explicitly either by using a saved account with a saved default instance or passing it in directly to QiskitRuntimeService().
qiskit_runtime_service.backends:WARNING:2026-03-06 15:48:53,036: Loading instance: Open_Sys, plan: open

Circuit 1: SWAP States

[6]:
circuit.refresh()
circuit.RY(1.4, 0)
circuit.RY(2.5, 1)
circuit.SWAP(0, 1)
circuit.draw_circuit(style="text")
     ┌───┐┌────┐┌──────────┐┌────┐┌────┐   ┌────┐   ┌────┐   ┌───────┐┌───┐
q_0: ┤ X ├┤ √X ├┤ Rz(-1.4) ├┤ √X ├┤ √X ├─■─┤ √X ├─■─┤ √X ├─■─┤ Rx(π) ├┤ X ├
     ├───┤├────┤├──────────┤├────┤├────┤ │ ├────┤ │ ├────┤ │ └───────┘└───┘
q_1: ┤ X ├┤ √X ├┤ Rz(-2.5) ├┤ √X ├┤ √X ├─■─┤ √X ├─■─┤ √X ├─■───────────────
     └───┘└────┘└──────────┘└────┘└────┘   └────┘   └────┘
[7]:
hardware_runner.create_circuits(
    circuit=circuit,
    measure_qubits=list(range(num_qubits))
)
[8]:
probs_pure_list.append(circuit.run_pure_state(list(range(num_qubits))))
probs_sim_list.append(circuit.execute(list(range(num_qubits))))

Circuit 2: Parameterized Circuit

Set up a parameterized circuit with different set of parameters

[ ]:
parameter_set = [np.random.uniform(-2*np.pi, 2*np.pi, size=8) for _ in range(2)]
[2026-03-06 15:49:20,127 E 404821 405340] core_worker_process.cc:842: Failed to establish connection to the metrics exporter agent. Metrics will not be exported. Exporter agent status: RpcError: Running out of retries to initialize the metrics agent. rpc_code: 14
[10]:
for circuit_num, params in enumerate(parameter_set):
    circuit.refresh()
    circuit.H(0)
    circuit.H(1)
    for i in range(len(params)//2):
        for j in range(num_qubits):
            circuit.RY(params[2*i+j], j)
        circuit.CZ(0, 1)
    circuit.draw_circuit(style="text")
    probs_pure_list.append(circuit.run_pure_state(list(range(num_qubits))))
    probs_sim_list.append(circuit.execute(list(range(num_qubits))))
    hardware_runner.create_circuits(circuit=circuit, measure_qubits=list(range(num_qubits)))
     ┌────┐┌─────────┐┌────┐┌───┐┌────┐ ┌────────────┐┌────┐   ┌───┐┌────┐»
q_0: ┤ √X ├┤ Rz(π/2) ├┤ √X ├┤ X ├┤ √X ├─┤ Rz(5.9209) ├┤ √X ├─■─┤ X ├┤ √X ├»
     ├────┤├─────────┤├────┤├───┤├────┤┌┴────────────┤├────┤ │ ├───┤├────┤»
q_1: ┤ √X ├┤ Rz(π/2) ├┤ √X ├┤ X ├┤ √X ├┤ Rz(-0.8332) ├┤ √X ├─■─┤ X ├┤ √X ├»
     └────┘└─────────┘└────┘└───┘└────┘└─────────────┘└────┘   └───┘└────┘»
«     ┌─────────────┐┌────┐   ┌───┐┌────┐ ┌────────────┐┌────┐   ┌───┐┌────┐»
«q_0: ┤ Rz(0.55698) ├┤ √X ├─■─┤ X ├┤ √X ├─┤ Rz(5.8255) ├┤ √X ├─■─┤ X ├┤ √X ├»
«     └┬────────────┤├────┤ │ ├───┤├────┤┌┴────────────┤├────┤ │ ├───┤├────┤»
«q_1: ─┤ Rz(-2.851) ├┤ √X ├─■─┤ X ├┤ √X ├┤ Rz(0.22728) ├┤ √X ├─■─┤ X ├┤ √X ├»
«      └────────────┘└────┘   └───┘└────┘└─────────────┘└────┘   └───┘└────┘»
«     ┌────────────┐┌────┐
«q_0: ┤ Rz(5.6758) ├┤ √X ├─■─
«     ├────────────┤├────┤ │
«q_1: ┤ Rz(4.3392) ├┤ √X ├─■─
«     └────────────┘└────┘
     ┌────┐┌─────────┐┌────┐┌───┐┌────┐┌─────────────┐┌────┐   ┌───┐┌────┐»
q_0: ┤ √X ├┤ Rz(π/2) ├┤ √X ├┤ X ├┤ √X ├┤ Rz(-3.0417) ├┤ √X ├─■─┤ X ├┤ √X ├»
     ├────┤├─────────┤├────┤├───┤├────┤├─────────────┤├────┤ │ ├───┤├────┤»
q_1: ┤ √X ├┤ Rz(π/2) ├┤ √X ├┤ X ├┤ √X ├┤ Rz(-4.4452) ├┤ √X ├─■─┤ X ├┤ √X ├»
     └────┘└─────────┘└────┘└───┘└────┘└─────────────┘└────┘   └───┘└────┘»
«     ┌─────────────┐┌────┐   ┌───┐┌────┐┌────────────┐┌────┐   ┌───┐┌────┐»
«q_0: ┤ Rz(-2.3893) ├┤ √X ├─■─┤ X ├┤ √X ├┤ Rz(5.2782) ├┤ √X ├─■─┤ X ├┤ √X ├»
«     ├─────────────┤├────┤ │ ├───┤├────┤├───────────┬┘├────┤ │ ├───┤├────┤»
«q_1: ┤ Rz(-4.5959) ├┤ √X ├─■─┤ X ├┤ √X ├┤ Rz(6.076) ├─┤ √X ├─■─┤ X ├┤ √X ├»
«     └─────────────┘└────┘   └───┘└────┘└───────────┘ └────┘   └───┘└────┘»
«     ┌────────────┐┌────┐
«q_0: ┤ Rz(-1.994) ├┤ √X ├─■─
«     ├───────────┬┘├────┤ │
«q_1: ┤ Rz(-1.95) ├─┤ √X ├─■─
«     └───────────┘ └────┘

Setup the Circuits for Submission

[11]:
hardware_runner.setup_circuits()
qiskit_runtime_service.backends:WARNING:2026-03-06 15:49:42,528: Using instance: Open_Sys, plan: open
qiskit_runtime_service.backends:WARNING:2026-03-06 15:49:43,350: Using instance: Open_Sys, plan: open
qiskit_runtime_service.backends:WARNING:2026-03-06 15:49:43,968: Using instance: Open_Sys, plan: open

Submit the Circuits

[12]:
job_id = hardware_runner.run()
qiskit_runtime_service.backends:WARNING:2026-03-06 15:49:45,335: Using instance: Open_Sys, plan: open
Job ID: d6lej2obfi7c73a2ceb0

Query Job Status

[14]:
hardware_runner.status()
[14]:
'DONE'

Job Cancellation

In the event the job hasn’t already been completed, they can be cancelled.

[ ]:
hardware_runner.cancel()

Get Results

[15]:
probs_hardware_list = hardware_runner.get_results()

Compare Results

To compare the results we use the Battacharyya Coefficient defined for discrete probability distributions by: \begin{equation} BC(p, q) = \sum_{i=1}^N \sqrt{p_i q_i} \end{equation}

[16]:
def battacharyya_coefficient(p, q):
    return np.sum(np.sqrt(p * q))
[19]:
for i in range(len(probs_pure_list)):
    print("Fidelity between Pure State Simulation and MCWF Simulation Results:\t", battacharyya_coefficient(probs_pure_list[i], probs_sim_list[i]))
    print("Fidelity between Pure State Simulation and Hardware Results:\t", battacharyya_coefficient(probs_pure_list[i], probs_hardware_list[i]))
    print("Fidelity between MCWF Simulation and Hardware Results:\t", battacharyya_coefficient(probs_sim_list[i], probs_hardware_list[i]))
    print("----------------------------------------------------------------------------------------------")
Fidelity between Pure State Simulation and MCWF Simulation Results:      0.9964907327425298
Fidelity between Pure State Simulation and Hardware Results:     0.9999492692239413
Fidelity between MCWF Simulation and Hardware Results:   0.996015383159569
----------------------------------------------------------------------------------------------
Fidelity between Pure State Simulation and MCWF Simulation Results:      0.9958387556303563
Fidelity between Pure State Simulation and Hardware Results:     0.9944099073651047
Fidelity between MCWF Simulation and Hardware Results:   0.9994129921498147
----------------------------------------------------------------------------------------------
Fidelity between Pure State Simulation and MCWF Simulation Results:      0.9945292416842664
Fidelity between Pure State Simulation and Hardware Results:     0.9897188030740816
Fidelity between MCWF Simulation and Hardware Results:   0.9954703694328254
----------------------------------------------------------------------------------------------

Shutdown Circuit

[20]:
circuit.shutdown()

Download this Notebook - /examples/run_multiple_on_hardware.ipynb