Add `.clear()` and `.copy_empty_like()` functionality to QuantumCircuit. (#8134)

* Add .copy_empty_like and .clear to QuantumCircuit

* Simplify copy_empty_like in QuantumCircuit

* Update docstring for copy_empty_like in QuantumCircuit

* Deepcopy global_phase for copy_empty_like in QuantumCircuit

* Add tests and refactor

* Add release note

* Add .copy_empty_like and .clear to QuantumCircuit

* Simplify copy_empty_like in QuantumCircuit

* Update docstring for copy_empty_like in QuantumCircuit

* Deepcopy global_phase for copy_empty_like in QuantumCircuit

* Add tests and refactor

* Add release note

* Update docstring

Co-authored-by: Julien Gacon <gaconju@gmail.com>

* Update docstring

Co-authored-by: Julien Gacon <gaconju@gmail.com>

* Update docstring

Co-authored-by: Julien Gacon <gaconju@gmail.com>

* Update test to check metadta and calibrations

* Add tests for circuit name

* Update releasenotes/notes/clear-circuit-b8edd4126f47d75a.yaml

Co-authored-by: Matthew Treinish <mtreinish@kortar.org>

Co-authored-by: Julien Gacon <gaconju@gmail.com>
Co-authored-by: Matthew Treinish <mtreinish@kortar.org>
Co-authored-by: mergify[bot] <37929162+mergify[bot]@users.noreply.github.com>
This commit is contained in:
Pedro Rivero 2022-06-16 18:10:01 -05:00 committed by GitHub
parent bcd98951ea
commit f47cd45e29
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 87 additions and 10 deletions

View File

@ -2118,18 +2118,9 @@ class QuantumCircuit:
Returns:
QuantumCircuit: a deepcopy of the current circuit, with the specified name
"""
cpy = copy.copy(self)
# copy registers correctly, in copy.copy they are only copied via reference
cpy.qregs = self.qregs.copy()
cpy.cregs = self.cregs.copy()
cpy._qubits = self._qubits.copy()
cpy._ancillas = self._ancillas.copy()
cpy._clbits = self._clbits.copy()
cpy._qubit_indices = self._qubit_indices.copy()
cpy._clbit_indices = self._clbit_indices.copy()
cpy = self.copy_empty_like(name)
instr_instances = {id(instr): instr for instr, _, __ in self._data}
instr_copies = {id_: instr.copy() for id_, instr in instr_instances.items()}
cpy._parameter_table = ParameterTable(
@ -2147,6 +2138,35 @@ class QuantumCircuit:
for inst, qargs, cargs in self._data
]
return cpy
def copy_empty_like(self, name: Optional[str] = None) -> "QuantumCircuit":
"""Return a copy of self with the same structure but empty.
That structure includes:
* name, calibrations and other metadata
* global phase
* all the qubits and clbits, including the registers
Args:
name (str): Name for the copied circuit. If None, then the name stays the same.
Returns:
QuantumCircuit: An empty copy of self.
"""
cpy = copy.copy(self)
# copy registers correctly, in copy.copy they are only copied via reference
cpy.qregs = self.qregs.copy()
cpy.cregs = self.cregs.copy()
cpy._qubits = self._qubits.copy()
cpy._ancillas = self._ancillas.copy()
cpy._clbits = self._clbits.copy()
cpy._qubit_indices = self._qubit_indices.copy()
cpy._clbit_indices = self._clbit_indices.copy()
cpy._parameter_table = ParameterTable()
cpy._data = []
cpy._calibrations = copy.deepcopy(self._calibrations)
cpy._metadata = copy.deepcopy(self._metadata)
@ -2154,6 +2174,14 @@ class QuantumCircuit:
cpy.name = name
return cpy
def clear(self) -> None:
"""Clear all instructions in self.
Clearing the circuits will keep the metadata and calibrations.
"""
self._data.clear()
self._parameter_table.clear()
def _create_creg(self, length: int, name: str) -> ClassicalRegister:
"""Creates a creg, checking if ClassicalRegister with same name exists"""
if name in [creg.name for creg in self.cregs]:

View File

@ -0,0 +1,13 @@
---
features:
- |
Added a new method :py:meth:`.QuantumCircuit.clear` which is used to to erase all instructions
from a QuantumCircuit. We clear both the data and the parameter table.
- |
Added a new method :py:meth:`QuantumCircuit.copy_empty_like` which is used to get a cleared copy of a
:class:`~.QuantumCircuit` instnace. This is logically equivalent to `qc.copy().clear()` however, it is done
avoiding a deepcopy of the original QuantumCircuit, and therefore it is more efficient. This functionality
already implemented for :class:`~.DAGCircuit`, and retains all relevant circuit properties other than the
instructions and associated parameters (e.g. registers, bits, name, metadata). Unlike the
:meth:`.DAGCircuit.copy_empty_like` method, this new :class:`~.QuantumCircuit` method allows for
an optional parameter to update the name of the copied circuit, mimicking ``qc.copy(name)``.

View File

@ -27,6 +27,7 @@ from qiskit.circuit.quantumregister import AncillaQubit, AncillaRegister, Qubit
from qiskit.test import QiskitTestCase
from qiskit.circuit.library.standard_gates import SGate
from qiskit.quantum_info import Operator
from qiskit.pulse import Schedule, Play, Gaussian, DriveChannel
@ddt
@ -478,6 +479,41 @@ class TestCircuitOperations(QiskitTestCase):
self.assertEqual(len(qc.cregs), 1)
self.assertEqual(len(copied.cregs), 2)
def test_copy_empty_like_circuit(self):
"""Test copy_empty_like method makes a clear copy."""
qr = QuantumRegister(2)
cr = ClassicalRegister(2)
qc = QuantumCircuit(qr, cr, global_phase=1.0, name="qc", metadata={"key": "value"})
qc.h(qr[0])
qc.measure(qr[0], cr[0])
qc.measure(qr[1], cr[1])
sched = Schedule(Play(Gaussian(160, 0.1, 40), DriveChannel(0)))
qc.add_calibration("h", [0, 1], sched)
copied = qc.copy_empty_like()
qc.clear()
self.assertEqual(qc, copied)
self.assertEqual(qc.global_phase, copied.global_phase)
self.assertEqual(qc.name, copied.name)
self.assertEqual(qc.metadata, copied.metadata)
self.assertEqual(qc.calibrations, copied.calibrations)
copied = qc.copy_empty_like("copy")
self.assertEqual(copied.name, "copy")
def test_clear_circuit(self):
"""Test clear method deletes instructions in circuit."""
qr = QuantumRegister(2)
cr = ClassicalRegister(2)
qc = QuantumCircuit(qr, cr)
qc.h(qr[0])
qc.measure(qr[0], cr[0])
qc.measure(qr[1], cr[1])
qc.clear()
self.assertEqual(len(qc.data), 0)
self.assertEqual(len(qc._parameter_table), 0)
def test_measure_active(self):
"""Test measure_active
Applies measurements only to non-idle qubits. Creates a ClassicalRegister of size equal to