microsoft/qdk

Public

mirrored fromhttps://github.com/microsoft/qdkAvailable

CodeCommitsIssuesPull requestsActionsInsightsSecurity
iadavis/pipeline-issue-debugging

Branches

Tags

  • No tags available.
0Branches0Tags
Go to file
Add file
Code

Clone

HTTPS

Download ZIP

samples/python_interop/submit_qiskit_circuit_to_azure.ipynb

298lines · modecode

1{
2 "cells": [
3 {
4 "cell_type": "markdown",
5 "id": "90f546a9",
6 "metadata": {},
7 "source": [
8 "# Submitting Qiskit Circuits to Azure Quantum with the QDK\n",
9 "\n",
10 "This notebook demonstrates two ways to run Qiskit `QuantumCircuit` jobs on Azure Quantum using the QDK: (A) direct submission via `AzureQuantumProvider` for a streamlined workflow, and (B) an explicit OpenQASM 3 → QIR compilation path for transparency and artifact inspection. It also shows how to handle parameterized circuits by binding parameters prior to execution."
11 ]
12 },
13 {
14 "cell_type": "markdown",
15 "id": "2b838c23",
16 "metadata": {},
17 "source": [
18 "This workflow demonstrates two methods of submission:\n",
19 "\n",
20 "### A. Direct submission via `AzureQuantumProvider` (recommended when available)\n",
21 "1. Build (or load) a Qiskit `QuantumCircuit`.\n",
22 "2. Reference an existing Azure Quantum workspace with `qdk.azure.Workspace`.\n",
23 "3. Instantiate `AzureQuantumProvider(workspace)` and pick a backend (`provider.get_backend(<target_name>)`).\n",
24 "4. Call `backend.run(circuit, shots, job_name=...)` and fetch results (`job.result().get_counts(circuit)`).\n",
25 "\n",
26 "### B. Submit via OpenQASM compilation (explicit OpenQASM → QIR → submit)\n",
27 "1. Build (or load) a Qiskit `QuantumCircuit`.\n",
28 "2. Convert it to OpenQASM 3 text (`qiskit.qasm3.dumps`).\n",
29 "3. Compile the OpenQASM 3 source to QIR with `qdk.openqasm.compile` (choose a `TargetProfile`).\n",
30 "4. Reference an existing Azure Quantum workspace with `qdk.azure.Workspace`.\n",
31 "5. Select a target (e.g. a simulator such as `rigetti.sim.qvm`).\n",
32 "6. Submit the QIR payload (`target.submit(qir, job_name, shots)`), then retrieve results (`job.get_results()`)."
33 ]
34 },
35 {
36 "cell_type": "markdown",
37 "id": "004e5982",
38 "metadata": {},
39 "source": [
40 "## Prerequisites\n",
41 "\n",
42 "This notebook assumes the `qdk`, Azure Quantum integration, and Qiskit packages are installed. You can install everything (including the Azure + Qiskit extras) with:"
43 ]
44 },
45 {
46 "cell_type": "code",
47 "execution_count": null,
48 "id": "dfa160e8",
49 "metadata": {},
50 "outputs": [],
51 "source": [
52 "%pip install \"qdk[azure,qiskit]\""
53 ]
54 },
55 {
56 "cell_type": "markdown",
57 "id": "b7f37bcd",
58 "metadata": {},
59 "source": [
60 "This installs:\n",
61 "- The base qdk package (compiler, OpenQASM/QIR tooling)\n",
62 "- Azure Quantum client dependencies for submission\n",
63 "- Qiskit for circuit construction\n",
64 "\n",
65 "After installing, restart the notebook kernel if it was already running. You can verify installation with:"
66 ]
67 },
68 {
69 "cell_type": "code",
70 "execution_count": null,
71 "id": "f7446ed1",
72 "metadata": {},
73 "outputs": [],
74 "source": [
75 "import qiskit, qdk, qdk.azure # should import without errors"
76 ]
77 },
78 {
79 "cell_type": "markdown",
80 "id": "4f761649",
81 "metadata": {},
82 "source": [
83 "## Submitting a simple Qiskit circuit\n",
84 "\n",
85 "We start with a minimal circuit that prepares single-qubit superpositions on two qubits and measures them. After constructing the circuit we’ll submit it to an Azure Quantum target."
86 ]
87 },
88 {
89 "cell_type": "code",
90 "execution_count": null,
91 "id": "e91dd2d7",
92 "metadata": {},
93 "outputs": [],
94 "source": [
95 "from qiskit import QuantumCircuit\n",
96 "\n",
97 "circuit = QuantumCircuit(2, 2)\n",
98 "\n",
99 "circuit.h(0)\n",
100 "circuit.measure(0, 0)\n",
101 "\n",
102 "circuit.h(1)\n",
103 "circuit.measure(1, 1)\n",
104 "\n",
105 "circuit.draw(output=\"text\")"
106 ]
107 },
108 {
109 "cell_type": "markdown",
110 "id": "efd50528",
111 "metadata": {},
112 "source": [
113 "## Configure Azure Quantum workspace connection\n",
114 "\n",
115 "To connect to an Azure workspace replace the following variables with your own values."
116 ]
117 },
118 {
119 "cell_type": "code",
120 "execution_count": null,
121 "id": "54206752",
122 "metadata": {},
123 "outputs": [],
124 "source": [
125 "subscription_id = 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx'\n",
126 "resource_group = 'myresourcegroup'\n",
127 "workspace_name = 'myworkspace'\n",
128 "location = 'westus'"
129 ]
130 },
131 {
132 "cell_type": "markdown",
133 "id": "cdae59f7",
134 "metadata": {},
135 "source": [
136 "### Approach A: Using Azure Quantum Provider\n",
137 "\n",
138 "Here we use the recommended submission method with `AzureQuantumProvider` to submit the Qiskit circuit straight to an Azure Quantum backend. This avoids having to explicitly do QASM translation or QIR compilation steps."
139 ]
140 },
141 {
142 "cell_type": "code",
143 "execution_count": null,
144 "id": "d9a0f59b",
145 "metadata": {},
146 "outputs": [],
147 "source": [
148 "from qdk.azure import Workspace\n",
149 "from qdk.azure.qiskit import AzureQuantumProvider\n",
150 "\n",
151 "def submit_qiskit_circuit_to_azure_provider(circuit, target_name, name, shots=100):\n",
152 "\n",
153 " workspace = Workspace(\n",
154 " subscription_id=subscription_id,\n",
155 " resource_group=resource_group,\n",
156 " name=workspace_name,\n",
157 " location=location,\n",
158 " )\n",
159 "\n",
160 " provider = AzureQuantumProvider(workspace)\n",
161 " backend = provider.get_backend(target_name)\n",
162 " job = backend.run(circuit, shots, job_name=name)\n",
163 " return job.result().get_counts(circuit)\n",
164 "\n",
165 "provider_counts = submit_qiskit_circuit_to_azure_provider(circuit, \"rigetti.sim.qvm\", \"qiskit-provider-job\")\n",
166 "print(provider_counts)"
167 ]
168 },
169 {
170 "cell_type": "markdown",
171 "id": "fbf60412",
172 "metadata": {},
173 "source": [
174 "### Approach B: Submit via OpenQASM compilation\n",
175 "\n",
176 "Below we show the longer path that exposes intermediate artifacts. This is useful if you want to inspect or transform OpenQASM/QIR, or integrate with tooling that consumes QIR directly.\n"
177 ]
178 },
179 {
180 "cell_type": "code",
181 "execution_count": null,
182 "id": "ee47d6f6",
183 "metadata": {},
184 "outputs": [],
185 "source": [
186 "from qiskit import qasm3\n",
187 "from qdk.openqasm import compile\n",
188 "from qdk import TargetProfile\n",
189 "\n",
190 "def submit_qiskit_circuit_to_azure_via_qasm(circuit, target_name, name, shots=100):\n",
191 " qasm3_str = qasm3.dumps(circuit)\n",
192 " qir = compile(qasm3_str, target_profile=TargetProfile.Base)\n",
193 "\n",
194 " workspace = Workspace(\n",
195 " subscription_id=subscription_id,\n",
196 " resource_group=resource_group,\n",
197 " name=workspace_name,\n",
198 " location=location,\n",
199 " )\n",
200 " target = workspace.get_targets(target_name)\n",
201 " job = target.submit(qir, name, shots=shots)\n",
202 " return job.get_results()\n",
203 "\n",
204 "results = submit_qiskit_circuit_to_azure_via_qasm(circuit, \"rigetti.sim.qvm\", \"qiskit-via-qasm-job\")\n",
205 "print(results)"
206 ]
207 },
208 {
209 "cell_type": "markdown",
210 "id": "9c84df75",
211 "metadata": {},
212 "source": [
213 "## Parameterized Qiskit circuits\n",
214 "\n",
215 "Many algorithms use symbolic parameters. Before submitting to azure (or before compiling to QIR), all circuit parameters must be bound to numeric values. Below we build a simple entangling ladder, apply a rotation parameterized by `θ` across all qubits, then uncompute the entanglement and measure the first qubit."
216 ]
217 },
218 {
219 "cell_type": "code",
220 "execution_count": null,
221 "id": "5d766661",
222 "metadata": {},
223 "outputs": [],
224 "source": [
225 "from qiskit import QuantumCircuit\n",
226 "from qiskit.circuit import Parameter\n",
227 "\n",
228 "def get_parameterized_circuit(n = 5) -> QuantumCircuit:\n",
229 " theta = Parameter(\"θ\")\n",
230 " qc = QuantumCircuit(n, 1)\n",
231 " qc.h(0)\n",
232 " for i in range(n - 1):\n",
233 " qc.cx(i, i + 1)\n",
234 " qc.rz(theta, range(n))\n",
235 "\n",
236 " for i in reversed(range(n - 1)):\n",
237 " qc.cx(i, i + 1)\n",
238 " qc.h(0)\n",
239 " qc.measure(0, 0)\n",
240 " return qc\n",
241 "\n",
242 "# Build the symbolic (parameterized) circuit\n",
243 "parameterized_circuit = get_parameterized_circuit()\n",
244 "\n",
245 "# Bind θ to a numeric value, then visualize the bound circuit\n",
246 "bound_circuit = parameterized_circuit.assign_parameters({\"θ\": 0.5})\n",
247 "\n",
248 "bound_circuit.draw(output=\"text\")"
249 ]
250 },
251 {
252 "cell_type": "markdown",
253 "id": "ee4d57b4",
254 "metadata": {},
255 "source": [
256 "## Submitting a bound parameterized circuit\n",
257 "\n",
258 "Here we submit the `bound_circuit` from above using the recommended `AzureQuantumProvider` approach. The printed result shows the measurement counts. Change the value of `θ` (or loop over several values) to explore how the outcome distribution varies."
259 ]
260 },
261 {
262 "cell_type": "code",
263 "execution_count": null,
264 "id": "d9bb3eb0",
265 "metadata": {},
266 "outputs": [],
267 "source": [
268 "results = submit_qiskit_circuit_to_azure_provider(\n",
269 " bound_circuit,\n",
270 " \"rigetti.sim.qvm\",\n",
271 " \"qiskit-parameterized-job\"\n",
272 ")\n",
273 "print(results)"
274 ]
275 }
276 ],
277 "metadata": {
278 "kernelspec": {
279 "display_name": ".venv",
280 "language": "python",
281 "name": "python3"
282 },
283 "language_info": {
284 "codemirror_mode": {
285 "name": "ipython",
286 "version": 3
287 },
288 "file_extension": ".py",
289 "mimetype": "text/x-python",
290 "name": "python",
291 "nbconvert_exporter": "python",
292 "pygments_lexer": "ipython3",
293 "version": "3.13.9"
294 }
295 },
296 "nbformat": 4,
297 "nbformat_minor": 5
298}
299