Jobs¶
Every execution path in this provider — QMBackend.run(), QMSamplerV2, and QMEstimatorV2 — returns a job handle immediately. The handle exposes the compiled QUA Program for inspection, bridges to the underlying QM SDK job, and builds Qiskit results when you call result().
For method signatures, see the Jobs API reference.
Job types¶
Class |
Returned by |
|
|---|---|---|
|
||
|
Same as |
|
|
||
|
|
|
|
Same as |
|
|
Same as |
Primitive jobs inherit QMPrimitiveJob. IQCC wrapper jobs mix in IQCCJobMixin for cloud diagnostics.
Typical lifecycle¶
job = backend.run(qc, shots=1024) # or sampler.run([pub]) / estimator.run([pub])
# job is submitted automatically for backend.run() and primitives
print(job.job_id) # QM SDK id after submit (was "pending" briefly)
print(job.status()) # JobStatus.RUNNING / DONE / …
result = job.result() # blocks until streams are complete
Method |
|
|
Notes |
|---|---|---|---|
|
Called inside |
Called by primitive |
Re-submit raises on primitives |
|
✓ |
✓ |
Maps QM SDK status to |
|
— |
✓ |
Convenience wrappers around |
|
✓ |
✓ |
Forwards to all underlying QM SDK jobs |
|
✓ |
✓ |
Builds Qiskit result from streamed data |
|
✓ |
✓ |
Return the QM SDK job at idx (default: |
|
✓ |
✓ |
Return the compiled |
|
✓ |
✓ |
Return the result-handles fetcher at idx (default: |
IQCCJob does not implement status() — poll via IQCC cloud APIs or inspect run_data.
IQCCSamplerJob and IQCCEstimatorJob do implement status() via IQCCJobMixin, but with important caveats:
IQCC execution is synchronous —
submit()blocks until the remote OPX program completes, soCloudJob.statusis unconditionally"completed"and carries no failure information.status()therefore ignoresCloudJob.statusentirely and inspects_run_data["stderr"]instead: it returnsJobStatus.ERRORwhen the cloud runtime’s stderr contains a Python traceback,JobStatus.DONEotherwise. Callresult()to get the fullIQCCCloudExecutionErrorwith the traceback text.
Chunked execution (max_circuits)¶
When the number of circuits or PUBs exceeds max_circuits, the provider automatically splits them into consecutive QUA programs and executes each chunk in order. Results are stitched back transparently — callers see a single Result / PrimitiveResult regardless of how many chunks were used.
# Run 50 PUBs with a hardware limit of 20 circuits per program
sampler = QMSamplerV2(backend)
job = sampler.run(pubs, max_circuits=20) # produces ceil(50/20) = 3 QUA programs
result = job.result() # stitched PrimitiveResult with 50 entries
The compiled programs are accessible on job.programs (a list) and via get_program(idx):
print(f"{len(job.programs)} QUA programs generated")
for i, prog in enumerate(job.programs):
print(f"=== chunk {i} ===")
print(generate_qua_script(prog))
Stream keys inside each chunk are local (0-based within the chunk), not global. The job tracks the mapping internally via compute_locator() and translates global pub/circuit indices to the correct chunk and local key during result assembly.
Standard QM vs IQCC output shape¶
The bit_array_from_measurement_stream helper in stream_assembly.py handles both backends:
Standard QM / SaaS —
fetch_all()returns a flat array;reshapenormalises it to(*pub.shape, shots).IQCC cloud —
fetch_all()may return an array with an extra leading dimension; the samereshapecollapses it to the expected shape, provided the total element count matches.
Both paths reach the same BitArray shape so downstream code is backend-agnostic.
Inspecting the generated QUA program¶
All job types expose the compiled QUA programs on job.programs — always a list[qm.Program], length 1 when no chunking occurred. Use get_program() to fetch the single program (index 0) without worrying about list indexing:
from qm import generate_qua_script
job = sampler.run([qc])
print(generate_qua_script(job.get_program()))
The same works for estimator and backend.run() jobs:
backend_job = backend.run(qc, shots=256)
estimator_job = estimator.run([(circuit, observables, param_values)])
print("=== backend.run() ===")
print(generate_qua_script(backend_job.get_program()))
print("=== Estimator ===")
print(generate_qua_script(estimator_job.get_program()))
job.programs is available immediately after the job object is constructed (before or after submit()), because compilation happens at job creation time.
For chunked jobs (multiple programs), iterate the list or fetch a specific chunk by index:
# Iterate all chunks:
for chunk_idx, prog in enumerate(job.programs):
print(f"=== chunk {chunk_idx} ===")
print(generate_qua_script(prog))
# Or fetch a specific chunk:
print(generate_qua_script(job.get_program(2))) # third chunk
Properties and attributes¶
Primitive jobs (QMSamplerJob, QMEstimatorJob)¶
Name |
Type |
Purpose |
|---|---|---|
|
|
PUBs passed to |
|
|
Snapshot of pubs, |
|
|
Same as above — sampler/estimator QUA programs |
|
|
One fetcher per submitted job (via |
|
|
Compiled execution plans — one per EstimatorPub; exposes observable grouping, parameter tables, and the switch-statement data streamed to the OPX |
IQCC wrapper jobs¶
Name |
Type |
Purpose |
|---|---|---|
|
|
Raw IQCC cloud record ( |
When the remote runtime fails, result() raises IQCCCloudExecutionError with the cloud traceback instead of a misleading local stream error. See Primitives — IQCC cloud failures.
from qiskit_qm_provider.job import IQCCCloudExecutionError
try:
result = job.result()
except IQCCCloudExecutionError as exc:
print(exc) # cloud stderr / traceback
print(job.run_data["stdout"]) # QM log lines from the remote runtime
Pushing data on a running job¶
For streamed primitives, parameter values are pushed after submit via the parameter tables bound at compile time. Use the getter methods to access the live handles:
job = sampler.run([(qc, param_values)])
# submit already ran
job.get_result_handles() # stream handle for the first (only) job
param_table.push_to_opx(..., job=job.get_qm_job(), qm=backend.qm)
On IQCC, streamed jobs auto-generate a sync hook script that performs this pushing on the cloud side (see Primitives).
Debugging checklist¶
Print the QUA —
print(generate_qua_script(job.get_program()))(or iteratejob.programsfor chunked jobs)Check job id —
job.job_idafter submitPoll status —
job.status()(not onIQCCJob; onIQCCSamplerJob/IQCCEstimatorJobthis checks stderr, not the QM SDK status property)IQCC failures —
job.run_databefore trustingresult()Stream keys —
job.get_result_handles()for the active stream fetcher