Fixes to stochastic_swap (#1555)

* stochastic mapper.

* pass implemented.

* start tests.

* basic tests pass.

* add a test.

* add test.

* stochastic mapper.

* pass implemented.

* start tests.

* basic tests pass.

* add a test.

* add test.

* lint

* maxsize < inf

* docstring

* Coupling new format

* style

* lint

* remove identity_wire_map, since can be constructed by extend_back

* no q

* add layout test.

* input is Layout object now.

* fix typo.

* updates to mapper to use layout object, tests failing.

* fix what broke from master merge.

* tests passing.

* remove special measurement code.

* get layout from property_set if it exists.

* rename mapper as a swapper

* lint

* removing unsed thigns

* more unused stuff

* missing-raises-doc

* return type

* var renaming

* add get classical bits method to dagcircuit.

* fix creg wiremap bugs.

* fix bugs and add tests.

* appease the linter.

* good var names. fix bug in transpiler property set init
This commit is contained in:
Andrew Cross 2018-12-19 01:24:02 -05:00 committed by Ali Javadi-Abhari
parent 92a18ff3b4
commit 77405e5171
5 changed files with 152 additions and 11 deletions

View File

@ -120,7 +120,7 @@ evaluation=10.0 - ((float(5 * error + warning + refactor + convention) / stateme
# pi = the PI constant
# op = operation iterator
# b = basis iterator
good-names=i,j,k,n,m,ex,v,w,x,y,z,Run,_,logger,q,r,qr,cr,qc,pi,op,b
good-names=i,j,k,n,m,ex,v,w,x,y,z,Run,_,logger,q,r,qr,cr,qc,pi,op,b,ar,br
# Bad variable names which should always be refused, separated by a comma
bad-names=foo,bar,toto,tutu,tata

View File

@ -92,6 +92,10 @@ class DAGCircuit:
"""Return a list of qubits as (QuantumRegister, index) pairs."""
return [(v, i) for k, v in self.qregs.items() for i in range(v.size)]
def get_bits(self):
"""Return a list of bits as (ClassicalRegister, index) pairs."""
return [(v, i) for k, v in self.cregs.items() for i in range(v.size)]
# TODO: unused function. is it needed?
def rename_register(self, regname, newname):
"""Rename a classical or quantum register throughout the circuit.

View File

@ -10,6 +10,7 @@
from abc import abstractmethod
from collections.abc import Hashable
from inspect import signature
from ._propertyset import PropertySet
class MetaPass(type):
@ -50,7 +51,7 @@ class BasePass(metaclass=MetaPass):
def __init__(self):
self.requires = [] # List of passes that requires
self.preserves = [] # List of passes that preserves
self.property_set = {} # This pass's pointer to the pass manager's property set.
self.property_set = PropertySet() # This pass's pointer to the pass manager's property set.
@classmethod
def normalize_parameters(cls, *args, **kwargs):

View File

@ -89,11 +89,11 @@ class StochasticSwap(TransformationPass):
"""
# If the property_set contains a layout, use it to
# override any layout passed to __init__
if "layout" in self.property_set:
if self.property_set["layout"]:
self.initial_layout = self.property_set["layout"]
self.input_layout = self.property_set["layout"]
new_dag = self._mapper(dag, self.coupling_map, trials=self.trials, seed=self.seed)
self.property_set["layout"] = self.initial_layout
# self.property_set["layout"] = self.initial_layout
return new_dag
def _layer_permutation(self, layer_partition, layout, qubit_subset,
@ -162,7 +162,7 @@ class StochasticSwap(TransformationPass):
if register[0] not in circ.qregs.values():
circ.add_qreg(register[0])
circ.add_basis_element("swap", 2)
return True, circ, 0, layout, bool(gates)
return True, circ, 0, layout, (not bool(gates))
# Begin loop over trials of randomized algorithm
num_qubits = len(layout)
@ -318,7 +318,10 @@ class StochasticSwap(TransformationPass):
logger.debug("layer_update: first multi-qubit gate layer")
# Output all layers up to this point
for j in range(i + 1):
# Make qubit edge map and extend by classical bits
edge_map = layout.combine_into_edge_map(self.initial_layout)
for bit in dagcircuit_output.get_bits():
edge_map[bit] = bit
dagcircuit_output.compose_back(layer_list[j]["graph"], edge_map)
# Otherwise, we output the current layer and the associated swap gates.
else:
@ -329,8 +332,11 @@ class StochasticSwap(TransformationPass):
dagcircuit_output.extend_back(best_circuit)
else:
logger.debug("layer_update: there are no swaps in this layer")
# Output this layer
# Make qubit edge map and extend by classical bits
edge_map = layout.combine_into_edge_map(self.initial_layout)
for bit in dagcircuit_output.get_bits():
edge_map[bit] = bit
# Output this layer
dagcircuit_output.compose_back(layer_list[i]["graph"], edge_map)
return dagcircuit_output
@ -397,6 +403,14 @@ class StochasticSwap(TransformationPass):
for creg in circuit_graph.cregs.values():
dagcircuit_output.add_creg(creg)
# Make a trivial wire mapping between the subcircuits
# returned by _layer_update and the circuit we build
identity_wire_map = {}
for qubit in circuit_graph.get_qubits():
identity_wire_map[qubit] = qubit
for bit in circuit_graph.get_bits():
identity_wire_map[bit] = bit
first_layer = True # True until first layer is output
logger.debug("initial_layout = %s", layout)
@ -461,7 +475,8 @@ class StochasticSwap(TransformationPass):
best_layout,
best_depth,
best_circuit,
serial_layerlist))
serial_layerlist),
identity_wire_map)
if first_layer:
first_layer = False
@ -479,13 +494,14 @@ class StochasticSwap(TransformationPass):
best_layout,
best_depth,
best_circuit,
layerlist))
layerlist),
identity_wire_map)
if first_layer:
first_layer = False
# This is the final edgemap that we need to correctly replace
# any measurements that needed to be removed before the swap
# This is the final edgemap. We might use it to correctly replace
# any measurements that needed to be removed earlier.
logger.debug("mapper: self.initial_layout = %s", pformat(self.initial_layout))
logger.debug("mapper: layout = %s", pformat(layout))
last_edgemap = layout.combine_into_edge_map(self.initial_layout)
@ -493,7 +509,9 @@ class StochasticSwap(TransformationPass):
# If first_layer is still set, the circuit only has single-qubit gates
# so we can use the initial layout to output the entire circuit
# This code is dead due to changes to first_layer above.
if first_layer:
logger.debug("mapper: first_layer flag still set")
layout = self.initial_layout
for i, layer in enumerate(layerlist):
edge_map = layout.combine_into_edge_map(self.initial_layout)

