From c3f419b8e152512fa83d5500b5379ad69a19e816 Mon Sep 17 00:00:00 2001 From: Matthew Treinish Date: Tue, 14 Sep 2021 14:19:43 -0400 Subject: [PATCH 1/3] Encapsulate instruction in args in Operation class This commit introduces a a new class for representing an instruction with it's operands, Operation. An Operation object contains 3 fields an instruction, a list of Qubits for the qargs, and a list of Clbits for the cargs. The operation class is now used for all enties in the QuantumCircuit's data attribute list, instead of the previous tuple of the form (instruction, qargs, cargs). For backwards compatibility an Operation object also implements the sequence protocol and can be used as a tuple, although named attribute performance will be better (ie operation.instruction returns faster than operation[0], but both return the same object). Moving forward we should start update the tuple usage internally to use attribute access instead. --- qiskit/circuit/__init__.py | 2 + qiskit/circuit/operation.py | 78 ++++++++++++++++++++++++++++ qiskit/circuit/quantumcircuit.py | 6 ++- qiskit/circuit/quantumcircuitdata.py | 10 +++- 4 files changed, 92 insertions(+), 4 deletions(-) create mode 100644 qiskit/circuit/operation.py diff --git a/qiskit/circuit/__init__.py b/qiskit/circuit/__init__.py index 0608765a1248..e7da2929f407 100644 --- a/qiskit/circuit/__init__.py +++ b/qiskit/circuit/__init__.py @@ -177,6 +177,7 @@ Clbit AncillaRegister AncillaQubit + Operation Gates and Instructions ---------------------- @@ -212,6 +213,7 @@ random.random_circuit """ from .quantumcircuit import QuantumCircuit +from .operation import Operation from .classicalregister import ClassicalRegister, Clbit from .quantumregister import QuantumRegister, Qubit, AncillaRegister, AncillaQubit from .gate import Gate diff --git a/qiskit/circuit/operation.py b/qiskit/circuit/operation.py new file mode 100644 index 000000000000..7aca8a35bffa --- /dev/null +++ b/qiskit/circuit/operation.py @@ -0,0 +1,78 @@ +# This code is part of Qiskit. +# +# (C) Copyright IBM 2021. +# +# 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. + +""" +Operation object +""" + +from collections.abc import Sequence + + +class Operation(Sequence): + """Class representation of a circuit operation + + An operation is an instruction with it's operands. + """ + + __slots__ = ("instruction", "qargs", "cargs") + + def __init__(self, instruction, qargs=None, cargs=None): + """Initialize a new instruction object + + Args: + instruction (qiskit.circuit.Instruction): The instruction object for + the operation + qargs (list): A list of :class:`~qiskit.circuit.Qubit` objects that + the instruction runs on + cargs (list): A list of :class:`~qiskit.circuit.Clbit` objects that + the instruction runs on + """ + self.instruction = instruction + if qargs is None: + self.qargs = [] + else: + self.qargs = qargs + if cargs is None: + self.cargs = [] + else: + self.cargs = cargs + + def __len__(self): + return 3 + + def __getitem__(self, index): + if index == 0: + return self.instruction + if index == 1: + return self.qargs + if index == 2: + return self.cargs + if isinstance(index, slice): + out_items = (self.instruction, self.qargs, self.cargs) + return out_items.__getitem__(index) + raise IndexError("Index %s is out of range" % index) + + def __eq__(self, other): + if isinstance(other, tuple): + if other[0] == self.instruction and other[1] == self.qargs and other[2] == self.cargs: + return True + return False + elif isinstance(other, Operation): + if ( + self.instruction == other.instruction + and self.qargs == other.qargs + and self.cargs == other.cargs + ): + return True + return False + else: + return False diff --git a/qiskit/circuit/quantumcircuit.py b/qiskit/circuit/quantumcircuit.py index 1e16d0afc32b..bb660096cd49 100644 --- a/qiskit/circuit/quantumcircuit.py +++ b/qiskit/circuit/quantumcircuit.py @@ -40,6 +40,7 @@ from qiskit.circuit.instruction import Instruction from qiskit.circuit.gate import Gate from qiskit.circuit.parameter import Parameter +from qiskit.circuit.operation import Operation from qiskit.qasm.qasm import Qasm from qiskit.qasm.exceptions import QasmError from qiskit.circuit.exceptions import CircuitError @@ -1195,8 +1196,8 @@ def _append( self._check_cargs(cargs) # add the instruction onto the given wires - instruction_context = instruction, qargs, cargs - self._data.append(instruction_context) + operation = Operation(instruction, qargs, cargs) + self._data.append(operation) self._update_parameter_table(instruction) @@ -1811,6 +1812,7 @@ def depth(self, filter_function: Optional[callable] = lambda x: not x[0]._direct # Add to the stacks of the qubits and # cbits used in the gate. reg_ints.append(bit_indices[reg]) + if (instr, qargs, cargs) in filter(filter_function, self._data): levels.append(op_stack[reg_ints[ind]] + 1) else: diff --git a/qiskit/circuit/quantumcircuitdata.py b/qiskit/circuit/quantumcircuitdata.py index ddeea69572c5..2deb1387d610 100644 --- a/qiskit/circuit/quantumcircuitdata.py +++ b/qiskit/circuit/quantumcircuitdata.py @@ -17,6 +17,7 @@ from qiskit.circuit.exceptions import CircuitError from qiskit.circuit.instruction import Instruction +from qiskit.circuit.operation import Operation class QuantumCircuitData(MutableSequence): @@ -54,13 +55,18 @@ def __setitem__(self, key, value): self._circuit._check_qargs(qargs) self._circuit._check_cargs(cargs) - self._circuit._data[key] = (instruction, qargs, cargs) + self._circuit._data[key] = Operation(instruction, qargs, cargs) self._circuit._update_parameter_table(instruction) def insert(self, index, value): self._circuit._data.insert(index, None) - self[index] = value + if isinstance(value, tuple): + self[index] = Operation(*value) + elif isinstance(index, Operation): + self[index] = value + else: + raise TypeError("Invalid element type %s" % type(value)) def __delitem__(self, i): del self._circuit._data[i] From c29489a640df0e5228f1e2299edfc13ae539796d Mon Sep 17 00:00:00 2001 From: Matthew Treinish Date: Tue, 14 Sep 2021 16:52:41 -0400 Subject: [PATCH 2/3] Fix test failures --- qiskit/circuit/operation.py | 3 +++ qiskit/circuit/quantumcircuitdata.py | 5 +---- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/qiskit/circuit/operation.py b/qiskit/circuit/operation.py index 7aca8a35bffa..fa1c7d1bcb98 100644 --- a/qiskit/circuit/operation.py +++ b/qiskit/circuit/operation.py @@ -76,3 +76,6 @@ def __eq__(self, other): return False else: return False + + def __repr__(self): + return repr((self.instruction, self.qargs, self.cargs)) diff --git a/qiskit/circuit/quantumcircuitdata.py b/qiskit/circuit/quantumcircuitdata.py index 2deb1387d610..62bf1451508b 100644 --- a/qiskit/circuit/quantumcircuitdata.py +++ b/qiskit/circuit/quantumcircuitdata.py @@ -63,10 +63,7 @@ def insert(self, index, value): self._circuit._data.insert(index, None) if isinstance(value, tuple): self[index] = Operation(*value) - elif isinstance(index, Operation): - self[index] = value - else: - raise TypeError("Invalid element type %s" % type(value)) + self[index] = value def __delitem__(self, i): del self._circuit._data[i] From ecae24b2ccca6f56adad5b60e294c0c369dc0cbc Mon Sep 17 00:00:00 2001 From: Matthew Treinish Date: Mon, 20 Sep 2021 17:00:19 -0400 Subject: [PATCH 3/3] Update qiskit/circuit/quantumcircuitdata.py Co-authored-by: Lev Bishop <18673315+levbishop@users.noreply.github.com> --- qiskit/circuit/quantumcircuitdata.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/qiskit/circuit/quantumcircuitdata.py b/qiskit/circuit/quantumcircuitdata.py index 62bf1451508b..7d4cc9bda5e8 100644 --- a/qiskit/circuit/quantumcircuitdata.py +++ b/qiskit/circuit/quantumcircuitdata.py @@ -63,7 +63,8 @@ def insert(self, index, value): self._circuit._data.insert(index, None) if isinstance(value, tuple): self[index] = Operation(*value) - self[index] = value + else: + self[index] = value def __delitem__(self, i): del self._circuit._data[i]