Skip to content

Commit

Permalink
Singletonized Measure and Reset instructions (#11170)
Browse files Browse the repository at this point in the history
* Singletonized 'Measure' and 'Reset' instructions and drafted a release note

* Added singleton key functionality and test cases for Measure() and Reset() singleton instructions

* Implemented corrections from review on test_singleton module
  • Loading branch information
Matrixmang0 committed Nov 14, 2023
1 parent af6fbd0 commit 7412951
Show file tree
Hide file tree
Showing 6 changed files with 79 additions and 24 deletions.
6 changes: 4 additions & 2 deletions qiskit/circuit/measure.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,17 +14,19 @@
Quantum measurement in the computational basis.
"""

from qiskit.circuit.instruction import Instruction
from qiskit.circuit.singleton import SingletonInstruction, stdlib_singleton_key
from qiskit.circuit.exceptions import CircuitError


class Measure(Instruction):
class Measure(SingletonInstruction):
"""Quantum measurement in the computational basis."""

def __init__(self, label=None, *, duration=None, unit="dt"):
"""Create new measurement instruction."""
super().__init__("measure", 1, 1, [], label=label, duration=duration, unit=unit)

_singleton_lookup_key = stdlib_singleton_key()

def broadcast_arguments(self, qargs, cargs):
qarg = qargs[0]
carg = cargs[0]
Expand Down
6 changes: 4 additions & 2 deletions qiskit/circuit/quantumcircuit.py
Original file line number Diff line number Diff line change
Expand Up @@ -59,8 +59,6 @@
from .bit import Bit
from .quantumcircuitdata import QuantumCircuitData, CircuitInstruction
from .delay import Delay
from .measure import Measure
from .reset import Reset

if typing.TYPE_CHECKING:
import qiskit # pylint: disable=cyclic-import
Expand Down Expand Up @@ -2180,6 +2178,8 @@ def reset(self, qubit: QubitSpecifier) -> InstructionSet:
Returns:
qiskit.circuit.InstructionSet: handle to the added instruction.
"""
from .reset import Reset

return self.append(Reset(), [qubit], [])

def measure(self, qubit: QubitSpecifier, cbit: ClbitSpecifier) -> InstructionSet:
Expand Down Expand Up @@ -2255,6 +2255,8 @@ def measure(self, qubit: QubitSpecifier, cbit: ClbitSpecifier) -> InstructionSet
circuit.measure(qreg[1], creg[1])
"""
from .measure import Measure

return self.append(Measure(), [qubit], [cbit])

def measure_active(self, inplace: bool = True) -> Optional["QuantumCircuit"]:
Expand Down
6 changes: 4 additions & 2 deletions qiskit/circuit/reset.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,16 +14,18 @@
Qubit reset to computational zero.
"""

from qiskit.circuit.instruction import Instruction
from qiskit.circuit.singleton import SingletonInstruction, stdlib_singleton_key


class Reset(Instruction):
class Reset(SingletonInstruction):
"""Qubit reset."""

def __init__(self, label=None, *, duration=None, unit="dt"):
"""Create new reset instruction."""
super().__init__("reset", 1, 0, [], label=label, duration=duration, unit=unit)

_singleton_lookup_key = stdlib_singleton_key()

def broadcast_arguments(self, qargs, cargs):
for qarg in qargs[0]:
yield [qarg], []
6 changes: 2 additions & 4 deletions qiskit/qasm2/parse.py
Original file line number Diff line number Diff line change
Expand Up @@ -234,15 +234,13 @@ def from_bytecode(bytecode, custom_instructions: Iterable[CustomInstruction]):
qc._append(CircuitInstruction(Measure(), (qubits[qubit],), (clbits[clbit],)))
elif opcode == OpCode.ConditionedMeasure:
qubit, clbit, creg, value = op.operands
measure = Measure()
measure.condition = (qc.cregs[creg], value)
measure = Measure().c_if(qc.cregs[creg], value)
qc._append(CircuitInstruction(measure, (qubits[qubit],), (clbits[clbit],)))
elif opcode == OpCode.Reset:
qc._append(CircuitInstruction(Reset(), (qubits[op.operands[0]],)))
elif opcode == OpCode.ConditionedReset:
qubit, creg, value = op.operands
reset = Reset()
reset.condition = (qc.cregs[creg], value)
reset = Reset().c_if(qc.cregs[creg], value)
qc._append(CircuitInstruction(reset, (qubits[qubit],)))
elif opcode == OpCode.Barrier:
op_qubits = op.operands[0]
Expand Down
32 changes: 32 additions & 0 deletions releasenotes/notes/singletonize-instructions-78723f68cd0ac03f.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
---
features:
- |
The following standard library instructions are now instances of
:class:`~.SingletonInstruction`:
* :class:`~.Measure`
* :class:`~.Reset`
This means that if these classes are instantiated as (e.g.) ``Measure()`` using
all the constructor defaults, they will all share a single global
instance. This results in large reduction in the memory overhead for > 1
object of these types and significantly faster object construction time.
upgrade:
- |
The following standard library instructions:
* :class:`~.Measure`
* :class:`~.Reset`
are immutable, unless the attributes ``label``, ``duration`` and ``unit`` are given as keyword
arguments during class construction.
The attributes :attr:`~.Instruction.label`, :attr:`~.Instruction.duration`, :attr:`~.Instruction.unit`,
and :attr:`~.Instruction.condition` attributes are all not publicly accessible and setting these attributes
directly is not allowed and it will raise an exception. If they are needed for a particular
instance you must ensure you have a mutable instance using :meth:`.Instruction.to_mutable`
and use :meth:`.Instruction.c_if` for :attr:`~.Instruction.condition`
For the singleton variant of these instructions, there is a special attribute
:attr:`~.SingletonInstruction._singleton_lookup_key`, that when called generates a key based on the input
arguments, which can be used for identifying and indexing these instructions within the framework.
47 changes: 33 additions & 14 deletions test/python/circuit/test_singleton.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@


"""
Tests for singleton gate behavior
Tests for singleton gate and instruction behavior
"""

import copy
Expand All @@ -36,15 +36,16 @@
XGate,
C4XGate,
)
from qiskit.circuit import Measure, Reset
from qiskit.circuit import Clbit, QuantumCircuit, QuantumRegister, ClassicalRegister
from qiskit.circuit.singleton import SingletonGate, SingletonInstruction
from qiskit.circuit.singleton import SingletonGate
from qiskit.converters import dag_to_circuit, circuit_to_dag

