-
Notifications
You must be signed in to change notification settings - Fork 2.5k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add measure_all, measure_active, remove_final_measures methods (#2993)
* Add measure_all, measure_active, remove_final_measurement methods * Add testing for measure_all, measure_active, remove_final_measurements * Rename remove_final_measurements to remove_final_measures * Rename test_remove_final_measurements to test_remove_final_measures * Fix incorrect method call in test_remove_final_measures * Fix remove_final_measures to only delete ClassicalRegister if it is unused. Fix measure_active to only check for non-idle qubits instead of non-idle qubits and clbits * Add test_remove_final_measures_multiple_measures * Remove 'gates' from docstrings when referring to measurements * Rename remove_final_measures to remove_final_measurements * Rework remove_final_measurements to use RemoveFinalMeasurements pass * Add RemoveFinalMeasurements pass * Add remove_final_measurements module * Rework test_remove_final_measurements_multiple_measures to work with new circuit.remove_final_measurements * Add pylint disable-cyclic-import to remove_final_measurements * tests * fix test * test to avoid name conflict * avoid code repetition * Add QuantumCircuit methods to add and remove final measurements * Add newline at end of file * Change inst.control to inst.condition
- Loading branch information
1 parent
ef828be
commit 7ac8f89
Showing
5 changed files
with
343 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,88 @@ | ||
# -*- coding: utf-8 -*- | ||
|
||
# This code is part of Qiskit. | ||
# | ||
# (C) Copyright IBM 2017, 2019. | ||
# | ||
# This code is licensed under the Apache License, Version 2.0. You may | ||
# obtain a copy of this license in the LICENSE.txt file in the root directory | ||
# of this source tree or at http://www.apache.org/licenses/LICENSE-2.0. | ||
# | ||
# Any modifications or derivative works of this code must retain this | ||
# copyright notice, and modified files need to carry a notice indicating | ||
# that they have been altered from the originals. | ||
|
||
|
||
""" | ||
This pass removes final barriers and final measurements, as well as the | ||
ClassicalRegisters they are connected to if the ClassicalRegister | ||
is unused. Measurements and barriers are considered final if they are | ||
followed by no other operations (aside from other measurements or barriers.) | ||
""" | ||
|
||
from qiskit.transpiler.basepasses import TransformationPass | ||
from qiskit.dagcircuit import DAGCircuit | ||
|
||
|
||
class RemoveFinalMeasurements(TransformationPass): | ||
"""Removes final measurements and barriers at the end of a circuit.""" | ||
|
||
def run(self, dag): | ||
"""Return a circuit with final measurements and barriers removed.""" | ||
|
||
final_op_types = ['measure', 'barrier'] | ||
final_ops = [] | ||
cregs_to_remove = dict() | ||
clbits_with_final_measures = set() | ||
|
||
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(suc.type == 'op' 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) | ||
|
||
if not final_ops: | ||
return dag | ||
|
||
new_dag = DAGCircuit() | ||
|
||
for node in final_ops: | ||
for carg in node.cargs: | ||
# Add the clbit that was attached to the measure we are removing | ||
clbits_with_final_measures.add(carg) | ||
dag.remove_op_node(node) | ||
|
||
# If the clbit is idle, add its register to list of registers we may remove | ||
for clbit in clbits_with_final_measures: | ||
if clbit in dag.idle_wires(): | ||
if clbit.register in cregs_to_remove: | ||
cregs_to_remove[clbit.register] += 1 | ||
else: | ||
cregs_to_remove[clbit.register] = 1 | ||
|
||
# Remove creg if all of its clbits were added above | ||
for key, val in zip(list(dag.cregs.keys()), list(dag.cregs.values())): | ||
if val in cregs_to_remove and cregs_to_remove[val] == val.size: | ||
del dag.cregs[key] | ||
|
||
# Fill new DAGCircuit | ||
for qreg in dag.qregs.values(): | ||
new_dag.add_qreg(qreg) | ||
for creg in dag.cregs.values(): | ||
new_dag.add_creg(creg) | ||
|
||
for node in dag.topological_op_nodes(): | ||
# copy the condition over too | ||
if node.condition: | ||
new_dag.apply_operation_back(node.op, qargs=node.qargs, cargs=node.cargs, | ||
condition=node.condition) | ||
else: | ||
new_dag.apply_operation_back(node.op, qargs=node.qargs, cargs=node.cargs) | ||
|
||
return new_dag |
84 changes: 84 additions & 0 deletions
84
releasenotes/notes/add-methods-to-add-and-remove-final-measurements-bcdd9977eacf8380.yaml
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,84 @@ | ||
--- | ||
features: | ||
- | | ||
Introduced new methods in ``QuantumCircuit`` which allows the seamless adding or removing | ||
of measurements at the end of a circuit. | ||
``measure_all()`` | ||
Adds a ``barrier`` followed by a ``measure`` operation to all qubits in the circuit. | ||
Creates a ``ClassicalRegister`` of size equal to the number of qubits in the circuit, | ||
which store the measurements. | ||
``measure_active()`` | ||
Adds a ``barrier`` followed by a ``measure`` operation to all active qubits in the circuit. | ||
A qubit is active if it has at least one other operation acting upon it. | ||
Creates a ``ClassicalRegister`` of size equal to the number of active qubits in the circuit, | ||
which store the measurements. | ||
``remove_final_measurements()`` | ||
Removes all final measurements and preceeding ``barrier`` from a circuit. | ||
A measurement is considered "final" if it is not followed by any other operation, | ||
excluding barriers and other measurements. | ||
After the measurements are removed, if all of the classical bits in the ``ClassicalRegister`` | ||
are idle (have no operations attached to them), then the ``ClassicalRegister`` is removed. | ||
Examples:: | ||
# Using measure_all() | ||
circuit = QuantumCircuit(2) | ||
circuit.h(0) | ||
circuit.measure_all() | ||
circuit.draw() | ||
# A ClassicalRegister with prefix measure was created. | ||
# It has 2 clbits because there are 2 qubits to measure | ||
┌───┐ ░ ┌─┐ | ||
q_0: |0>┤ H ├─░─┤M├─── | ||
└───┘ ░ └╥┘┌─┐ | ||
q_1: |0>──────░──╫─┤M├ | ||
░ ║ └╥┘ | ||
measure_0: 0 ═════════╩══╬═ | ||
║ | ||
measure_1: 0 ════════════╩═ | ||
# Using measure_active() | ||
circuit = QuantumCircuit(2) | ||
circuit.h(0) | ||
circuit.measure_active() | ||
circuit.draw() | ||
# This ClassicalRegister only has 1 clbit because only 1 qubit is active | ||
┌───┐ ░ ┌─┐ | ||
q_0: |0>┤ H ├─░─┤M├ | ||
└───┘ ░ └╥┘ | ||
q_1: |0>──────░──╫─ | ||
░ ║ | ||
measure_0: 0 ═════════╩═ | ||
# Using remove_final_measurements() | ||
# Assuming circuit_all and circuit_active are the circuits from the measure_all and | ||
# measure_active examples above respectively | ||
circuit_all.remove_final_measurements() | ||
circuit_all.draw() | ||
# The ClassicalRegister is removed because, after the measurements were removed, | ||
# all of its clbits were idle | ||
┌───┐ | ||
q_0: |0>┤ H ├ | ||
└───┘ | ||
q_1: |0>───── | ||
circuit_active.remove_final_measurements() | ||
circuit_active.draw() | ||
# This will result in the same circuit | ||
┌───┐ | ||
q_0: |0>┤ H ├ | ||
└───┘ | ||
q_1: |0>───── |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters