mirror of https://github.com/Qiskit/qiskit.git
introduce ddt, test already-mapped circuits in the transpiler (#2563)
* fix * cleaning up * lint * preset_passmanagers/level3.py * test * requirements-dev.txt from #2559 * docstring * dsc * docstring * case are dicts * simpler approach * docstring * avoid double zip * lint * add name * add name * name * decorator * lint * lint * no METATEST * lint * revert changes to preset pass managers * docstring * small consistency tweak * style
This commit is contained in:
parent
513af7f1c1
commit
fd76c94d73
|
@ -15,6 +15,7 @@
|
||||||
"""Functionality and helpers for testing Qiskit."""
|
"""Functionality and helpers for testing Qiskit."""
|
||||||
|
|
||||||
from .base import QiskitTestCase
|
from .base import QiskitTestCase
|
||||||
from .decorators import requires_aer_provider, online_test, slow_test, requires_qe_access
|
from .decorators import requires_aer_provider, online_test, slow_test, requires_qe_access, \
|
||||||
|
combine
|
||||||
from .reference_circuits import ReferenceCircuits
|
from .reference_circuits import ReferenceCircuits
|
||||||
from .utils import Path
|
from .utils import Path
|
||||||
|
|
|
@ -19,6 +19,8 @@ import os
|
||||||
import sys
|
import sys
|
||||||
import unittest
|
import unittest
|
||||||
from warnings import warn
|
from warnings import warn
|
||||||
|
from itertools import product
|
||||||
|
from ddt import data, unpack
|
||||||
|
|
||||||
from qiskit.util import _has_connection
|
from qiskit.util import _has_connection
|
||||||
from .testing_options import get_test_options
|
from .testing_options import get_test_options
|
||||||
|
@ -184,3 +186,37 @@ def online_test(func):
|
||||||
|
|
||||||
|
|
||||||
TEST_OPTIONS = get_test_options()
|
TEST_OPTIONS = get_test_options()
|
||||||
|
|
||||||
|
|
||||||
|
class Case(dict):
|
||||||
|
""" A test case, see https://ddt.readthedocs.io/en/latest/example.html MyList."""
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
def generate_cases(dsc=None, name=None, **kwargs):
|
||||||
|
"""Combines kwargs in cartesian product and creates Case with them"""
|
||||||
|
ret = []
|
||||||
|
keys = kwargs.keys()
|
||||||
|
vals = kwargs.values()
|
||||||
|
for values in product(*vals):
|
||||||
|
case = Case(zip(keys, values))
|
||||||
|
if dsc is not None:
|
||||||
|
setattr(case, "__doc__", dsc.format(**case))
|
||||||
|
if name is not None:
|
||||||
|
setattr(case, "__name__", name.format(**case))
|
||||||
|
ret.append(case)
|
||||||
|
return ret
|
||||||
|
|
||||||
|
|
||||||
|
def combine(**kwargs):
|
||||||
|
"""Decorator to create combinations and tests
|
||||||
|
@combine(level=[0, 1, 2, 3],
|
||||||
|
circuit=[a, b, c, d],
|
||||||
|
dsc='Test circuit {circuit.__name__} with level {level}',
|
||||||
|
name='{circuit.__name__}_level{level}')
|
||||||
|
"""
|
||||||
|
|
||||||
|
def deco(func):
|
||||||
|
return data(*generate_cases(**kwargs))(unpack(func))
|
||||||
|
|
||||||
|
return deco
|
||||||
|
|
|
@ -15,3 +15,4 @@ wheel
|
||||||
cython>=0.27.1
|
cython>=0.27.1
|
||||||
pillow>=4.2.1
|
pillow>=4.2.1
|
||||||
pylatexenc>=1.4
|
pylatexenc>=1.4
|
||||||
|
ddt>=1.2.0
|
||||||
|
|
|
@ -14,7 +14,9 @@
|
||||||
|
|
||||||
"""Tests preset pass manager functionalities"""
|
"""Tests preset pass manager functionalities"""
|
||||||
|
|
||||||
from qiskit.test import QiskitTestCase
|
from ddt import ddt, data
|
||||||
|
|
||||||
|
from qiskit.test import QiskitTestCase, combine
|
||||||
from qiskit.compiler import transpile, assemble
|
from qiskit.compiler import transpile, assemble
|
||||||
from qiskit import QuantumCircuit, ClassicalRegister, QuantumRegister
|
from qiskit import QuantumCircuit, ClassicalRegister, QuantumRegister
|
||||||
from qiskit.extensions.standard import U2Gate, U3Gate
|
from qiskit.extensions.standard import U2Gate, U3Gate
|
||||||
|
@ -22,48 +24,56 @@ from qiskit.test.mock import (FakeTenerife, FakeMelbourne,
|
||||||
FakeRueschlikon, FakeTokyo, FakePoughkeepsie)
|
FakeRueschlikon, FakeTokyo, FakePoughkeepsie)
|
||||||
|
|
||||||
|
|
||||||
|
def emptycircuit():
|
||||||
|
"""Empty circuit"""
|
||||||
|
return QuantumCircuit()
|
||||||
|
|
||||||
|
|
||||||
|
def is_swap_mapped():
|
||||||
|
"""See https://github.com/Qiskit/qiskit-terra/issues/2532"""
|
||||||
|
circuit = QuantumCircuit(5)
|
||||||
|
circuit.cx(2, 4)
|
||||||
|
return circuit
|
||||||
|
|
||||||
|
|
||||||
|
@ddt
|
||||||
class TestPresetPassManager(QiskitTestCase):
|
class TestPresetPassManager(QiskitTestCase):
|
||||||
"""Test preset passmanagers work as expected."""
|
"""Test preset passmanagers work as expected."""
|
||||||
|
|
||||||
def test_no_coupling_map(self):
|
@combine(level=[0, 1, 2, 3],
|
||||||
|
dsc='Test that coupling_map can be None (level={level})',
|
||||||
|
name='coupling_map_none_level{level}')
|
||||||
|
def test_no_coupling_map(self, level):
|
||||||
"""Test that coupling_map can be None"""
|
"""Test that coupling_map can be None"""
|
||||||
q = QuantumRegister(2, name='q')
|
q = QuantumRegister(2, name='q')
|
||||||
test = QuantumCircuit(q)
|
circuit = QuantumCircuit(q)
|
||||||
test.cz(q[0], q[1])
|
circuit.cz(q[0], q[1])
|
||||||
for level in [0, 1, 2, 3]:
|
result = transpile(circuit, basis_gates=['u1', 'u2', 'u3', 'cx'], optimization_level=level)
|
||||||
with self.subTest(level=level):
|
self.assertIsInstance(result, QuantumCircuit)
|
||||||
test2 = transpile(test, basis_gates=['u1', 'u2', 'u3', 'cx'],
|
|
||||||
optimization_level=level)
|
|
||||||
self.assertIsInstance(test2, QuantumCircuit)
|
|
||||||
|
|
||||||
|
|
||||||
class TestFakeBackendTranspiling(QiskitTestCase):
|
@ddt
|
||||||
"""Test transpiling on mock backends work properly"""
|
class TestTranspileLevels(QiskitTestCase):
|
||||||
|
"""Test transpiler on fake backend"""
|
||||||
|
|
||||||
def setUp(self):
|
@combine(circuit=[emptycircuit, is_swap_mapped],
|
||||||
|
level=[0, 1, 2, 3],
|
||||||
|
backend=[FakeTenerife(), FakeMelbourne(), FakeRueschlikon(), FakeTokyo(),
|
||||||
|
FakePoughkeepsie(), None],
|
||||||
|
dsc='Transpiler {circuit.__name__} on {backend} backend at level {level}',
|
||||||
|
name='{circuit.__name__}_{backend}_level{level}')
|
||||||
|
def test(self, circuit, level, backend):
|
||||||
|
"""All the levels with all the backends"""
|
||||||
|
result = transpile(circuit(), backend=backend, optimization_level=level, seed_transpiler=42)
|
||||||
|
self.assertIsInstance(result, QuantumCircuit)
|
||||||
|
|
||||||
q = QuantumRegister(2)
|
|
||||||
c = ClassicalRegister(2)
|
|
||||||
|
|
||||||
self._circuit = QuantumCircuit(q, c)
|
@ddt
|
||||||
self._circuit.h(q[0])
|
class TestInitialLayouts(QiskitTestCase):
|
||||||
self._circuit.cx(q[0], q[1])
|
"""Test transpiing with different layouts"""
|
||||||
self._circuit.measure(q, c)
|
|
||||||
|
|
||||||
def test_optimization_level(self):
|
@data(0, 1, 2, 3)
|
||||||
"""Test several backends with all optimization levels"""
|
def test_layout_1711(self, level):
|
||||||
for backend in [FakeTenerife(), FakeMelbourne(), FakeRueschlikon(),
|
|
||||||
FakeTokyo(), FakePoughkeepsie()]:
|
|
||||||
for optimization_level in range(4):
|
|
||||||
result = transpile(
|
|
||||||
[self._circuit],
|
|
||||||
backend=backend,
|
|
||||||
optimization_level=optimization_level
|
|
||||||
)
|
|
||||||
self.assertIsInstance(result, QuantumCircuit)
|
|
||||||
|
|
||||||
# TODO: make these tests more compact with ddt
|
|
||||||
def test_initial_layout_1(self):
|
|
||||||
"""Test that a user-given initial layout is respected,
|
"""Test that a user-given initial layout is respected,
|
||||||
in the qobj.
|
in the qobj.
|
||||||
|
|
||||||
|
@ -84,21 +94,19 @@ class TestFakeBackendTranspiling(QiskitTestCase):
|
||||||
|
|
||||||
backend = FakeRueschlikon()
|
backend = FakeRueschlikon()
|
||||||
|
|
||||||
for optimization_level in range(4):
|
qc_b = transpile(qc, backend, initial_layout=initial_layout, optimization_level=level)
|
||||||
qc_b = transpile(qc, backend, initial_layout=initial_layout,
|
qobj = assemble(qc_b)
|
||||||
optimization_level=optimization_level)
|
|
||||||
qobj = assemble(qc_b)
|
|
||||||
|
|
||||||
self.assertEqual(qc_b.layout._p2v, final_layout)
|
self.assertEqual(qc_b.layout._p2v, final_layout)
|
||||||
|
|
||||||
compiled_ops = qobj.experiments[0].instructions
|
compiled_ops = qobj.experiments[0].instructions
|
||||||
for operation in compiled_ops:
|
for operation in compiled_ops:
|
||||||
if operation.name == 'cx':
|
if operation.name == 'cx':
|
||||||
self.assertIn(operation.qubits, backend.configuration().coupling_map)
|
self.assertIn(operation.qubits, backend.configuration().coupling_map)
|
||||||
self.assertIn(operation.qubits, [[15, 0], [15, 2]])
|
self.assertIn(operation.qubits, [[15, 0], [15, 2]])
|
||||||
|
|
||||||
# TODO: make these tests more compact with ddt
|
@data(0, 1, 2, 3)
|
||||||
def test_initial_layout_2(self):
|
def test_layout_2532(self, level):
|
||||||
"""Test that a user-given initial layout is respected,
|
"""Test that a user-given initial layout is respected,
|
||||||
in the transpiled circuit.
|
in the transpiled circuit.
|
||||||
|
|
||||||
|
@ -117,19 +125,17 @@ class TestFakeBackendTranspiling(QiskitTestCase):
|
||||||
11: qr[2], 12: ancilla[7], 13: ancilla[8]}
|
11: qr[2], 12: ancilla[7], 13: ancilla[8]}
|
||||||
backend = FakeMelbourne()
|
backend = FakeMelbourne()
|
||||||
|
|
||||||
for optimization_level in range(4):
|
qc_b = transpile(qc, backend, initial_layout=initial_layout, optimization_level=level)
|
||||||
qc_b = transpile(qc, backend, initial_layout=initial_layout,
|
|
||||||
optimization_level=optimization_level)
|
|
||||||
|
|
||||||
self.assertEqual(qc_b.layout._p2v, final_layout)
|
self.assertEqual(qc_b.layout._p2v, final_layout)
|
||||||
|
|
||||||
for gate, qubits, _ in qc_b:
|
for gate, qubits, _ in qc_b:
|
||||||
if gate.name == 'cx':
|
if gate.name == 'cx':
|
||||||
for qubit in qubits:
|
for qubit in qubits:
|
||||||
self.assertIn(qubit.index, [11, 3])
|
self.assertIn(qubit.index, [11, 3])
|
||||||
|
|
||||||
# TODO: make these tests more compact with ddt
|
@data(0, 1, 2, 3)
|
||||||
def test_initial_layout_3(self):
|
def test_layout_2503(self, level):
|
||||||
"""Test that a user-given initial layout is respected,
|
"""Test that a user-given initial layout is respected,
|
||||||
even if cnots are not in the coupling map.
|
even if cnots are not in the coupling map.
|
||||||
|
|
||||||
|
@ -155,16 +161,14 @@ class TestFakeBackendTranspiling(QiskitTestCase):
|
||||||
|
|
||||||
backend = FakePoughkeepsie()
|
backend = FakePoughkeepsie()
|
||||||
|
|
||||||
for optimization_level in range(4):
|
qc_b = transpile(qc, backend, initial_layout=initial_layout, optimization_level=level)
|
||||||
qc_b = transpile(qc, backend, initial_layout=initial_layout,
|
|
||||||
optimization_level=optimization_level)
|
|
||||||
|
|
||||||
self.assertEqual(qc_b.layout._p2v, final_layout)
|
self.assertEqual(qc_b.layout._p2v, final_layout)
|
||||||
|
|
||||||
gate_0, qubits_0, _ = qc_b[0]
|
gate_0, qubits_0, _ = qc_b[0]
|
||||||
gate_1, qubits_1, _ = qc_b[1]
|
gate_1, qubits_1, _ = qc_b[1]
|
||||||
|
|
||||||
self.assertIsInstance(gate_0, U3Gate)
|
self.assertIsInstance(gate_0, U3Gate)
|
||||||
self.assertEqual(qubits_0[0].index, 6)
|
self.assertEqual(qubits_0[0].index, 6)
|
||||||
self.assertIsInstance(gate_1, U2Gate)
|
self.assertIsInstance(gate_1, U2Gate)
|
||||||
self.assertEqual(qubits_1[0].index, 12)
|
self.assertEqual(qubits_1[0].index, 12)
|
||||||
|
|
Loading…
Reference in New Issue