Removed the usage of stochastic swap trivial_flag as it can lead to single-qubit gates being omitted (#3285)

* removed usage of trivial_flag that indicates when a layer should be skipped by layer_update (#3197)

* removed trivial_flag from stochastic_swap and added a test for omitted gates

* lint
This commit is contained in:
brandhsn 2019-10-22 15:38:39 +02:00 committed by Kevin Krsulich
parent 812e213a01
commit 31cdd7428c
2 changed files with 38 additions and 22 deletions

View File

@ -129,13 +129,12 @@ class StochasticSwap(TransformationPass):
trials (int): Number of attempts the randomized algorithm makes.
Returns:
Tuple: success_flag, best_circuit, best_depth, best_layout, trivial_flag
Tuple: success_flag, best_circuit, best_depth, best_layout
If success_flag is True, then best_circuit contains a DAGCircuit with
the swap circuit, best_depth contains the depth of the swap circuit,
and best_layout contains the new positions of the data qubits after the
swap circuit has been applied. The trivial_flag is set if the layer
has no multi-qubit gates.
swap circuit has been applied.
Raises:
TranspilerError: if anything went wrong.
@ -235,13 +234,13 @@ class StochasticSwap(TransformationPass):
for i, layer in enumerate(layerlist):
# Attempt to find a permutation for this layer
success_flag, best_circuit, best_depth, best_layout, trivial_flag \
success_flag, best_circuit, best_depth, best_layout \
= self._layer_permutation(layer["partition"], layout,
qubit_subset, coupling_graph,
trials)
logger.debug("mapper: layer %d", i)
logger.debug("mapper: success_flag=%s,best_depth=%s,trivial_flag=%s",
success_flag, str(best_depth), trivial_flag)
logger.debug("mapper: success_flag=%s,best_depth=%s",
success_flag, str(best_depth))
# If this fails, try one gate at a time in this layer
if not success_flag:
@ -252,29 +251,21 @@ class StochasticSwap(TransformationPass):
# Go through each gate in the layer
for j, serial_layer in enumerate(serial_layerlist):
success_flag, best_circuit, best_depth, best_layout, trivial_flag = \
success_flag, best_circuit, best_depth, best_layout = \
self._layer_permutation(
serial_layer["partition"],
layout, qubit_subset,
coupling_graph,
trials)
logger.debug("mapper: layer %d, sublayer %d", i, j)
logger.debug("mapper: success_flag=%s,best_depth=%s,"
"trivial_flag=%s",
success_flag, str(best_depth), trivial_flag)
logger.debug("mapper: success_flag=%s,best_depth=%s,",
success_flag, str(best_depth))
# Give up if we fail again
if not success_flag:
raise TranspilerError("swap mapper failed: " +
"layer %d, sublayer %d" % (i, j))
# If this layer is only single-qubit gates,
# and we have yet to see multi-qubit gates,
# continue to the next inner iteration
if trivial_flag:
logger.debug("mapper: skip to next sublayer")
continue
# Update the record of qubit positions
# for each inner iteration
layout = best_layout
@ -330,7 +321,7 @@ def _layer_permutation(layer_partition, layout, qubit_subset,
rng (RandomState): Random number generator.
Returns:
Tuple: success_flag, best_circuit, best_depth, best_layout, trivial_flag
Tuple: success_flag, best_circuit, best_depth, best_layout
Raises:
TranspilerError: if anything went wrong.
@ -364,7 +355,7 @@ def _layer_permutation(layer_partition, layout, qubit_subset,
logger.debug("layer_permutation: nothing to do")
circ = DAGCircuit()
circ.add_qreg(canonical_register)
return True, circ, 0, layout, (not bool(gates))
return True, circ, 0, layout
# Begin loop over trials of randomized algorithm
num_qubits = len(layout)
@ -418,7 +409,7 @@ def _layer_permutation(layer_partition, layout, qubit_subset,
# trials have failed
if best_layout is None:
logger.debug("layer_permutation: failed!")
return False, None, None, None, False
return False, None, None, None
edgs = best_edges.edges()
trivial_layout = Layout.generate_trivial_layout(canonical_register)
@ -431,7 +422,7 @@ def _layer_permutation(layer_partition, layout, qubit_subset,
# Otherwise, we return our result for this layer
logger.debug("layer_permutation: success!")
best_lay = best_layout.to_layout(qregs)
return True, best_circuit, best_depth, best_lay, False
return True, best_circuit, best_depth, best_lay
def regtuple_to_numeric(items, qregs):

View File

@ -16,7 +16,7 @@
import unittest
from qiskit.transpiler.passes import StochasticSwap
from qiskit.transpiler import CouplingMap
from qiskit.transpiler import CouplingMap, PassManager
from qiskit.transpiler.exceptions import TranspilerError
from qiskit.converters import circuit_to_dag
from qiskit import QuantumRegister, ClassicalRegister, QuantumCircuit
@ -511,6 +511,31 @@ class TestStochasticSwap(QiskitTestCase):
with self.assertRaises(TranspilerError):
_ = pass_.run(dag)
def test_single_gates_omitted(self):
"""Test if single qubit gates are omitted."""
coupling_map = [[0, 1], [1, 0], [1, 2], [1, 3], [2, 1], [3, 1], [3, 4], [4, 3]]
qr = QuantumRegister(5, 'q')
cr = ClassicalRegister(5, 'c')
circuit = QuantumCircuit(qr, cr)
circuit.cx(qr[0], qr[4])
circuit.cx(qr[1], qr[2])
circuit.u3(1, 1.5, 0.7, qr[3])
expected = QuantumCircuit(qr, cr)
expected.cx(qr[1], qr[2])
expected.u3(1, 1.5, 0.7, qr[3])
expected.swap(qr[0], qr[1])
expected.swap(qr[3], qr[4])
expected.cx(qr[1], qr[3])
expected_dag = circuit_to_dag(expected)
stochastic = StochasticSwap(CouplingMap(coupling_map), seed=0)
after = PassManager(stochastic).run(circuit)
after = circuit_to_dag(after)
self.assertEqual(expected_dag, after)
if __name__ == '__main__':
unittest.main()