microsoft/qdk

Public

mirrored from https://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/compiler/qsc/src/interpret/circuit_tests.rs

1538lines · 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::{
8 interpret::{CircuitGenerationMethod, Error},
9 target::Profile,
10};
11use expect_test::expect;
12use miette::Diagnostic;
13use qsc_circuit::{Circuit, TracerConfig};
14use qsc_data_structures::{language_features::LanguageFeatures, source::SourceMap};
15use qsc_eval::output::GenericReceiver;
16use qsc_passes::PackageType;
17
18fn interpreter(code: &str, package_type: PackageType, profile: Profile) -> Interpreter {
19 let sources = SourceMap::new([("test.qs".into(), code.into())], None);
20 let (std_id, store) = crate::compile::package_store_with_stdlib(profile.into());
21 Interpreter::new(
22 sources,
23 package_type,
24 profile.into(),
25 LanguageFeatures::default(),
26 store,
27 &[(std_id, None)],
28 )
29 .expect("interpreter creation should succeed")
30}
31
32fn interpreter_with_circuit_trace(code: &str, profile: Profile) -> Interpreter {
33 let sources = SourceMap::new([("test.qs".into(), code.into())], None);
34 let (std_id, store) = crate::compile::package_store_with_stdlib(profile.into());
35 Interpreter::with_circuit_trace(
36 sources,
37 PackageType::Exe,
38 profile.into(),
39 LanguageFeatures::default(),
40 store,
41 &[(std_id, None)],
42 default_test_tracer_config(),
43 )
44 .expect("interpreter creation should succeed")
45}
46
47#[allow(clippy::needless_pass_by_value)]
48fn circuit(code: &str, entry: CircuitEntryPoint) -> String {
49 circuit_with_options(
50 code,
51 Profile::Unrestricted,
52 entry,
53 CircuitGenerationMethod::ClassicalEval,
54 default_test_tracer_config(),
55 )
56 .expect("circuit generation should succeed")
57 .to_string()
58}
59
60fn circuit_err(
61 code: &str,
62 entry: CircuitEntryPoint,
63 method: CircuitGenerationMethod,
64 tracer_config: TracerConfig,
65) -> Vec<Error> {
66 circuit_with_options(code, Profile::Unrestricted, entry, method, tracer_config)
67 .expect_err("circuit generation should fail")
68}
69
70fn circuit_with_options(
71 code: &str,
72 profile: Profile,
73 entry: CircuitEntryPoint,
74 method: CircuitGenerationMethod,
75 config: TracerConfig,
76) -> Result<Circuit, Vec<Error>> {
77 let mut interpreter = interpreter(code, PackageType::Exe, profile);
78 interpreter.set_quantum_seed(Some(2));
79 interpreter.circuit(entry, method, config)
80}
81
82fn default_test_tracer_config() -> TracerConfig {
83 TracerConfig {
84 max_operations: TracerConfig::DEFAULT_MAX_OPERATIONS,
85 source_locations: true,
86 group_by_scope: true,
87 prune_classical_qubits: false,
88 }
89}
90
91#[test]
92fn empty() {
93 let circ = circuit(
94 r#"
95 namespace Test {
96 @EntryPoint()
97 operation Main() : Unit {
98 Message("hi");
99 }
100 }
101 "#,
102 CircuitEntryPoint::EntryPoint,
103 );
104
105 expect![""].assert_eq(&circ);
106}
107
108#[test]
109fn one_gate() {
110 let circ = circuit(
111 r"
112 namespace Test {
113 @EntryPoint()
114 operation Main() : Unit {
115 use q = Qubit();
116 H(q);
117 }
118 }
119 ",
120 CircuitEntryPoint::EntryPoint,
121 );
122
123 expect![[r#"
124 q_0@test.qs:4:20 ─ H@test.qs:5:20 ──
125 "#]]
126 .assert_eq(&circ);
127}
128
129#[test]
130fn measure_same_qubit_twice() {
131 let circ = circuit(
132 r"
133 namespace Test {
134 @EntryPoint()
135 operation Main() : Result[] {
136 use q = Qubit();
137 H(q);
138 let r1 = M(q);
139 let r2 = M(q);
140 [r1, r2]
141 }
142 }
143 ",
144 CircuitEntryPoint::EntryPoint,
145 );
146
147 expect![[r#"
148 q_0@test.qs:4:20 ─ H@test.qs:5:20 ─── M@test.qs:6:29 ─── M@test.qs:7:29 ──
149 ╘══════════════════╪═════════
150 ╘═════════
151 "#]]
152 .assert_eq(&circ);
153}
154
155#[test]
156fn toffoli() {
157 let circ = circuit(
158 r"
159 namespace Test {
160 @EntryPoint()
161 operation Main() : Unit {
162 use q = Qubit[3];
163 CCNOT(q[0], q[1], q[2]);
164 }
165 }
166 ",
167 CircuitEntryPoint::EntryPoint,
168 );
169
170 expect![[r#"
171 q_0@test.qs:4:20 ──────── ● ────────
172 q_1@test.qs:4:20 ──────── ● ────────
173 q_2@test.qs:4:20 ─ X@test.qs:5:20 ──
174 "#]]
175 .assert_eq(&circ);
176}
177
178#[test]
179fn rotation_gate() {
180 let circ = circuit(
181 r"
182 namespace Test {
183 @EntryPoint()
184 operation Main() : Unit {
185 use q = Qubit();
186 Rx(Microsoft.Quantum.Math.PI()/2.0, q);
187 }
188 }
189 ",
190 CircuitEntryPoint::EntryPoint,
191 );
192
193 expect![[r#"
194 q_0@test.qs:4:20 ─ Rx(1.5708)@test.qs:5:20 ─
195 "#]]
196 .assert_eq(&circ);
197}
198
199#[test]
200fn grouping_nested_callables() {
201 let circ = circuit_with_options(
202 r"
203 namespace Test {
204 @EntryPoint()
205 operation Main() : Unit {
206 use q = Qubit();
207 Foo(q);
208 MResetZ(q);
209 }
210
211 operation Foo(q: Qubit) : Unit {
212 H(q);
213 }
214 }
215 ",
216 Profile::Unrestricted,
217 CircuitEntryPoint::EntryPoint,
218 CircuitGenerationMethod::ClassicalEval,
219 TracerConfig {
220 max_operations: usize::MAX,
221 source_locations: false,
222 group_by_scope: true,
223 prune_classical_qubits: false,
224 },
225 )
226 .expect("circuit generation should succeed");
227
228 expect![[r#"
229 q_0 ─ [ [Main] ─── [ [Foo] ─── H ──── ] ──── M ──── |0〉 ──── ] ──
230 [ ╘══════════════ ] ══
231 "#]]
232 .assert_eq(&circ.display_with_groups().to_string());
233}
234
235#[test]
236fn classical_for_loop_is_grouped() {
237 let circ = circuit_with_options(
238 r"
239 namespace Test {
240 @EntryPoint()
241 operation Main() : Unit {
242 use q = Qubit();
243 for i in 0..2 {
244 Foo(q);
245 }
246 }
247
248 operation Foo(q: Qubit) : Unit {
249 X(q);
250 Y(q);
251 }
252 }
253 ",
254 Profile::Unrestricted,
255 CircuitEntryPoint::EntryPoint,
256 CircuitGenerationMethod::ClassicalEval,
257 TracerConfig {
258 max_operations: 1000,
259 source_locations: true,
260 group_by_scope: true,
261 prune_classical_qubits: false,
262 },
263 )
264 .expect("circuit generation should succeed");
265
266 let circ = circ.display_with_groups().to_string();
267
268 expect![[r#"
269 q_0@test.qs:4:20 ─ [ [Main] ─── [ [loop: 0..2@test.qs:5:20] ── [ [(1)@test.qs:5:34] ─── [ [Foo@test.qs:6:24] ─── X@test.qs:11:20 ── Y@test.qs:12:20 ─── ] ──── ] ─── [ [(2)@test.qs:5:34] ─── [ [Foo@test.qs:6:24] ─── X@test.qs:11:20 ── Y@test.qs:12:20 ─── ] ──── ] ─── [ [(3)@test.qs:5:34] ─── [ [Foo@test.qs:6:24] ─── X@test.qs:11:20 ── Y@test.qs:12:20 ─── ] ──── ] ──── ] ──── ] ──
270 "#]]
271 .assert_eq(&circ);
272}
273
274#[test]
275fn dynamic_for_loop_is_grouped() {
276 let circ = circuit_with_options(
277 r"
278 operation Main() : Unit {
279 use qubit = Qubit();
280 repeat {
281 H(qubit);
282 } until M(qubit) == Zero
283 fixup {
284 Reset(qubit);
285 }
286 }
287 ",
288 Profile::Unrestricted,
289 CircuitEntryPoint::EntryPoint,
290 CircuitGenerationMethod::Simulate,
291 TracerConfig {
292 max_operations: 1000,
293 source_locations: true,
294 group_by_scope: true,
295 prune_classical_qubits: false,
296 },
297 )
298 .expect("circuit generation should succeed");
299
300 let circ = circ.display_with_groups().to_string();
301
302 expect![[r#"
303 q_0@test.qs:2:15 ─ [ [Main] ─── [ [loop: M(qubit) == Zero@test.qs:3:16] ── [ [(1)@test.qs:3:23] ─── H@test.qs:4:20 ─── M@test.qs:5:24 ──── |0〉@test.qs:7:20 ───── ] ─── [ [(2)@test.qs:3:23] ─── H@test.qs:4:20 ─── M@test.qs:5:24 ──── |0〉@test.qs:7:20 ───── ] ─── [ [(3)@test.qs:3:23] ─── H@test.qs:4:20 ─── M@test.qs:5:24 ──── |0〉@test.qs:7:20 ───── ] ─── [ [(4)@test.qs:3:23] ─── H@test.qs:4:20 ─── M@test.qs:5:24 ──── ] ──── ] ──── ] ──
304 [ [ [ ╘══════════════════════════════════ ] ═══════════════════════════════════════════════════════╪════════════════════════════════════════════════════════════════════════════════════════════╪════════════════════════════════════════════════════════════════════════════════════════════╪══════════════════ ] ════ ] ══
305 [ [ [ ╘══════════════════════════════════ ] ═══════════════════════════════════════════════════════╪════════════════════════════════════════════════════════════════════════════════════════════╪══════════════════ ] ════ ] ══
306 [ [ [ ╘══════════════════════════════════ ] ═══════════════════════════════════════════════════════╪══════════════════ ] ════ ] ══
307 [ [ [ ╘═══════════ ] ════ ] ════ ] ══
308 "#]]
309 .assert_eq(&circ);
310}
311
312#[test]
313fn repeat_until_loop_is_grouped() {
314 let circ = circuit_with_options(
315 r"
316 namespace Test {
317 @EntryPoint()
318 operation Main() : Unit {
319 use q = Qubit();
320 mutable i = 0;
321 repeat {
322 Foo(q);
323 } until i == 2
324 fixup {
325 set i += 1;
326 }
327 }
328
329 operation Foo(q: Qubit) : Unit {
330 X(q);
331 Y(q);
332 }
333 }
334 ",
335 Profile::Unrestricted,
336 CircuitEntryPoint::EntryPoint,
337 CircuitGenerationMethod::ClassicalEval,
338 TracerConfig {
339 max_operations: 1000,
340 source_locations: true,
341 group_by_scope: true,
342 prune_classical_qubits: false,
343 },
344 )
345 .expect("circuit generation should succeed");
346
347 let circ = circ.display_with_groups().to_string();
348
349 expect![[r#"
350 q_0@test.qs:4:20 ─ [ [Main] ─── [ [loop: i == 2@test.qs:6:20] ── [ [(1)@test.qs:6:27] ─── [ [Foo@test.qs:7:24] ─── X@test.qs:15:20 ── Y@test.qs:16:20 ─── ] ──── ] ─── [ [(2)@test.qs:6:27] ─── [ [Foo@test.qs:7:24] ─── X@test.qs:15:20 ── Y@test.qs:16:20 ─── ] ──── ] ─── [ [(3)@test.qs:6:27] ─── [ [Foo@test.qs:7:24] ─── X@test.qs:15:20 ── Y@test.qs:16:20 ─── ] ──── ] ──── ] ──── ] ──
351 "#]]
352 .assert_eq(&circ);
353}
354
355#[test]
356fn while_loop_is_grouped() {
357 let circ = circuit_with_options(
358 r"
359 namespace Test {
360 @EntryPoint()
361 operation Main() : Unit {
362 use q = Qubit();
363 mutable i = 0;
364 while (i < 2) {
365 Foo(q);
366 set i += 1;
367 }
368 }
369
370 operation Foo(q: Qubit) : Unit {
371 X(q);
372 Y(q);
373 }
374 }
375 ",
376 Profile::Unrestricted,
377 CircuitEntryPoint::EntryPoint,
378 CircuitGenerationMethod::ClassicalEval,
379 TracerConfig {
380 max_operations: 1000,
381 source_locations: true,
382 group_by_scope: true,
383 prune_classical_qubits: false,
384 },
385 )
386 .expect("circuit generation should succeed");
387
388 let circ = circ.display_with_groups().to_string();
389
390 expect![[r#"
391 q_0@test.qs:4:20 ─ [ [Main] ─── [ [loop: i < 2@test.qs:6:20] ─── [ [(1)@test.qs:6:34] ─── [ [Foo@test.qs:7:24] ─── X@test.qs:13:20 ── Y@test.qs:14:20 ─── ] ──── ] ─── [ [(2)@test.qs:6:34] ─── [ [Foo@test.qs:7:24] ─── X@test.qs:13:20 ── Y@test.qs:14:20 ─── ] ──── ] ──── ] ──── ] ──
392 "#]]
393 .assert_eq(&circ);
394}
395
396#[test]
397fn loop_single_iteration_is_not_grouped() {
398 let circ = circuit_with_options(
399 r"
400 namespace Test {
401 @EntryPoint()
402 operation Main() : Unit {
403 use q = Qubit();
404 for i in 0..0 {
405 Foo(q);
406 }
407 }
408
409 operation Foo(q: Qubit) : Unit {
410 X(q);
411 Y(q);
412 }
413 }
414 ",
415 Profile::Unrestricted,
416 CircuitEntryPoint::EntryPoint,
417 CircuitGenerationMethod::ClassicalEval,
418 TracerConfig {
419 max_operations: 1000,
420 source_locations: true,
421 group_by_scope: true,
422 prune_classical_qubits: false,
423 },
424 )
425 .expect("circuit generation should succeed");
426
427 let circ = circ.display_with_groups().to_string();
428
429 expect![[r#"
430 q_0@test.qs:4:20 ─ [ [Main] ─── [ [Foo@test.qs:6:24] ─── X@test.qs:11:20 ── Y@test.qs:12:20 ─── ] ──── ] ──
431 "#]]
432 .assert_eq(&circ);
433}
434
435#[test]
436fn loop_vertical_is_not_grouped() {
437 let circ = circuit_with_options(
438 r"
439 namespace Test {
440 @EntryPoint()
441 operation Main() : Unit {
442 use qs = Qubit[6];
443 for i in 0..5 {
444 Foo(qs[i]);
445 }
446 }
447
448 operation Foo(q: Qubit) : Unit {
449 X(q);
450 }
451 }
452 ",
453 Profile::Unrestricted,
454 CircuitEntryPoint::EntryPoint,
455 CircuitGenerationMethod::ClassicalEval,
456 TracerConfig {
457 max_operations: 1000,
458 source_locations: true,
459 group_by_scope: true,
460 prune_classical_qubits: false,
461 },
462 )
463 .expect("circuit generation should succeed");
464
465 let circ = circ.display_with_groups().to_string();
466
467 expect![[r#"
468 q_0@test.qs:4:20 ─ [ [Main] ─── [ [Foo@test.qs:6:24] ─── X@test.qs:11:20 ─── ] ──── ] ──
469 q_1@test.qs:4:20 ───── [ ────── [ [Foo@test.qs:6:24] ─── X@test.qs:11:20 ─── ] ──── ] ──
470 q_2@test.qs:4:20 ───── [ ────── [ [Foo@test.qs:6:24] ─── X@test.qs:11:20 ─── ] ──── ] ──
471 q_3@test.qs:4:20 ───── [ ────── [ [Foo@test.qs:6:24] ─── X@test.qs:11:20 ─── ] ──── ] ──
472 q_4@test.qs:4:20 ───── [ ────── [ [Foo@test.qs:6:24] ─── X@test.qs:11:20 ─── ] ──── ] ──
473 q_5@test.qs:4:20 ───── [ ────── [ [Foo@test.qs:6:24] ─── X@test.qs:11:20 ─── ] ──── ] ──
474 "#]]
475 .assert_eq(&circ);
476}
477
478#[test]
479fn for_loop_nested() {
480 let circ = circuit_with_options(
481 r"
482 namespace Test {
483 @EntryPoint()
484 operation Main() : Unit {
485 use qs = Qubit[3];
486 for j in 0..2 {
487 for i in 0..2 {
488 Foo(qs[i]);
489 }
490 }
491 }
492
493 operation Foo(q: Qubit) : Unit {
494 X(q);
495 }
496 }
497 ",
498 Profile::Unrestricted,
499 CircuitEntryPoint::EntryPoint,
500 CircuitGenerationMethod::ClassicalEval,
501 TracerConfig {
502 max_operations: 1000,
503 source_locations: true,
504 group_by_scope: true,
505 prune_classical_qubits: false,
506 },
507 )
508 .expect("circuit generation should succeed");
509
510 let circ = circ.display_with_groups().to_string();
511
512 expect![[r#"
513 q_0@test.qs:4:20 ─ [ [Main] ─── [ [loop: 0..2@test.qs:5:20] ── [ [(1)@test.qs:5:34] ─── [ [Foo@test.qs:7:28] ─── X@test.qs:13:20 ─── ] ──── ] ─── [ [(2)@test.qs:5:34] ─── [ [Foo@test.qs:7:28] ─── X@test.qs:13:20 ─── ] ──── ] ─── [ [(3)@test.qs:5:34] ─── [ [Foo@test.qs:7:28] ─── X@test.qs:13:20 ─── ] ──── ] ──── ] ──── ] ──
514 q_1@test.qs:4:20 ───── [ ─────────────────── [ ───────────────────────── [ ──────────── [ [Foo@test.qs:7:28] ─── X@test.qs:13:20 ─── ] ──── ] ───────────── [ ──────────── [ [Foo@test.qs:7:28] ─── X@test.qs:13:20 ─── ] ──── ] ───────────── [ ──────────── [ [Foo@test.qs:7:28] ─── X@test.qs:13:20 ─── ] ──── ] ──── ] ──── ] ──
515 q_2@test.qs:4:20 ───── [ ─────────────────── [ ───────────────────────── [ ──────────── [ [Foo@test.qs:7:28] ─── X@test.qs:13:20 ─── ] ──── ] ───────────── [ ──────────── [ [Foo@test.qs:7:28] ─── X@test.qs:13:20 ─── ] ──── ] ───────────── [ ──────────── [ [Foo@test.qs:7:28] ─── X@test.qs:13:20 ─── ] ──── ] ──── ] ──── ] ──
516 "#]]
517 .assert_eq(&circ);
518}
519
520#[test]
521fn m_base_profile() {
522 let circ = circuit_with_options(
523 r"
524 namespace Test {
525 import Std.Measurement.*;
526 @EntryPoint()
527 operation Main() : Result[] {
528 use q = Qubit();
529 H(q);
530 [M(q)]
531 }
532 }
533 ",
534 Profile::Base,
535 CircuitEntryPoint::EntryPoint,
536 CircuitGenerationMethod::ClassicalEval,
537 default_test_tracer_config(),
538 )
539 .expect("circuit generation should succeed");
540
541 expect![[r#"
542 q_0@test.qs:5:20 ─ H@test.qs:6:20 ─── M@test.qs:7:21 ──
543 ╘═════════
544 "#]]
545 .assert_eq(&circ.to_string());
546}
547
548#[test]
549fn m_default_profile() {
550 let circ = circuit(
551 r"
552 namespace Test {
553 import Std.Measurement.*;
554 @EntryPoint()
555 operation Main() : Result[] {
556 use q = Qubit();
557 H(q);
558 [M(q)]
559 }
560 }
561 ",
562 CircuitEntryPoint::EntryPoint,
563 );
564
565 expect![[r#"
566 q_0@test.qs:5:20 ─ H@test.qs:6:20 ─── M@test.qs:7:21 ──
567 ╘═════════
568 "#]]
569 .assert_eq(&circ);
570}
571
572#[test]
573fn mresetz_unrestricted_profile() {
574 let circ = circuit(
575 r"
576 namespace Test {
577 import Std.Measurement.*;
578 @EntryPoint()
579 operation Main() : Result[] {
580 use q = Qubit();
581 H(q);
582 [MResetZ(q)]
583 }
584 }
585 ",
586 CircuitEntryPoint::EntryPoint,
587 );
588
589 expect![[r#"
590 q_0@test.qs:5:20 ─ H@test.qs:6:20 ─── M@test.qs:7:21 ──── |0〉@test.qs:7:21 ───
591 ╘════════════════════════════════
592 "#]]
593 .assert_eq(&circ);
594}
595
596#[test]
597fn mresetz_base_profile() {
598 let circ = circuit_with_options(
599 r"
600 namespace Test {
601 import Std.Measurement.*;
602 @EntryPoint()
603 operation Main() : Result[] {
604 use q = Qubit();
605 H(q);
606 [MResetZ(q)]
607 }
608 }
609 ",
610 Profile::Base,
611 CircuitEntryPoint::EntryPoint,
612 CircuitGenerationMethod::ClassicalEval,
613 default_test_tracer_config(),
614 )
615 .expect("circuit generation should succeed");
616
617 // code gen in Base turns the MResetZ into an M
618 expect![[r#"
619 q_0@test.qs:5:20 ─ H@test.qs:6:20 ─── M@test.qs:7:21 ──── |0〉@test.qs:7:21 ───
620 ╘════════════════════════════════
621 "#]]
622 .assert_eq(&circ.to_string());
623}
624
625#[test]
626fn qubit_relabel() {
627 let circ = circuit(
628 "
629 namespace Test {
630 operation Main() : Unit {
631 use (q1, q2) = (Qubit(), Qubit());
632 H(q1);
633 CNOT(q1, q2);
634 Relabel([q1, q2], [q2, q1]);
635 H(q1);
636 CNOT(q1, q2);
637 MResetZ(q1);
638 MResetZ(q2);
639 }
640 }
641 ",
642 CircuitEntryPoint::EntryPoint,
643 );
644
645 expect![[r#"
646 q_0@test.qs:3:32 ─ H@test.qs:4:16 ────────── ● ──────────────────────────── X@test.qs:8:16 ─── M@test.qs:10:16 ─── |0〉@test.qs:10:16 ──
647 │ │ ╘════════════════════════════════
648 q_1@test.qs:3:41 ──────────────────── X@test.qs:5:16 ─── H@test.qs:7:16 ────────── ● ───────── M@test.qs:9:16 ──── |0〉@test.qs:9:16 ───
649 ╘════════════════════════════════
650 "#]]
651 .assert_eq(&circ);
652}
653
654#[test]
655fn qubit_reuse() {
656 let circ = circuit(
657 "
658 namespace Test {
659 operation Main() : Unit {
660 {
661 use q1 = Qubit();
662 X(q1);
663 MResetZ(q1);
664 }
665 {
666 use q2 = Qubit();
667 Y(q2);
668 MResetZ(q2);
669 }
670 }
671 }
672 ",
673 CircuitEntryPoint::EntryPoint,
674 );
675
676 expect![[r#"
677 q_0@test.qs:4:20, test.qs:9:20 ─ X@test.qs:5:20 ─── M@test.qs:6:20 ──── |0〉@test.qs:6:20 ──── Y@test.qs:10:20 ── M@test.qs:11:20 ─── |0〉@test.qs:11:20 ──
678 ╘════════════════════════════════════════════════════════════╪════════════════════════════════
679 ╘════════════════════════════════
680 "#]]
681 .assert_eq(&circ);
682}
683
684#[test]
685fn qubit_reuse_no_measurements() {
686 let circ = circuit(
687 "
688 namespace Test {
689 operation Main() : Unit {
690 {
691 use q1 = Qubit();
692 X(q1);
693 Reset(q1);
694 }
695 {
696 use q2 = Qubit();
697 Y(q2);
698 Reset(q2);
699 }
700 }
701 }
702 ",
703 CircuitEntryPoint::EntryPoint,
704 );
705
706 expect![[r#"
707 q_0@test.qs:4:20, test.qs:9:20 ─ X@test.qs:5:20 ──── |0〉@test.qs:6:20 ──── Y@test.qs:10:20 ─── |0〉@test.qs:11:20 ──
708 "#]]
709 .assert_eq(&circ);
710}
711
712#[test]
713fn unrestricted_profile_result_comparison() {
714 let mut interpreter = interpreter_with_circuit_trace(
715 r"
716 namespace Test {
717 import Std.Measurement.*;
718 @EntryPoint()
719 operation Main() : Result[] {
720 use q1 = Qubit();
721 use q2 = Qubit();
722 H(q1);
723 H(q2);
724 let r1 = M(q1);
725 let r2 = M(q2);
726 if (r1 == r2) {
727 X(q1);
728 }
729 ResetAll([q1, q2]);
730 [r1, r2]
731 }
732 }
733 ",
734 Profile::Unrestricted,
735 );
736
737 interpreter.set_quantum_seed(Some(2));
738
739 let circuit_err = interpreter
740 .circuit(
741 CircuitEntryPoint::EntryPoint,
742 CircuitGenerationMethod::ClassicalEval,
743 default_test_tracer_config(),
744 )
745 .expect_err("circuit should return error")
746 .pop()
747 .expect("error should exist");
748
749 expect!["Qsc.Eval.ResultComparisonUnsupported"].assert_eq(
750 &circuit_err
751 .code()
752 .expect("error code should exist")
753 .to_string(),
754 );
755
756 let circuit = interpreter.get_circuit();
757 expect![""].assert_eq(&circuit.to_string());
758
759 let mut out = std::io::sink();
760 let mut r = GenericReceiver::new(&mut out);
761
762 // Result comparisons are okay when tracing
763 // circuit with the simulator.
764 let circ = interpreter
765 .circuit(
766 CircuitEntryPoint::EntryPoint,
767 CircuitGenerationMethod::Simulate,
768 default_test_tracer_config(),
769 )
770 .expect("circuit generation should succeed");
771
772 expect![[r#"
773 q_0@test.qs:5:20 ─ H@test.qs:7:20 ─── M@test.qs:9:29 ───── X@test.qs:12:24 ───── |0〉@test.qs:14:20 ──
774 ╘═══════════════════════════════════════════════════════
775 q_1@test.qs:6:20 ─ H@test.qs:8:20 ─── M@test.qs:10:29 ─── |0〉@test.qs:14:20 ─────────────────────────
776 ╘═══════════════════════════════════════════════════════
777 "#]]
778 .assert_eq(&circ.to_string());
779
780 // Result comparisons are also okay if calling
781 // get_circuit() after incremental evaluation,
782 // because we're using the current simulator
783 // state.
784 interpreter
785 .eval_fragments(&mut r, "Test.Main();")
786 .expect("eval should succeed");
787
788 let circuit = interpreter.get_circuit();
789 expect![[r#"
790 q_0@test.qs:5:20 ─ H@test.qs:7:20 ─── M@test.qs:9:29 ───── X@test.qs:12:24 ───── |0〉@test.qs:14:20 ──
791 ╘═══════════════════════════════════════════════════════
792 q_1@test.qs:6:20 ─ H@test.qs:8:20 ─── M@test.qs:10:29 ─── |0〉@test.qs:14:20 ─────────────────────────
793 ╘═══════════════════════════════════════════════════════
794 "#]]
795 .assert_eq(&circuit.to_string());
796}
797
798#[test]
799fn custom_intrinsic() {
800 let circ = circuit(
801 r"
802 namespace Test {
803 operation foo(q: Qubit): Unit {
804 body intrinsic;
805 }
806
807 @EntryPoint()
808 operation Main() : Unit {
809 use q = Qubit();
810 foo(q);
811 }
812 }",
813 CircuitEntryPoint::EntryPoint,
814 );
815
816 expect![[r#"
817 q_0@test.qs:8:12 ─ foo@test.qs:9:12 ──
818 "#]]
819 .assert_eq(&circ);
820}
821
822#[test]
823fn custom_intrinsic_classical_arg() {
824 let circ = circuit(
825 r"
826 namespace Test {
827 operation foo(n: Int): Unit {
828 body intrinsic;
829 }
830
831 @EntryPoint()
832 operation Main() : Unit {
833 use q = Qubit();
834 X(q);
835 foo(4);
836 }
837 }",
838 CircuitEntryPoint::EntryPoint,
839 );
840
841 // A custom intrinsic that doesn't take qubits just doesn't
842 // show up on the circuit.
843 expect![[r#"
844 q_0@test.qs:8:12 ─ X@test.qs:9:12 ──
845 "#]]
846 .assert_eq(&circ);
847}
848
849#[test]
850fn custom_intrinsic_one_classical_arg() {
851 let circ = circuit(
852 r"
853 namespace Test {
854 operation foo(n: Int, q: Qubit): Unit {
855 body intrinsic;
856 }
857
858 @EntryPoint()
859 operation Main() : Unit {
860 use q = Qubit();
861 X(q);
862 foo(4, q);
863 }
864 }",
865 CircuitEntryPoint::EntryPoint,
866 );
867
868 expect![[r#"
869 q_0@test.qs:8:12 ─ X@test.qs:9:12 ─── foo(4)@test.qs:10:12 ──
870 "#]]
871 .assert_eq(&circ);
872}
873
874#[test]
875fn custom_intrinsic_mixed_args() {
876 let circ = circuit(
877 r"
878 namespace Test {
879 import Std.ResourceEstimation.*;
880
881 @EntryPoint()
882 operation Main() : Unit {
883 use qs = Qubit[10];
884 AccountForEstimates(
885 [
886 AuxQubitCount(1),
887 TCount(2),
888 RotationCount(3),
889 RotationDepth(4),
890 CczCount(5),
891 MeasurementCount(6),
892 ],
893 PSSPCLayout(),
894 qs);
895 }
896 }",
897 CircuitEntryPoint::EntryPoint,
898 );
899
900 expect![[r#"
901 q_0@test.qs:6:12 ─ AccountForEstimatesInternal([(0, 1), (1, 2), (2, 3), (3, 4), (4, 5), (5, 6)], 1)@test.qs:7:12 ─
902
903 q_1@test.qs:6:12 ─ AccountForEstimatesInternal([(0, 1), (1, 2), (2, 3), (3, 4), (4, 5), (5, 6)], 1)@test.qs:7:12 ─
904
905 q_2@test.qs:6:12 ─ AccountForEstimatesInternal([(0, 1), (1, 2), (2, 3), (3, 4), (4, 5), (5, 6)], 1)@test.qs:7:12 ─
906
907 q_3@test.qs:6:12 ─ AccountForEstimatesInternal([(0, 1), (1, 2), (2, 3), (3, 4), (4, 5), (5, 6)], 1)@test.qs:7:12 ─
908
909 q_4@test.qs:6:12 ─ AccountForEstimatesInternal([(0, 1), (1, 2), (2, 3), (3, 4), (4, 5), (5, 6)], 1)@test.qs:7:12 ─
910
911 q_5@test.qs:6:12 ─ AccountForEstimatesInternal([(0, 1), (1, 2), (2, 3), (3, 4), (4, 5), (5, 6)], 1)@test.qs:7:12 ─
912
913 q_6@test.qs:6:12 ─ AccountForEstimatesInternal([(0, 1), (1, 2), (2, 3), (3, 4), (4, 5), (5, 6)], 1)@test.qs:7:12 ─
914
915 q_7@test.qs:6:12 ─ AccountForEstimatesInternal([(0, 1), (1, 2), (2, 3), (3, 4), (4, 5), (5, 6)], 1)@test.qs:7:12 ─
916
917 q_8@test.qs:6:12 ─ AccountForEstimatesInternal([(0, 1), (1, 2), (2, 3), (3, 4), (4, 5), (5, 6)], 1)@test.qs:7:12 ─
918
919 q_9@test.qs:6:12 ─ AccountForEstimatesInternal([(0, 1), (1, 2), (2, 3), (3, 4), (4, 5), (5, 6)], 1)@test.qs:7:12 ─
920 "#]]
921 .assert_eq(&circ);
922}
923
924#[test]
925fn custom_intrinsic_apply_idle_noise() {
926 let circ = circuit(
927 r"
928 namespace Test {
929 import Std.Diagnostics.*;
930 @EntryPoint()
931 operation Main() : Unit {
932 ConfigurePauliNoise(BitFlipNoise(1.0));
933 use q = Qubit();
934 ApplyIdleNoise(q);
935 }
936 }",
937 CircuitEntryPoint::EntryPoint,
938 );
939
940 expect![[r#"
941 q_0@test.qs:6:12 ─ ApplyIdleNoise@test.qs:7:12 ─
942 "#]]
943 .assert_eq(&circ);
944}
945
946#[test]
947fn operation_with_qubits() {
948 let circ = circuit(
949 r"
950 namespace Test {
951 @EntryPoint()
952 operation Main() : Result[] { [] }
953
954 operation Test(q1: Qubit, q2: Qubit) : Result[] {
955 H(q1);
956 CNOT(q1, q2);
957 [M(q1), M(q2)]
958 }
959
960 }",
961 CircuitEntryPoint::Operation("Test.Test".into()),
962 );
963
964 expect![[r#"
965 q_0@test.qs:5:27 ─ H@test.qs:6:16 ────────── ● ───────── M@test.qs:8:17 ──
966 │ ╘═════════
967 q_1@test.qs:5:38 ──────────────────── X@test.qs:7:16 ─── M@test.qs:8:24 ──
968 ╘═════════
969 "#]]
970 .assert_eq(&circ);
971}
972
973#[test]
974fn operation_with_qubit_arrays() {
975 let circ = circuit(
976 r"
977 namespace Test {
978 @EntryPoint()
979 operation Main() : Result[] { [] }
980
981 import Std.Measurement.*;
982 operation Test(q1: Qubit[], q2: Qubit[][], q3: Qubit[][][], q: Qubit) : Result[] {
983 for q in q1 {
984 H(q);
985 }
986 for qs in q2 {
987 for q in qs {
988 X(q);
989 }
990 }
991 for qss in q3 {
992 for qs in qss {
993 for q in qs {
994 Y(q);
995 }
996 }
997 }
998 X(q);
999 MeasureEachZ(q1)
1000 }
1001 }",
1002 CircuitEntryPoint::Operation("Test.Test".into()),
1003 );
1004
1005 expect![[r#"
1006 q_0@test.qs:6:27 ─ H@test.qs:8:20 ─── M@test.qs:23:16 ─
1007 ╘═════════
1008 q_1@test.qs:6:27 ─ H@test.qs:8:20 ─── M@test.qs:23:16 ─
1009 ╘═════════
1010 q_2@test.qs:6:40 ─ X@test.qs:12:24 ────────────────────
1011 q_3@test.qs:6:40 ─ X@test.qs:12:24 ────────────────────
1012 q_4@test.qs:6:40 ─ X@test.qs:12:24 ────────────────────
1013 q_5@test.qs:6:40 ─ X@test.qs:12:24 ────────────────────
1014 q_6@test.qs:6:55 ─ Y@test.qs:18:28 ────────────────────
1015 q_7@test.qs:6:55 ─ Y@test.qs:18:28 ────────────────────
1016 q_8@test.qs:6:55 ─ Y@test.qs:18:28 ────────────────────
1017 q_9@test.qs:6:55 ─ Y@test.qs:18:28 ────────────────────
1018 q_10@test.qs:6:55 ─ Y@test.qs:18:28 ────────────────────
1019 q_11@test.qs:6:55 ─ Y@test.qs:18:28 ────────────────────
1020 q_12@test.qs:6:55 ─ Y@test.qs:18:28 ────────────────────
1021 q_13@test.qs:6:55 ─ Y@test.qs:18:28 ────────────────────
1022 q_14@test.qs:6:72 ─ X@test.qs:22:16 ────────────────────
1023 "#]]
1024 .assert_eq(&circ);
1025}
1026
1027#[test]
1028fn adjoint_operation() {
1029 let circ = circuit(
1030 r"
1031 namespace Test {
1032 @EntryPoint()
1033 operation Main() : Result[] { [] }
1034
1035 operation Foo (q : Qubit) : Unit
1036 is Adj + Ctl {
1037
1038 body (...) {
1039 X(q);
1040 }
1041
1042 adjoint (...) {
1043 Y(q);
1044 }
1045
1046 controlled (cs, ...) {
1047 }
1048 }
1049
1050 }",
1051 CircuitEntryPoint::Operation("Adjoint Test.Foo".into()),
1052 );
1053
1054 expect![[r#"
1055 q_0@test.qs:5:27 ─ Y@test.qs:13:20 ─
1056 "#]]
1057 .assert_eq(&circ);
1058}
1059
1060#[test]
1061fn lambda() {
1062 let circ = circuit(
1063 r"
1064 namespace Test {
1065 @EntryPoint()
1066 operation Main() : Result[] { [] }
1067 }",
1068 CircuitEntryPoint::Operation("q => H(q)".into()),
1069 );
1070
1071 expect![[r#"
1072 q_0@line_0:0:0 ─ H@<entry>:2:18 ──
1073 "#]]
1074 .assert_eq(&circ);
1075}
1076
1077#[test]
1078fn controlled_operation() {
1079 let circ_err = circuit_err(
1080 r"
1081 namespace Test {
1082 @EntryPoint()
1083 operation Main() : Result[] { [] }
1084
1085 operation SWAP (q1 : Qubit, q2 : Qubit) : Unit
1086 is Adj + Ctl {
1087
1088 body (...) {
1089 CNOT(q1, q2);
1090 CNOT(q2, q1);
1091 CNOT(q1, q2);
1092 }
1093
1094 adjoint (...) {
1095 SWAP(q1, q2);
1096 }
1097
1098 controlled (cs, ...) {
1099 CNOT(q1, q2);
1100 Controlled CNOT(cs, (q2, q1));
1101 CNOT(q1, q2);
1102 }
1103 }
1104
1105 }",
1106 CircuitEntryPoint::Operation("Controlled Test.SWAP".into()),
1107 CircuitGenerationMethod::ClassicalEval,
1108 default_test_tracer_config(),
1109 );
1110
1111 // Controlled operations are not supported at the moment.
1112 // We don't generate an accurate call signature with the tuple arguments.
1113 expect![[r"
1114 [
1115 Circuit(
1116 ControlledUnsupported,
1117 ),
1118 ]
1119 "]]
1120 .assert_debug_eq(&circ_err);
1121}
1122
1123#[test]
1124fn internal_operation() {
1125 let circ = circuit(
1126 r"
1127 namespace Test {
1128 @EntryPoint()
1129 operation Main() : Result[] { [] }
1130
1131 internal operation Test(q1: Qubit, q2: Qubit) : Result[] {
1132 H(q1);
1133 CNOT(q1, q2);
1134 [M(q1), M(q2)]
1135 }
1136 }",
1137 CircuitEntryPoint::Operation("Test.Test".into()),
1138 );
1139
1140 expect![[r#"
1141 q_0@test.qs:5:36 ─ H@test.qs:6:16 ────────── ● ───────── M@test.qs:8:17 ──
1142 │ ╘═════════
1143 q_1@test.qs:5:47 ──────────────────── X@test.qs:7:16 ─── M@test.qs:8:24 ──
1144 ╘═════════
1145 "#]]
1146 .assert_eq(&circ);
1147}
1148
1149#[test]
1150fn operation_with_non_qubit_args() {
1151 let circ_err = circuit_err(
1152 r"
1153 namespace Test {
1154 @EntryPoint()
1155 operation Main() : Result[] { [] }
1156
1157 operation Test(q1: Qubit, q2: Qubit, i: Int) : Unit {
1158 }
1159
1160 }",
1161 CircuitEntryPoint::Operation("Test.Test".into()),
1162 CircuitGenerationMethod::ClassicalEval,
1163 default_test_tracer_config(),
1164 );
1165
1166 expect![[r"
1167 [
1168 Circuit(
1169 NoQubitParameters,
1170 ),
1171 ]
1172 "]]
1173 .assert_debug_eq(&circ_err);
1174}
1175
1176#[test]
1177fn operation_with_long_gates_properly_aligned() {
1178 let circ = circuit(
1179 r"
1180 namespace Test {
1181 import Std.Measurement.*;
1182
1183 @EntryPoint()
1184 operation Main() : Result[] {
1185 use q0 = Qubit();
1186 use q1 = Qubit();
1187
1188 H(q0);
1189 H(q1);
1190 X(q1);
1191 Ry(1.0, q1);
1192 CNOT(q0, q1);
1193 M(q0);
1194
1195 use q2 = Qubit();
1196
1197 H(q2);
1198 Rx(1.0, q2);
1199 H(q2);
1200 Rx(1.0, q2);
1201 H(q2);
1202 Rx(1.0, q2);
1203
1204 use q3 = Qubit();
1205
1206 Rxx(1.0, q1, q3);
1207
1208 CNOT(q0, q3);
1209
1210 [M(q1), M(q3)]
1211 }
1212 }
1213 ",
1214 CircuitEntryPoint::EntryPoint,
1215 );
1216
1217 expect![[r#"
1218 q_0@test.qs:6:20 ─ H@test.qs:9:20 ───────────────────────────────────────────────────────────────────────── ● ────────────── M@test.qs:14:20 ─────────────────────────────────────────────────────────────────── ● ───────────────────────────
1219 │ ╘════════════════════════════════════════════════════════════════════════════╪════════════════════════════
1220 q_1@test.qs:7:20 ─ H@test.qs:10:20 ─────── X@test.qs:11:20 ─────── Ry(1.0000)@test.qs:12:20 ──────── X@test.qs:13:20 ─────────────────────────────────────────────────────── Rxx(1.0000)@test.qs:27:20 ──────────┼────────── M@test.qs:31:21 ─
1221 ┆ │ ╘═════════
1222 q_2@test.qs:16:20 ─ H@test.qs:18:20 ── Rx(1.0000)@test.qs:19:20 ──────── H@test.qs:20:20 ─────── Rx(1.0000)@test.qs:21:20 ─── H@test.qs:22:20 ── Rx(1.0000)@test.qs:23:20 ────────────────┆───────────────────────┼────────────────────────────
1223 q_3@test.qs:25:20 ─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── Rxx(1.0000)@test.qs:27:20 ── X@test.qs:29:20 ── M@test.qs:31:28 ─
1224 ╘═════════
1225 "#]]
1226 .assert_eq(&circ);
1227}
1228
1229#[test]
1230fn operation_with_subsequent_qubits_gets_horizontal_lines() {
1231 let circ = circuit(
1232 r"
1233 namespace Test {
1234 import Std.Measurement.*;
1235
1236 @EntryPoint()
1237 operation Main() : Unit {
1238 use q0 = Qubit();
1239 use q1 = Qubit();
1240 Rxx(1.0, q0, q1);
1241
1242 use q2 = Qubit();
1243 use q3 = Qubit();
1244 Rxx(1.0, q2, q3);
1245 }
1246 }
1247 ",
1248 CircuitEntryPoint::EntryPoint,
1249 );
1250
1251 expect![[r#"
1252 q_0@test.qs:6:20 ─ Rxx(1.0000)@test.qs:8:20 ──
1253
1254 q_1@test.qs:7:20 ─ Rxx(1.0000)@test.qs:8:20 ──
1255 q_2@test.qs:10:20 ─ Rxx(1.0000)@test.qs:12:20 ─
1256
1257 q_3@test.qs:11:20 ─ Rxx(1.0000)@test.qs:12:20 ─
1258 "#]]
1259 .assert_eq(&circ);
1260}
1261
1262#[test]
1263fn operation_with_subsequent_qubits_no_double_rows() {
1264 let circ = circuit(
1265 r"
1266 namespace Test {
1267 import Std.Measurement.*;
1268
1269 @EntryPoint()
1270 operation Main() : Unit {
1271 use q0 = Qubit();
1272 use q1 = Qubit();
1273 Rxx(1.0, q0, q1);
1274 Rxx(1.0, q0, q1);
1275 }
1276 }
1277 ",
1278 CircuitEntryPoint::EntryPoint,
1279 );
1280
1281 expect![[r#"
1282 q_0@test.qs:6:20 ─ Rxx(1.0000)@test.qs:8:20 ─── Rxx(1.0000)@test.qs:9:20 ──
1283 ┆ ┆
1284 q_1@test.qs:7:20 ─ Rxx(1.0000)@test.qs:8:20 ─── Rxx(1.0000)@test.qs:9:20 ──
1285 "#]]
1286 .assert_eq(&circ);
1287}
1288
1289#[test]
1290fn operation_with_subsequent_qubits_no_added_rows() {
1291 let circ = circuit(
1292 r"
1293 namespace Test {
1294 import Std.Measurement.*;
1295
1296 @EntryPoint()
1297 operation Main() : Result[] {
1298 use q0 = Qubit();
1299 use q1 = Qubit();
1300 Rxx(1.0, q0, q1);
1301
1302 use q2 = Qubit();
1303 use q3 = Qubit();
1304 Rxx(1.0, q2, q3);
1305
1306 [M(q0), M(q2)]
1307 }
1308 }
1309 ",
1310 CircuitEntryPoint::EntryPoint,
1311 );
1312
1313 expect![[r#"
1314 q_0@test.qs:6:20 ─ Rxx(1.0000)@test.qs:8:20 ─── M@test.qs:14:21 ─
1315 ┆ ╘═════════
1316 q_1@test.qs:7:20 ─ Rxx(1.0000)@test.qs:8:20 ─────────────────────
1317 q_2@test.qs:10:20 ─ Rxx(1.0000)@test.qs:12:20 ── M@test.qs:14:28 ─
1318 ┆ ╘═════════
1319 q_3@test.qs:11:20 ─ Rxx(1.0000)@test.qs:12:20 ────────────────────
1320 "#]]
1321 .assert_eq(&circ);
1322}
1323
1324#[test]
1325fn operation_declared_in_eval() {
1326 let mut interpreter = interpreter("", PackageType::Lib, Profile::Unrestricted);
1327 let mut out = std::io::sink();
1328 let mut r = GenericReceiver::new(&mut out);
1329
1330 interpreter
1331 .eval_fragments(
1332 &mut r,
1333 "operation Foo() : Result { use q = Qubit(); H(q); return M(q) }",
1334 )
1335 .expect("eval should succeed");
1336
1337 let c = interpreter
1338 .circuit(
1339 CircuitEntryPoint::EntryExpr("Foo()".into()),
1340 CircuitGenerationMethod::ClassicalEval,
1341 TracerConfig {
1342 max_operations: usize::MAX,
1343 source_locations: false,
1344 group_by_scope: true,
1345 prune_classical_qubits: false,
1346 },
1347 )
1348 .expect("circuit generation should succeed");
1349
1350 expect![[r#"
1351 q_0 ─ [ [Foo] ─── H ──── M ──── ] ──
1352 [ ╘═════ ] ══
1353 "#]]
1354 .assert_eq(&c.display_with_groups().to_string());
1355}
1356
1357/// Tests that invoke circuit generation through the debugger.
1358mod debugger_stepping {
1359 use super::Debugger;
1360 use crate::target::Profile;
1361 use expect_test::expect;
1362 use qsc_data_structures::language_features::LanguageFeatures;
1363 use qsc_data_structures::line_column::Encoding;
1364 use qsc_data_structures::source::SourceMap;
1365 use qsc_eval::{StepAction, StepResult, output::GenericReceiver};
1366 use std::fmt::Write;
1367
1368 /// Steps through the code in the debugger and collects the
1369 /// circuit representation at each step.
1370 fn generate_circuit_steps(code: &str, profile: Profile) -> String {
1371 let sources = SourceMap::new([("test.qs".into(), code.into())], None);
1372 let (std_id, store) = crate::compile::package_store_with_stdlib(profile.into());
1373 let mut debugger = Debugger::new(
1374 sources,
1375 profile.into(),
1376 Encoding::Utf8,
1377 LanguageFeatures::default(),
1378 store,
1379 &[(std_id, None)],
1380 )
1381 .expect("debugger creation should succeed");
1382
1383 debugger.interpreter.set_quantum_seed(Some(2));
1384
1385 let mut out = std::io::sink();
1386 let mut r = GenericReceiver::new(&mut out);
1387
1388 let mut circs = String::new();
1389 let mut result = debugger
1390 .eval_step(&mut r, &[], StepAction::In)
1391 .expect("step should succeed");
1392
1393 write!(&mut circs, "step:\n{}", debugger.circuit()).expect("write should succeed");
1394 while !matches!(result, StepResult::Return(_)) {
1395 result = debugger
1396 .eval_step(&mut r, &[], StepAction::Next)
1397 .expect("step should succeed");
1398
1399 write!(&mut circs, "step:\n{}", debugger.circuit()).expect("write should succeed");
1400 }
1401 circs
1402 }
1403
1404 #[test]
1405 fn base_profile() {
1406 let circs = generate_circuit_steps(
1407 r"
1408 namespace Test {
1409 import Std.Measurement.*;
1410 @EntryPoint()
1411 operation Main() : Result[] {
1412 use q = Qubit();
1413 H(q);
1414 let r = M(q);
1415 Reset(q);
1416 [r]
1417 }
1418 }
1419 ",
1420 Profile::Base,
1421 );
1422
1423 expect![[r#"
1424 step:
1425 step:
1426 q_0@test.qs:5:24
1427 step:
1428 q_0@test.qs:5:24 ─ H@test.qs:6:24 ──
1429 step:
1430 q_0@test.qs:5:24 ─ H@test.qs:6:24 ─── M@test.qs:7:32 ──
1431 ╘═════════
1432 step:
1433 q_0@test.qs:5:24 ─ H@test.qs:6:24 ─── M@test.qs:7:32 ──── |0〉@test.qs:8:24 ───
1434 ╘════════════════════════════════
1435 step:
1436 q_0@test.qs:5:24 ─ H@test.qs:6:24 ─── M@test.qs:7:32 ──── |0〉@test.qs:8:24 ───
1437 ╘════════════════════════════════
1438 step:
1439 q_0@test.qs:5:24 ─ H@test.qs:6:24 ─── M@test.qs:7:32 ──── |0〉@test.qs:8:24 ───
1440 ╘════════════════════════════════
1441 "#]]
1442 .assert_eq(&circs);
1443 }
1444
1445 #[test]
1446 fn unrestricted_profile() {
1447 let circs = generate_circuit_steps(
1448 r"
1449 namespace Test {
1450 import Std.Measurement.*;
1451 @EntryPoint()
1452 operation Main() : Result[] {
1453 use q = Qubit();
1454 H(q);
1455 let r = M(q);
1456 Reset(q);
1457 [r]
1458 }
1459 }
1460 ",
1461 Profile::Unrestricted,
1462 );
1463
1464 expect![[r#"
1465 step:
1466 step:
1467 q_0@test.qs:5:24
1468 step:
1469 q_0@test.qs:5:24 ─ H@test.qs:6:24 ──
1470 step:
1471 q_0@test.qs:5:24 ─ H@test.qs:6:24 ─── M@test.qs:7:32 ──
1472 ╘═════════
1473 step:
1474 q_0@test.qs:5:24 ─ H@test.qs:6:24 ─── M@test.qs:7:32 ──── |0〉@test.qs:8:24 ───
1475 ╘════════════════════════════════
1476 step:
1477 q_0@test.qs:5:24 ─ H@test.qs:6:24 ─── M@test.qs:7:32 ──── |0〉@test.qs:8:24 ───
1478 ╘════════════════════════════════
1479 step:
1480 q_0@test.qs:5:24 ─ H@test.qs:6:24 ─── M@test.qs:7:32 ──── |0〉@test.qs:8:24 ───
1481 ╘════════════════════════════════
1482 "#]]
1483 .assert_eq(&circs);
1484 }
1485
1486 #[test]
1487 fn unrestricted_profile_result_comparison() {
1488 let circs = generate_circuit_steps(
1489 r"
1490 namespace Test {
1491 import Std.Measurement.*;
1492 @EntryPoint()
1493 operation Main() : Result[] {
1494 use q = Qubit();
1495 H(q);
1496 let r = M(q);
1497 if (r == One) {
1498 X(q);
1499 }
1500 [r]
1501 }
1502 }
1503 ",
1504 Profile::Unrestricted,
1505 );
1506
1507 // We set the random seed in the test to account for
1508 // the nondeterministic output. Since the debugger is running
1509 // the real simulator, the circuit is going to vary from run to run
1510 // depending on measurement outcomes.
1511 expect![[r#"
1512 step:
1513 step:
1514 q_0@test.qs:5:24
1515 step:
1516 q_0@test.qs:5:24 ─ H@test.qs:6:24 ──
1517 step:
1518 q_0@test.qs:5:24 ─ H@test.qs:6:24 ─── M@test.qs:7:32 ──
1519 ╘═════════
1520 step:
1521 q_0@test.qs:5:24 ─ H@test.qs:6:24 ─── M@test.qs:7:32 ──
1522 ╘═════════
1523 step:
1524 q_0@test.qs:5:24 ─ H@test.qs:6:24 ─── M@test.qs:7:32 ─── X@test.qs:9:28 ──
1525 ╘════════════════════════════
1526 step:
1527 q_0@test.qs:5:24 ─ H@test.qs:6:24 ─── M@test.qs:7:32 ─── X@test.qs:9:28 ──
1528 ╘════════════════════════════
1529 step:
1530 q_0@test.qs:5:24 ─ H@test.qs:6:24 ─── M@test.qs:7:32 ─── X@test.qs:9:28 ──
1531 ╘════════════════════════════
1532 step:
1533 q_0@test.qs:5:24 ─ H@test.qs:6:24 ─── M@test.qs:7:32 ─── X@test.qs:9:28 ──
1534 ╘════════════════════════════
1535 "#]]
1536 .assert_eq(&circs);
1537 }
1538}
1539