99// RUN: quantum-opt %s -split-input-file --gate-decomposition | FileCheck %s
1010
1111// -----
12- // This test checks if an even number of CNOT gates will be cancelled out.
12+ // This test checks if a series equal to the identity will be cancelled out.
1313
1414module {
15- // CHECK-LABEL: func.func @testEvenNegationSeries
16- func.func @testEvenNegationSeries () {
15+ // CHECK-LABEL: func.func @testIdentitySeries
16+ func.func @testIdentitySeries () {
1717 // CHECK: %[[Q0_0:.*]] = mqtopt.allocQubit
1818 // CHECK: %[[Q1_0:.*]] = mqtopt.allocQubit
1919
@@ -93,20 +93,57 @@ module {
9393 }
9494}
9595
96+ // -----
97+ // This test checks if an odd number of CNOT gates with ctrl/target swapped will be reduced to a single CNOT.
98+
99+ module {
100+ // CHECK-LABEL: func.func @testCNotOtherDirection
101+ func.func @testCNotOtherDirection () {
102+ // CHECK: %[[Q0_0:.*]] = mqtopt.allocQubit
103+ // CHECK: %[[Q1_0:.*]] = mqtopt.allocQubit
104+
105+ // CHECK-NOT: mqtopt.i(%[[ANY:.*]])
106+ // CHECK: %[[Q0_0]], %[[Q1_0]] = mqtopt.x() %[[Q0_0]] ctrl %[[Q1_0]]
107+
108+ // CHECK: mqtopt.deallocQubit %[[Q0_1]]
109+ // CHECK: mqtopt.deallocQubit %[[Q1_1]]
110+
111+ // ensure no other operations are inserted
112+ // CHECK-NOT: mqtopt.[[ANY:.*]]
113+
114+ %q0_0 = mqtopt.allocQubit
115+ %q1_0 = mqtopt.allocQubit
116+
117+ %q1_1 , %q0_1 = mqtopt.i () %q1_0 ctrl %q0_0: !mqtopt.Qubit ctrl !mqtopt.Qubit
118+ %q1_2 , %q0_2 = mqtopt.x () %q1_1 ctrl %q0_1: !mqtopt.Qubit ctrl !mqtopt.Qubit
119+ %q1_3 , %q0_3 = mqtopt.i () %q1_2 ctrl %q0_2: !mqtopt.Qubit ctrl !mqtopt.Qubit
120+
121+ mqtopt.deallocQubit %q0_3
122+ mqtopt.deallocQubit %q1_3
123+
124+ return
125+ }
126+ }
127+
96128// -----
97129// This test checks if a two-qubit series containing a single-qubit gate is decomposed correctly.
98130
99131module {
100132 // CHECK-LABEL: func.func @testSeriesOneQubitOpInbetween
101133 func.func @testSeriesOneQubitOpInbetween () {
134+ // CHECK: %[[C2:.*]] = arith.constant -1.5707
135+ // CHECK: %[[C1:.*]] = arith.constant 3.14159
136+ // CHECK: %[[C0:.*]] = arith.constant 1.57079
137+
102138 // CHECK: %[[Q0_0:.*]] = mqtopt.allocQubit
103139 // CHECK: %[[Q1_0:.*]] = mqtopt.allocQubit
104140
105141 // CHECK: mqtopt.gphase(%[[C0:.*]])
106- // CHECK: %[[Q0_1:.*]] = mqtopt.ry(%[[C1:.*]]) %[[Q0_0]]
107- // CHECK: %[[Q0_2:.*]] = mqtopt.rz(%[[C1]]) %[[Q0_1]]
142+ // CHECK: %[[Q0_1:.*]] = mqtopt.rz(%[[C0]]) %[[Q0_0]]
143+ // CHECK: %[[Q0_2:.*]] = mqtopt.ry(%[[C1:.*]]) %[[Q0_1]]
144+ // CHECK: %[[Q0_3:.*]] = mqtopt.rz(%[[C2:.*]]) %[[Q0_2]]
108145
109- // CHECK: mqtopt.deallocQubit %[[Q0_2 ]]
146+ // CHECK: mqtopt.deallocQubit %[[Q0_3 ]]
110147 // CHECK: mqtopt.deallocQubit %[[Q1_0]]
111148
112149 %q0_0 = mqtopt.allocQubit
@@ -129,14 +166,19 @@ module {
129166module {
130167 // CHECK-LABEL: func.func @testSeriesStartingOneQubitOp
131168 func.func @testSeriesStartingOneQubitOp () {
169+ // CHECK: %[[C2:.*]] = arith.constant -1.5707
170+ // CHECK: %[[C1:.*]] = arith.constant 3.14159
171+ // CHECK: %[[C0:.*]] = arith.constant 1.57079
172+
132173 // CHECK: %[[Q0_0:.*]] = mqtopt.allocQubit
133174 // CHECK: %[[Q1_0:.*]] = mqtopt.allocQubit
134175
135176 // CHECK: mqtopt.gphase(%[[C0:.*]])
136- // CHECK: %[[Q0_1:.*]] = mqtopt.ry(%[[C1:.*]]) %[[Q0_0]]
137- // CHECK: %[[Q0_2:.*]] = mqtopt.rz(%[[C1]]) %[[Q0_1]]
177+ // CHECK: %[[Q0_1:.*]] = mqtopt.rz(%[[C0]]) %[[Q0_0]]
178+ // CHECK: %[[Q0_2:.*]] = mqtopt.ry(%[[C1:.*]]) %[[Q0_1]]
179+ // CHECK: %[[Q0_3:.*]] = mqtopt.rz(%[[C2:.*]]) %[[Q0_2]]
138180
139- // CHECK: mqtopt.deallocQubit %[[Q0_2 ]]
181+ // CHECK: mqtopt.deallocQubit %[[Q0_3 ]]
140182 // CHECK: mqtopt.deallocQubit %[[Q1_0]]
141183
142184 %q0_0 = mqtopt.allocQubit
@@ -159,14 +201,19 @@ module {
159201module {
160202 // CHECK-LABEL: func.func @testSeriesEndingOneQubitOp
161203 func.func @testSeriesEndingOneQubitOp () {
204+ // CHECK: %[[C2:.*]] = arith.constant -1.5707
205+ // CHECK: %[[C1:.*]] = arith.constant 3.14159
206+ // CHECK: %[[C0:.*]] = arith.constant 1.57079
207+
162208 // CHECK: %[[Q0_0:.*]] = mqtopt.allocQubit
163209 // CHECK: %[[Q1_0:.*]] = mqtopt.allocQubit
164210
165211 // CHECK: mqtopt.gphase(%[[C0:.*]])
166- // CHECK: %[[Q0_1:.*]] = mqtopt.ry(%[[C1:.*]]) %[[Q0_0]]
167- // CHECK: %[[Q0_2:.*]] = mqtopt.rz(%[[C1]]) %[[Q0_1]]
212+ // CHECK: %[[Q0_1:.*]] = mqtopt.rz(%[[C0]]) %[[Q0_0]]
213+ // CHECK: %[[Q0_2:.*]] = mqtopt.ry(%[[C1:.*]]) %[[Q0_1]]
214+ // CHECK: %[[Q0_3:.*]] = mqtopt.rz(%[[C2:.*]]) %[[Q0_2]]
168215
169- // CHECK: mqtopt.deallocQubit %[[Q0_2 ]]
216+ // CHECK: mqtopt.deallocQubit %[[Q0_3 ]]
170217 // CHECK: mqtopt.deallocQubit %[[Q1_0]]
171218
172219 %q0_0 = mqtopt.allocQubit
@@ -228,23 +275,53 @@ module {
228275module {
229276 // CHECK-LABEL: func.func @testTwoBasisGateDecomposition
230277 func.func @testTwoBasisGateDecomposition () {
278+ // CHECK: %[[C0:.*]] = arith.constant -2.356194490
279+ // CHECK: %[[C1:.*]] = arith.constant -1.070796326
280+ // CHECK: %[[C2:.*]] = arith.constant -0.370796326
281+ // CHECK: %[[C3:.*]] = arith.constant -2.526112944
282+ // CHECK: %[[C4:.*]] = arith.constant 1.0471975511
283+ // CHECK: %[[C5:.*]] = arith.constant 0.6154797086
284+ // CHECK: %[[C6:.*]] = arith.constant -3.141592653
285+ // CHECK: %[[C7:.*]] = arith.constant 2.7707963267
286+ // CHECK: %[[C8:.*]] = arith.constant -1.570796326
287+ // CHECK: %[[C9:.*]] = arith.constant 0.7853981633
288+ // CHECK: %[[C10:.*]] = arith.constant 2.5000
289+ // CHECK: %[[C11:.*]] = arith.constant 1.570796326
290+ // CHECK: %[[C12:.*]] = arith.constant -1.57079632
291+ // CHECK: %[[C13:.*]] = arith.constant 8.881784197
292+
231293 // CHECK: %[[Q0_0:.*]] = mqtopt.allocQubit
232294 // CHECK: %[[Q1_0:.*]] = mqtopt.allocQubit
233- // CHECK: %[[Q2_0:.*]] = mqtopt.allocQubit
234295
235- // CHECK-NOT: mqtopt.gphase(%[[ANY:.*]])
236-
237- // CHECK: mqtopt.deallocQubit %[[Q0_5]]
238- // CHECK: mqtopt.deallocQubit %[[Q1_4]]
239- // CHECK: mqtopt.deallocQubit %[[Q2_1]]
296+ // CHECK: mqtopt.gphase(%[[C13]])
297+ // CHECK: %[[Q0_1:.*]] = mqtopt.rz(%[[C12]]) %[[Q0_0]]
298+ // CHECK: %[[Q0_2:.*]] = mqtopt.ry(%[[C11]]) %[[Q0_1]]
299+ // CHECK: %[[Q0_3:.*]] = mqtopt.rz(%[[C11]]) %[[Q0_2]]
300+ // CHECK: %[[Q1_1:.*]] = mqtopt.rz(%[[C10]]) %[[Q1_0]]
301+ // CHECK: %[[Q1_2:.*]] = mqtopt.ry(%[[C9]]) %[[Q1_1]]
302+ // CHECK: %[[Q1_3:.*]] = mqtopt.rz(%[[C8]]) %[[Q1_2]]
303+ // CHECK: %[[Q1_4:.*]], %[[Q0_4:.*]] = mqtopt.x() %[[Q1_3]] ctrl %[[Q0_3]]
304+ // CHECK: %[[Q0_5:.*]] = mqtopt.rz(%[[C11]]) %[[Q0_4]]
305+ // CHECK: %[[Q0_6:.*]] = mqtopt.ry(%[[C7]]) %[[Q0_5]]
306+ // CHECK: %[[Q0_7:.*]] = mqtopt.rz(%[[C6]]) %[[Q0_6]]
307+ // CHECK: %[[Q1_5:.*]] = mqtopt.rz(%[[C5]]) %[[Q1_4]]
308+ // CHECK: %[[Q1_6:.*]] = mqtopt.ry(%[[C4]]) %[[Q1_5]]
309+ // CHECK: %[[Q1_7:.*]] = mqtopt.rz(%[[C3]]) %[[Q1_6]]
310+ // CHECK: %[[Q1_8:.*]], %[[Q0_8:.*]] = mqtopt.x() %[[Q1_7]] ctrl %[[Q0_7]]
311+ // CHECK: %[[Q0_9:.*]] = mqtopt.ry(%[[C2]]) %[[Q0_8]]
312+ // CHECK: %[[Q0_10:.*]] = mqtopt.rz(%[[C1]]) %[[Q0_9]]
313+ // CHECK: %[[Q1_9:.*]] = mqtopt.rz(%[[C12]]) %[[Q1_8]]
314+ // CHECK: %[[Q1_10:.*]] = mqtopt.ry(%[[C0]]) %[[Q1_9]]
315+
316+ // CHECK: mqtopt.deallocQubit %[[Q0_10]]
317+ // CHECK: mqtopt.deallocQubit %[[Q1_10]]
240318
241319 %cst0 = arith.constant 2.5 : f64
242320 %cst1 = arith.constant 1.2 : f64
243321 %cst2 = arith.constant 0.5 : f64
244322
245323 %q0_0 = mqtopt.allocQubit
246324 %q1_0 = mqtopt.allocQubit
247- %q2_0 = mqtopt.allocQubit
248325
249326 %q0_x , %q1_x = mqtopt.i () %q0_0 ctrl %q1_0: !mqtopt.Qubit ctrl !mqtopt.Qubit
250327 %q0_1 = mqtopt.h () %q0_x: !mqtopt.Qubit
@@ -266,54 +343,38 @@ module {
266343
267344 mqtopt.deallocQubit %q0_9
268345 mqtopt.deallocQubit %q1_9
269- mqtopt.deallocQubit %q2_0
270346
271347 return
272348 }
273349}
274350
351+ // -----
352+ // This test checks if two single-qubit series (connected by an identity) remain separate without the insertion of a basis gate.
353+
275354module {
276- // CHECK-LABEL: func.func @testCNotOtherDirection
277- func.func @testCNotOtherDirection () {
355+ // CHECK-LABEL: func.func @testSingleQubitSeries
356+ func.func @testSingleQubitSeries () {
278357 // CHECK: %[[Q0_0:.*]] = mqtopt.allocQubit
279358 // CHECK: %[[Q1_0:.*]] = mqtopt.allocQubit
280- // CHECK: %[[Q2_0:.*]] = mqtopt.allocQubit
281359
282- // CHECK-NOT: mqtopt.gphase( %[[ANY :.*]])
360+ // CHECK: %[[Q0_1:.*]], %[[Q1_1 :.*]] = mqtopt.x() %[[Q0_0]] ctrl %[[Q1_0]]
283361
284- // CHECK: mqtopt.deallocQubit %[[Q0_5]]
285- // CHECK: mqtopt.deallocQubit %[[Q1_4]]
286- // CHECK: mqtopt.deallocQubit %[[Q2_1]]
362+ // CHECK: mqtopt.deallocQubit %[[Q0_1]]
363+ // CHECK: mqtopt.deallocQubit %[[Q1_1]]
287364
288365 %cst0 = arith.constant 2.5 : f64
289366 %cst1 = arith.constant 1.2 : f64
290- %cst2 = arith.constant 0.5 : f64
291367
292368 %q0_0 = mqtopt.allocQubit
293369 %q1_0 = mqtopt.allocQubit
294- %q2_0 = mqtopt.allocQubit
295370
296- %q0_1 = mqtopt.i () %q0_0: !mqtopt.Qubit
297- %q0_2 = mqtopt.i () %q0_1: !mqtopt.Qubit
298- %q0_3 , %q1_1 = mqtopt.x () %q0_2 ctrl %q1_0: !mqtopt.Qubit ctrl !mqtopt.Qubit
299- %q0_4 = mqtopt.i () %q0_3: !mqtopt.Qubit
300- %q0_5 = mqtopt.i () %q0_4: !mqtopt.Qubit
301- %q0_6 = mqtopt.i () %q0_5: !mqtopt.Qubit
302- %q0_7 = mqtopt.i () %q0_6: !mqtopt.Qubit
303- %q0_8 = mqtopt.i () %q0_7: !mqtopt.Qubit
304- %q0_9 = mqtopt.i () %q0_8: !mqtopt.Qubit
305- %q1_2 = mqtopt.i () %q1_1: !mqtopt.Qubit
306- %q1_3 = mqtopt.i () %q1_2: !mqtopt.Qubit
307- %q1_4 = mqtopt.i () %q1_3: !mqtopt.Qubit
308- %q1_5 = mqtopt.i () %q1_4: !mqtopt.Qubit
309- %q1_6 = mqtopt.i () %q1_5: !mqtopt.Qubit
310- %q1_7 = mqtopt.i () %q1_6: !mqtopt.Qubit
311- %q1_8 = mqtopt.i () %q1_7: !mqtopt.Qubit
312- %q1_9 = mqtopt.i () %q1_8: !mqtopt.Qubit
371+ %q0_1 , %q1_1 = mqtopt.i () %q0_0 ctrl %q1_0: !mqtopt.Qubit ctrl !mqtopt.Qubit
372+ %q0_2 = mqtopt.ry (%cst0 ) %q0_1: !mqtopt.Qubit
373+ %q1_2 = mqtopt.rx (%cst1 ) %q1_1: !mqtopt.Qubit
374+ %q1_3 = mqtopt.rx (%cst1 ) %q1_2: !mqtopt.Qubit
313375
314- mqtopt.deallocQubit %q0_9
315- mqtopt.deallocQubit %q1_9
316- mqtopt.deallocQubit %q2_0
376+ mqtopt.deallocQubit %q0_2
377+ mqtopt.deallocQubit %q1_3
317378
318379 return
319380 }
@@ -323,40 +384,53 @@ module {
323384// This test checks if two single-qubit series (connected by an identity) remain separate without the insertion of a basis gate.
324385
325386module {
326- // CHECK-LABEL: func.func @testSingleQubitSeries
327- func.func @testSingleQubitSeries () {
387+ // CHECK-LABEL: func.func @testThreeBasisGateDecomposition
388+ func.func @testThreeBasisGateDecomposition () {
328389 // CHECK: %[[Q0_0:.*]] = mqtopt.allocQubit
329390 // CHECK: %[[Q1_0:.*]] = mqtopt.allocQubit
391+ // CHECK: %[[Q2_0:.*]] = mqtopt.allocQubit
330392
331- // CHECK: %[[Q0_1:.*]], %[[Q1_1 :.*]] = mqtopt.x() %[[Q0_0]] ctrl %[[Q1_0]]
393+ // CHECK-NOT: mqtopt.gphase( %[[ANY :.*]])
332394
333- // CHECK: mqtopt.deallocQubit %[[Q0_1]]
334- // CHECK: mqtopt.deallocQubit %[[Q1_1]]
395+ // CHECK: mqtopt.deallocQubit %[[Q0_5]]
396+ // CHECK: mqtopt.deallocQubit %[[Q1_4]]
397+ // CHECK: mqtopt.deallocQubit %[[Q2_1]]
335398
336399 %cst0 = arith.constant 2.5 : f64
337400 %cst1 = arith.constant 1.2 : f64
401+ %cst2 = arith.constant 0.5 : f64
338402
339403 %q0_0 = mqtopt.allocQubit
340404 %q1_0 = mqtopt.allocQubit
405+ %q2_0 = mqtopt.allocQubit
341406
342- %q0_1 , %q1_1 = mqtopt.i () %q0_0 ctrl %q1_0: !mqtopt.Qubit ctrl !mqtopt.Qubit
343- %q0_2 = mqtopt.ry (%cst0 ) %q0_1: !mqtopt.Qubit
344- %q1_2 = mqtopt.rx (%cst1 ) %q1_1: !mqtopt.Qubit
345- %q1_3 = mqtopt.rx (%cst1 ) %q1_2: !mqtopt.Qubit
407+ %q0_x , %q1_x = mqtopt.i () %q0_0 ctrl %q1_0: !mqtopt.Qubit ctrl !mqtopt.Qubit
408+ %q0_1 = mqtopt.h () %q0_x: !mqtopt.Qubit
409+ %q1_1 , %q0_2 = mqtopt.x () %q1_x ctrl %q0_1: !mqtopt.Qubit ctrl !mqtopt.Qubit
410+ %q0_3 , %q1_2 = mqtopt.rzz (%cst0 ) %q0_2 , %q1_1: !mqtopt.Qubit , !mqtopt.Qubit
411+ %q1_3 = mqtopt.ry (%cst1 ) %q1_2: !mqtopt.Qubit
412+ %q0_4 = mqtopt.rx (%cst1 ) %q0_3: !mqtopt.Qubit
413+ %q0_5 , %q1_4 = mqtopt.x () %q0_4 ctrl %q1_3: !mqtopt.Qubit ctrl !mqtopt.Qubit
414+ %q0_6 = mqtopt.rz (%cst2 ) %q0_5: !mqtopt.Qubit
415+ %q0_7 , %q1_5 = mqtopt.rxx (%cst0 ) %q0_6 , %q1_4: !mqtopt.Qubit , !mqtopt.Qubit
416+ %q0_8 , %q1_6 = mqtopt.ryy (%cst2 ) %q0_7 , %q1_5: !mqtopt.Qubit , !mqtopt.Qubit
417+ // make series longer to enforce decomposition
418+ %q0_9 , %q1_7 = mqtopt.i () %q0_8 ctrl %q1_6: !mqtopt.Qubit ctrl !mqtopt.Qubit
346419
347- mqtopt.deallocQubit %q0_2
348- mqtopt.deallocQubit %q1_3
420+ mqtopt.deallocQubit %q0_9
421+ mqtopt.deallocQubit %q1_7
422+ mqtopt.deallocQubit %q2_0
349423
350424 return
351425 }
352426}
353427
354428// -----
355- // This test checks if two single-qubit series (connected by an identity) remain separate without the insertion of a basis gate .
429+ // This test checks if the repeated application of the decomposition works by "interrupting" the first series and then having a second one .
356430
357431module {
358- // CHECK-LABEL: func.func @testThreeBasisGateDecomposition
359- func.func @testThreeBasisGateDecomposition () {
432+ // CHECK-LABEL: func.func @testRepeatedDecomposition
433+ func.func @testRepeatedDecomposition () {
360434 // CHECK: %[[Q0_0:.*]] = mqtopt.allocQubit
361435 // CHECK: %[[Q1_0:.*]] = mqtopt.allocQubit
362436 // CHECK: %[[Q2_0:.*]] = mqtopt.allocQubit
@@ -395,4 +469,3 @@ module {
395469 return
396470 }
397471}
398-
0 commit comments