Submit a job, then choose when to execute it¶
Follow a one-qubit X circuit through the local Backend and Job interface. Complete your first experiment, use the installed environment, and run from the repository root.
X maps |0⟩ to |1⟩. With ideal evolution, all 16 shots should therefore be 1. This simple prediction lets you focus on when computation happens rather than on sampling variation.
Observe the lazy local lifecycle¶
"""Submit a local program through the common Backend and Job interface.
The lesson separates program declaration from execution. ``LocalBackend.run``
returns a lazy Job; ``status`` and ``result`` expose lifecycle and result facts
without introducing a cloud or hardware transport.
"""
from __future__ import annotations
import json
from cascaqit import Circuit, LocalBackend
def main() -> None:
"""Observe a complete local Job lifecycle."""
circuit = Circuit(1, program_id="lesson.platform.beginner").x(0).measure_all()
backend = LocalBackend(seed=401)
# Job creation is separate from result materialization.
job = backend.run(circuit, shots=16)
queued = job.status()
result = job.result()
completed = job.status()
cached = job.result()
payload = {
"track": "sdk_platform_engineer",
"level": "beginner",
"lesson": "backend_job",
"facts": {
"queued_state": queued.state,
"completed_state": completed.state,
"executions_before_result": queued.execution_count,
"executions_after_result": completed.execution_count,
"executions_after_cached_read": job.status().execution_count,
"cached_result_matches": cached.stable_hash() == result.stable_hash(),
"backend_id": completed.backend_id,
"counts": result.counts,
"counts_total": sum(result.counts.values()),
},
"boundaries": {
"hardware_execution": False,
"cloud_execution": False,
"network_accessed": False,
"credentials_loaded": False,
},
}
print(json.dumps(payload, sort_keys=True))
if __name__ == "__main__":
main()
python3 examples/user/tracks/sdk_platform_engineer/01_beginner_backend_job_en.py
backend.run(...) validates and prepares a Job handle. Numerical execution starts when job.result() is called. job.status() reads the current status without starting the runner. This local job runs synchronously inside the result call; queued does not mean it was sent to a remote worker.
{
"boundaries": {
"cloud_execution": false,
"credentials_loaded": false,
"hardware_execution": false,
"network_accessed": false
},
"facts": {
"backend_id": "local.simulator",
"cached_result_matches": true,
"completed_state": "completed",
"counts": {
"1": 16
},
"counts_total": 16,
"executions_after_cached_read": 1,
"executions_after_result": 1,
"executions_before_result": 0,
"queued_state": "queued"
},
"lesson": "backend_job",
"level": "beginner",
"track": "sdk_platform_engineer"
}
The first snapshot is queued with zero executions. The result call takes the job through running to completed, with one execution. Because this script samples status only before and after that synchronous call, it does not observe the intermediate running state directly.
The second result() call returns the cached result. cached_result_matches should be true and the execution count should remain one. Repeated reads of this handle are different from submitting another backend.run(...), which creates a separate in-memory job. This lesson does not enable persistent storage or an idempotency key.
Keep the Job's execution status separate from its quantum result. A completed job can produce an unexpected physical distribution if the circuit or interpretation is wrong. Here both checks are simple: the status must complete and counts must be exactly 16 occurrences of 1.
Try cancellation and another input¶
- Insert
job.cancel()immediately before the firstjob.result(). Read the status and then attempt to obtain a result. - Call
job.cancel()after completion. Does it undo the result or change the terminal status? - Replace X with H. Which lifecycle facts stay the same, and which count prediction changes?
Cancelling a queued job sets cancelled without executing it. Asking for its result raises LOCAL_EXECUTION_JOB_CANCELLED. Cancelling after completion leaves the terminal job unchanged. H gives equal state probabilities, but 16 finite samples need not split evenly; the lazy execution and cached-read behavior stay the same.
The job lifecycle lists the common states and transitions. Do not turn status polling into a busy loop to trigger local work; call result() when you want execution. Continue with results and diagnostics to inspect what that execution returned.