microsoft/qdk

Public

mirrored from https://github.com/microsoft/qdkAvailable

CodeCommitsIssuesPull requestsActionsInsightsSecurity
alex/pythontelem

Branches

Tags

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

Clone

HTTPS

Download ZIP

compiler/qsc/src/interpret/circuit_tests.rs

1086lines · modecode

1// Copyright (c) Microsoft Corporation.
2// Licensed under the MIT License.
3
4#![allow(clippy::unicode_not_nfc)]
5
6use super::{CircuitEntryPoint, Debugger, Interpreter};
7use crate::target::Profile;
8use expect_test::expect;
9use miette::Diagnostic;
10use qsc_data_structures::language_features::LanguageFeatures;
11use qsc_eval::output::GenericReceiver;
12use qsc_frontend::compile::SourceMap;
13use qsc_passes::PackageType;
14
15fn interpreter(code: &str, profile: Profile) -> Interpreter {
16 let sources = SourceMap::new([("test.qs".into(), code.into())], None);
17 let (std_id, store) = crate::compile::package_store_with_stdlib(profile.into());
18 Interpreter::new(
19 sources,
20 PackageType::Exe,
21 profile.into(),
22 LanguageFeatures::default(),
23 store,
24 &[(std_id, None)],
25 )
26 .expect("interpreter creation should succeed")
27}
28
29#[test]
30fn empty() {
31 let mut interpreter = interpreter(
32 r#"
33 namespace Test {
34 @EntryPoint()
35 operation Main() : Unit {
36 Message("hi");
37 }
38 }
39 "#,
40 Profile::Unrestricted,
41 );
42
43 let circ = interpreter
44 .circuit(CircuitEntryPoint::EntryPoint, false)
45 .expect("circuit generation should succeed");
46
47 expect![].assert_eq(&circ.to_string());
48}
49
50#[test]
51fn one_gate() {
52 let mut interpreter = interpreter(
53 r"
54 namespace Test {
55 @EntryPoint()
56 operation Main() : Unit {
57 use q = Qubit();
58 H(q);
59 }
60 }
61 ",
62 Profile::Unrestricted,
63 );
64
65 let circ = interpreter
66 .circuit(CircuitEntryPoint::EntryPoint, false)
67 .expect("circuit generation should succeed");
68
69 expect![[r"
70 q_0 ── H ──
71 "]]
72 .assert_eq(&circ.to_string());
73}
74
75#[test]
76fn measure_same_qubit_twice() {
77 let mut interpreter = interpreter(
78 r"
79 namespace Test {
80 @EntryPoint()
81 operation Main() : Result[] {
82 use q = Qubit();
83 H(q);
84 let r1 = M(q);
85 let r2 = M(q);
86 [r1, r2]
87 }
88 }
89 ",
90 Profile::Unrestricted,
91 );
92
93 let circ = interpreter
94 .circuit(CircuitEntryPoint::EntryPoint, false)
95 .expect("circuit generation should succeed");
96
97 expect![["
98 q_0 ── H ──── M ──── M ──
99 ╘══════╪═══
100 ╘═══
101 "]]
102 .assert_eq(&circ.to_string());
103}
104
105#[test]
106fn toffoli() {
107 let mut interpreter = interpreter(
108 r"
109 namespace Test {
110 @EntryPoint()
111 operation Main() : Unit {
112 use q = Qubit[3];
113 CCNOT(q[0], q[1], q[2]);
114 }
115 }
116 ",
117 Profile::Unrestricted,
118 );
119
120 let circ = interpreter
121 .circuit(CircuitEntryPoint::EntryPoint, false)
122 .expect("circuit generation should succeed");
123
124 expect![[r"
125 q_0 ── ● ──
126 q_1 ── ● ──
127 q_2 ── X ──
128 "]]
129 .assert_eq(&circ.to_string());
130}
131
132#[test]
133fn rotation_gate() {
134 let mut interpreter = interpreter(
135 r"
136 namespace Test {
137 @EntryPoint()
138 operation Main() : Unit {
139 use q = Qubit();
140 Rx(Microsoft.Quantum.Math.PI()/2.0, q);
141 }
142 }
143 ",
144 Profile::Unrestricted,
145 );
146
147 let circ = interpreter
148 .circuit(CircuitEntryPoint::EntryPoint, false)
149 .expect("circuit generation should succeed");
150
151 // The wire isn't visible here since the gate label is longer
152 // than the static column width, but we can live with it.
153 expect![[r"
154 q_0 rx(1.5708)
155 "]]
156 .assert_eq(&circ.to_string());
157}
158
159#[test]
160fn classical_for_loop() {
161 let mut interpreter = interpreter(
162 r"
163 namespace Test {
164 @EntryPoint()
165 operation Main() : Unit {
166 use q = Qubit();
167 for i in 0..5 {
168 X(q);
169 }
170 }
171 }
172 ",
173 Profile::Unrestricted,
174 );
175
176 let circ = interpreter
177 .circuit(CircuitEntryPoint::EntryPoint, false)
178 .expect("circuit generation should succeed");
179
180 expect![[r"
181 q_0 ── X ──── X ──── X ──── X ──── X ──── X ──
182 "]]
183 .assert_eq(&circ.to_string());
184}
185
186#[test]
187fn m_base_profile() {
188 let mut interpreter = interpreter(
189 r"
190 namespace Test {
191 import Std.Measurement.*;
192 @EntryPoint()
193 operation Main() : Result[] {
194 use q = Qubit();
195 H(q);
196 [M(q)]
197 }
198 }
199 ",
200 Profile::Base,
201 );
202
203 let circ = interpreter
204 .circuit(CircuitEntryPoint::EntryPoint, false)
205 .expect("circuit generation should succeed");
206
207 expect![[r"
208 q_0 ── H ──── Z ────────────────
209 q_1 ── H ──── ● ──── H ──── M ──
210 ╘═══
211 "]]
212 .assert_eq(&circ.to_string());
213}
214
215#[test]
216fn m_unrestricted_profile() {
217 let mut interpreter = interpreter(
218 r"
219 namespace Test {
220 import Std.Measurement.*;
221 @EntryPoint()
222 operation Main() : Result[] {
223 use q = Qubit();
224 H(q);
225 [M(q)]
226 }
227 }
228 ",
229 Profile::Unrestricted,
230 );
231
232 let circ = interpreter
233 .circuit(CircuitEntryPoint::EntryPoint, false)
234 .expect("circuit generation should succeed");
235
236 expect![[r"
237 q_0 ── H ──── M ──
238 ╘═══
239 "]]
240 .assert_eq(&circ.to_string());
241}
242
243#[test]
244fn mresetz_unrestricted_profile() {
245 let mut interpreter = interpreter(
246 r"
247 namespace Test {
248 import Std.Measurement.*;
249 @EntryPoint()
250 operation Main() : Result[] {
251 use q = Qubit();
252 H(q);
253 [MResetZ(q)]
254 }
255 }
256 ",
257 Profile::Unrestricted,
258 );
259
260 let circ = interpreter
261 .circuit(CircuitEntryPoint::EntryPoint, false)
262 .expect("circuit generation should succeed");
263
264 expect![[r"
265 q_0 ── H ──── M ─── |0〉 ─
266 ╘══════════
267 "]]
268 .assert_eq(&circ.to_string());
269}
270
271#[test]
272fn mresetz_base_profile() {
273 let mut interpreter = interpreter(
274 r"
275 namespace Test {
276 import Std.Measurement.*;
277 @EntryPoint()
278 operation Main() : Result[] {
279 use q = Qubit();
280 H(q);
281 [MResetZ(q)]
282 }
283 }
284 ",
285 Profile::Base,
286 );
287
288 let circ = interpreter
289 .circuit(CircuitEntryPoint::EntryPoint, false)
290 .expect("circuit generation should succeed");
291
292 expect![[r"
293 q_0 ── H ──── M ──
294 ╘═══
295 "]]
296 .assert_eq(&circ.to_string());
297}
298
299#[test]
300fn unrestricted_profile_result_comparison() {
301 let mut interpreter = interpreter(
302 r"
303 namespace Test {
304 import Std.Measurement.*;
305 @EntryPoint()
306 operation Main() : Result[] {
307 use q1 = Qubit();
308 use q2 = Qubit();
309 H(q1);
310 H(q2);
311 let r1 = M(q1);
312 let r2 = M(q2);
313 if (r1 == r2) {
314 X(q1);
315 }
316 ResetAll([q1, q2]);
317 [r1, r2]
318 }
319 }
320 ",
321 Profile::Unrestricted,
322 );
323
324 interpreter.set_quantum_seed(Some(2));
325
326 let circuit_err = interpreter
327 .circuit(CircuitEntryPoint::EntryPoint, false)
328 .expect_err("circuit should return error")
329 .pop()
330 .expect("error should exist");
331
332 expect!["Qsc.Eval.ResultComparisonUnsupported"].assert_eq(
333 &circuit_err
334 .code()
335 .expect("error code should exist")
336 .to_string(),
337 );
338
339 let circuit = interpreter.get_circuit();
340 expect![""].assert_eq(&circuit.to_string());
341
342 let mut out = std::io::sink();
343 let mut r = GenericReceiver::new(&mut out);
344
345 // Result comparisons are okay when tracing
346 // circuit with the simulator.
347 let circ = interpreter
348 .circuit(CircuitEntryPoint::EntryPoint, true)
349 .expect("circuit generation should succeed");
350
351 expect![[r"
352 q_0 ── H ──── M ──── X ─── |0〉 ─
353 ╘═════════════════
354 q_1 ── H ──── M ─── |0〉 ────────
355 ╘═════════════════
356 "]]
357 .assert_eq(&circ.to_string());
358
359 // Result comparisons are also okay if calling
360 // get_circuit() after incremental evaluation,
361 // because we're using the current simulator
362 // state.
363 interpreter
364 .eval_fragments(&mut r, "Test.Main();")
365 .expect("eval should succeed");
366
367 let circuit = interpreter.get_circuit();
368 expect![[r"
369 q_0 ── H ──── M ──── X ─── |0〉 ─
370 ╘═════════════════
371 q_1 ── H ──── M ─── |0〉 ────────
372 ╘═════════════════
373 "]]
374 .assert_eq(&circuit.to_string());
375}
376
377#[test]
378fn custom_intrinsic() {
379 let mut interpreter = interpreter(
380 r"
381 namespace Test {
382 operation foo(q: Qubit): Unit {
383 body intrinsic;
384 }
385
386 @EntryPoint()
387 operation Main() : Unit {
388 use q = Qubit();
389 foo(q);
390 }
391 }",
392 Profile::Unrestricted,
393 );
394
395 let circ = interpreter
396 .circuit(CircuitEntryPoint::EntryPoint, false)
397 .expect("circuit generation should succeed");
398
399 expect![[r"
400 q_0 ─ foo ─
401 "]]
402 .assert_eq(&circ.to_string());
403}
404
405#[test]
406fn custom_intrinsic_classical_arg() {
407 let mut interpreter = interpreter(
408 r"
409 namespace Test {
410 operation foo(n: Int): Unit {
411 body intrinsic;
412 }
413
414 @EntryPoint()
415 operation Main() : Unit {
416 use q = Qubit();
417 X(q);
418 foo(4);
419 }
420 }",
421 Profile::Unrestricted,
422 );
423
424 let circ = interpreter
425 .circuit(CircuitEntryPoint::EntryPoint, false)
426 .expect("circuit generation should succeed");
427
428 // A custom intrinsic that doesn't take qubits just doesn't
429 // show up on the circuit.
430 expect![[r"
431 q_0 ── X ──
432 "]]
433 .assert_eq(&circ.to_string());
434}
435
436#[test]
437fn custom_intrinsic_one_classical_arg() {
438 let mut interpreter = interpreter(
439 r"
440 namespace Test {
441 operation foo(n: Int, q: Qubit): Unit {
442 body intrinsic;
443 }
444
445 @EntryPoint()
446 operation Main() : Unit {
447 use q = Qubit();
448 X(q);
449 foo(4, q);
450 }
451 }",
452 Profile::Unrestricted,
453 );
454
455 let circ = interpreter
456 .circuit(CircuitEntryPoint::EntryPoint, false)
457 .expect("circuit generation should succeed");
458
459 // A custom intrinsic that doesn't take qubits just doesn't
460 // show up on the circuit.
461 expect![[r"
462 q_0 ── X ── foo(4)
463 "]]
464 .assert_eq(&circ.to_string());
465}
466
467#[test]
468fn custom_intrinsic_mixed_args() {
469 let mut interpreter = interpreter(
470 r"
471 namespace Test {
472 import Std.ResourceEstimation.*;
473
474 @EntryPoint()
475 operation Main() : Unit {
476 use qs = Qubit[10];
477 AccountForEstimates(
478 [
479 AuxQubitCount(1),
480 TCount(2),
481 RotationCount(3),
482 RotationDepth(4),
483 CczCount(5),
484 MeasurementCount(6),
485 ],
486 PSSPCLayout(),
487 qs);
488 }
489 }",
490 Profile::Unrestricted,
491 );
492
493 let circ = interpreter
494 .circuit(CircuitEntryPoint::EntryPoint, false)
495 .expect("circuit generation should succeed");
496
497 // This is one gate that spans ten target wires, even though the
498 // text visualization doesn't convey that clearly.
499 expect![[r"
500 q_0 AccountForEstimatesInternal([(0, 1), (1, 2), (2, 3), (3, 4), (4, 5), (5, 6)], 1)
501 q_1 AccountForEstimatesInternal([(0, 1), (1, 2), (2, 3), (3, 4), (4, 5), (5, 6)], 1)
502 q_2 AccountForEstimatesInternal([(0, 1), (1, 2), (2, 3), (3, 4), (4, 5), (5, 6)], 1)
503 q_3 AccountForEstimatesInternal([(0, 1), (1, 2), (2, 3), (3, 4), (4, 5), (5, 6)], 1)
504 q_4 AccountForEstimatesInternal([(0, 1), (1, 2), (2, 3), (3, 4), (4, 5), (5, 6)], 1)
505 q_5 AccountForEstimatesInternal([(0, 1), (1, 2), (2, 3), (3, 4), (4, 5), (5, 6)], 1)
506 q_6 AccountForEstimatesInternal([(0, 1), (1, 2), (2, 3), (3, 4), (4, 5), (5, 6)], 1)
507 q_7 AccountForEstimatesInternal([(0, 1), (1, 2), (2, 3), (3, 4), (4, 5), (5, 6)], 1)
508 q_8 AccountForEstimatesInternal([(0, 1), (1, 2), (2, 3), (3, 4), (4, 5), (5, 6)], 1)
509 q_9 AccountForEstimatesInternal([(0, 1), (1, 2), (2, 3), (3, 4), (4, 5), (5, 6)], 1)
510 "]]
511 .assert_eq(&circ.to_string());
512
513 assert_eq!(circ.operations.len(), 1);
514}
515
516#[test]
517fn operation_with_qubits() {
518 let mut interpreter = interpreter(
519 r"
520 namespace Test {
521 @EntryPoint()
522 operation Main() : Result[] { [] }
523
524 operation Test(q1: Qubit, q2: Qubit) : Result[] {
525 H(q1);
526 CNOT(q1, q2);
527 [M(q1), M(q2)]
528 }
529
530 }",
531 Profile::Unrestricted,
532 );
533
534 let circ = interpreter
535 .circuit(CircuitEntryPoint::Operation("Test.Test".into()), false)
536 .expect("circuit generation should succeed");
537
538 expect![[r"
539 q_0 ── H ──── ● ──── M ──
540 │ ╘═══
541 q_1 ───────── X ──── M ──
542 ╘═══
543 "]]
544 .assert_eq(&circ.to_string());
545}
546
547#[test]
548fn operation_with_qubits_base_profile() {
549 let mut interpreter = interpreter(
550 r"
551 namespace Test {
552 @EntryPoint()
553 operation Main() : Result[] { [] }
554
555 operation Test(q1: Qubit, q2: Qubit) : Result[] {
556 H(q1);
557 CNOT(q1, q2);
558 [M(q1), M(q2)]
559 }
560
561 }",
562 Profile::Base,
563 );
564
565 let circ = interpreter
566 .circuit(CircuitEntryPoint::Operation("Test.Test".into()), false)
567 .expect("circuit generation should succeed");
568
569 expect![[r"
570 q_0 ── H ──── ● ──── Z ──────────────────────────────
571 q_1 ───────── X ─────┼──────────── Z ────────────────
572 q_2 ── H ─────────── ● ──── H ─────┼───── M ─────────
573 │ ╘══════════
574 q_3 ── H ───────────────────────── ● ──── H ──── M ──
575 ╘═══
576 "]]
577 .assert_eq(&circ.to_string());
578}
579
580#[test]
581fn operation_with_qubit_arrays() {
582 let mut interpreter = interpreter(
583 r"
584 namespace Test {
585 @EntryPoint()
586 operation Main() : Result[] { [] }
587
588 import Std.Measurement.*;
589 operation Test(q1: Qubit[], q2: Qubit[][], q3: Qubit[][][], q: Qubit) : Result[] {
590 for q in q1 {
591 H(q);
592 }
593 for qs in q2 {
594 for q in qs {
595 X(q);
596 }
597 }
598 for qss in q3 {
599 for qs in qss {
600 for q in qs {
601 Y(q);
602 }
603 }
604 }
605 X(q);
606 MeasureEachZ(q1)
607 }
608 }",
609 Profile::Unrestricted,
610 );
611
612 let circ = interpreter
613 .circuit(CircuitEntryPoint::Operation("Test.Test".into()), false)
614 .expect("circuit generation should succeed");
615
616 expect![[r"
617 q_0 ── H ──── M ──
618 ╘═══
619 q_1 ── H ──── M ──
620 ╘═══
621 q_2 ── X ─────────
622 q_3 ── X ─────────
623 q_4 ── X ─────────
624 q_5 ── X ─────────
625 q_6 ── Y ─────────
626 q_7 ── Y ─────────
627 q_8 ── Y ─────────
628 q_9 ── Y ─────────
629 q_10 ── Y ─────────
630 q_11 ── Y ─────────
631 q_12 ── Y ─────────
632 q_13 ── Y ─────────
633 q_14 ── X ─────────
634 "]]
635 .assert_eq(&circ.to_string());
636}
637
638#[test]
639fn adjoint_operation() {
640 let mut interpreter = interpreter(
641 r"
642 namespace Test {
643 @EntryPoint()
644 operation Main() : Result[] { [] }
645
646 operation Foo (q : Qubit) : Unit
647 is Adj + Ctl {
648
649 body (...) {
650 X(q);
651 }
652
653 adjoint (...) {
654 Y(q);
655 }
656
657 controlled (cs, ...) {
658 }
659 }
660
661 }",
662 Profile::Unrestricted,
663 );
664
665 let circ = interpreter
666 .circuit(
667 CircuitEntryPoint::Operation("Adjoint Test.Foo".into()),
668 false,
669 )
670 .expect("circuit generation should succeed");
671
672 expect![[r"
673 q_0 ── Y ──
674 "]]
675 .assert_eq(&circ.to_string());
676}
677
678#[test]
679fn lambda() {
680 let mut interpreter = interpreter(
681 r"
682 namespace Test {
683 @EntryPoint()
684 operation Main() : Result[] { [] }
685 }",
686 Profile::Unrestricted,
687 );
688
689 let circ = interpreter
690 .circuit(CircuitEntryPoint::Operation("q => H(q)".into()), false)
691 .expect("circuit generation should succeed");
692
693 expect![[r"
694 q_0 ── H ──
695 "]]
696 .assert_eq(&circ.to_string());
697}
698
699#[test]
700fn controlled_operation() {
701 let mut interpreter = interpreter(
702 r"
703 namespace Test {
704 @EntryPoint()
705 operation Main() : Result[] { [] }
706
707 operation SWAP (q1 : Qubit, q2 : Qubit) : Unit
708 is Adj + Ctl {
709
710 body (...) {
711 CNOT(q1, q2);
712 CNOT(q2, q1);
713 CNOT(q1, q2);
714 }
715
716 adjoint (...) {
717 SWAP(q1, q2);
718 }
719
720 controlled (cs, ...) {
721 CNOT(q1, q2);
722 Controlled CNOT(cs, (q2, q1));
723 CNOT(q1, q2);
724 }
725 }
726
727 }",
728 Profile::Unrestricted,
729 );
730
731 let circ_err = interpreter
732 .circuit(
733 CircuitEntryPoint::Operation("Controlled Test.SWAP".into()),
734 false,
735 )
736 .expect_err("circuit generation should fail");
737
738 // Controlled operations are not supported at the moment.
739 // We don't generate an accurate call signature with the tuple arguments.
740 expect![[r"
741 [
742 Circuit(
743 ControlledUnsupported,
744 ),
745 ]
746 "]]
747 .assert_debug_eq(&circ_err);
748}
749
750#[test]
751#[allow(clippy::too_many_lines)]
752fn internal_operation() {
753 let mut interpreter = interpreter(
754 r"
755 namespace Test {
756 @EntryPoint()
757 operation Main() : Result[] { [] }
758
759 internal operation Test(q1: Qubit, q2: Qubit) : Result[] {
760 H(q1);
761 CNOT(q1, q2);
762 [M(q1), M(q2)]
763 }
764 }",
765 Profile::Unrestricted,
766 );
767
768 let circ_err = interpreter
769 .circuit(CircuitEntryPoint::Operation("Test.Test".into()), false)
770 .expect("circuit generation should not fail");
771
772 expect![[r#"
773 Circuit {
774 operations: [
775 Operation {
776 gate: "H",
777 display_args: None,
778 is_controlled: false,
779 is_adjoint: false,
780 is_measurement: false,
781 controls: [],
782 targets: [
783 Register {
784 q_id: 0,
785 type: 0,
786 c_id: None,
787 },
788 ],
789 children: [],
790 },
791 Operation {
792 gate: "X",
793 display_args: None,
794 is_controlled: true,
795 is_adjoint: false,
796 is_measurement: false,
797 controls: [
798 Register {
799 q_id: 0,
800 type: 0,
801 c_id: None,
802 },
803 ],
804 targets: [
805 Register {
806 q_id: 1,
807 type: 0,
808 c_id: None,
809 },
810 ],
811 children: [],
812 },
813 Operation {
814 gate: "Measure",
815 display_args: None,
816 is_controlled: false,
817 is_adjoint: false,
818 is_measurement: true,
819 controls: [
820 Register {
821 q_id: 0,
822 type: 0,
823 c_id: None,
824 },
825 ],
826 targets: [
827 Register {
828 q_id: 0,
829 type: 1,
830 c_id: Some(
831 0,
832 ),
833 },
834 ],
835 children: [],
836 },
837 Operation {
838 gate: "Measure",
839 display_args: None,
840 is_controlled: false,
841 is_adjoint: false,
842 is_measurement: true,
843 controls: [
844 Register {
845 q_id: 1,
846 type: 0,
847 c_id: None,
848 },
849 ],
850 targets: [
851 Register {
852 q_id: 1,
853 type: 1,
854 c_id: Some(
855 0,
856 ),
857 },
858 ],
859 children: [],
860 },
861 ],
862 qubits: [
863 Qubit {
864 id: 0,
865 num_children: 1,
866 },
867 Qubit {
868 id: 1,
869 num_children: 1,
870 },
871 ],
872 }
873 "#]]
874 .assert_debug_eq(&circ_err);
875}
876
877#[test]
878fn operation_with_non_qubit_args() {
879 let mut interpreter = interpreter(
880 r"
881 namespace Test {
882 @EntryPoint()
883 operation Main() : Result[] { [] }
884
885 operation Test(q1: Qubit, q2: Qubit, i: Int) : Unit {
886 }
887
888 }",
889 Profile::Unrestricted,
890 );
891
892 let circ_err = interpreter
893 .circuit(CircuitEntryPoint::Operation("Test.Test".into()), false)
894 .expect_err("circuit generation should fail");
895
896 expect![[r"
897 [
898 Circuit(
899 NoQubitParameters,
900 ),
901 ]
902 "]]
903 .assert_debug_eq(&circ_err);
904}
905
906/// Tests that invoke circuit generation throught the debugger.
907mod debugger_stepping {
908 use super::Debugger;
909 use crate::target::Profile;
910 use expect_test::expect;
911 use qsc_data_structures::language_features::LanguageFeatures;
912 use qsc_data_structures::line_column::Encoding;
913 use qsc_eval::{output::GenericReceiver, StepAction, StepResult};
914 use qsc_frontend::compile::SourceMap;
915 use std::fmt::Write;
916
917 /// Steps through the code in the debugger and collects the
918 /// circuit representation at each step.
919 fn generate_circuit_steps(code: &str, profile: Profile) -> String {
920 let sources = SourceMap::new([("test.qs".into(), code.into())], None);
921 let (std_id, store) = crate::compile::package_store_with_stdlib(profile.into());
922 let mut debugger = Debugger::new(
923 sources,
924 profile.into(),
925 Encoding::Utf8,
926 LanguageFeatures::default(),
927 store,
928 &[(std_id, None)],
929 )
930 .expect("debugger creation should succeed");
931
932 debugger.interpreter.set_quantum_seed(Some(2));
933
934 let mut out = std::io::sink();
935 let mut r = GenericReceiver::new(&mut out);
936
937 let mut circs = String::new();
938 let mut result = debugger
939 .eval_step(&mut r, &[], StepAction::In)
940 .expect("step should succeed");
941
942 write!(&mut circs, "step:\n{}", debugger.circuit()).expect("write should succeed");
943 while !matches!(result, StepResult::Return(_)) {
944 result = debugger
945 .eval_step(&mut r, &[], StepAction::Next)
946 .expect("step should succeed");
947
948 write!(&mut circs, "step:\n{}", debugger.circuit()).expect("write should succeed");
949 }
950 circs
951 }
952
953 #[test]
954 fn base_profile() {
955 let circs = generate_circuit_steps(
956 r"
957 namespace Test {
958 import Std.Measurement.*;
959 @EntryPoint()
960 operation Main() : Result[] {
961 use q = Qubit();
962 H(q);
963 let r = M(q);
964 Reset(q);
965 [r]
966 }
967 }
968 ",
969 Profile::Base,
970 );
971
972 // Surprising but expected: Reset gates would *not* normally
973 // be generated in Base Profile, but they are here, since
974 // when running in tandem with the simulator, the resulting
975 // circuit is intended to match the calls into the simulator.
976 //
977 // Note the circuit still looks different than what would be
978 // generated in Unrestricted Profile for the same code,
979 // due to conditional compilation in the standard library.
980 expect![["
981 step:
982 step:
983 q_0
984 step:
985 q_0 ── H ──
986 step:
987 q_0 ── H ──── Z ───────────────────────
988 q_1 ── H ──── ● ──── H ──── M ─── |0〉 ─
989 ╘══════════
990 step:
991 q_0 ── H ──── Z ─── |0〉 ───────────────
992 q_1 ── H ──── ● ──── H ──── M ─── |0〉 ─
993 ╘══════════
994 step:
995 q_0 ── H ──── Z ─── |0〉 ───────────────
996 q_1 ── H ──── ● ──── H ──── M ─── |0〉 ─
997 ╘══════════
998 "]]
999 .assert_eq(&circs);
1000 }
1001
1002 #[test]
1003 fn unrestricted_profile() {
1004 let circs = generate_circuit_steps(
1005 r"
1006 namespace Test {
1007 import Std.Measurement.*;
1008 @EntryPoint()
1009 operation Main() : Result[] {
1010 use q = Qubit();
1011 H(q);
1012 let r = M(q);
1013 Reset(q);
1014 [r]
1015 }
1016 }
1017 ",
1018 Profile::Unrestricted,
1019 );
1020
1021 expect![[r"
1022 step:
1023 step:
1024 q_0
1025 step:
1026 q_0 ── H ──
1027 step:
1028 q_0 ── H ──── M ──
1029 ╘═══
1030 step:
1031 q_0 ── H ──── M ─── |0〉 ─
1032 ╘══════════
1033 step:
1034 q_0 ── H ──── M ─── |0〉 ─
1035 ╘══════════
1036 "]]
1037 .assert_eq(&circs);
1038 }
1039
1040 #[test]
1041 fn unrestricted_profile_result_comparison() {
1042 let circs = generate_circuit_steps(
1043 r"
1044 namespace Test {
1045 import Std.Measurement.*;
1046 @EntryPoint()
1047 operation Main() : Result[] {
1048 use q = Qubit();
1049 H(q);
1050 let r = M(q);
1051 if (r == One) {
1052 X(q);
1053 }
1054 [r]
1055 }
1056 }
1057 ",
1058 Profile::Unrestricted,
1059 );
1060
1061 // We set the random seed in the test to account for
1062 // the nondeterministic output. Since the debugger is running
1063 // the real simulator, the circuit is going to vary from run to run
1064 // depending on measurement outcomes.
1065 expect![[r"
1066 step:
1067 step:
1068 q_0
1069 step:
1070 q_0 ── H ──
1071 step:
1072 q_0 ── H ──── M ──
1073 ╘═══
1074 step:
1075 q_0 ── H ──── M ──
1076 ╘═══
1077 step:
1078 q_0 ── H ──── M ──── X ──
1079 ╘══════════
1080 step:
1081 q_0 ── H ──── M ──── X ──
1082 ╘══════════
1083 "]]
1084 .assert_eq(&circs);
1085 }
1086}
1087