Skip to content

Commit 88ad901

Browse files
authored
Merge fe1c3ac into 52a6bd4
2 parents 52a6bd4 + fe1c3ac commit 88ad901

File tree

8 files changed

+83
-245
lines changed

8 files changed

+83
-245
lines changed

compiler/qsc/src/interpret.rs

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -759,7 +759,6 @@ impl Interpreter {
759759
sim.chained.finish()
760760
} else {
761761
let mut sim = CircuitBuilder::new(CircuitConfig {
762-
base_profile: self.capabilities.is_empty(),
763762
max_operations: CircuitConfig::DEFAULT_MAX_OPERATIONS,
764763
});
765764

@@ -1004,14 +1003,6 @@ fn sim_circuit_backend() -> BackendChain<SparseSim, CircuitBuilder> {
10041003
BackendChain::new(
10051004
SparseSim::new(),
10061005
CircuitBuilder::new(CircuitConfig {
1007-
// When using in conjunction with the simulator,
1008-
// the circuit builder should *not* perform base profile
1009-
// decompositions, in order to match the simulator's behavior.
1010-
//
1011-
// Note that conditional compilation (e.g. @Config(Base) attributes)
1012-
// will still respect the selected profile. This also
1013-
// matches the behavior of the simulator.
1014-
base_profile: false,
10151006
max_operations: CircuitConfig::DEFAULT_MAX_OPERATIONS,
10161007
}),
10171008
)

compiler/qsc/src/interpret/circuit_tests.rs

Lines changed: 22 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -202,11 +202,10 @@ fn m_base_profile() {
202202
.circuit(CircuitEntryPoint::EntryPoint, false)
203203
.expect("circuit generation should succeed");
204204

205-
expect![[r"
206-
q_0 ── H ──── Z ────────────────
207-
q_1 ── H ──── ● ──── H ──── M ──
208-
╘═══
209-
"]]
205+
expect![[r#"
206+
q_0 ── H ──── M ──
207+
╘═══
208+
"#]]
210209
.assert_eq(&circ.to_string());
211210
}
212211

@@ -287,10 +286,10 @@ fn mresetz_base_profile() {
287286
.circuit(CircuitEntryPoint::EntryPoint, false)
288287
.expect("circuit generation should succeed");
289288

290-
expect![[r"
291-
q_0 ── H ──── M ──
292-
╘═══
293-
"]]
289+
expect![[r#"
290+
q_0 ── H ──── M ──── |0〉 ──
291+
╘════════════
292+
"#]]
294293
.assert_eq(&circ.to_string());
295294
}
296295

@@ -597,14 +596,12 @@ fn operation_with_qubits_base_profile() {
597596
.circuit(CircuitEntryPoint::Operation("Test.Test".into()), false)
598597
.expect("circuit generation should succeed");
599598

600-
expect![[r"
601-
q_0 ── H ──── ● ──── Z ──────────────────────────────
602-
q_1 ───────── X ─────┼──────────── Z ────────────────
603-
q_2 ── H ─────────── ● ──── H ─────┼───── M ─────────
604-
│ ╘══════════
605-
q_3 ── H ───────────────────────── ● ──── H ──── M ──
606-
╘═══
607-
"]]
599+
expect![[r#"
600+
q_0 ── H ──── ● ──── M ──
601+
│ ╘═══
602+
q_1 ───────── X ──── M ──
603+
╘═══
604+
"#]]
608605
.assert_eq(&circ.to_string());
609606
}
610607

@@ -1071,29 +1068,22 @@ mod debugger_stepping {
10711068
// be generated in Base Profile, but they are here, since
10721069
// when running in tandem with the simulator, the resulting
10731070
// circuit is intended to match the calls into the simulator.
1074-
//
1075-
// Note the circuit still looks different than what would be
1076-
// generated in Unrestricted Profile for the same code,
1077-
// due to conditional compilation in the standard library.
1078-
expect![["
1071+
expect![[r#"
10791072
step:
10801073
step:
10811074
q_0
10821075
step:
10831076
q_0 ── H ──
10841077
step:
1085-
q_0 ── H ──── Z ─────────────────────────
1086-
q_1 ── H ──── ● ──── H ──── M ──── |0〉 ──
1087-
╘════════════
1078+
q_0 ── H ──── M ──
1079+
╘═══
10881080
step:
1089-
q_0 ── H ──── Z ──── |0〉 ──────────────────
1090-
q_1 ── H ──── ● ───── H ───── M ──── |0〉 ──
1091-
╘════════════
1081+
q_0 ── H ──── M ──── |0〉 ──
1082+
╘════════════
10921083
step:
1093-
q_0 ── H ──── Z ──── |0〉 ──────────────────
1094-
q_1 ── H ──── ● ───── H ───── M ──── |0〉 ──
1095-
╘════════════
1096-
"]]
1084+
q_0 ── H ──── M ──── |0〉 ──
1085+
╘════════════
1086+
"#]]
10971087
.assert_eq(&circs);
10981088
}
10991089

compiler/qsc/src/interpret/tests.rs

Lines changed: 20 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -884,21 +884,17 @@ mod given_interpreter {
884884
885885
define void @ENTRYPOINT__main() #0 {
886886
block_0:
887-
call void @__quantum__qis__h__body(%Qubit* inttoptr (i64 1 to %Qubit*))
888-
call void @__quantum__qis__cz__body(%Qubit* inttoptr (i64 1 to %Qubit*), %Qubit* inttoptr (i64 0 to %Qubit*))
889-
call void @__quantum__qis__h__body(%Qubit* inttoptr (i64 1 to %Qubit*))
890-
call void @__quantum__qis__m__body(%Qubit* inttoptr (i64 1 to %Qubit*), %Result* inttoptr (i64 0 to %Result*))
887+
call void @__quantum__qis__cx__body(%Qubit* inttoptr (i64 0 to %Qubit*), %Qubit* inttoptr (i64 1 to %Qubit*))
888+
call void @__quantum__qis__m__body(%Qubit* inttoptr (i64 0 to %Qubit*), %Result* inttoptr (i64 0 to %Result*))
891889
call void @__quantum__rt__result_record_output(%Result* inttoptr (i64 0 to %Result*), i8* null)
892890
ret void
893891
}
894892
895-
declare void @__quantum__qis__h__body(%Qubit*)
896-
897-
declare void @__quantum__qis__cz__body(%Qubit*, %Qubit*)
893+
declare void @__quantum__qis__m__body(%Qubit*, %Result*) #1
898894
899895
declare void @__quantum__rt__result_record_output(%Result*, i8*)
900896
901-
declare void @__quantum__qis__m__body(%Qubit*, %Result*) #1
897+
declare void @__quantum__qis__cx__body(%Qubit*, %Qubit*)
902898
903899
attributes #0 = { "entry_point" "output_labeling_schema" "qir_profiles"="base_profile" "required_num_qubits"="2" "required_num_results"="1" }
904900
attributes #1 = { "irreversible" }
@@ -1083,21 +1079,17 @@ mod given_interpreter {
10831079
10841080
define void @ENTRYPOINT__main() #0 {
10851081
block_0:
1086-
call void @__quantum__qis__h__body(%Qubit* inttoptr (i64 1 to %Qubit*))
1087-
call void @__quantum__qis__cz__body(%Qubit* inttoptr (i64 1 to %Qubit*), %Qubit* inttoptr (i64 0 to %Qubit*))
1088-
call void @__quantum__qis__h__body(%Qubit* inttoptr (i64 1 to %Qubit*))
1089-
call void @__quantum__qis__m__body(%Qubit* inttoptr (i64 1 to %Qubit*), %Result* inttoptr (i64 0 to %Result*))
1082+
call void @__quantum__qis__cx__body(%Qubit* inttoptr (i64 0 to %Qubit*), %Qubit* inttoptr (i64 1 to %Qubit*))
1083+
call void @__quantum__qis__m__body(%Qubit* inttoptr (i64 0 to %Qubit*), %Result* inttoptr (i64 0 to %Result*))
10901084
call void @__quantum__rt__result_record_output(%Result* inttoptr (i64 0 to %Result*), i8* null)
10911085
ret void
10921086
}
10931087
1094-
declare void @__quantum__qis__h__body(%Qubit*)
1095-
1096-
declare void @__quantum__qis__cz__body(%Qubit*, %Qubit*)
1088+
declare void @__quantum__qis__m__body(%Qubit*, %Result*) #1
10971089
10981090
declare void @__quantum__rt__result_record_output(%Result*, i8*)
10991091
1100-
declare void @__quantum__qis__m__body(%Qubit*, %Result*) #1
1092+
declare void @__quantum__qis__cx__body(%Qubit*, %Qubit*)
11011093
11021094
attributes #0 = { "entry_point" "output_labeling_schema" "qir_profiles"="base_profile" "required_num_qubits"="2" "required_num_results"="1" }
11031095
attributes #1 = { "irreversible" }
@@ -1131,21 +1123,17 @@ mod given_interpreter {
11311123
11321124
define void @ENTRYPOINT__main() #0 {
11331125
block_0:
1134-
call void @__quantum__qis__h__body(%Qubit* inttoptr (i64 1 to %Qubit*))
1135-
call void @__quantum__qis__cz__body(%Qubit* inttoptr (i64 1 to %Qubit*), %Qubit* inttoptr (i64 0 to %Qubit*))
1136-
call void @__quantum__qis__h__body(%Qubit* inttoptr (i64 1 to %Qubit*))
1137-
call void @__quantum__qis__m__body(%Qubit* inttoptr (i64 1 to %Qubit*), %Result* inttoptr (i64 0 to %Result*))
1126+
call void @__quantum__qis__cx__body(%Qubit* inttoptr (i64 0 to %Qubit*), %Qubit* inttoptr (i64 1 to %Qubit*))
1127+
call void @__quantum__qis__m__body(%Qubit* inttoptr (i64 0 to %Qubit*), %Result* inttoptr (i64 0 to %Result*))
11381128
call void @__quantum__rt__result_record_output(%Result* inttoptr (i64 0 to %Result*), i8* null)
11391129
ret void
11401130
}
11411131
1142-
declare void @__quantum__qis__h__body(%Qubit*)
1143-
1144-
declare void @__quantum__qis__cz__body(%Qubit*, %Qubit*)
1132+
declare void @__quantum__qis__m__body(%Qubit*, %Result*) #1
11451133
11461134
declare void @__quantum__rt__result_record_output(%Result*, i8*)
11471135
1148-
declare void @__quantum__qis__m__body(%Qubit*, %Result*) #1
1136+
declare void @__quantum__qis__cx__body(%Qubit*, %Qubit*)
11491137
11501138
attributes #0 = { "entry_point" "output_labeling_schema" "qir_profiles"="base_profile" "required_num_qubits"="2" "required_num_results"="1" }
11511139
attributes #1 = { "irreversible" }
@@ -1211,21 +1199,17 @@ mod given_interpreter {
12111199
12121200
define void @ENTRYPOINT__main() #0 {
12131201
block_0:
1214-
call void @__quantum__qis__h__body(%Qubit* inttoptr (i64 1 to %Qubit*))
1215-
call void @__quantum__qis__cz__body(%Qubit* inttoptr (i64 1 to %Qubit*), %Qubit* inttoptr (i64 0 to %Qubit*))
1216-
call void @__quantum__qis__h__body(%Qubit* inttoptr (i64 1 to %Qubit*))
1217-
call void @__quantum__qis__m__body(%Qubit* inttoptr (i64 1 to %Qubit*), %Result* inttoptr (i64 0 to %Result*))
1202+
call void @__quantum__qis__cx__body(%Qubit* inttoptr (i64 0 to %Qubit*), %Qubit* inttoptr (i64 1 to %Qubit*))
1203+
call void @__quantum__qis__m__body(%Qubit* inttoptr (i64 0 to %Qubit*), %Result* inttoptr (i64 0 to %Result*))
12181204
call void @__quantum__rt__result_record_output(%Result* inttoptr (i64 0 to %Result*), i8* null)
12191205
ret void
12201206
}
12211207
1222-
declare void @__quantum__qis__h__body(%Qubit*)
1223-
1224-
declare void @__quantum__qis__cz__body(%Qubit*, %Qubit*)
1208+
declare void @__quantum__qis__m__body(%Qubit*, %Result*) #1
12251209
12261210
declare void @__quantum__rt__result_record_output(%Result*, i8*)
12271211
1228-
declare void @__quantum__qis__m__body(%Qubit*, %Result*) #1
1212+
declare void @__quantum__qis__cx__body(%Qubit*, %Qubit*)
12291213
12301214
attributes #0 = { "entry_point" "output_labeling_schema" "qir_profiles"="base_profile" "required_num_qubits"="2" "required_num_results"="1" }
12311215
attributes #1 = { "irreversible" }
@@ -1271,21 +1255,17 @@ mod given_interpreter {
12711255
12721256
define void @ENTRYPOINT__main() #0 {
12731257
block_0:
1274-
call void @__quantum__qis__h__body(%Qubit* inttoptr (i64 1 to %Qubit*))
1275-
call void @__quantum__qis__cz__body(%Qubit* inttoptr (i64 1 to %Qubit*), %Qubit* inttoptr (i64 0 to %Qubit*))
1276-
call void @__quantum__qis__h__body(%Qubit* inttoptr (i64 1 to %Qubit*))
1277-
call void @__quantum__qis__m__body(%Qubit* inttoptr (i64 1 to %Qubit*), %Result* inttoptr (i64 0 to %Result*))
1258+
call void @__quantum__qis__cx__body(%Qubit* inttoptr (i64 0 to %Qubit*), %Qubit* inttoptr (i64 1 to %Qubit*))
1259+
call void @__quantum__qis__m__body(%Qubit* inttoptr (i64 0 to %Qubit*), %Result* inttoptr (i64 0 to %Result*))
12781260
call void @__quantum__rt__result_record_output(%Result* inttoptr (i64 0 to %Result*), i8* null)
12791261
ret void
12801262
}
12811263
1282-
declare void @__quantum__qis__h__body(%Qubit*)
1283-
1284-
declare void @__quantum__qis__cz__body(%Qubit*, %Qubit*)
1264+
declare void @__quantum__qis__m__body(%Qubit*, %Result*) #1
12851265
12861266
declare void @__quantum__rt__result_record_output(%Result*, i8*)
12871267
1288-
declare void @__quantum__qis__m__body(%Qubit*, %Result*) #1
1268+
declare void @__quantum__qis__cx__body(%Qubit*, %Qubit*)
12891269
12901270
attributes #0 = { "entry_point" "output_labeling_schema" "qir_profiles"="base_profile" "required_num_qubits"="2" "required_num_results"="1" }
12911271
attributes #1 = { "irreversible" }

compiler/qsc_circuit/src/builder.rs

Lines changed: 21 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -56,48 +56,34 @@ impl Backend for Builder {
5656
}
5757

5858
fn m(&mut self, q: usize) -> Self::ResultType {
59-
if self.config.base_profile {
60-
// defer the measurement and reset the qubit
61-
self.remapper.mreset(q)
62-
} else {
63-
let mapped_q = self.map(q);
64-
// In the Circuit schema, result id is per-qubit
65-
let res_id = self.num_measurements_for_qubit(mapped_q);
66-
let id = self.remapper.m(q);
59+
let mapped_q = self.map(q);
60+
// In the Circuit schema, result id is per-qubit
61+
let res_id = self.num_measurements_for_qubit(mapped_q);
62+
let id = self.remapper.m(q);
6763

68-
self.push_gate(measurement_gate(mapped_q.0, res_id));
69-
id
70-
}
64+
self.push_gate(measurement_gate(mapped_q.0, res_id));
65+
id
7166
}
7267

7368
fn mresetz(&mut self, q: usize) -> Self::ResultType {
74-
if self.config.base_profile {
75-
// defer the measurement
76-
self.remapper.mreset(q)
77-
} else {
78-
let mapped_q = self.map(q);
79-
// In the Circuit schema, result id is per-qubit
80-
let res_id = self.num_measurements_for_qubit(mapped_q);
81-
// We don't actually need the Remapper since we're not
82-
// remapping any qubits, but it's handy for keeping track of measurements
83-
let id = self.remapper.m(q);
84-
85-
// Ideally MResetZ would be atomic but we don't currently have
86-
// a way to visually represent that. So decompose it into
87-
// a measurement and a reset gate.
88-
self.push_gate(measurement_gate(mapped_q.0, res_id));
89-
self.push_gate(gate(KET_ZERO, [mapped_q]));
90-
id
91-
}
69+
let mapped_q = self.map(q);
70+
// In the Circuit schema, result id is per-qubit
71+
let res_id = self.num_measurements_for_qubit(mapped_q);
72+
// We don't actually need the Remapper since we're not
73+
// remapping any qubits, but it's handy for keeping track of measurements
74+
let id = self.remapper.m(q);
75+
76+
// Ideally MResetZ would be atomic but we don't currently have
77+
// a way to visually represent that. So decompose it into
78+
// a measurement and a reset gate.
79+
self.push_gate(measurement_gate(mapped_q.0, res_id));
80+
self.push_gate(gate(KET_ZERO, [mapped_q]));
81+
id
9282
}
9383

9484
fn reset(&mut self, q: usize) {
95-
if self.config.base_profile {
96-
self.remapper.reset(q);
97-
} else {
98-
let mapped_q = self.map(q);
99-
self.push_gate(gate(KET_ZERO, [mapped_q]));
100-
}
85+
let mapped_q = self.map(q);
86+
self.push_gate(gate(KET_ZERO, [mapped_q]));
10187
}
10288

10389
fn rx(&mut self, theta: f64, q: usize) {
@@ -267,18 +253,6 @@ impl Builder {
267253
}
268254

269255
fn finish_circuit(&self, mut circuit: Circuit) -> Circuit {
270-
// add deferred measurements
271-
if self.config.base_profile {
272-
for (qubit, _) in &self.remapper.qubit_measurement_counts {
273-
if self.max_ops_exceeded || circuit.operations.len() >= self.config.max_operations {
274-
break;
275-
}
276-
277-
// guaranteed one measurement per qubit, so result is always 0
278-
circuit.operations.push(measurement_gate(qubit.0, 0));
279-
}
280-
}
281-
282256
// add qubit declarations
283257
for i in 0..self.remapper.num_qubits() {
284258
let num_measurements = self.num_measurements_for_qubit(WireId(i));
@@ -408,16 +382,6 @@ impl Remapper {
408382
id
409383
}
410384

411-
fn mreset(&mut self, q: usize) -> usize {
412-
let id = self.m(q);
413-
self.reset(q);
414-
id
415-
}
416-
417-
fn reset(&mut self, q: usize) {
418-
self.qubit_map.remove(q);
419-
}
420-
421385
fn qubit_allocate(&mut self) -> usize {
422386
let id = self.next_qubit_id;
423387
self.next_qubit_id += 1;

compiler/qsc_circuit/src/builder/tests.rs

Lines changed: 5 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,7 @@ use expect_test::expect;
66

77
#[test]
88
fn exceed_max_operations() {
9-
let mut builder = Builder::new(Config {
10-
base_profile: false,
11-
max_operations: 2,
12-
});
9+
let mut builder = Builder::new(Config { max_operations: 2 });
1310

1411
let q = builder.qubit_allocate();
1512

@@ -31,10 +28,7 @@ fn exceed_max_operations() {
3128

3229
#[test]
3330
fn exceed_max_operations_deferred_measurements() {
34-
let mut builder = Builder::new(Config {
35-
base_profile: true, // deferred measurements
36-
max_operations: 2,
37-
});
31+
let mut builder = Builder::new(Config { max_operations: 2 });
3832

3933
let q = builder.qubit_allocate();
4034

@@ -48,11 +42,10 @@ fn exceed_max_operations_deferred_measurements() {
4842

4943
// The current behavior is to silently truncate the circuit
5044
// if it exceeds the maximum allowed number of operations.
51-
// The measurement will be dropped.
45+
// The second X will be dropped.
5246
expect![[r#"
53-
q_0 ── X ──
54-
55-
q_1 ── X ──
47+
q_0 ── X ──── M ──
48+
╘═══
5649
"#]]
5750
.assert_eq(&circuit.to_string());
5851
}

compiler/qsc_circuit/src/circuit.rs

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -79,8 +79,6 @@ pub struct Qubit {
7979

8080
#[derive(Clone, Debug, Copy, Default)]
8181
pub struct Config {
82-
/// Perform Base Profile decompositions
83-
pub base_profile: bool,
8482
/// Maximum number of operations the builder will add to the circuit
8583
pub max_operations: usize,
8684
}

0 commit comments

Comments
 (0)