Azure Quantum
Azure Quantum is an aggregator: one connection unlocks Quantinuum,
IonQ-via-Azure, Rigetti, Pasqal, and IQM targets. It is also the only
provider that runs Q# programs on real hardware (compiled to QIR), and
the recommended path to Quantinuum hardware — the direct quantinuum
provider requires pytket-quantinuum<0.26
(why), while Azure’s
Quantinuum targets work with current SDKs.
Workspace setup
Section titled “Workspace setup”- In the Azure portal, create a Quantum workspace (subscription → resource group → workspace; note the location).
- Install the SDK in the kernel environment — the setup wizard’s
azureentry, i.e.pip install azure-quantum(catalog). - Authenticate the machine: the kernel uses azure.quantum’s default
credential chain (
az login, a browser prompt, environment service principal, managed identity — in the standard Azure order). There is deliberately no token field in Nuclei’s credential form.
Credentials
Section titled “Credentials”Four fields, sent via hardware_connect:
| Key | Required | Default |
|---|---|---|
subscription_id | yes | — |
resource_group | yes | — |
workspace_name | yes | — |
location | no | eastus |
{ "type": "hardware_connect", "provider": "azure", "credentials": { "subscription_id": "00000000-0000-0000-0000-000000000000", "resource_group": "my-quantum-rg", "workspace_name": "my-workspace", "location": "eastus" }}connect validates by listing the workspace’s targets over the network —
success: false usually means wrong workspace coordinates or a missing
az login. On success the four fields persist to the OS keyring like any
provider (overview).
Targets
Section titled “Targets”hardware_list_backends with provider: "azure" maps workspace targets to
BackendInfo — with caveats worth
knowing:
statusisonlinewhen Azure reports availability containingavailable, otherwisemaintenance.queue_lengthis filled from Azure’s average queue time — it is a time figure, not a number of jobs.qubit_countis hardcoded by name prefix (quantinuum56,ionq29,rigetti80,pasqal100,iqm20) — estimates, not live calibration data; unrecognized targets report 0.connectivity,gate_set, andaverage_error_rateare not populated.
Submitting Python
Section titled “Submitting Python”Python code goes through the standard extraction path: the kernel exec()s
it, pulls the Qiskit QuantumCircuit (search order qiskit → cirq → cudaq),
and calls target.submit(circuit, shots=shots). Translation to the
target’s native format relies on the azure-quantum SDK’s framework plugins
— install the matching extra (e.g. pip install "azure-quantum[qiskit]")
in the kernel environment.
# Submitted as hardware_submit code with provider "azure",# backend e.g. "ionq.simulator" — illustrative, not replay-tested.from qiskit import QuantumCircuit
qc = QuantumCircuit(2, 2)qc.h(0)qc.cx(0, 1)qc.measure([0, 1], [0, 1])Submitting Q#
Section titled “Submitting Q#”Q# source never runs as Python — it is compiled to QIR via the Q#
adapter and the resulting QIR program object is what target.submit
receives. Profile selection is automatic:
| Backend name contains | QIR target profile |
|---|---|
quantinuum (case-insensitive) | Adaptive_RI — mid-circuit measurement + classical feedback |
| anything else | Base |
{ "type": "hardware_submit", "provider": "azure", "backend": "quantinuum.sim.h1-1e", "shots": 500, "code": "operation Main() : Result[] {\n use qs = Qubit[2];\n H(qs[0]);\n CNOT(qs[0], qs[1]);\n return [M(qs[0]), M(qs[1])];\n}\n", "language": "qsharp"}[ { "type": "hardware_job_submitted", "job": { "id": "8f4b8f6e-1c2d-4e5f-9a0b-3c4d5e6f7a8b", "provider": "azure", "backend": "quantinuum.sim.h1-1e", "status": "queued", "queue_position": null, "shots": 500, "submitted_at": "2026-06-10T12:00:00.000000+00:00", "error": null } }]The usual Q# entry-point rules
apply (Main(), else the last zero-parameter operation). A program that
compiles locally under the Unrestricted profile can still fail QIR
compilation under Base — surfaced in the error envelope.
Results coercion
Section titled “Results coercion”Providers behind Azure disagree about result shape, so the kernel coerces
everything into integer counts before hardware_result.data.measurements:
| Provider returns | Coercion |
|---|---|
| Integer counts (Quantinuum style) | Passed through. |
| Float distribution — all values in [0, 1] summing to ~1.0 (±0.01) | Treated as probabilities, scaled by the shot count (IonQ style; includes the deterministic {"0": 1.0} case). |
| Other floats | Rounded to the nearest integer (counts serialized as floats). |
Array-style keys — [0, 1], (1, 0), nested | Normalized element-wise to "01"-style strings. Plain string/int keys pass through verbatim (IonQ integer state keys are legitimate). |
| Two keys normalizing to the same state | Counts summed, not last-wins. |
| Anything unrecognizable (empty dict, negative values, malformed keys) | data.error with a truncated raw preview — never a silent empty success. |
While the job is pending, hardware_results returns
{"status": "running", "message": ...} — keep polling.
Testing tips
Section titled “Testing tips”ionq.simulator— IonQ’s cloud simulator, free, the cheapest way to prove the whole pipeline end-to-end.quantinuum.sim.h1-1sc— Quantinuum’s syntax checker: validates compilation/submission for free but returns no meaningful counts.- Quantinuum emulator targets (e.g.
quantinuum.sim.h1-1e) consume workspace credit but model real-device noise. - Start with low
shotsand confirm the coercedmeasurementsshape before burning hardware credit.
Caveats
Section titled “Caveats”- The job id is Nuclei’s, not Azure’s. Handles carry a locally generated UUID; the Azure portal shows Azure’s own id — cross-referencing is manual.
- Restart semantics: kernel restart turns in-flight Azure jobs
stale; results are then unrecoverable through Nuclei (the job itself survives in the Azure portal). Details. - No queue positions: Azure doesn’t expose one, so
hardware_statusreportsqueue_position: -1(“unknown”) for pending jobs. - Cancellation maps to
status: "failed"like every provider — there is nocancelledwire status.