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:
Luciano 2019-07-11 09:38:32 -04:00 committed by Ali Javadi-Abhari
parent 513af7f1c1
commit fd76c94d73
4 changed files with 107 additions and 65 deletions

View File

@ -15,6 +15,7 @@
"""Functionality and helpers for testing Qiskit."""
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 .utils import Path

View File

@ -19,6 +19,8 @@ import os
import sys
import unittest
from warnings import warn
from itertools import product
from ddt import data, unpack
from qiskit.util import _has_connection
from .testing_options import get_test_options
@ -184,3 +186,37 @@ def online_test(func):
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

View File

@ -15,3 +15,4 @@ wheel
cython>=0.27.1
pillow>=4.2.1
pylatexenc>=1.4
ddt>=1.2.0

View File

@ -14,7 +14,9 @@
"""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 import QuantumCircuit, ClassicalRegister, QuantumRegister
from qiskit.extensions.standard import U2Gate, U3Gate
@ -22,48 +24,56 @@ from qiskit.test.mock import (FakeTenerife, FakeMelbourne,
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):
"""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"""
q = QuantumRegister(2, name='q')
test = QuantumCircuit(q)
test.cz(q[0], q[1])
for level in [0, 1, 2, 3]:
with self.subTest(level=level):
test2 = transpile(test, basis_gates=['u1', 'u2', 'u3', 'cx'],
optimization_level=level)
self.assertIsInstance(test2, QuantumCircuit)
circuit = QuantumCircuit(q)
circuit.cz(q[0], q[1])
result = transpile(circuit, basis_gates=['u1', 'u2', 'u3', 'cx'], optimization_level=level)
self.assertIsInstance(result, QuantumCircuit)
class TestFakeBackendTranspiling(QiskitTestCase):
"""Test transpiling on mock backends work properly"""
@ddt
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)
self._circuit.h(q[0])
self._circuit.cx(q[0], q[1])
self._circuit.measure(q, c)
@ddt
class TestInitialLayouts(QiskitTestCase):
"""Test transpiing with different layouts"""
def test_optimization_level(self):
"""Test several backends with all optimization levels"""
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):
@data(0, 1, 2, 3)
def test_layout_1711(self, level):
"""Test that a user-given initial layout is respected,
in the qobj.
@ -84,21 +94,19 @@ class TestFakeBackendTranspiling(QiskitTestCase):
backend = FakeRueschlikon()
for optimization_level in range(4):
qc_b = transpile(qc, backend, initial_layout=initial_layout,
optimization_level=optimization_level)
qobj = assemble(qc_b)
qc_b = transpile(qc, backend, initial_layout=initial_layout, optimization_level=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
for operation in compiled_ops:
if operation.name == 'cx':
self.assertIn(operation.qubits, backend.configuration().coupling_map)
self.assertIn(operation.qubits, [[15, 0], [15, 2]])
compiled_ops = qobj.experiments[0].instructions
for operation in compiled_ops:
if operation.name == 'cx':
self.assertIn(operation.qubits, backend.configuration().coupling_map)
self.assertIn(operation.qubits, [[15, 0], [15, 2]])
# TODO: make these tests more compact with ddt
def test_initial_layout_2(self):
@data(0, 1, 2, 3)
def test_layout_2532(self, level):
"""Test that a user-given initial layout is respected,
in the transpiled circuit.
@ -117,19 +125,17 @@ class TestFakeBackendTranspiling(QiskitTestCase):
11: qr[2], 12: ancilla[7], 13: ancilla[8]}
backend = FakeMelbourne()
for optimization_level in range(4):
qc_b = transpile(qc, backend, initial_layout=initial_layout,
optimization_level=optimization_level)
qc_b = transpile(qc, backend, initial_layout=initial_layout, optimization_level=level)
self.assertEqual(qc_b.layout._p2v, final_layout)
self.assertEqual(qc_b.layout._p2v, final_layout)
for gate, qubits, _ in qc_b:
if gate.name == 'cx':
for qubit in qubits:
self.assertIn(qubit.index, [11, 3])
for gate, qubits, _ in qc_b:
if gate.name == 'cx':
for qubit in qubits:
self.assertIn(qubit.index, [11, 3])
# TODO: make these tests more compact with ddt
def test_initial_layout_3(self):
@data(0, 1, 2, 3)
def test_layout_2503(self, level):
"""Test that a user-given initial layout is respected,
even if cnots are not in the coupling map.
@ -155,16 +161,14 @@ class TestFakeBackendTranspiling(QiskitTestCase):
backend = FakePoughkeepsie()
for optimization_level in range(4):
qc_b = transpile(qc, backend, initial_layout=initial_layout,
optimization_level=optimization_level)
qc_b = transpile(qc, backend, initial_layout=initial_layout, optimization_level=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_1, qubits_1, _ = qc_b[1]
gate_0, qubits_0, _ = qc_b[0]
gate_1, qubits_1, _ = qc_b[1]
self.assertIsInstance(gate_0, U3Gate)
self.assertEqual(qubits_0[0].index, 6)
self.assertIsInstance(gate_1, U2Gate)
self.assertEqual(qubits_1[0].index, 12)
self.assertIsInstance(gate_0, U3Gate)
self.assertEqual(qubits_0[0].index, 6)
self.assertIsInstance(gate_1, U2Gate)
self.assertEqual(qubits_1[0].index, 12)