forked from Qiskit/qiskit
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathtest_sabre_layout.py
393 lines (359 loc) · 15.2 KB
/
test_sabre_layout.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
# This code is part of Qiskit.
#
# (C) Copyright IBM 2017, 2020.
#
# This code is licensed under the Apache License, Version 2.0. You may
# obtain a copy of this license in the LICENSE.txt file in the root directory
# of this source tree or at http://www.apache.org/licenses/LICENSE-2.0.
#
# Any modifications or derivative works of this code must retain this
# copyright notice, and modified files need to carry a notice indicating
# that they have been altered from the originals.
"""Test the SabreLayout pass"""
import unittest
from qiskit import QuantumRegister, QuantumCircuit
from qiskit.transpiler import CouplingMap, AnalysisPass, PassManager
from qiskit.transpiler.passes import SabreLayout, DenseLayout
from qiskit.transpiler.exceptions import TranspilerError
from qiskit.converters import circuit_to_dag
from qiskit.test import QiskitTestCase
from qiskit.compiler.transpiler import transpile
from qiskit.providers.fake_provider import FakeAlmaden, FakeAlmadenV2
from qiskit.providers.fake_provider import FakeKolkata
from qiskit.providers.fake_provider import FakeMontreal
class TestSabreLayout(QiskitTestCase):
"""Tests the SabreLayout pass"""
def setUp(self):
super().setUp()
self.cmap20 = FakeAlmaden().configuration().coupling_map
def test_5q_circuit_20q_coupling(self):
"""Test finds layout for 5q circuit on 20q device."""
# ┌───┐
# q_0: ──■───────┤ X ├───────────────
# │ └─┬─┘┌───┐
# q_1: ──┼────■────┼──┤ X ├───────■──
# ┌─┴─┐ │ │ ├───┤┌───┐┌─┴─┐
# q_2: ┤ X ├──┼────┼──┤ X ├┤ X ├┤ X ├
# └───┘┌─┴─┐ │ └───┘└─┬─┘└───┘
# q_3: ─────┤ X ├──■─────────┼───────
# └───┘ │
# q_4: ──────────────────────■───────
qr = QuantumRegister(5, "q")
circuit = QuantumCircuit(qr)
circuit.cx(qr[0], qr[2])
circuit.cx(qr[1], qr[3])
circuit.cx(qr[3], qr[0])
circuit.x(qr[2])
circuit.cx(qr[4], qr[2])
circuit.x(qr[1])
circuit.cx(qr[1], qr[2])
dag = circuit_to_dag(circuit)
pass_ = SabreLayout(CouplingMap(self.cmap20), seed=0, swap_trials=32, layout_trials=32)
pass_.run(dag)
layout = pass_.property_set["layout"]
self.assertEqual([layout[q] for q in circuit.qubits], [16, 7, 11, 12, 13])
def test_6q_circuit_20q_coupling(self):
"""Test finds layout for 6q circuit on 20q device."""
# ┌───┐┌───┐┌───┐┌───┐┌───┐
# q0_0: ┤ X ├┤ X ├┤ X ├┤ X ├┤ X ├
# └─┬─┘└─┬─┘└─┬─┘└─┬─┘└─┬─┘
# q0_1: ──┼────■────┼────┼────┼──
# │ ┌───┐ │ │ │
# q0_2: ──┼──┤ X ├──┼────■────┼──
# │ └───┘ │ │
# q1_0: ──■─────────┼─────────┼──
# ┌───┐ │ │
# q1_1: ─────┤ X ├──┼─────────■──
# └───┘ │
# q1_2: ────────────■────────────
qr0 = QuantumRegister(3, "q0")
qr1 = QuantumRegister(3, "q1")
circuit = QuantumCircuit(qr0, qr1)
circuit.cx(qr1[0], qr0[0])
circuit.cx(qr0[1], qr0[0])
circuit.cx(qr1[2], qr0[0])
circuit.x(qr0[2])
circuit.cx(qr0[2], qr0[0])
circuit.x(qr1[1])
circuit.cx(qr1[1], qr0[0])
dag = circuit_to_dag(circuit)
pass_ = SabreLayout(CouplingMap(self.cmap20), seed=0, swap_trials=32, layout_trials=32)
pass_.run(dag)
layout = pass_.property_set["layout"]
self.assertEqual([layout[q] for q in circuit.qubits], [7, 8, 12, 6, 11, 13])
def test_6q_circuit_20q_coupling_with_partial(self):
"""Test finds layout for 6q circuit on 20q device."""
# ┌───┐┌───┐┌───┐┌───┐┌───┐
# q0_0: ┤ X ├┤ X ├┤ X ├┤ X ├┤ X ├
# └─┬─┘└─┬─┘└─┬─┘└─┬─┘└─┬─┘
# q0_1: ──┼────■────┼────┼────┼──
# │ ┌───┐ │ │ │
# q0_2: ──┼──┤ X ├──┼────■────┼──
# │ └───┘ │ │
# q1_0: ──■─────────┼─────────┼──
# ┌───┐ │ │
# q1_1: ─────┤ X ├──┼─────────■──
# └───┘ │
# q1_2: ────────────■────────────
qr0 = QuantumRegister(3, "q0")
qr1 = QuantumRegister(3, "q1")
circuit = QuantumCircuit(qr0, qr1)
circuit.cx(qr1[0], qr0[0])
circuit.cx(qr0[1], qr0[0])
circuit.cx(qr1[2], qr0[0])
circuit.x(qr0[2])
circuit.cx(qr0[2], qr0[0])
circuit.x(qr1[1])
circuit.cx(qr1[1], qr0[0])
pm = PassManager(
[
DensePartialSabreTrial(CouplingMap(self.cmap20)),
SabreLayout(CouplingMap(self.cmap20), seed=0, swap_trials=32, layout_trials=0),
]
)
pm.run(circuit)
layout = pm.property_set["layout"]
self.assertEqual([layout[q] for q in circuit.qubits], [1, 3, 5, 2, 6, 0])
def test_6q_circuit_20q_coupling_with_target(self):
"""Test finds layout for 6q circuit on 20q device."""
# ┌───┐┌───┐┌───┐┌───┐┌───┐
# q0_0: ┤ X ├┤ X ├┤ X ├┤ X ├┤ X ├
# └─┬─┘└─┬─┘└─┬─┘└─┬─┘└─┬─┘
# q0_1: ──┼────■────┼────┼────┼──
# │ ┌───┐ │ │ │
# q0_2: ──┼──┤ X ├──┼────■────┼──
# │ └───┘ │ │
# q1_0: ──■─────────┼─────────┼──
# ┌───┐ │ │
# q1_1: ─────┤ X ├──┼─────────■──
# └───┘ │
# q1_2: ────────────■────────────
qr0 = QuantumRegister(3, "q0")
qr1 = QuantumRegister(3, "q1")
circuit = QuantumCircuit(qr0, qr1)
circuit.cx(qr1[0], qr0[0])
circuit.cx(qr0[1], qr0[0])
circuit.cx(qr1[2], qr0[0])
circuit.x(qr0[2])
circuit.cx(qr0[2], qr0[0])
circuit.x(qr1[1])
circuit.cx(qr1[1], qr0[0])
dag = circuit_to_dag(circuit)
target = FakeAlmadenV2().target
pass_ = SabreLayout(target, seed=0, swap_trials=32, layout_trials=32)
pass_.run(dag)
layout = pass_.property_set["layout"]
self.assertEqual([layout[q] for q in circuit.qubits], [7, 8, 12, 6, 11, 13])
def test_layout_with_classical_bits(self):
"""Test sabre layout with classical bits recreate from issue #8635."""
qc = QuantumCircuit.from_qasm_str(
"""
OPENQASM 2.0;
include "qelib1.inc";
qreg q4833[1];
qreg q4834[6];
qreg q4835[7];
creg c982[2];
creg c983[2];
creg c984[2];
rzz(0) q4833[0],q4834[4];
cu(0,-6.1035156e-05,0,1e-05) q4834[1],q4835[2];
swap q4834[0],q4834[2];
cu(-1.1920929e-07,0,-0.33333333,0) q4833[0],q4834[2];
ccx q4835[2],q4834[5],q4835[4];
measure q4835[4] -> c984[0];
ccx q4835[2],q4835[5],q4833[0];
measure q4835[5] -> c984[1];
measure q4834[0] -> c982[1];
u(10*pi,0,1.9) q4834[5];
measure q4834[3] -> c984[1];
measure q4835[0] -> c982[0];
rz(0) q4835[1];
"""
)
res = transpile(qc, FakeKolkata(), layout_method="sabre", seed_transpiler=1234)
self.assertIsInstance(res, QuantumCircuit)
layout = res._layout.initial_layout
self.assertEqual(
[layout[q] for q in qc.qubits], [13, 10, 11, 12, 17, 14, 22, 26, 5, 16, 25, 19, 7, 8]
)
# pylint: disable=line-too-long
def test_layout_many_search_trials(self):
"""Test recreate failure from randomized testing that overflowed."""
qc = QuantumCircuit.from_qasm_str(
"""
OPENQASM 2.0;
include "qelib1.inc";
qreg q18585[14];
creg c1423[5];
creg c1424[4];
creg c1425[3];
barrier q18585[4],q18585[5],q18585[12],q18585[1];
cz q18585[11],q18585[3];
cswap q18585[8],q18585[10],q18585[6];
u(-2.00001,6.1035156e-05,-1.9) q18585[2];
barrier q18585[3],q18585[6],q18585[5],q18585[8],q18585[10],q18585[9],q18585[11],q18585[2],q18585[12],q18585[7],q18585[13],q18585[4],q18585[0],q18585[1];
cp(0) q18585[2],q18585[4];
cu(-0.99999,0,0,0) q18585[7],q18585[1];
cu(0,0,0,2.1507119) q18585[6],q18585[3];
barrier q18585[13],q18585[0],q18585[12],q18585[3],q18585[2],q18585[10];
ry(-1.1044662) q18585[13];
barrier q18585[13];
id q18585[12];
barrier q18585[12],q18585[6];
cu(-1.9,1.9,-1.5,0) q18585[10],q18585[0];
barrier q18585[13];
id q18585[8];
barrier q18585[12];
barrier q18585[12],q18585[1],q18585[9];
sdg q18585[2];
rz(-10*pi) q18585[6];
u(0,27.566433,1.9) q18585[1];
barrier q18585[12],q18585[11],q18585[9],q18585[4],q18585[7],q18585[0],q18585[13],q18585[3];
cu(-0.99999,-5.9604645e-08,-0.5,2.00001) q18585[3],q18585[13];
rx(-5.9604645e-08) q18585[7];
p(1.1) q18585[13];
barrier q18585[12],q18585[13],q18585[10],q18585[9],q18585[7],q18585[4];
z q18585[10];
measure q18585[7] -> c1423[2];
barrier q18585[0],q18585[3],q18585[7],q18585[4],q18585[1],q18585[8],q18585[6],q18585[11],q18585[5];
barrier q18585[5],q18585[2],q18585[8],q18585[3],q18585[6];
"""
)
res = transpile(
qc,
FakeMontreal(),
layout_method="sabre",
routing_method="stochastic",
seed_transpiler=12345,
)
self.assertIsInstance(res, QuantumCircuit)
layout = res._layout.initial_layout
self.assertEqual(
[layout[q] for q in qc.qubits], [22, 7, 2, 12, 1, 5, 14, 4, 11, 0, 16, 15, 3, 10]
)
class DensePartialSabreTrial(AnalysisPass):
"""Pass to run dense layout as a sabre trial."""
def __init__(self, cmap):
self.dense_pass = DenseLayout(cmap)
super().__init__()
def run(self, dag):
self.dense_pass.run(dag)
self.property_set["sabre_starting_layouts"] = [self.dense_pass.property_set["layout"]]
class TestDisjointDeviceSabreLayout(QiskitTestCase):
"""Test SabreLayout with a disjoint coupling map."""
def setUp(self):
super().setUp()
self.dual_grid_cmap = CouplingMap(
[[0, 1], [0, 2], [1, 3], [2, 3], [4, 5], [4, 6], [5, 7], [5, 8]]
)
def test_dual_ghz(self):
"""Test a basic example with 2 circuit components and 2 cmap components."""
qc = QuantumCircuit(8, name="double dhz")
qc.h(0)
qc.cz(0, 1)
qc.cz(0, 2)
qc.h(3)
qc.cx(3, 4)
qc.cx(3, 5)
qc.cx(3, 6)
qc.cx(3, 7)
layout_routing_pass = SabreLayout(
self.dual_grid_cmap, seed=123456, swap_trials=1, layout_trials=1
)
layout_routing_pass(qc)
layout = layout_routing_pass.property_set["layout"]
self.assertEqual([layout[q] for q in qc.qubits], [3, 1, 2, 5, 4, 6, 7, 8])
def test_dual_ghz_with_wide_barrier(self):
"""Test a basic example with 2 circuit components and 2 cmap components."""
qc = QuantumCircuit(8, name="double dhz")
qc.h(0)
qc.cz(0, 1)
qc.cz(0, 2)
qc.h(3)
qc.cx(3, 4)
qc.cx(3, 5)
qc.cx(3, 6)
qc.cx(3, 7)
qc.measure_all()
layout_routing_pass = SabreLayout(
self.dual_grid_cmap, seed=123456, swap_trials=1, layout_trials=1
)
layout_routing_pass(qc)
layout = layout_routing_pass.property_set["layout"]
self.assertEqual([layout[q] for q in qc.qubits], [3, 1, 2, 5, 4, 6, 7, 8])
def test_dual_ghz_with_intermediate_barriers(self):
"""Test dual ghz circuit with intermediate barriers local to each componennt."""
qc = QuantumCircuit(8, name="double dhz")
qc.h(0)
qc.cz(0, 1)
qc.cz(0, 2)
qc.barrier(0, 1, 2)
qc.h(3)
qc.cx(3, 4)
qc.cx(3, 5)
qc.barrier(4, 5, 6)
qc.cx(3, 6)
qc.cx(3, 7)
qc.measure_all()
layout_routing_pass = SabreLayout(
self.dual_grid_cmap, seed=123456, swap_trials=1, layout_trials=1
)
layout_routing_pass(qc)
layout = layout_routing_pass.property_set["layout"]
self.assertEqual([layout[q] for q in qc.qubits], [3, 1, 2, 5, 4, 6, 7, 8])
def test_dual_ghz_with_intermediate_spanning_barriers(self):
"""Test dual ghz circuit with barrier in the middle across components."""
qc = QuantumCircuit(8, name="double dhz")
qc.h(0)
qc.cz(0, 1)
qc.cz(0, 2)
qc.barrier(0, 1, 2, 4, 5)
qc.h(3)
qc.cx(3, 4)
qc.cx(3, 5)
qc.cx(3, 6)
qc.cx(3, 7)
qc.measure_all()
layout_routing_pass = SabreLayout(
self.dual_grid_cmap, seed=123456, swap_trials=1, layout_trials=1
)
layout_routing_pass(qc)
layout = layout_routing_pass.property_set["layout"]
self.assertEqual([layout[q] for q in qc.qubits], [3, 1, 2, 5, 4, 6, 7, 8])
def test_too_large_components(self):
"""Assert trying to run a circuit with too large a connected component raises."""
qc = QuantumCircuit(8)
qc.h(0)
for i in range(1, 6):
qc.cx(0, i)
qc.h(7)
qc.cx(7, 6)
layout_routing_pass = SabreLayout(
self.dual_grid_cmap, seed=123456, swap_trials=1, layout_trials=1
)
with self.assertRaises(TranspilerError):
layout_routing_pass(qc)
def test_with_partial_layout(self):
"""Test a partial layout with a disjoint connectivity graph."""
qc = QuantumCircuit(8, name="double dhz")
qc.h(0)
qc.cz(0, 1)
qc.cz(0, 2)
qc.h(3)
qc.cx(3, 4)
qc.cx(3, 5)
qc.cx(3, 6)
qc.cx(3, 7)
qc.measure_all()
pm = PassManager(
[
DensePartialSabreTrial(self.dual_grid_cmap),
SabreLayout(self.dual_grid_cmap, seed=123456, swap_trials=1, layout_trials=1),
]
)
pm.run(qc)
layout = pm.property_set["layout"]
self.assertEqual([layout[q] for q in qc.qubits], [3, 1, 2, 5, 4, 6, 7, 8])
if __name__ == "__main__":
unittest.main()