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

source/pip/tests-integration/devices/test_atom_reorder.py

672lines · modecode

1# Copyright (c) Microsoft Corporation.
2# Licensed under the MIT License.
3
4import pytest
5from expecttest import assert_expected_inline
6
7import qsharp
8from qsharp._device._atom._reorder import Reorder
9from qsharp._device._atom import NeutralAtomDevice
10from .validation import PerQubitOrdering, check_qubit_ordering_unchanged
11
12try:
13 import pyqir
14
15 PYQIR_AVAILABLE = True
16except ImportError:
17 PYQIR_AVAILABLE = False
18
19SKIP_REASON = "PyQIR is not available"
20
21
22@pytest.mark.skipif(not PYQIR_AVAILABLE, reason=SKIP_REASON)
23def test_reorder_no_changes_to_simple_ordered_program() -> None:
24 qir = qsharp.compile(
25 """
26 {
27 use (q1, q2) = (Qubit(), Qubit());
28 SX(q1);
29 CZ(q1, q2);
30 (MResetZ(q1), MResetZ(q2))
31 }
32 """
33 )
34
35 module = pyqir.Module.from_ir(pyqir.Context(), str(qir))
36 before = PerQubitOrdering()
37 before.run(module)
38 Reorder(NeutralAtomDevice()).run(module)
39 after = PerQubitOrdering()
40 after.run(module)
41 check_qubit_ordering_unchanged(after, before)
42
43 assert_expected_inline(
44 str(module),
45 """\
46
47%Qubit = type opaque
48%Result = type opaque
49
50@empty_tag = internal constant [1 x i8] zeroinitializer
51@0 = internal constant [6 x i8] c"0_t0r\\00"
52@1 = internal constant [6 x i8] c"1_t1r\\00"
53
54define i64 @ENTRYPOINT__main() #0 {
55block_0:
56 call void @__quantum__rt__initialize(i8* null)
57 call void @__quantum__qis__sx__body(%Qubit* null)
58 call void @__quantum__qis__cz__body(%Qubit* null, %Qubit* inttoptr (i64 1 to %Qubit*))
59 call void @__quantum__qis__mresetz__body(%Qubit* null, %Result* null)
60 call void @__quantum__qis__mresetz__body(%Qubit* inttoptr (i64 1 to %Qubit*), %Result* inttoptr (i64 1 to %Result*))
61 call void @__quantum__rt__tuple_record_output(i64 2, i8* getelementptr inbounds ([1 x i8], [1 x i8]* @empty_tag, i64 0, i64 0))
62 call void @__quantum__rt__result_record_output(%Result* null, i8* getelementptr inbounds ([6 x i8], [6 x i8]* @0, i64 0, i64 0))
63 call void @__quantum__rt__result_record_output(%Result* inttoptr (i64 1 to %Result*), i8* getelementptr inbounds ([6 x i8], [6 x i8]* @1, i64 0, i64 0))
64 ret i64 0
65}
66
67declare void @__quantum__rt__initialize(i8*)
68
69declare void @__quantum__qis__sx__body(%Qubit*)
70
71declare void @__quantum__qis__cz__body(%Qubit*, %Qubit*)
72
73declare void @__quantum__qis__mresetz__body(%Qubit*, %Result*) #1
74
75declare void @__quantum__rt__tuple_record_output(i64, i8*)
76
77declare void @__quantum__rt__result_record_output(%Result*, i8*)
78
79attributes #0 = { "entry_point" "output_labeling_schema" "qir_profiles"="adaptive_profile" "required_num_qubits"="2" "required_num_results"="2" }
80attributes #1 = { "irreversible" }
81
82!llvm.module.flags = !{!0, !1, !2, !3, !4, !6}
83
84!0 = !{i32 1, !"qir_major_version", i32 1}
85!1 = !{i32 7, !"qir_minor_version", i32 0}
86!2 = !{i32 1, !"dynamic_qubit_management", i1 false}
87!3 = !{i32 1, !"dynamic_result_management", i1 false}
88!4 = !{i32 5, !"int_computations", !5}
89!5 = !{!"i64"}
90!6 = !{i32 5, !"float_computations", !7}
91!7 = !{!"double"}
92""",
93 )
94
95
96@pytest.mark.skipif(not PYQIR_AVAILABLE, reason=SKIP_REASON)
97def test_reorder_groups_matching_sequential_gates_into_same_step() -> None:
98 qir = qsharp.compile(
99 """
100 {
101 use (q1, q2, q3, q4) = (Qubit(), Qubit(), Qubit(), Qubit());
102 SX(q1);
103 CZ(q1, q2);
104 let (r1, r2) = (MResetZ(q1), MResetZ(q2));
105 SX(q3);
106 CZ(q3, q4);
107 let (r3, r4) = (MResetZ(q3), MResetZ(q4));
108 (r1, r2, r3, r4)
109 }
110 """
111 )
112
113 module = pyqir.Module.from_ir(pyqir.Context(), str(qir))
114 before = PerQubitOrdering()
115 before.run(module)
116 Reorder(NeutralAtomDevice()).run(module)
117 after = PerQubitOrdering()
118 after.run(module)
119 check_qubit_ordering_unchanged(after, before)
120
121 assert_expected_inline(
122 str(module),
123 """\
124
125%Qubit = type opaque
126%Result = type opaque
127
128@empty_tag = internal constant [1 x i8] zeroinitializer
129@0 = internal constant [6 x i8] c"0_t0r\\00"
130@1 = internal constant [6 x i8] c"1_t1r\\00"
131@2 = internal constant [6 x i8] c"2_t2r\\00"
132@3 = internal constant [6 x i8] c"3_t3r\\00"
133
134define i64 @ENTRYPOINT__main() #0 {
135block_0:
136 call void @__quantum__rt__initialize(i8* null)
137 call void @__quantum__qis__sx__body(%Qubit* null)
138 call void @__quantum__qis__sx__body(%Qubit* inttoptr (i64 2 to %Qubit*))
139 call void @__quantum__qis__cz__body(%Qubit* null, %Qubit* inttoptr (i64 1 to %Qubit*))
140 call void @__quantum__qis__cz__body(%Qubit* inttoptr (i64 2 to %Qubit*), %Qubit* inttoptr (i64 3 to %Qubit*))
141 call void @__quantum__qis__mresetz__body(%Qubit* null, %Result* null)
142 call void @__quantum__qis__mresetz__body(%Qubit* inttoptr (i64 1 to %Qubit*), %Result* inttoptr (i64 1 to %Result*))
143 call void @__quantum__qis__mresetz__body(%Qubit* inttoptr (i64 2 to %Qubit*), %Result* inttoptr (i64 2 to %Result*))
144 call void @__quantum__qis__mresetz__body(%Qubit* inttoptr (i64 3 to %Qubit*), %Result* inttoptr (i64 3 to %Result*))
145 call void @__quantum__rt__tuple_record_output(i64 4, i8* getelementptr inbounds ([1 x i8], [1 x i8]* @empty_tag, i64 0, i64 0))
146 call void @__quantum__rt__result_record_output(%Result* null, i8* getelementptr inbounds ([6 x i8], [6 x i8]* @0, i64 0, i64 0))
147 call void @__quantum__rt__result_record_output(%Result* inttoptr (i64 1 to %Result*), i8* getelementptr inbounds ([6 x i8], [6 x i8]* @1, i64 0, i64 0))
148 call void @__quantum__rt__result_record_output(%Result* inttoptr (i64 2 to %Result*), i8* getelementptr inbounds ([6 x i8], [6 x i8]* @2, i64 0, i64 0))
149 call void @__quantum__rt__result_record_output(%Result* inttoptr (i64 3 to %Result*), i8* getelementptr inbounds ([6 x i8], [6 x i8]* @3, i64 0, i64 0))
150 ret i64 0
151}
152
153declare void @__quantum__rt__initialize(i8*)
154
155declare void @__quantum__qis__sx__body(%Qubit*)
156
157declare void @__quantum__qis__cz__body(%Qubit*, %Qubit*)
158
159declare void @__quantum__qis__mresetz__body(%Qubit*, %Result*) #1
160
161declare void @__quantum__rt__tuple_record_output(i64, i8*)
162
163declare void @__quantum__rt__result_record_output(%Result*, i8*)
164
165attributes #0 = { "entry_point" "output_labeling_schema" "qir_profiles"="adaptive_profile" "required_num_qubits"="4" "required_num_results"="4" }
166attributes #1 = { "irreversible" }
167
168!llvm.module.flags = !{!0, !1, !2, !3, !4, !6}
169
170!0 = !{i32 1, !"qir_major_version", i32 1}
171!1 = !{i32 7, !"qir_minor_version", i32 0}
172!2 = !{i32 1, !"dynamic_qubit_management", i1 false}
173!3 = !{i32 1, !"dynamic_result_management", i1 false}
174!4 = !{i32 5, !"int_computations", !5}
175!5 = !{!"i64"}
176!6 = !{i32 5, !"float_computations", !7}
177!7 = !{!"double"}
178""",
179 )
180
181
182@pytest.mark.skipif(not PYQIR_AVAILABLE, reason=SKIP_REASON)
183def test_reorder_moves_gates_past_measurements_that_overlap_qubit_and_result_ids() -> (
184 None
185):
186 qir = qsharp.compile(
187 """
188 {
189 use (q1, q2) = (Qubit(), Qubit());
190 SX(q2);
191 let r2 = MResetZ(q2);
192 SX(q1);
193 let r1 = MResetZ(q1);
194 (r1, r2)
195 }
196 """
197 )
198
199 module = pyqir.Module.from_ir(pyqir.Context(), str(qir))
200 before = PerQubitOrdering()
201 before.run(module)
202 Reorder(NeutralAtomDevice()).run(module)
203 after = PerQubitOrdering()
204 after.run(module)
205 check_qubit_ordering_unchanged(after, before)
206
207 assert_expected_inline(
208 str(module),
209 """\
210
211%Qubit = type opaque
212%Result = type opaque
213
214@empty_tag = internal constant [1 x i8] zeroinitializer
215@0 = internal constant [6 x i8] c"0_t0r\\00"
216@1 = internal constant [6 x i8] c"1_t1r\\00"
217
218define i64 @ENTRYPOINT__main() #0 {
219block_0:
220 call void @__quantum__rt__initialize(i8* null)
221 call void @__quantum__qis__sx__body(%Qubit* null)
222 call void @__quantum__qis__sx__body(%Qubit* inttoptr (i64 1 to %Qubit*))
223 call void @__quantum__qis__mresetz__body(%Qubit* null, %Result* inttoptr (i64 1 to %Result*))
224 call void @__quantum__qis__mresetz__body(%Qubit* inttoptr (i64 1 to %Qubit*), %Result* null)
225 call void @__quantum__rt__tuple_record_output(i64 2, i8* getelementptr inbounds ([1 x i8], [1 x i8]* @empty_tag, i64 0, i64 0))
226 call void @__quantum__rt__result_record_output(%Result* inttoptr (i64 1 to %Result*), i8* getelementptr inbounds ([6 x i8], [6 x i8]* @0, i64 0, i64 0))
227 call void @__quantum__rt__result_record_output(%Result* null, i8* getelementptr inbounds ([6 x i8], [6 x i8]* @1, i64 0, i64 0))
228 ret i64 0
229}
230
231declare void @__quantum__rt__initialize(i8*)
232
233declare void @__quantum__qis__sx__body(%Qubit*)
234
235declare void @__quantum__qis__mresetz__body(%Qubit*, %Result*) #1
236
237declare void @__quantum__rt__tuple_record_output(i64, i8*)
238
239declare void @__quantum__rt__result_record_output(%Result*, i8*)
240
241attributes #0 = { "entry_point" "output_labeling_schema" "qir_profiles"="adaptive_profile" "required_num_qubits"="2" "required_num_results"="2" }
242attributes #1 = { "irreversible" }
243
244!llvm.module.flags = !{!0, !1, !2, !3, !4, !6}
245
246!0 = !{i32 1, !"qir_major_version", i32 1}
247!1 = !{i32 7, !"qir_minor_version", i32 0}
248!2 = !{i32 1, !"dynamic_qubit_management", i1 false}
249!3 = !{i32 1, !"dynamic_result_management", i1 false}
250!4 = !{i32 5, !"int_computations", !5}
251!5 = !{!"i64"}
252!6 = !{i32 5, !"float_computations", !7}
253!7 = !{!"double"}
254""",
255 )
256
257
258@pytest.mark.skipif(not PYQIR_AVAILABLE, reason=SKIP_REASON)
259def test_reorder_keeps_dependent_gates_in_order() -> None:
260 qir = qsharp.compile(
261 """
262 {
263 use (q1, q2) = (Qubit(), Qubit());
264 SX(q1);
265 CZ(q1, q2);
266 SX(q1);
267 CZ(q1, q2);
268 (MResetZ(q1), MResetZ(q2))
269 }
270 """
271 )
272
273 module = pyqir.Module.from_ir(pyqir.Context(), str(qir))
274 before = PerQubitOrdering()
275 before.run(module)
276 Reorder(NeutralAtomDevice()).run(module)
277 after = PerQubitOrdering()
278 after.run(module)
279 check_qubit_ordering_unchanged(after, before)
280
281 assert_expected_inline(
282 str(module),
283 """\
284
285%Qubit = type opaque
286%Result = type opaque
287
288@empty_tag = internal constant [1 x i8] zeroinitializer
289@0 = internal constant [6 x i8] c"0_t0r\\00"
290@1 = internal constant [6 x i8] c"1_t1r\\00"
291
292define i64 @ENTRYPOINT__main() #0 {
293block_0:
294 call void @__quantum__rt__initialize(i8* null)
295 call void @__quantum__qis__sx__body(%Qubit* null)
296 call void @__quantum__qis__cz__body(%Qubit* null, %Qubit* inttoptr (i64 1 to %Qubit*))
297 call void @__quantum__qis__sx__body(%Qubit* null)
298 call void @__quantum__qis__cz__body(%Qubit* null, %Qubit* inttoptr (i64 1 to %Qubit*))
299 call void @__quantum__qis__mresetz__body(%Qubit* null, %Result* null)
300 call void @__quantum__qis__mresetz__body(%Qubit* inttoptr (i64 1 to %Qubit*), %Result* inttoptr (i64 1 to %Result*))
301 call void @__quantum__rt__tuple_record_output(i64 2, i8* getelementptr inbounds ([1 x i8], [1 x i8]* @empty_tag, i64 0, i64 0))
302 call void @__quantum__rt__result_record_output(%Result* null, i8* getelementptr inbounds ([6 x i8], [6 x i8]* @0, i64 0, i64 0))
303 call void @__quantum__rt__result_record_output(%Result* inttoptr (i64 1 to %Result*), i8* getelementptr inbounds ([6 x i8], [6 x i8]* @1, i64 0, i64 0))
304 ret i64 0
305}
306
307declare void @__quantum__rt__initialize(i8*)
308
309declare void @__quantum__qis__sx__body(%Qubit*)
310
311declare void @__quantum__qis__cz__body(%Qubit*, %Qubit*)
312
313declare void @__quantum__qis__mresetz__body(%Qubit*, %Result*) #1
314
315declare void @__quantum__rt__tuple_record_output(i64, i8*)
316
317declare void @__quantum__rt__result_record_output(%Result*, i8*)
318
319attributes #0 = { "entry_point" "output_labeling_schema" "qir_profiles"="adaptive_profile" "required_num_qubits"="2" "required_num_results"="2" }
320attributes #1 = { "irreversible" }
321
322!llvm.module.flags = !{!0, !1, !2, !3, !4, !6}
323
324!0 = !{i32 1, !"qir_major_version", i32 1}
325!1 = !{i32 7, !"qir_minor_version", i32 0}
326!2 = !{i32 1, !"dynamic_qubit_management", i1 false}
327!3 = !{i32 1, !"dynamic_result_management", i1 false}
328!4 = !{i32 5, !"int_computations", !5}
329!5 = !{!"i64"}
330!6 = !{i32 5, !"float_computations", !7}
331!7 = !{!"double"}
332""",
333 )
334
335
336@pytest.mark.skipif(not PYQIR_AVAILABLE, reason=SKIP_REASON)
337def test_reorder_sorts_gates_by_qubit_id() -> None:
338 qir = qsharp.compile(
339 """
340 {
341 use qs = Qubit[5];
342 SX(qs[3]);
343 SX(qs[1]);
344 SX(qs[4]);
345 SX(qs[0]);
346 SX(qs[2]);
347 let r3 = MResetZ(qs[3]);
348 let r1 = MResetZ(qs[1]);
349 let r4 = MResetZ(qs[4]);
350 let r0 = MResetZ(qs[0]);
351 let r2 = MResetZ(qs[2]);
352 [r0, r1, r2, r3, r4]
353 }
354 """
355 )
356
357 module = pyqir.Module.from_ir(pyqir.Context(), str(qir))
358 before = PerQubitOrdering()
359 before.run(module)
360 Reorder(NeutralAtomDevice()).run(module)
361 after = PerQubitOrdering()
362 after.run(module)
363 check_qubit_ordering_unchanged(after, before)
364
365 assert_expected_inline(
366 str(module),
367 """\
368
369%Qubit = type opaque
370%Result = type opaque
371
372@empty_tag = internal constant [1 x i8] zeroinitializer
373@0 = internal constant [6 x i8] c"0_a0r\\00"
374@1 = internal constant [6 x i8] c"1_a1r\\00"
375@2 = internal constant [6 x i8] c"2_a2r\\00"
376@3 = internal constant [6 x i8] c"3_a3r\\00"
377@4 = internal constant [6 x i8] c"4_a4r\\00"
378
379define i64 @ENTRYPOINT__main() #0 {
380block_0:
381 call void @__quantum__rt__initialize(i8* null)
382 call void @__quantum__qis__sx__body(%Qubit* null)
383 call void @__quantum__qis__sx__body(%Qubit* inttoptr (i64 1 to %Qubit*))
384 call void @__quantum__qis__sx__body(%Qubit* inttoptr (i64 2 to %Qubit*))
385 call void @__quantum__qis__sx__body(%Qubit* inttoptr (i64 3 to %Qubit*))
386 call void @__quantum__qis__sx__body(%Qubit* inttoptr (i64 4 to %Qubit*))
387 call void @__quantum__qis__mresetz__body(%Qubit* null, %Result* inttoptr (i64 3 to %Result*))
388 call void @__quantum__qis__mresetz__body(%Qubit* inttoptr (i64 1 to %Qubit*), %Result* inttoptr (i64 1 to %Result*))
389 call void @__quantum__qis__mresetz__body(%Qubit* inttoptr (i64 2 to %Qubit*), %Result* inttoptr (i64 4 to %Result*))
390 call void @__quantum__qis__mresetz__body(%Qubit* inttoptr (i64 3 to %Qubit*), %Result* null)
391 call void @__quantum__qis__mresetz__body(%Qubit* inttoptr (i64 4 to %Qubit*), %Result* inttoptr (i64 2 to %Result*))
392 call void @__quantum__rt__array_record_output(i64 5, i8* getelementptr inbounds ([1 x i8], [1 x i8]* @empty_tag, i64 0, i64 0))
393 call void @__quantum__rt__result_record_output(%Result* inttoptr (i64 3 to %Result*), i8* getelementptr inbounds ([6 x i8], [6 x i8]* @0, i64 0, i64 0))
394 call void @__quantum__rt__result_record_output(%Result* inttoptr (i64 1 to %Result*), i8* getelementptr inbounds ([6 x i8], [6 x i8]* @1, i64 0, i64 0))
395 call void @__quantum__rt__result_record_output(%Result* inttoptr (i64 4 to %Result*), i8* getelementptr inbounds ([6 x i8], [6 x i8]* @2, i64 0, i64 0))
396 call void @__quantum__rt__result_record_output(%Result* null, i8* getelementptr inbounds ([6 x i8], [6 x i8]* @3, i64 0, i64 0))
397 call void @__quantum__rt__result_record_output(%Result* inttoptr (i64 2 to %Result*), i8* getelementptr inbounds ([6 x i8], [6 x i8]* @4, i64 0, i64 0))
398 ret i64 0
399}
400
401declare void @__quantum__rt__initialize(i8*)
402
403declare void @__quantum__qis__sx__body(%Qubit*)
404
405declare void @__quantum__qis__mresetz__body(%Qubit*, %Result*) #1
406
407declare void @__quantum__rt__array_record_output(i64, i8*)
408
409declare void @__quantum__rt__result_record_output(%Result*, i8*)
410
411attributes #0 = { "entry_point" "output_labeling_schema" "qir_profiles"="adaptive_profile" "required_num_qubits"="5" "required_num_results"="5" }
412attributes #1 = { "irreversible" }
413
414!llvm.module.flags = !{!0, !1, !2, !3, !4, !6}
415
416!0 = !{i32 1, !"qir_major_version", i32 1}
417!1 = !{i32 7, !"qir_minor_version", i32 0}
418!2 = !{i32 1, !"dynamic_qubit_management", i1 false}
419!3 = !{i32 1, !"dynamic_result_management", i1 false}
420!4 = !{i32 5, !"int_computations", !5}
421!5 = !{!"i64"}
422!6 = !{i32 5, !"float_computations", !7}
423!7 = !{!"double"}
424""",
425 )
426
427
428@pytest.mark.skipif(not PYQIR_AVAILABLE, reason=SKIP_REASON)
429def test_reorder_sorts_cz_to_end_of_step() -> None:
430 qir = qsharp.compile(
431 """
432 {
433 use qs = Qubit[4];
434 SX(qs[3]);
435 CZ(qs[1], qs[0]);
436 SX(qs[2]);
437 }
438 """
439 )
440
441 module = pyqir.Module.from_ir(pyqir.Context(), str(qir))
442 before = PerQubitOrdering()
443 before.run(module)
444 Reorder(NeutralAtomDevice()).run(module)
445 after = PerQubitOrdering()
446 after.run(module)
447 check_qubit_ordering_unchanged(after, before)
448
449 assert_expected_inline(
450 str(module),
451 """\
452
453%Qubit = type opaque
454
455@empty_tag = internal constant [1 x i8] zeroinitializer
456
457define i64 @ENTRYPOINT__main() #0 {
458block_0:
459 call void @__quantum__rt__initialize(i8* null)
460 call void @__quantum__qis__sx__body(%Qubit* inttoptr (i64 2 to %Qubit*))
461 call void @__quantum__qis__sx__body(%Qubit* inttoptr (i64 3 to %Qubit*))
462 call void @__quantum__qis__cz__body(%Qubit* inttoptr (i64 1 to %Qubit*), %Qubit* null)
463 call void @__quantum__rt__tuple_record_output(i64 0, i8* getelementptr inbounds ([1 x i8], [1 x i8]* @empty_tag, i64 0, i64 0))
464 ret i64 0
465}
466
467declare void @__quantum__rt__initialize(i8*)
468
469declare void @__quantum__qis__sx__body(%Qubit*)
470
471declare void @__quantum__qis__cz__body(%Qubit*, %Qubit*)
472
473declare void @__quantum__rt__tuple_record_output(i64, i8*)
474
475attributes #0 = { "entry_point" "output_labeling_schema" "qir_profiles"="adaptive_profile" "required_num_qubits"="4" "required_num_results"="0" }
476
477!llvm.module.flags = !{!0, !1, !2, !3, !4, !6}
478
479!0 = !{i32 1, !"qir_major_version", i32 1}
480!1 = !{i32 7, !"qir_minor_version", i32 0}
481!2 = !{i32 1, !"dynamic_qubit_management", i1 false}
482!3 = !{i32 1, !"dynamic_result_management", i1 false}
483!4 = !{i32 5, !"int_computations", !5}
484!5 = !{!"i64"}
485!6 = !{i32 5, !"float_computations", !7}
486!7 = !{!"double"}
487""",
488 )
489
490
491@pytest.mark.skipif(not PYQIR_AVAILABLE, reason=SKIP_REASON)
492def test_reorder_respects_read_result_and_classical_compute() -> None:
493 qir = qsharp.compile(
494 """
495 {
496 use (q1, q2) = (Qubit(), Qubit());
497 SX(q1);
498 let r1 = MResetZ(q1);
499 let r2 = MResetZ(q2);
500 let angle = if r1 == One {
501 if r2 == One {
502 SX(q1);
503 0.0
504 } else {
505 Rz(1.0, q1);
506 1.0
507 }
508 } else {
509 if r2 == One {
510 Rz(2.0, q1);
511 2.0
512 } else {
513 Rz(3.0, q1);
514 3.0
515 }
516 };
517 Rz(2.0 * angle, q2);
518 }
519 """
520 )
521
522 module = pyqir.Module.from_ir(pyqir.Context(), str(qir))
523 Reorder(NeutralAtomDevice()).run(module)
524
525 assert_expected_inline(
526 str(module),
527 """\
528
529%Qubit = type opaque
530%Result = type opaque
531
532@empty_tag = internal constant [1 x i8] zeroinitializer
533
534define i64 @ENTRYPOINT__main() #0 {
535block_0:
536 call void @__quantum__rt__initialize(i8* null)
537 call void @__quantum__qis__sx__body(%Qubit* null)
538 call void @__quantum__qis__mresetz__body(%Qubit* null, %Result* null)
539 call void @__quantum__qis__mresetz__body(%Qubit* inttoptr (i64 1 to %Qubit*), %Result* inttoptr (i64 1 to %Result*))
540 %0 = call i1 @__quantum__rt__read_result(%Result* null)
541 br i1 %0, label %block_1, label %block_2
542
543block_1: ; preds = %block_0
544 %1 = call i1 @__quantum__rt__read_result(%Result* inttoptr (i64 1 to %Result*))
545 br i1 %1, label %block_3, label %block_4
546
547block_2: ; preds = %block_0
548 %2 = call i1 @__quantum__rt__read_result(%Result* inttoptr (i64 1 to %Result*))
549 br i1 %2, label %block_5, label %block_6
550
551block_3: ; preds = %block_1
552 call void @__quantum__qis__sx__body(%Qubit* null)
553 br label %block_7
554
555block_4: ; preds = %block_1
556 call void @__quantum__qis__rz__body(double 1.000000e+00, %Qubit* null)
557 br label %block_7
558
559block_5: ; preds = %block_2
560 call void @__quantum__qis__rz__body(double 2.000000e+00, %Qubit* null)
561 br label %block_8
562
563block_6: ; preds = %block_2
564 call void @__quantum__qis__rz__body(double 3.000000e+00, %Qubit* null)
565 br label %block_8
566
567block_7: ; preds = %block_4, %block_3
568 %3 = phi double [ 0.000000e+00, %block_3 ], [ 1.000000e+00, %block_4 ]
569 br label %block_9
570
571block_8: ; preds = %block_6, %block_5
572 %4 = phi double [ 2.000000e+00, %block_5 ], [ 3.000000e+00, %block_6 ]
573 br label %block_9
574
575block_9: ; preds = %block_8, %block_7
576 %5 = phi double [ %3, %block_7 ], [ %4, %block_8 ]
577 %6 = fmul double 2.000000e+00, %5
578 call void @__quantum__qis__rz__body(double %6, %Qubit* inttoptr (i64 1 to %Qubit*))
579 call void @__quantum__rt__tuple_record_output(i64 0, i8* getelementptr inbounds ([1 x i8], [1 x i8]* @empty_tag, i64 0, i64 0))
580 ret i64 0
581}
582
583declare void @__quantum__rt__initialize(i8*)
584
585declare void @__quantum__qis__sx__body(%Qubit*)
586
587declare void @__quantum__qis__mresetz__body(%Qubit*, %Result*) #1
588
589declare i1 @__quantum__rt__read_result(%Result*)
590
591declare void @__quantum__qis__rz__body(double, %Qubit*)
592
593declare void @__quantum__rt__tuple_record_output(i64, i8*)
594
595attributes #0 = { "entry_point" "output_labeling_schema" "qir_profiles"="adaptive_profile" "required_num_qubits"="2" "required_num_results"="2" }
596attributes #1 = { "irreversible" }
597
598!llvm.module.flags = !{!0, !1, !2, !3, !4, !6}
599
600!0 = !{i32 1, !"qir_major_version", i32 1}
601!1 = !{i32 7, !"qir_minor_version", i32 0}
602!2 = !{i32 1, !"dynamic_qubit_management", i1 false}
603!3 = !{i32 1, !"dynamic_result_management", i1 false}
604!4 = !{i32 5, !"int_computations", !5}
605!5 = !{!"i64"}
606!6 = !{i32 5, !"float_computations", !7}
607!7 = !{!"double"}
608""",
609 )
610
611
612@pytest.mark.skipif(not PYQIR_AVAILABLE, reason=SKIP_REASON)
613def test_reorder_preserves_per_qubit_order_on_large_program() -> None:
614 qir = qsharp.compile(
615 """
616 {
617 import Std.Math.PI;
618 operation IsingModel2DEvolution(
619 N1 : Int,
620 N2 : Int,
621 J : Double,
622 g : Double,
623 evolutionTime : Double,
624 numberOfSteps : Int
625 ) : Result[] {
626 use qubits = Qubit[N1 * N2];
627 let qubitsAs2D = Std.Arrays.Chunks(N2, qubits);
628 let dt : Double = evolutionTime / Std.Convert.IntAsDouble(numberOfSteps);
629 let theta_x = - g * dt;
630 let theta_zz = J * dt;
631 for i in 1..numberOfSteps {
632 for q in qubits {
633 Rx(2.0 * theta_x, q);
634 }
635 for row in 0..N1-1 {
636 for col in 0..2..N2-2 {
637 Rzz(2.0 * theta_zz, qubitsAs2D[row][col], qubitsAs2D[row][col + 1]);
638 }
639 for col in 1..2..N2-2 {
640 Rzz(2.0 * theta_zz, qubitsAs2D[row][col], qubitsAs2D[row][col + 1]);
641 }
642 }
643 for col in 0..N2-1 {
644 for row in 0..2..N1-2 {
645 Rzz(2.0 * theta_zz, qubitsAs2D[row][col], qubitsAs2D[row + 1][col]);
646 }
647 for row in 1..2..N1-2 {
648 Rzz(2.0 * theta_zz, qubitsAs2D[row][col], qubitsAs2D[row + 1][col]);
649 }
650 }
651 }
652 MResetEachZ(qubits)
653 }
654 IsingModel2DEvolution(
655 10,
656 10,
657 PI() / 2.0,
658 PI() / 2.0,
659 10.0,
660 10
661 )
662 }
663 """
664 )
665
666 module = pyqir.Module.from_ir(pyqir.Context(), str(qir))
667 before = PerQubitOrdering()
668 before.run(module)
669 Reorder(NeutralAtomDevice()).run(module)
670 after = PerQubitOrdering()
671 after.run(module)
672 check_qubit_ordering_unchanged(after, before)
673