from qiskit.test.base import QiskitTestCase


class TestSingletonGate(QiskitTestCase):
"""Qiskit SingletonGate tests."""
class TestSingleton(QiskitTestCase):
"""Qiskit SingletonGate and SingletonInstruction tests."""

def test_default_singleton(self):
gate = HGate()
Expand Down Expand Up @@ -325,20 +326,38 @@ def __init__(self, x):
self.assertEqual(gate.x, 1)
self.assertIsNot(MyAbstractGate(1), MyAbstractGate(1))

def test_inherit_singleton(self):
class Measure(SingletonInstruction):
def __init__(self):
super().__init__("measure", 1, 1, [])
def test_return_type_singleton_instructions(self):
measure = Measure()
new_measure = Measure()
self.assertIs(measure, new_measure)
self.assertIs(measure.base_class, Measure)
self.assertIsInstance(measure, Measure)

reset = Reset()
new_reset = Reset()
self.assertIs(reset, new_reset)
self.assertIs(reset.base_class, Reset)
self.assertIsInstance(reset, Reset)

def test_singleton_instruction_integration(self):
measure = Measure()
reset = Reset()
qc = QuantumCircuit(1, 1)
qc.measure(0, 0)
qc.reset(0)
self.assertIs(qc.data[0].operation, measure)
self.assertIs(qc.data[1].operation, reset)

def test_inherit_singleton_instructions(self):
class ESPMeasure(Measure):
pass

base = Measure()
esp = ESPMeasure()
self.assertIs(esp, ESPMeasure())
self.assertIsNot(esp, base)
self.assertIs(base.base_class, Measure)
self.assertIs(esp.base_class, ESPMeasure)
measure_base = Measure()
esp_measure = ESPMeasure()
self.assertIs(esp_measure, ESPMeasure())
self.assertIsNot(esp_measure, measure_base)
self.assertIs(measure_base.base_class, Measure)
self.assertIs(esp_measure.base_class, ESPMeasure)

def test_singleton_with_default(self):
# Explicitly setting the label to its default.
Expand Down

0 comments on commit 7412951

Please sign in to comment.