Skip to content

Commit

Permalink
Allow for circuit measure methods to return a new circuit with inplac…
Browse files Browse the repository at this point in the history
…e kwarg (#3755)

* all inplace kwarg to measure_all

* fix style

* fix lint

* Update quantumcircuit.py

* add inplace to other measure methods

* add release note

Co-authored-by: mergify[bot] <37929162+mergify[bot]@users.noreply.github.com>
  • Loading branch information
nonhermitian and mergify[bot] authored Jan 30, 2020
1 parent 592c898 commit e4b3bd5
Show file tree
Hide file tree
Showing 3 changed files with 135 additions and 19 deletions.
92 changes: 73 additions & 19 deletions qiskit/circuit/quantumcircuit.py
Original file line number Diff line number Diff line change
Expand Up @@ -1106,42 +1106,91 @@ def _create_creg(self, length, name):
new_creg = ClassicalRegister(length, name)
return new_creg

def measure_active(self):
def measure_active(self, inplace=True):
"""Adds measurement to all non-idle qubits. Creates a new ClassicalRegister with
a size equal to the number of non-idle qubits being measured.
Returns a new circuit with measurements if `inplace=False`.
Parameters:
inplace (bool): All measurements inplace or return new circuit.
Returns:
QuantumCircuit: Returns circuit with measurements when `inplace = False`.
"""
from qiskit.converters.circuit_to_dag import circuit_to_dag
dag = circuit_to_dag(self)
qubits_to_measure = [qubit for qubit in self.qubits if qubit not in dag.idle_wires()]
new_creg = self._create_creg(len(qubits_to_measure), 'measure')
self.add_register(new_creg)
self.barrier()
self.measure(qubits_to_measure, new_creg)

def measure_all(self):
if inplace:
circ = self
else:
circ = self.copy()
dag = circuit_to_dag(circ)
qubits_to_measure = [qubit for qubit in circ.qubits if qubit not in dag.idle_wires()]
new_creg = circ._create_creg(len(qubits_to_measure), 'measure')
circ.add_register(new_creg)
circ.barrier()
circ.measure(qubits_to_measure, new_creg)

if not inplace:
return circ
else:
return None

def measure_all(self, inplace=True):
"""Adds measurement to all qubits. Creates a new ClassicalRegister with a
size equal to the number of qubits being measured.
Returns a new circuit with measurements if `inplace=False`.
Parameters:
inplace (bool): All measurements inplace or return new circuit.
Returns:
QuantumCircuit: Returns circuit with measurements when `inplace = False`.
"""
new_creg = self._create_creg(len(self.qubits), 'measure')
self.add_register(new_creg)
self.barrier()
self.measure(self.qubits, new_creg)
if inplace:
circ = self
else:
circ = self.copy()

def remove_final_measurements(self):
new_creg = circ._create_creg(len(circ.qubits), 'measure')
circ.add_register(new_creg)
circ.barrier()
circ.measure(circ.qubits, new_creg)

if not inplace:
return circ
else:
return None

def remove_final_measurements(self, inplace=True):
"""Removes final measurement on all qubits if they are present.
Deletes the ClassicalRegister that was used to store the values from these measurements
if it is idle.
Returns a new circuit without measurements if `inplace=False`.
Parameters:
inplace (bool): All measurements removed inplace or return new circuit.
Returns:
QuantumCircuit: Returns circuit with measurements removed when `inplace = False`.
"""
# pylint: disable=cyclic-import
from qiskit.transpiler.passes import RemoveFinalMeasurements
from qiskit.converters import circuit_to_dag
dag = circuit_to_dag(self)

if inplace:
circ = self
else:
circ = self.copy()

dag = circuit_to_dag(circ)
remove_final_meas = RemoveFinalMeasurements()
new_dag = remove_final_meas.run(dag)

# Set self's cregs and instructions to match the new DAGCircuit's
self.data.clear()
self.cregs = list(new_dag.cregs.values())
# Set circ cregs and instructions to match the new DAGCircuit's
circ.data.clear()
circ.cregs = list(new_dag.cregs.values())

for node in new_dag.topological_op_nodes():
qubits = []
Expand All @@ -1155,7 +1204,12 @@ def remove_final_measurements(self):
# Get arguments for classical condition (if any)
inst = node.op.copy()
inst.condition = node.condition
self.append(inst, qubits, clbits)
circ.append(inst, qubits, clbits)

if not inplace:
return circ
else:
return None

@staticmethod
def from_qasm_file(path):
Expand Down
7 changes: 7 additions & 0 deletions releasenotes/notes/copy-measure-methods-562f0c1096f93145.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
upgrade:
- |
QuantumCircuit methods `measure_active`, `measure_all`, and
`remove_final_measurements` now take the `inplace` keyword
argument that, when, `False` return a modified copy of the
circuit.
55 changes: 55 additions & 0 deletions test/python/circuit/test_circuit_operations.py
Original file line number Diff line number Diff line change
Expand Up @@ -180,6 +180,29 @@ def test_measure_active(self):

self.assertEqual(expected, circuit)

def test_measure_active_copy(self):
"""Test measure_active copy
Applies measurements only to non-idle qubits. Creates a ClassicalRegister of size equal to
the amount of non-idle qubits to store the measured values.
"""
qr = QuantumRegister(4)
cr = ClassicalRegister(2, 'measure')

circuit = QuantumCircuit(qr)
circuit.h(qr[0])
circuit.h(qr[2])
new_circuit = circuit.measure_active(inplace=False)

expected = QuantumCircuit(qr)
expected.h(qr[0])
expected.h(qr[2])
expected.add_register(cr)
expected.barrier()
expected.measure([qr[0], qr[2]], [cr[0], cr[1]])

self.assertEqual(expected, new_circuit)
self.assertFalse('measure' in circuit.count_ops().keys())

def test_measure_active_repetition(self):
"""Test measure_active in a circuit with a 'measure' creg.
measure_active should be aware that the creg 'measure' might exists.
Expand Down Expand Up @@ -212,6 +235,22 @@ def test_measure_all(self):

self.assertEqual(expected, circuit)

def test_measure_all_copy(self):
"""Test measure_all with inplace=False
"""
qr = QuantumRegister(2)
cr = ClassicalRegister(2, 'measure')

circuit = QuantumCircuit(qr)
new_circuit = circuit.measure_all(inplace=False)

expected = QuantumCircuit(qr, cr)
expected.barrier()
expected.measure(qr, cr)

self.assertEqual(expected, new_circuit)
self.assertFalse('measure' in circuit.count_ops().keys())

def test_measure_all_repetition(self):
"""Test measure_all in a circuit with a 'measure' creg.
measure_all should be aware that the creg 'measure' might exists.
Expand Down Expand Up @@ -241,6 +280,22 @@ def test_remove_final_measurements(self):

self.assertEqual(expected, circuit)

def test_remove_final_measurements_copy(self):
"""Test remove_final_measurements on copy
Removes all measurements at end of circuit.
"""
qr = QuantumRegister(2)
cr = ClassicalRegister(2, 'measure')

circuit = QuantumCircuit(qr, cr)
circuit.measure(qr, cr)
new_circuit = circuit.remove_final_measurements(inplace=False)

expected = QuantumCircuit(qr)

self.assertEqual(expected, new_circuit)
self.assertTrue('measure' in circuit.count_ops().keys())

def test_remove_final_measurements_multiple_measures(self):
"""Test remove_final_measurements only removes measurements at the end of the circuit
remove_final_measurements should not remove measurements in the beginning or middle of the
Expand Down

0 comments on commit e4b3bd5

Please sign in to comment.