Batches of jobs
We recommend to group jobs with the same sequence in a single batch. On the batch page of the web portal, you will be able to monitor all the jobs and execute bulk actions to download their results or cancel them.
Lifecycle of a batch
Section titled “Lifecycle of a batch”A new batch has the PENDING status and is added to the targeted backend’s queue. When the batch is at the top of the queue and the backend is idle, it is popped from the queue and the status is updated to RUNNING. All the jobs of that batch will be executed on the backend in the order they were submitted. Each job is also created with status PENDING, updated to RUNNING when the execution starts and ends up with a termination status DONE or ERROR. Once all the jobs of the batch reach a termination status, the batch status is updated to DONE and the backend moves on to the next one in the queue.
Before a job starts running, you may cancel so that it is not executed on the backend. The job status will be updated to CANCELED and your project will be refunded for the credits deducted for that job. You can cancel the entire batch, which removes it from the queue if it has not started or otherwise cancels all its pending jobs. Batches and jobs can be canceled from the portal or via the PasqalCloudClient.
Open batches for variational algorithms
Section titled “Open batches for variational algorithms”For variational algorithms, you cannot know in advance the variables for all the jobs to add to the batch.
In that case, you should create an “open” batch for which you can keep adding new jobs while it is PENDING or RUNNING.
Typically, you can create an open batch with one or more jobs, then wait for these jobs to terminate, get their results and postprocess them to compute the variables for the next job.
Then, add one or more new jobs to the batch - the backend is reserved for your batch until it is DONE so these new jobs will be executed immediately.
Here is an example on how to create an open batch, add jobs to it and close it:
# Create an open batch with 1 jobbackend = QPUBackend(sequence=sequence, connection=connection)
# Use open_batch() as a context manager to open a batchwith backend.open_batch(): results = backend.run( job_params=[{"runs": 50, "variables": {"omega_max": 9.5}}], )
# Add some jobs to it and wait for the jobs to be terminated backend.run( job_params=[ {"runs": 50, "variables": {"omega_max": 10}}, {"runs": 50, "variables": {"omega_max": 10.5}}, ], wait=True, )
# The batch is closed automatically when exiting the context managerBatching jobs with different registers
Section titled “Batching jobs with different registers”Jobs of a batch must share the same parametrized sequence which usually defines a register. However you can define their sequence using a mappable register - this lets you define a different register for each job.
from pulser import Sequence, Pulsefrom pulser.register.special_layouts import TriangularLatticeLayoutfrom pasqal_cloud import PasqalCloudConnection, QPUBackend
connection = PasqalCloudConnection(username="<email>", project_id="<project_id>")
# Fetches devices available through this connectiondevices = connection.fetch_available_devices()
# Get a device object with the specs of our Fresnel QPUdevice = devices["FRESNEL_CAN1"]
# let's create a layout shared by our jobslayout = TriangularLatticeLayout(n_traps=60, spacing=5)# we create a mappable register of 30 qubits out of this layoutmap_register = layout.make_mappable_register(n_qubits=30)
# let's build a basic sequence for this mappable register and serialize itseq = Sequence(map_register, device)seq.declare_channel("rydberg", "rydberg_global")seq.add( Pulse.ConstantPulse(duration=100, amplitude=1, detuning=0, phase=0), "rydberg",)
# now let's create a batch using this sequence# the first job will use a register with atoms in the traps 1, 5 and 7# the second job will use a register with atoms in the traps 2, 4, 8 and 26backend = QPUBackend(sequence=seq, connection=connection)results = backend.run( job_params=[ {"runs": 100, "variables": {"qubits": {"q0": 1, "q1": 5, "q2": 7}}}, {"runs": 100, "variables": {"qubits": {"q0": 2, "q1": 4, "q2": 8, "q3": 26}}}, ])from pulser import Sequence, Pulsefrom pulser.register.special_layouts import TriangularLatticeLayoutfrom pasqal_cloud import PasqalCloudConnection, QPUBackend
connection = PasqalCloudConnection(username="<email>", project_id="<project_id>", region="sa")
# Fetches devices available through this connectiondevices = connection.fetch_available_devices()
# Get a device object with the specs of our Fresnel QPUdevice = devices["FRESNEL_SA1"]
# let's create a layout shared by our jobslayout = TriangularLatticeLayout(n_traps=60, spacing=5)# we create a mappable register of 30 qubits out of this layoutmap_register = layout.make_mappable_register(n_qubits=30)
# let's build a basic sequence for this mappable register and serialize itseq = Sequence(map_register, device)seq.declare_channel("rydberg", "rydberg_global")seq.add( Pulse.ConstantPulse(duration=100, amplitude=1, detuning=0, phase=0), "rydberg",)
# now let's create a batch using this sequence# the first job will use a register with atoms in the traps 1, 5 and 7# the second job will use a register with atoms in the traps 2, 4, 8 and 26backend = QPUBackend(sequence=seq, connection=connection)results = backend.run( job_params=[ {"runs": 100, "variables": {"qubits": {"q0": 1, "q1": 5, "q2": 7}}}, {"runs": 100, "variables": {"qubits": {"q0": 2, "q1": 4, "q2": 8, "q3": 26}}}, ])Actions on batches and jobs
Section titled “Actions on batches and jobs”Those actions are possible through the PasqalCloudClient accessible from the connection.
Get job results
Section titled “Get job results”Job results are available only for jobs marked as DONE.
To get the results (in JSON format) of an individual job, navigate to the Batches page (link on the top navigation). Then, inside the list of batches, click on the batch containing the job wanted. You will access the Batch details page, where all jobs assigned to the current batch are listed. Click on the job wanted in the list. You will then access its page, where you can get the results by clicking the Download results button on the top right corner.
Get all job results from a batch
Section titled “Get all job results from a batch”You can get all jobs results (in JSON format) from a batch at once only when the batch is marked as done. To do so, you can navigate to the Batches page (link on the top navigation). Then, in the list, click on the batch containing the done job wanted to access the Job details page. There, you can get the results by clicking on the Download results button on the top right corner.
Get a list of jobs
Section titled “Get a list of jobs”It is possible to get all jobs or a selection of jobs with the get_jobs method. This method uses a pagination system that you have to handle. By default, a page returns 100 jobs, but it can be changed.
Here are few examples of how to use it:
from pasqal_cloud.utils.filters import JobFilters, PaginationParamsfrom pasqal_cloud.utils.constants import JobStatus
cloud_client = connection.cloud_client
# Get the first 100 jobs, no filters appliedcloud_client.get_jobs()
# Get the first 40 jobs, no filters appliedcloud_client.get_jobs(pagination_params=PaginationParams(limit=40))
# Get the first 100 jobs from a given batchcloud_client.get_jobs(filters=JobFilters(batch_id="batch_id"))
# Get the first 100 jobs in error from a specific projectcloud_client.get_jobs(filters=JobFilters(status=JobStatus.ERROR, project_id="project_id"))
# Get two jobs using two idscloud_client.get_jobs(filters=JobFilters(id=["job_id_1", "job_id_2"]))
# Get the first 20 cancelled jobs created in a given period from a specific list of userscloud_client.get_jobs(limit=20, filters=JobFilters(status=JobStatus.CANCELED, start_date=datetime(...), end_date=datetime(...), user_id=["user_id_1", "user_id_2"]))
# Get the total number of jobs matching the filterscloud_client.get_jobs(pagination_params=PaginationParams(offset=0)).total
# Get the first 300 jobs, no filters appliedjobs = []jobs.extend(cloud_client.get_jobs(pagination_params=PaginationParams(offset=0)).results)jobs.extend(cloud_client.get_jobs(pagination_params=PaginationParams(offset=100)).results)jobs.extend(cloud_client.get_jobs(pagination_params=PaginationParams(offset=200)).results)Retry a batch of jobs
Section titled “Retry a batch of jobs”It is possible to retry a selection of jobs from a CLOSED batch with the rebatch method.
from pasqal_cloud.utils.filters import RebatchFiltersfrom pasqal_cloud.utils.constants import JobStatus
cloud_client = connection.cloud_client
# Retry all jobs from a given batchcloud_client.rebatch(batch_id)
# Retry the first job of a batchcloud_client.rebatch(batch_id, RebatchFilters(id=batch.ordered_jobs[0].id))
# Retry all jobs in errorcloud_client.rebatch(batch_id, RebatchFilters(status=JobStatus.ERROR))
# Retry cancelled jobs created in a given periodcloud_client.rebatch(batch_id, RebatchFilters(status=JobStatus.CANCELED, start_date=datetime(...), end_date=datetime(...)))
# Retry jobs that have a run number between 5 and 10cloud_client.rebatch(batch_id, RebatchFilters(min_runs=5, max_runs=10))Retry a job in an open batch
Section titled “Retry a job in an open batch”It is possible to retry a single job in a same open batch as an original job using batch.retry. The batch must be open in order for this method to work.
cloud_client = connection.cloud_client
with backend.open_batch() as op: results = backend.run(...)
batch = cloud_client.get_batch(results.batch_id)
batch.retry(batch.ordered_jobs[0])
# Like for adding a job you can choose to wait for results.batch.retry(batch.ordered_jobs[0], wait=True)Get a List of supported device specifications
Section titled “Get a List of supported device specifications”The PasqalCloudClient provides a method to retrieve the device specs currently defined on Pasqal’s cloud platform. They define the physical constraints of our QPUs, and these constraints enforce some rules on the pulser sequence that can be run on QPUs (e.g., max number of atoms, available pulse channels, …)
cloud_client = connection.cloud_clientcloud_client.get_device_specs_dict()The method returns a dict object mapping a device type to a serialized device specs. These specs can be used to instantiate a Device instance in the Pulser library.