View File

@ -386,7 +386,7 @@ class TestStochasticSwap(QiskitTestCase):
# q_0: |0>───────────────────────────────┤ X ├──■──────────────────┤M├
# ┌───┐ ┌───┐└───┘ │ ┌───┐┌─┐ └╥┘
# q_1: |0>──────────────────┤ Y ├─X─┤ T ├───────┼───────┤ X ├┤M├────╫─
# ┌───┐ └───┘ │ └───┘ ┌─┴─┐┌───┐└─┬─┘└╥┘┌─┐ ║
# ┌───┐ └───┘ │ └───┘ ┌─┴─┐┌───┐└─┬─┘└╥┘┌─┐ ║
# q_2: |0>┤ Z ├──■────────────────X───────────┤ X ├┤ S ├──■───╫─┤M├─╫─
# └───┘┌─┴─┐┌───┐┌─┐ └───┘└───┘ ║ └╥┘ ║
# q_3: |0>─────┤ X ├┤ H ├┤M├──────────────────────────────────╫──╫──╫─
@ -460,6 +460,124 @@ class TestStochasticSwap(QiskitTestCase):
self.assertEqual(dag, after)
def test_congestion(self):
"""Test code path that falls back to serial layers."""
coupling = CouplingMap(couplinglist=[[0, 1], [1, 2], [1, 3]])
qr = QuantumRegister(2, 'q')
ar = QuantumRegister(2, 'a')
cr = ClassicalRegister(4, 'c')
circ = QuantumCircuit(qr, ar, cr)
circ.cx(qr[1], ar[0])
circ.cx(qr[0], ar[1])
circ.measure(qr[0], cr[0])
circ.h(qr)
circ.h(ar)
circ.cx(qr[0], qr[1])
circ.cx(ar[0], ar[1])
circ.measure(qr[0], cr[0])
circ.measure(qr[1], cr[1])
circ.measure(ar[0], cr[2])
circ.measure(ar[1], cr[3])
dag = circuit_to_dag(circ)
# ┌─┐┌───┐ ┌─┐
# q_0: |0>─────────────────■──────────────────┤M├┤ H ├──■─────┤M├
# ┌───┐ │ └╥┘└───┘┌─┴─┐┌─┐└╥┘
# q_1: |0>──■───────┤ H ├──┼───────────────────╫──────┤ X ├┤M├─╫─
# ┌─┴─┐┌───┐└───┘ │ ┌─┐ ║ └───┘└╥┘ ║
# a_0: |0>┤ X ├┤ H ├───────┼─────────■─────┤M├─╫────────────╫──╫─
# └───┘└───┘ ┌─┴─┐┌───┐┌─┴─┐┌─┐└╥┘ ║ ║ ║
# a_1: |0>───────────────┤ X ├┤ H ├┤ X ├┤M├─╫──╫────────────╫──╫─
# └───┘└───┘└───┘└╥┘ ║ ║ ║ ║
# c_0: 0 ═══════════════════════════════╬══╬══╩════════════╬══╩═
# ║ ║ ║
# c_1: 0 ═══════════════════════════════╬══╬═══════════════╩════
# ║ ║
# c_2: 0 ═══════════════════════════════╬══╩════════════════════
# ║
# c_3: 0 ═══════════════════════════════╩═══════════════════════
#
# ┌─┐┌───┐ ┌─┐
# q_0: |0>────────────────────■──┤M├┤ H ├──────────────────■──┤M├──────
# ┌─┴─┐└╥┘└───┘┌───┐┌───┐ ┌─┴─┐└╥┘┌─┐
# q_1: |0>──■───X───────────┤ X ├─╫──────┤ H ├┤ X ├─X────┤ X ├─╫─┤M├───
# ┌─┴─┐ │ ┌───┐└───┘ ║ └───┘└─┬─┘ │ └───┘ ║ └╥┘┌─┐
# a_0: |0>┤ X ├─┼──────┤ H ├──────╫─────────────■───┼──────────╫──╫─┤M├
# └───┘ │ ┌───┐└───┘ ║ │ ┌─┐ ║ ║ └╥┘
# a_1: |0>──────X─┤ H ├───────────╫─────────────────X─┤M├──────╫──╫──╫─
# └───┘ ║ └╥┘ ║ ║ ║
# c_0: 0 ════════════════════════╩════════════════════╬═══════╩══╬══╬═
# ║ ║ ║
# c_1: 0 ═════════════════════════════════════════════╬══════════╩══╬═
# ║ ║
# c_2: 0 ═════════════════════════════════════════════╬═════════════╩═
# ║
# c_3: 0 ═════════════════════════════════════════════╩═══════════════
#
# Layout from mapper:
# {(QuantumRegister(2, 'q'), 0): 0,
# (QuantumRegister(2, 'q'), 1): 1,
# (QuantumRegister(2, 'a'), 0): 2,
# (QuantumRegister(2, 'a'), 1): 3}
#
# 2
# |
# 0 - 1 - 3
expected = QuantumCircuit(qr, ar, cr)
expected.cx(qr[1], ar[0])
expected.h(ar[0])
expected.swap(qr[1], ar[1])
expected.cx(qr[0], qr[1])
expected.h(ar[1])
expected.h(qr[1])
expected.cx(ar[0], qr[1])
expected.measure(qr[0], cr[0])
expected.h(qr[0])
expected.measure(ar[0], cr[2])
expected.swap(ar[1], qr[1])
expected.cx(qr[0], qr[1])
expected.measure(ar[1], cr[3])
expected.measure(qr[1], cr[1])
expected.measure(qr[0], cr[0])
expected_dag = circuit_to_dag(expected)
layout = Layout([(QuantumRegister(2, 'q'), 0),
(QuantumRegister(2, 'q'), 1),
(QuantumRegister(2, 'a'), 0),
(QuantumRegister(2, 'a'), 1)])
pass_ = StochasticSwap(coupling, layout, 20, 13)
after = pass_.run(dag)
self.assertEqual(expected_dag, after)
def test_all_single_qubit(self):
"""Test all trivial layers."""
coupling = CouplingMap(couplinglist=[[0, 1], [1, 2], [1, 3]])
qr = QuantumRegister(2, 'q')
ar = QuantumRegister(2, 'a')
cr = ClassicalRegister(4, 'c')
circ = QuantumCircuit(qr, ar, cr)
circ.h(qr)
circ.h(ar)
circ.s(qr)
circ.s(ar)
circ.t(qr)
circ.t(ar)
circ.measure(qr[0], cr[0]) # intentional duplicate
circ.measure(qr[0], cr[0])
circ.measure(qr[1], cr[1])
circ.measure(ar[0], cr[2])
circ.measure(ar[1], cr[3])
dag = circuit_to_dag(circ)
layout = Layout([(QuantumRegister(2, 'q'), 0),
(QuantumRegister(2, 'q'), 1),
(QuantumRegister(2, 'a'), 0),
(QuantumRegister(2, 'a'), 1)])
pass_ = StochasticSwap(coupling, layout, 20, 13)
after = pass_.run(dag)
self.assertEqual(dag, after)
if __name__ == '__main__':
unittest.main()