mirror of https://github.com/Qiskit/qiskit.git
Fix Hoare optimizer failure for successive gates of three (#7278)
* Record deleted gates in _multigate_optto * Move come code from _multigate_opt to a subroutine * Create a release note for the bug fix * Rename max_idx to from_idx and update comments * Remove reference to private function in release note Co-authored-by: Jake Lishman <jake.lishman@ibm.com> Co-authored-by: mergify[bot] <37929162+mergify[bot]@users.noreply.github.com>
This commit is contained in:
parent
8dbb7183c6
commit
605283d67e
|
@ -232,23 +232,24 @@ class HoareOptimizer(TransformationPass):
|
|||
|
||||
self._add_postconditions(gate, ctrl_ones, trgtqb, trgtvar)
|
||||
|
||||
def _target_successive_seq(self, qubit):
|
||||
"""gates are target successive if they have the same set of target
|
||||
qubits and follow each other immediately on these target qubits
|
||||
(consider sequences of length 2 for now)
|
||||
def _remove_successive_identity(self, dag, qubit, from_idx=None):
|
||||
"""remove gates that have the same set of target qubits, follow each
|
||||
other immediately on these target qubits, and combine to the
|
||||
identity (consider sequences of length 2 for now)
|
||||
Args:
|
||||
dag (DAGCircuit): the directed acyclic graph to run on.
|
||||
qubit (Qubit): qubit cache to inspect
|
||||
Returns:
|
||||
list(list(DAGOpNode or DAGOutNode)): list of target successive gate sequences for
|
||||
this qubit's cache
|
||||
from_idx (int): only gates whose indexes in the cache are larger
|
||||
than this value can be removed
|
||||
"""
|
||||
seqs = []
|
||||
for i in range(len(self.gatecache[qubit]) - 1):
|
||||
i = 0
|
||||
while i < len(self.gatecache[qubit]) - 1:
|
||||
append = True
|
||||
node1 = self.gatecache[qubit][i]
|
||||
node2 = self.gatecache[qubit][i + 1]
|
||||
trgtqb1 = self._seperate_ctrl_trgt(node1)[2]
|
||||
trgtqb2 = self._seperate_ctrl_trgt(node2)[2]
|
||||
i += 1
|
||||
|
||||
if trgtqb1 != trgtqb2:
|
||||
continue
|
||||
|
@ -260,10 +261,14 @@ class HoareOptimizer(TransformationPass):
|
|||
except (IndexError, ValueError):
|
||||
continue
|
||||
|
||||
if append:
|
||||
seqs.append([node1, node2])
|
||||
|
||||
return seqs
|
||||
seq = [node1, node2]
|
||||
if append and self._is_identity(seq) and self._seq_as_one(seq):
|
||||
i += 1
|
||||
for node in seq:
|
||||
dag.remove_op_node(node)
|
||||
if from_idx is None or self.gatecache[qubit].index(node) > from_idx:
|
||||
for qbt in node.qargs:
|
||||
self.gatecache[qbt].remove(node)
|
||||
|
||||
def _is_identity(self, sequence):
|
||||
"""determine whether the sequence of gates combines to the identity
|
||||
|
@ -334,19 +339,7 @@ class HoareOptimizer(TransformationPass):
|
|||
return
|
||||
|
||||
# try to optimize this qubit's pipeline
|
||||
for seq in self._target_successive_seq(qubit):
|
||||
if self._is_identity(seq) and self._seq_as_one(seq):
|
||||
for node in seq:
|
||||
dag.remove_op_node(node)
|
||||
# if recursive call, gate will be removed further down
|
||||
if max_idx is None:
|
||||
for qbt in node.qargs:
|
||||
self.gatecache[qbt].remove(node)
|
||||
else:
|
||||
if self.gatecache[qubit].index(node) > max_idx:
|
||||
for qbt in node.qargs:
|
||||
self.gatecache[qbt].remove(node)
|
||||
|
||||
self._remove_successive_identity(dag, qubit, max_idx)
|
||||
if len(self.gatecache[qubit]) < self.size and max_idx is None:
|
||||
# unless in a rec call, we are done if the cache isn't full
|
||||
return
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
fixes:
|
||||
- |
|
||||
Fixed a bug in the Hoare optimizer transpilation pass where it could attempt to remove a gate twice if it could be separately combined with both its predecessor and its successor to form the identity.
|
||||
Refer to `#7271 <https://github.com/Qiskit/qiskit-terra/issues/7271>`__ for more details.
|
|
@ -175,6 +175,26 @@ class TestHoareOptimizer(QiskitTestCase):
|
|||
|
||||
self.assertEqual(result, circuit_to_dag(expected))
|
||||
|
||||
def test_successive_identity_removal(self):
|
||||
"""Should remove a successive pair of H gates applying
|
||||
on the same qubit.
|
||||
"""
|
||||
circuit = QuantumCircuit(1)
|
||||
circuit.h(0)
|
||||
circuit.h(0)
|
||||
circuit.h(0)
|
||||
|
||||
expected = QuantumCircuit(1)
|
||||
expected.h(0)
|
||||
|
||||
stv = Statevector.from_label("0" * circuit.num_qubits)
|
||||
self.assertEqual(stv & circuit, stv & expected)
|
||||
|
||||
pass_ = HoareOptimizer(size=4)
|
||||
result = pass_.run(circuit_to_dag(circuit))
|
||||
|
||||
self.assertEqual(result, circuit_to_dag(expected))
|
||||
|
||||
def test_targetsuccessive_identity_removal(self):
|
||||
"""Should remove pair of controlled target successive
|
||||
which are the inverse of each other, if they can be
|
||||
|
|
Loading…
Reference in New Issue