mirror of https://github.com/Qiskit/qiskit.git
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:
parent
92a18ff3b4
commit
77405e5171
|
@ -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
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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):
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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()
|
||||
|
|
Loading…
Reference in New Issue