Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve efficiency of RemoveFinalMeasurement transpiler pass #7039

Merged
merged 5 commits into from
Sep 17, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 21 additions & 8 deletions qiskit/dagcircuit/dagcircuit.py
Original file line number Diff line number Diff line change
Expand Up @@ -786,17 +786,30 @@ def idle_wires(self, ignore=None):

Yields:
Bit: Bit in idle wire.

Raises:
DAGCircuitError: If the DAG is invalid
"""
if ignore is None:
ignore = []
ignore = set()
ignore_set = set(ignore)
for wire in self._wires:
nodes = [
node
for node in self.nodes_on_wire(wire, only_ops=True)
if node.op.name not in ignore
]
if len(nodes) == 0:
yield wire
if not ignore:
try:
child = next(self.successors(self.input_map[wire]))
except StopIteration as e:
raise DAGCircuitError(
"Invalid dagcircuit input node %s has no output" % self.input_map[wire]
) from e
Comment on lines +800 to +803
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Out of curiosity, we don't usually guard against a malformed DAGCircuit, was there a reason to here?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pylint was yelling at me locally about raising stopiteration without it. This made it happy...

if isinstance(child, DAGOutNode):
yield wire
else:
for node in self.nodes_on_wire(wire, only_ops=True):
if node.op.name not in ignore_set:
# If we found an op node outside of ignore we can stop iterating over the wire
break
else:
yield wire

def size(self):
"""Return the number of operations."""
Expand Down
27 changes: 6 additions & 21 deletions qiskit/transpiler/passes/utils/remove_final_measurements.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,25 +34,16 @@ def run(self, dag):
Returns:
DAGCircuit: the optimized DAG.
"""
final_op_types = ["measure", "barrier"]
final_op_types = {"measure", "barrier"}
final_ops = []
cregs_to_remove = dict()
clbits_with_final_measures = set()
clbit_registers = {clbit: creg for creg in dag.cregs.values() for clbit in creg}

for candidate_node in dag.named_nodes(*final_op_types):
is_final_op = True

for _, child_successors in dag.bfs_successors(candidate_node):
if any(
isinstance(suc, DAGOpNode) and suc.name not in final_op_types
for suc in child_successors
):
is_final_op = False
break

if is_final_op:
final_ops.append(candidate_node)
for qubit in dag.qubits:
op_node = next(dag.predecessors(dag.output_map[qubit]))
if isinstance(op_node, DAGOpNode) and op_node.op.name in final_op_types:
final_ops.append(op_node)

if not final_ops:
return dag
Expand All @@ -77,10 +68,4 @@ def run(self, dag):
if val in cregs_to_remove and cregs_to_remove[val] == val.size:
del dag.cregs[key]

new_dag = dag._copy_circuit_metadata()

for node in dag.topological_op_nodes():
# copy the condition over too
new_dag.apply_operation_back(node.op, qargs=node.qargs, cargs=node.cargs)

return new_dag
return dag