Skip to content

Results are limited to the current section : Qoolqit

Execution

In this page, you will learn how to:

  • run a QuantumProgram on local/remote emulators and QPUs.
  • inspect and extract the execution results
  • choose between different emulator backends
  • use a connection to run programs remotely through your cloud provider.
  • submit remote jobs, query their status and retrieve results

As anticipated, a QuantumProgram can be run on multiple backends provided by Pasqal and external providers:

  • locally installed emulators
  • remote cloud emulators
  • QPUs

Remote emulators and QPU require credentials to submit a job. More information on how to access a QPU through your favorite cloud provider, is available at Pasqal's website (external). Later, we will briefly show how to authenticate and send a remote job.

Let us revisit the quantum program definition described before in the Quantum programs page.

from qoolqit import Constant, Drive, MockDevice, QuantumProgram, Ramp, Register
# Create the register
register = Register.from_coordinates([(0,1), (0,-1), (2,0)])
# Defining the drive parameters
omega = 0.8
delta_i = -2.0 * omega
delta_f = -delta_i
T = 25.0
# Defining the drive
wf_amp = Constant(T, omega)
wf_det = Ramp(T, delta_i, delta_f)
drive = Drive(amplitude = wf_amp, detuning = wf_det)
# Creating the program
program = QuantumProgram(register, drive)
# Compiling the Program
device = MockDevice()
program.compile_to(device)

Local emulators run quantum simulations directly on your machine. They are ideal for development, testing, and small-scale quantum programs. QoolQit provides easy access to local emulation through the LocalEmulator class, which allows you to run quantum programs locally.

For all emulators, a job handler is returned, to which you can query the results. Emulating locally will only return completed jobs, as opposed to remote emulators, which we will discuss later.

from qoolqit.execution import LocalEmulator
emulator = LocalEmulator()
job = emulator.run(program)
results = job.results()

The LocalEmulator allows to emulate the program run on different backends provided by Pasqal:

  • QutipBackendV2: Based on Qutip, runs programs with up to ~12 qubits and return qutip objects in the results (default).
  • SVBackend: PyTorch based state vectors and sparse matrices emulator. Runs programs with up to ~25 qubits and return torch objects in the results. Requires installing the emu-sv package.
  • MPSBackend: PyTorch based emulator using Matrix Product States (MPS). Runs programs with up to ~80 qubits and return torch objects in the results. Requires installing the emu-mps package.

To use a particular backend it is sufficient to specify it through the backend_type argument:

from qoolqit.execution import BackendType, LocalEmulator
emulator = LocalEmulator(backend_type=BackendType.QutipBackendV2)

The call emulator.run(program) will return a Job object type. All execution methods (LocalEmulator.run(), RemoteEmulator.run(), and QPU.run()) return a Job object that serves as a handler for managing the execution lifecycle and to fetch the results once the computation is completed. For more info about this specific object, please, have a look at Qoolqit documentation. As an example, lets inspect the results we got in the previous run:

# single result in the sequence
results.get_result_tags()
# single result in the sequence
final_bitstrings = results.final_bitstrings
final_bitstrings

Remote emulators run on cloud infrastructure, allowing you to simulate larger quantum systems without local computational constraints. As anticipated, for remote workflows credentials to create a connection are required. Here we will show how to create the specific handler of Pasqal Cloud services. Again, for more information about Pasqal Cloud and other providers, please refer to the Pasqal Cloud website (external).

Let's first initialize a connection. Without providing the actual credentials, we can only create an empty connection object, for displaying purposes only:

from pulser_pasqal import PasqalCloud
# connection = PasqalCloud(
# username=USERNAME, # Your username or email address for the Pasqal Cloud Platform
# password=PASSWORD, # The password for your Pasqal Cloud Platform account
# project_id=PROJECT_ID, # The ID of the project associated to your account
# )
connection = PasqalCloud()
from qoolqit.execution import RemoteEmulator
remote_emulator = RemoteEmulator(connection=connection)
from qoolqit.execution import (
BackendType,
EmulationConfig,
Occupation,
RemoteEmulator,
)
# define the observables to be evaluated at the specified times
observables = (Occupation(evaluation_times=[0.5, 1.0]),)
# emulation configuration to add observables and include hardware modulation
emulation_config = EmulationConfig(observables=observables, with_modulation=True)
# initialize the remote emulator with the custom configuration and num_shots
remote_emulator = RemoteEmulator(
backend_type=BackendType.EmuMPSBackend,
connection=connection,
emulation_config=emulation_config,
num_shots=1000,
)

Handling remote results: job and status management

Section titled “Handling remote results: job and status management”

Remote emulators and QPU both have a run() method that will return a job handler.

job = remote_emulator.run(program)

If your program requires intensive resources to be run, or if QPU happens to be on maintenance, results might not be immediately available. For this reason, the job handler provides several key methods for monitoring and retrieving results:

Querying Job Status:

# Check the current status of the job
status = job.get_status()
print(f"Job status: {status}") # Returns: PENDING, RUNNING, DONE, ERROR, etc.

Retrieving Job Results:

# Get results (blocks until completion for remote jobs)
results = job.results()
# Get results with timeout (raises TimeoutError if exceeded)
results = job.results(timeout=300) # 5 minutes timeout

Please note that depending on the provider connection lifecycle, job.results() may not allow to wait indefinitely. It is good practice to always check the status of the job before retrieving results.

Job Identification and Retrieval:

from qoolqit.execution import get_batch_id
# Get the unique batch identifier for the job
batch_id = get_batch_id(job)
# Get the unique job identifier
job_id = job.job_id()
# For remote jobs, retrieve a job using its ID
from qoolqit.execution import retrieve_remote_job
retrieved_job = retrieve_remote_job(connection, job_id, batch_id=batch_id)

Note that local emulator jobs complete immediately and always return DONE status, while remote jobs (remote emulators and QPUs) may remain in PENDING or RUNNING states before completion.

A connection object can also be used to run the program directly on a QPU.

Then, to see the list of available devices, run:

connection.fetch_available_devices()
from qoolqit.devices import Device
device = Device.from_connection(connection, "FRESNEL")
program.compile_to(device=device)
from qoolqit.execution import QPU
qpu = QPU(connection=connection, num_shots=500)

When running on QPUs, consider:

  • Limited shots: QPU time is precious, so choose your number shots carefully
  • Hardware constraints: Your program must be compiled for the specific QPU device
  • Queue times: QPU jobs may wait in queue before execution

This notebook covered the three main execution backends in QoolQit:

  1. Local Emulators: Fast, local simulation for development and testing
  2. Remote Emulators: Cloud-based simulation for larger quantum systems
  3. QPUs: Real quantum hardware execution

Each backend has its use cases, and the choice depends on your specific needs:

  • Use local emulators for quick prototyping and small systems
  • Use remote emulators for larger simulations beyond local capabilities
  • Use QPUs for real quantum experiments and final validation

For more detailed configuration options for emulators, see the Extended Usage documentation.