-
Notifications
You must be signed in to change notification settings - Fork 2.3k
/
quantumcircuitdata.py
136 lines (102 loc) · 4.76 KB
/
quantumcircuitdata.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
# This code is part of Qiskit.
#
# (C) Copyright IBM 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.
"""A wrapper class for the purposes of validating modifications to
QuantumCircuit.data while maintaining the interface of a python list."""
from collections.abc import MutableSequence
import qiskit._accelerate.circuit
from .exceptions import CircuitError
from .instruction import Instruction
from .operation import Operation
CircuitInstruction = qiskit._accelerate.circuit.CircuitInstruction
class QuantumCircuitData(MutableSequence):
"""A wrapper class for the purposes of validating modifications to
QuantumCircuit.data while maintaining the interface of a python list."""
def __init__(self, circuit):
self._circuit = circuit
def __getitem__(self, i):
return self._circuit._data[i]
def __setitem__(self, key, value):
# For now (Terra 0.21), the `QuantumCircuit.data` setter is meant to perform validation, so
# we do the same qubit checks that `QuantumCircuit.append` would do.
if isinstance(value, CircuitInstruction):
operation, qargs, cargs = value.operation, value.qubits, value.clbits
else:
# Handle the legacy 3-tuple format.
operation, qargs, cargs = value
value = self._resolve_legacy_value(operation, qargs, cargs)
self._circuit._data[key] = value
def _resolve_legacy_value(self, operation, qargs, cargs) -> CircuitInstruction:
"""Resolve the old-style 3-tuple into the new :class:`CircuitInstruction` type."""
if not isinstance(operation, Operation) and hasattr(operation, "to_instruction"):
operation = operation.to_instruction()
if not isinstance(operation, Operation):
raise CircuitError("object is not an Operation.")
expanded_qargs = [self._circuit._qbit_argument_conversion(qarg) for qarg in qargs or []]
expanded_cargs = [self._circuit._cbit_argument_conversion(carg) for carg in cargs or []]
if isinstance(operation, Instruction):
broadcast_args = list(operation.broadcast_arguments(expanded_qargs, expanded_cargs))
else:
broadcast_args = list(
Instruction.broadcast_arguments(operation, expanded_qargs, expanded_cargs)
)
if len(broadcast_args) > 1:
raise CircuitError(
"QuantumCircuit.data modification does not support argument broadcasting."
)
qargs, cargs = broadcast_args[0]
self._circuit._check_dups(qargs)
return CircuitInstruction(operation, tuple(qargs), tuple(cargs))
def insert(self, index, value):
self._circuit._data.insert(index, value.replace(qubits=(), clbits=()))
try:
self[index] = value
except CircuitError:
del self._circuit._data[index]
raise
def __iter__(self):
return iter(self._circuit._data)
def __delitem__(self, i):
del self._circuit._data[i]
def __len__(self):
return len(self._circuit._data)
def __cast(self, other):
return list(other._circuit._data) if isinstance(other, QuantumCircuitData) else other
def __repr__(self):
return repr(list(self._circuit._data))
def __lt__(self, other):
return list(self._circuit._data) < self.__cast(other)
def __le__(self, other):
return list(self._circuit._data) <= self.__cast(other)
def __eq__(self, other):
return self._circuit._data == self.__cast(other)
def __gt__(self, other):
return list(self._circuit._data) > self.__cast(other)
def __ge__(self, other):
return list(self._circuit._data) >= self.__cast(other)
def __add__(self, other):
return list(self._circuit._data) + self.__cast(other)
def __radd__(self, other):
return self.__cast(other) + list(self._circuit._data)
def __mul__(self, n):
return list(self._circuit._data) * n
def __rmul__(self, n):
return n * list(self._circuit._data)
def sort(self, *args, **kwargs):
"""In-place stable sort. Accepts arguments of list.sort."""
data = list(self._circuit._data)
data.sort(*args, **kwargs)
self._circuit._data.clear()
self._circuit._data.reserve(len(data))
self._circuit._data.extend(data)
def copy(self):
"""Returns a shallow copy of instruction list."""
return list(self._circuit._data)