microsoft/qdk

Public

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

CodeCommitsIssuesPull requestsActionsInsightsSecurity
billti/qdk_package

Branches

Tags

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

Clone

HTTPS

Download ZIP

source/pip/tests/test_interpreter.py

692lines ยท modecode

1# Copyright (c) Microsoft Corporation.
2# Licensed under the MIT License.
3
4from textwrap import dedent
5from qsharp._native import (
6 Interpreter,
7 Result,
8 Pauli,
9 QSharpError,
10 TargetProfile,
11)
12from qsharp._qsharp import qsharp_value_to_python_value
13import pytest
14
15# Test helpers
16
17
18def check_interpret(source: str, expect: str):
19 e = Interpreter(TargetProfile.Unrestricted)
20 value = qsharp_value_to_python_value(e.interpret(source))
21 assert str(value) == expect
22
23
24def check_invoke(source: str, callable: str, expect: str):
25 e = None
26 f = None
27
28 def _make_callable(callable, namespace, callable_name):
29 nonlocal f
30 f = callable
31
32 e = Interpreter(TargetProfile.Unrestricted, make_callable=_make_callable)
33 e.interpret(source)
34 e.interpret(callable)
35 value = qsharp_value_to_python_value(e.invoke(f))
36 assert str(value) == expect
37
38
39def check_run(entry_expr: str, expect: str):
40 e = Interpreter(TargetProfile.Unrestricted)
41 value = qsharp_value_to_python_value(e.run(entry_expr))
42 assert str(value) == expect
43
44
45def check_circuit(entry_expr: str, expect):
46 e = Interpreter(TargetProfile.Unrestricted)
47 value = e.circuit(entry_expr)
48 assert str(value) == expect
49
50
51def check_qir(source: str, entry_expr, expect):
52 e = Interpreter(TargetProfile.Base)
53 e.interpret(source)
54 value = e.qir(entry_expr)
55 assert str(value) == expect
56
57
58def check_estimate(source: str):
59 e = Interpreter(TargetProfile.Unrestricted)
60 e.estimate("", source)
61
62
63# Tests for the native Q# interpreter class
64
65
66def test_output() -> None:
67 e = Interpreter(TargetProfile.Unrestricted)
68
69 def callback(output):
70 nonlocal called
71 called = True
72 assert output.__repr__() == "Hello, world!"
73
74 called = False
75 value = e.interpret('Message("Hello, world!")', callback)
76 assert called
77
78
79def test_dump_output() -> None:
80 e = Interpreter(TargetProfile.Unrestricted)
81
82 def callback(output):
83 nonlocal called
84 called = True
85 assert output.__repr__() == "STATE:\n|10โŸฉ: 1.0000+0.0000๐‘–"
86
87 called = False
88 value = e.interpret(
89 """
90 use q1 = Qubit();
91 use q2 = Qubit();
92 X(q1);
93 Microsoft.Quantum.Diagnostics.DumpMachine();
94 ResetAll([q1, q2]);
95 """,
96 callback,
97 )
98 assert called
99
100
101def test_quantum_seed() -> None:
102 e = Interpreter(TargetProfile.Unrestricted)
103 e.set_quantum_seed(42)
104 value1 = e.interpret(
105 "{ use qs = Qubit[16]; for q in qs { H(q); }; Microsoft.Quantum.Measurement.MResetEachZ(qs) }"
106 )
107 e = Interpreter(TargetProfile.Unrestricted)
108 e.set_quantum_seed(42)
109 value2 = e.interpret(
110 "{ use qs = Qubit[16]; for q in qs { H(q); }; Microsoft.Quantum.Measurement.MResetEachZ(qs) }"
111 )
112 assert value1 == value2
113
114
115def test_classical_seed() -> None:
116 e = Interpreter(TargetProfile.Unrestricted)
117 e.set_classical_seed(42)
118 value1 = e.interpret(
119 "{ mutable res = []; for _ in 0..15{ set res += [Microsoft.Quantum.Random.DrawRandomInt(0, 100)]; }; res }"
120 )
121 e = Interpreter(TargetProfile.Unrestricted)
122 e.set_classical_seed(42)
123 value2 = e.interpret(
124 "{ mutable res = []; for _ in 0..15{ set res += [Microsoft.Quantum.Random.DrawRandomInt(0, 100)]; }; res }"
125 )
126 assert value1 == value2
127
128
129def test_dump_machine() -> None:
130 e = Interpreter(TargetProfile.Unrestricted)
131
132 def callback(output):
133 assert output.__repr__() == "STATE:\n|10โŸฉ: 1.0000+0.0000๐‘–"
134
135 value = e.interpret(
136 """
137 use q1 = Qubit();
138 use q2 = Qubit();
139 X(q1);
140 Microsoft.Quantum.Diagnostics.DumpMachine();
141 """,
142 callback,
143 )
144 state_dump = e.dump_machine()
145 assert state_dump.qubit_count == 2
146 state_dump = state_dump.get_dict()
147 assert len(state_dump) == 1
148 assert state_dump[2].real == 1.0
149 assert state_dump[2].imag == 0.0
150
151
152def test_error() -> None:
153 e = Interpreter(TargetProfile.Unrestricted)
154
155 with pytest.raises(QSharpError) as excinfo:
156 e.interpret("a864")
157 assert str(excinfo.value).find("name error") != -1
158
159
160def test_multiple_errors() -> None:
161 e = Interpreter(TargetProfile.Unrestricted)
162
163 with pytest.raises(QSharpError) as excinfo:
164 e.interpret("operation Foo() : Unit { Bar(); Baz(); }")
165 assert str(excinfo.value).find("`Bar` not found") != -1
166 assert str(excinfo.value).find("`Baz` not found") != -1
167
168
169def test_multiple_statements() -> None:
170 e = Interpreter(TargetProfile.Unrestricted)
171 value = e.interpret("1; Zero")
172 assert value == Result.Zero
173
174
175def test_value_int() -> None:
176 e = Interpreter(TargetProfile.Unrestricted)
177 value = e.interpret("5")
178 assert value == 5
179
180
181def test_value_double() -> None:
182 e = Interpreter(TargetProfile.Unrestricted)
183 value = e.interpret("3.1")
184 assert value == 3.1
185
186
187def test_value_complex() -> None:
188 e = Interpreter(TargetProfile.Unrestricted)
189 value = e.interpret("new Std.Math.Complex { Real = 2.0, Imag = 3.0 }")
190 assert value == 2 + 3j
191
192
193def test_value_bool() -> None:
194 e = Interpreter(TargetProfile.Unrestricted)
195 value = e.interpret("true")
196 assert value == True
197
198
199def test_value_string() -> None:
200 e = Interpreter(TargetProfile.Unrestricted)
201 value = e.interpret('"hello"')
202 assert value == "hello"
203
204
205def test_value_result() -> None:
206 e = Interpreter(TargetProfile.Unrestricted)
207 value = e.interpret("One")
208 assert value == Result.One
209
210
211def test_value_pauli() -> None:
212 e = Interpreter(TargetProfile.Unrestricted)
213 value = e.interpret("PauliX")
214 assert value == Pauli.X
215
216
217def test_value_tuple() -> None:
218 e = Interpreter(TargetProfile.Unrestricted)
219 value = e.interpret('(1, "hello", One)')
220 assert value == (1, "hello", Result.One)
221
222
223def test_value_unit() -> None:
224 e = Interpreter(TargetProfile.Unrestricted)
225 value = e.interpret("()")
226 assert value is None
227
228
229def test_value_array() -> None:
230 e = Interpreter(TargetProfile.Unrestricted)
231 value = e.interpret("[1, 2, 3]")
232 assert value == [1, 2, 3]
233
234
235def test_value_udt() -> None:
236 udt_def = "struct Data { a: Int, b: Int }"
237 new_udt = "new Data { a = 2, b = 3 }"
238 callable = f"function makeData() : Data {{ {new_udt} }}"
239 entry_expr = f"{{ {udt_def} {new_udt} }}"
240 output = "Data(a=2, b=3)"
241
242 check_interpret(entry_expr, output)
243 check_run(entry_expr, output)
244 check_invoke(udt_def, callable, output)
245 check_circuit(entry_expr, "")
246 check_estimate(entry_expr)
247 with pytest.raises(QSharpError, match="Qsc.CapabilitiesCk.UseOfAdvancedOutput"):
248 check_qir(udt_def + callable, "makeData()", "")
249
250
251def test_value_nested_udts() -> None:
252 udt_def = """
253 struct Data { a: Int, b: MoreData }
254 struct MoreData { c: Int, d: Int }
255 """
256 new_udt = "new Data { a = 2, b = new MoreData { c = 3, d = 4 } }"
257 callable = f"function makeData() : Data {{ {new_udt} }}"
258 entry_expr = f"{{ {udt_def} {new_udt} }}"
259 output = "Data(a=2, b=MoreData(c=3, d=4))"
260
261 check_interpret(entry_expr, output)
262 check_run(entry_expr, output)
263 check_invoke(udt_def, callable, output)
264 check_circuit(entry_expr, "")
265 check_estimate(entry_expr)
266 with pytest.raises(QSharpError, match="Qsc.CapabilitiesCk.UseOfAdvancedOutput"):
267 check_qir(udt_def + callable, "makeData()", "")
268
269
270def test_value_udts_with_complex_field() -> None:
271 udt_def = "struct Data { a: Std.Math.Complex }"
272 new_udt = "new Data { a = new Std.Math.Complex { Real = 2.0, Imag = 3.0 } }"
273 callable = f"function makeData() : Data {{ {new_udt} }}"
274 entry_expr = f"{{ {udt_def} {new_udt} }}"
275 output = "Data(a=(2+3j))"
276
277 check_interpret(entry_expr, output)
278 check_run(entry_expr, output)
279 check_invoke(udt_def, callable, output)
280 check_circuit(entry_expr, "")
281 check_estimate(entry_expr)
282 with pytest.raises(QSharpError, match="Qsc.CapabilitiesCk.UseOfAdvancedOutput"):
283 check_qir(udt_def + callable, "makeData()", "")
284
285
286def test_value_udts_with_array_field() -> None:
287 udt_def = "struct Data { a: Int[] }"
288 new_udt = "new Data { a = [2, 3, 4] }"
289 callable = f"function makeData() : Data {{ {new_udt} }}"
290 entry_expr = f"{{ {udt_def} {new_udt} }}"
291 output = "Data(a=[2, 3, 4])"
292
293 check_interpret(entry_expr, output)
294 check_run(entry_expr, output)
295 check_invoke(udt_def, callable, output)
296 check_circuit(entry_expr, "")
297 check_estimate(entry_expr)
298 with pytest.raises(QSharpError, match="Qsc.CapabilitiesCk.UseOfAdvancedOutput"):
299 check_qir(udt_def + callable, "makeData()", "")
300
301
302def test_value_udts_with_tuple_field() -> None:
303 udt_def = "struct Data { a: (Int, Int, Int) }"
304 new_udt = "new Data { a = (2, 3, 4) }"
305 callable = f"function makeData() : Data {{ {new_udt} }}"
306 entry_expr = f"{{ {udt_def} {new_udt} }}"
307 output = "Data(a=(2, 3, 4))"
308
309 check_interpret(entry_expr, output)
310 check_run(entry_expr, output)
311 check_invoke(udt_def, callable, output)
312 check_circuit(entry_expr, "")
313 check_estimate(entry_expr)
314 with pytest.raises(QSharpError, match="Qsc.CapabilitiesCk.UseOfAdvancedOutput"):
315 check_qir(udt_def + callable, "makeData()", "")
316
317
318def test_value_array_of_udts() -> None:
319 udt_def = "struct Data { a: Int }"
320 new_udt = "[new Data { a = 2 }, new Data { a = 3 }]"
321 callable = f"function makeData() : Data[] {{ {new_udt} }}"
322 entry_expr = f"{{ {udt_def} {new_udt} }}"
323 output = "[Data(a=2), Data(a=3)]"
324
325 check_interpret(entry_expr, output)
326 check_run(entry_expr, output)
327 check_invoke(udt_def, callable, output)
328 check_circuit(entry_expr, "")
329 check_estimate(entry_expr)
330 with pytest.raises(QSharpError, match="Qsc.CapabilitiesCk.UseOfAdvancedOutput"):
331 check_qir(udt_def + callable, "makeData()", "")
332
333
334def test_value_array_of_complex() -> None:
335 new_udt = "[new Std.Math.Complex { Real = 2.0, Imag = 3.0 }]"
336 callable = f"function makeData() : Std.Math.Complex[] {{ {new_udt} }}"
337 entry_expr = f"{{ {new_udt} }}"
338 output = "[(2+3j)]"
339
340 check_interpret(entry_expr, output)
341 check_run(entry_expr, output)
342 check_invoke("", callable, output)
343 check_circuit(entry_expr, "")
344 check_estimate(entry_expr)
345 with pytest.raises(QSharpError, match="Qsc.CapabilitiesCk.UseOfAdvancedOutput"):
346 check_qir(callable, "makeData()", "")
347
348
349def test_value_tuple_of_udts() -> None:
350 udt_def = "struct Data { a: Int }"
351 new_udt = "(new Data { a = 2 }, new Data { a = 3 })"
352 callable = f"function makeData() : (Data, Data) {{ {new_udt} }}"
353 entry_expr = f"{{ {udt_def} {new_udt} }}"
354 output = "(Data(a=2), Data(a=3))"
355
356 check_interpret(entry_expr, output)
357 check_run(entry_expr, output)
358 check_invoke(udt_def, callable, output)
359 check_circuit(entry_expr, "")
360 check_estimate(entry_expr)
361 with pytest.raises(QSharpError, match="Qsc.CapabilitiesCk.UseOfAdvancedOutput"):
362 check_qir(udt_def + callable, "makeData()", "")
363
364
365def test_value_tuple_of_complex() -> None:
366 new_udt = "(new Std.Math.Complex { Real = 2.0, Imag = 3.0 },)"
367 callable = f"function makeData() : (Std.Math.Complex,) {{ {new_udt} }}"
368 entry_expr = f"{{ {new_udt} }}"
369 output = "((2+3j),)"
370
371 check_interpret(entry_expr, output)
372 check_run(entry_expr, output)
373 check_invoke("", callable, output)
374 check_circuit(entry_expr, "")
375 check_estimate(entry_expr)
376 with pytest.raises(QSharpError, match="Qsc.CapabilitiesCk.UseOfAdvancedOutput"):
377 check_qir(callable, "makeData()", "")
378
379
380def test_target_error() -> None:
381 e = Interpreter(TargetProfile.Base)
382 with pytest.raises(QSharpError) as excinfo:
383 e.interpret(
384 "operation Program() : Result { use q = Qubit(); if M(q) == Zero { return Zero } else { return One } }"
385 )
386 assert str(excinfo.value).startswith("Qsc.CapabilitiesCk.UseOfDynamicBool")
387
388
389def test_qirgen_compile_error() -> None:
390 e = Interpreter(TargetProfile.Base)
391 e.interpret("operation Program() : Int { return 0 }")
392 with pytest.raises(QSharpError) as excinfo:
393 e.qir("Foo()")
394 assert str(excinfo.value).startswith("Qsc.Resolve.NotFound")
395
396
397def test_error_spans_from_multiple_lines() -> None:
398 e = Interpreter(TargetProfile.Unrestricted)
399
400 # Qsc.Resolve.Ambiguous is chosen as a test case
401 # because it contains multiple spans which can be from different lines
402 e.interpret("namespace Other { operation DumpMachine() : Unit { } }")
403 e.interpret("open Other;")
404 e.interpret("open Microsoft.Quantum.Diagnostics;")
405 with pytest.raises(QSharpError) as excinfo:
406 e.interpret("DumpMachine()")
407 assert str(excinfo.value).startswith("Qsc.Resolve.Ambiguous")
408
409
410def test_qirgen() -> None:
411 e = Interpreter(TargetProfile.Base)
412 e.interpret("operation Program() : Result { use q = Qubit(); return M(q) }")
413 qir = e.qir("Program()")
414 assert isinstance(qir, str)
415
416
417def test_run_with_shots() -> None:
418 e = Interpreter(TargetProfile.Unrestricted)
419
420 def callback(output):
421 nonlocal called
422 called += 1
423 assert output.__repr__() == "Hello, world!"
424
425 called = 0
426 e.interpret('operation Foo() : Unit { Message("Hello, world!"); }', callback)
427 assert called == 0
428
429 value = []
430 for _ in range(5):
431 value.append(e.run("Foo()", callback))
432 assert called == 5
433
434 assert value == [None, None, None, None, None]
435
436
437def test_dump_circuit() -> None:
438 e = Interpreter(TargetProfile.Unrestricted)
439 e.interpret(
440 """
441 use q1 = Qubit();
442 use q2 = Qubit();
443 X(q1);
444 """
445 )
446 circuit = e.dump_circuit()
447 assert str(circuit) == dedent(
448 """\
449 q_0 โ”€โ”€ X โ”€โ”€
450 q_1 โ”€โ”€โ”€โ”€โ”€โ”€โ”€
451 """
452 )
453
454 e.interpret("X(q2);")
455 circuit = e.dump_circuit()
456 assert str(circuit) == dedent(
457 """\
458 q_0 โ”€โ”€ X โ”€โ”€
459 q_1 โ”€โ”€ X โ”€โ”€
460 """
461 )
462
463
464def test_entry_expr_circuit() -> None:
465 e = Interpreter(TargetProfile.Unrestricted)
466 e.interpret("operation Foo() : Result { use q = Qubit(); H(q); return M(q) }")
467 circuit = e.circuit("Foo()")
468 assert str(circuit) == dedent(
469 """\
470 q_0 โ”€โ”€ H โ”€โ”€โ”€โ”€ M โ”€โ”€
471 โ•˜โ•โ•โ•
472 """
473 )
474
475
476def test_swap_label_circuit() -> None:
477 e = Interpreter(TargetProfile.Unrestricted)
478 e.interpret(
479 "operation Foo() : Unit { use q1 = Qubit(); use q2 = Qubit(); X(q1); Relabel([q1, q2], [q2, q1]); X(q2); }"
480 )
481 circuit = e.circuit("Foo()")
482 assert str(circuit) == dedent(
483 """\
484 q_0 โ”€โ”€ X โ”€โ”€โ”€โ”€ X โ”€โ”€
485 q_1 โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
486 """
487 )
488
489
490def test_callables_failing_profile_validation_are_not_registered() -> None:
491 e = Interpreter(TargetProfile.Adaptive_RI)
492 with pytest.raises(Exception) as excinfo:
493 e.interpret(
494 "operation Foo() : Double { use q = Qubit(); mutable x = 1.0; if MResetZ(q) == One { set x = 2.0; } x }"
495 )
496 assert "Qsc.CapabilitiesCk.UseOfDynamicDouble" in str(excinfo)
497 # In this case, the callable Foo failed compilation late enough that the symbol is bound. This makes later
498 # use of `Foo` valid from a name resolution standpoint, but the callable cannot be invoked because it was found
499 # to be invalid for the current profile. To stay consistent with the behavior of other compilations that
500 # leave unbound symbols, the call will compile but fail to run.
501 with pytest.raises(Exception) as excinfo:
502 e.interpret("Foo()")
503 assert "Qsc.Eval.UnboundName" in str(excinfo)
504
505
506def test_once_callable_fails_profile_validation_it_fails_compile_to_QIR() -> None:
507 e = Interpreter(TargetProfile.Adaptive_RI)
508 with pytest.raises(Exception) as excinfo:
509 e.interpret(
510 "operation Foo() : Double { use q = Qubit(); mutable x = 1.0; if MResetZ(q) == One { set x = 2.0; } x }"
511 )
512 assert "Qsc.CapabilitiesCk.UseOfDynamicDouble" in str(excinfo)
513 with pytest.raises(Exception) as excinfo:
514 e.qir("{Foo();}")
515 assert "Qsc.PartialEval.EvaluationFailed" in str(excinfo)
516 assert "name is not bound" in str(excinfo)
517
518
519def test_once_rca_validation_fails_following_calls_do_not_fail() -> None:
520 e = Interpreter(TargetProfile.Adaptive_RI)
521 with pytest.raises(Exception) as excinfo:
522 e.interpret(
523 "operation Foo() : Double { use q = Qubit(); mutable x = 1.0; if MResetZ(q) == One { set x = 2.0; } x }"
524 )
525 assert "Qsc.CapabilitiesCk.UseOfDynamicDouble" in str(excinfo)
526 value = e.interpret("let x = 5; x")
527 assert value == 5
528
529
530def test_adaptive_errors_are_raised_when_interpreting() -> None:
531 e = Interpreter(TargetProfile.Adaptive_RI)
532 with pytest.raises(Exception) as excinfo:
533 e.interpret(
534 "operation Foo() : Double { use q = Qubit(); mutable x = 1.0; if MResetZ(q) == One { set x = 2.0; } x }"
535 )
536 assert "Qsc.CapabilitiesCk.UseOfDynamicDouble" in str(excinfo)
537
538
539def test_adaptive_errors_are_raised_from_entry_expr() -> None:
540 e = Interpreter(TargetProfile.Adaptive_RI)
541 e.interpret("use q = Qubit();")
542 with pytest.raises(Exception) as excinfo:
543 e.run("{mutable x = 1.0; if MResetZ(q) == One { set x = 2.0; }}")
544 assert "Qsc.CapabilitiesCk.UseOfDynamicDouble" in str(excinfo)
545
546
547def test_adaptive_ri_qir_can_be_generated() -> None:
548 adaptive_input = """
549 namespace Test {
550 import Std.Math.*;
551 open QIR.Intrinsic;
552 @EntryPoint()
553 operation Main() : Result {
554 use q = Qubit();
555 let pi_over_two = 4.0 / 2.0;
556 __quantum__qis__rz__body(pi_over_two, q);
557 mutable some_angle = ArcSin(0.0);
558 __quantum__qis__rz__body(some_angle, q);
559 set some_angle = ArcCos(-1.0) / PI();
560 __quantum__qis__rz__body(some_angle, q);
561 __quantum__qis__mresetz__body(q)
562 }
563 }
564 """
565 e = Interpreter(TargetProfile.Adaptive_RI)
566 e.interpret(adaptive_input)
567 qir = e.qir("Test.Main()")
568 assert qir == dedent(
569 """\
570 %Result = type opaque
571 %Qubit = type opaque
572
573 define void @ENTRYPOINT__main() #0 {
574 block_0:
575 call void @__quantum__qis__rz__body(double 2.0, %Qubit* inttoptr (i64 0 to %Qubit*))
576 call void @__quantum__qis__rz__body(double 0.0, %Qubit* inttoptr (i64 0 to %Qubit*))
577 call void @__quantum__qis__rz__body(double 1.0, %Qubit* inttoptr (i64 0 to %Qubit*))
578 call void @__quantum__qis__mresetz__body(%Qubit* inttoptr (i64 0 to %Qubit*), %Result* inttoptr (i64 0 to %Result*))
579 call void @__quantum__rt__result_record_output(%Result* inttoptr (i64 0 to %Result*), i8* null)
580 ret void
581 }
582
583 declare void @__quantum__qis__rz__body(double, %Qubit*)
584
585 declare void @__quantum__qis__mresetz__body(%Qubit*, %Result*) #1
586
587 declare void @__quantum__rt__result_record_output(%Result*, i8*)
588
589 attributes #0 = { "entry_point" "output_labeling_schema" "qir_profiles"="adaptive_profile" "required_num_qubits"="1" "required_num_results"="1" }
590 attributes #1 = { "irreversible" }
591
592 ; module flags
593
594 !llvm.module.flags = !{!0, !1, !2, !3, !4}
595
596 !0 = !{i32 1, !"qir_major_version", i32 1}
597 !1 = !{i32 7, !"qir_minor_version", i32 0}
598 !2 = !{i32 1, !"dynamic_qubit_management", i1 false}
599 !3 = !{i32 1, !"dynamic_result_management", i1 false}
600 !4 = !{i32 1, !"int_computations", !"i64"}
601 """
602 )
603
604
605def test_base_qir_can_be_generated() -> None:
606 base_input = """
607 namespace Test {
608 import Std.Math.*;
609 open QIR.Intrinsic;
610 @EntryPoint()
611 operation Main() : Result {
612 use q = Qubit();
613 let pi_over_two = 4.0 / 2.0;
614 __quantum__qis__rz__body(pi_over_two, q);
615 mutable some_angle = ArcSin(0.0);
616 __quantum__qis__rz__body(some_angle, q);
617 set some_angle = ArcCos(-1.0) / PI();
618 __quantum__qis__rz__body(some_angle, q);
619 __quantum__qis__mresetz__body(q)
620 }
621 }
622 """
623 e = Interpreter(TargetProfile.Base)
624 e.interpret(base_input)
625 qir = e.qir("Test.Main()")
626 assert qir == dedent(
627 """\
628 %Result = type opaque
629 %Qubit = type opaque
630
631 define void @ENTRYPOINT__main() #0 {
632 block_0:
633 call void @__quantum__qis__rz__body(double 2.0, %Qubit* inttoptr (i64 0 to %Qubit*))
634 call void @__quantum__qis__rz__body(double 0.0, %Qubit* inttoptr (i64 0 to %Qubit*))
635 call void @__quantum__qis__rz__body(double 1.0, %Qubit* inttoptr (i64 0 to %Qubit*))
636 call void @__quantum__qis__m__body(%Qubit* inttoptr (i64 0 to %Qubit*), %Result* inttoptr (i64 0 to %Result*))
637 call void @__quantum__rt__result_record_output(%Result* inttoptr (i64 0 to %Result*), i8* null)
638 ret void
639 }
640
641 declare void @__quantum__qis__rz__body(double, %Qubit*)
642
643 declare void @__quantum__rt__result_record_output(%Result*, i8*)
644
645 declare void @__quantum__qis__m__body(%Qubit*, %Result*) #1
646
647 attributes #0 = { "entry_point" "output_labeling_schema" "qir_profiles"="base_profile" "required_num_qubits"="1" "required_num_results"="1" }
648 attributes #1 = { "irreversible" }
649
650 ; module flags
651
652 !llvm.module.flags = !{!0, !1, !2, !3}
653
654 !0 = !{i32 1, !"qir_major_version", i32 1}
655 !1 = !{i32 7, !"qir_minor_version", i32 0}
656 !2 = !{i32 1, !"dynamic_qubit_management", i1 false}
657 !3 = !{i32 1, !"dynamic_result_management", i1 false}
658 """
659 )
660
661
662def test_operation_circuit() -> None:
663 e = Interpreter(TargetProfile.Unrestricted)
664 e.interpret("operation Foo(q: Qubit) : Result { H(q); return M(q) }")
665 circuit = e.circuit(operation="Foo")
666 assert str(circuit) == dedent(
667 """\
668 q_0 โ”€โ”€ H โ”€โ”€โ”€โ”€ M โ”€โ”€
669 โ•˜โ•โ•โ•
670 """
671 )
672
673
674def test_unsupported_operation_circuit() -> None:
675 e = Interpreter(TargetProfile.Unrestricted)
676 e.interpret("operation Foo(n: Int) : Result { return One }")
677 with pytest.raises(QSharpError) as excinfo:
678 circuit = e.circuit(operation="Foo")
679 assert (
680 str(excinfo.value).find(
681 "expression does not evaluate to an operation that takes qubit parameters"
682 )
683 != -1
684 )
685
686
687def test_results_are_comparable() -> None:
688 e = Interpreter(TargetProfile.Unrestricted)
689 r = e.interpret("[One, Zero]")
690 assert r == [Result.One, Result.Zero]
691 r.sort()
692 assert r == [Result.Zero, Result.One]
693