qiskit-aer 0.17.2__cp314-cp314-macosx_11_0_arm64.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- qiskit_aer/VERSION.txt +1 -0
- qiskit_aer/__init__.py +89 -0
- qiskit_aer/aererror.py +30 -0
- qiskit_aer/aerprovider.py +119 -0
- qiskit_aer/backends/__init__.py +20 -0
- qiskit_aer/backends/aer_compiler.py +1085 -0
- qiskit_aer/backends/aer_simulator.py +1025 -0
- qiskit_aer/backends/aerbackend.py +679 -0
- qiskit_aer/backends/backend_utils.py +567 -0
- qiskit_aer/backends/backendconfiguration.py +395 -0
- qiskit_aer/backends/backendproperties.py +590 -0
- qiskit_aer/backends/compatibility.py +287 -0
- qiskit_aer/backends/controller_wrappers.cpython-314-darwin.so +0 -0
- qiskit_aer/backends/libomp.dylib +0 -0
- qiskit_aer/backends/name_mapping.py +306 -0
- qiskit_aer/backends/qasm_simulator.py +925 -0
- qiskit_aer/backends/statevector_simulator.py +330 -0
- qiskit_aer/backends/unitary_simulator.py +316 -0
- qiskit_aer/jobs/__init__.py +35 -0
- qiskit_aer/jobs/aerjob.py +143 -0
- qiskit_aer/jobs/utils.py +66 -0
- qiskit_aer/library/__init__.py +204 -0
- qiskit_aer/library/control_flow_instructions/__init__.py +16 -0
- qiskit_aer/library/control_flow_instructions/jump.py +47 -0
- qiskit_aer/library/control_flow_instructions/mark.py +30 -0
- qiskit_aer/library/control_flow_instructions/store.py +29 -0
- qiskit_aer/library/default_qubits.py +44 -0
- qiskit_aer/library/instructions_table.csv +21 -0
- qiskit_aer/library/save_instructions/__init__.py +44 -0
- qiskit_aer/library/save_instructions/save_amplitudes.py +168 -0
- qiskit_aer/library/save_instructions/save_clifford.py +63 -0
- qiskit_aer/library/save_instructions/save_data.py +129 -0
- qiskit_aer/library/save_instructions/save_density_matrix.py +91 -0
- qiskit_aer/library/save_instructions/save_expectation_value.py +257 -0
- qiskit_aer/library/save_instructions/save_matrix_product_state.py +71 -0
- qiskit_aer/library/save_instructions/save_probabilities.py +156 -0
- qiskit_aer/library/save_instructions/save_stabilizer.py +70 -0
- qiskit_aer/library/save_instructions/save_state.py +79 -0
- qiskit_aer/library/save_instructions/save_statevector.py +120 -0
- qiskit_aer/library/save_instructions/save_superop.py +62 -0
- qiskit_aer/library/save_instructions/save_unitary.py +63 -0
- qiskit_aer/library/set_instructions/__init__.py +19 -0
- qiskit_aer/library/set_instructions/set_density_matrix.py +78 -0
- qiskit_aer/library/set_instructions/set_matrix_product_state.py +83 -0
- qiskit_aer/library/set_instructions/set_stabilizer.py +77 -0
- qiskit_aer/library/set_instructions/set_statevector.py +78 -0
- qiskit_aer/library/set_instructions/set_superop.py +78 -0
- qiskit_aer/library/set_instructions/set_unitary.py +78 -0
- qiskit_aer/noise/__init__.py +265 -0
- qiskit_aer/noise/device/__init__.py +25 -0
- qiskit_aer/noise/device/models.py +397 -0
- qiskit_aer/noise/device/parameters.py +202 -0
- qiskit_aer/noise/errors/__init__.py +30 -0
- qiskit_aer/noise/errors/base_quantum_error.py +119 -0
- qiskit_aer/noise/errors/pauli_error.py +283 -0
- qiskit_aer/noise/errors/pauli_lindblad_error.py +363 -0
- qiskit_aer/noise/errors/quantum_error.py +451 -0
- qiskit_aer/noise/errors/readout_error.py +355 -0
- qiskit_aer/noise/errors/standard_errors.py +498 -0
- qiskit_aer/noise/noise_model.py +1231 -0
- qiskit_aer/noise/noiseerror.py +30 -0
- qiskit_aer/noise/passes/__init__.py +18 -0
- qiskit_aer/noise/passes/local_noise_pass.py +160 -0
- qiskit_aer/noise/passes/relaxation_noise_pass.py +137 -0
- qiskit_aer/primitives/__init__.py +44 -0
- qiskit_aer/primitives/estimator.py +751 -0
- qiskit_aer/primitives/estimator_v2.py +159 -0
- qiskit_aer/primitives/sampler.py +361 -0
- qiskit_aer/primitives/sampler_v2.py +256 -0
- qiskit_aer/quantum_info/__init__.py +32 -0
- qiskit_aer/quantum_info/states/__init__.py +16 -0
- qiskit_aer/quantum_info/states/aer_densitymatrix.py +313 -0
- qiskit_aer/quantum_info/states/aer_state.py +525 -0
- qiskit_aer/quantum_info/states/aer_statevector.py +302 -0
- qiskit_aer/utils/__init__.py +44 -0
- qiskit_aer/utils/noise_model_inserter.py +66 -0
- qiskit_aer/utils/noise_transformation.py +431 -0
- qiskit_aer/version.py +86 -0
- qiskit_aer-0.17.2.dist-info/METADATA +209 -0
- qiskit_aer-0.17.2.dist-info/RECORD +83 -0
- qiskit_aer-0.17.2.dist-info/WHEEL +6 -0
- qiskit_aer-0.17.2.dist-info/licenses/LICENSE.txt +203 -0
- qiskit_aer-0.17.2.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,302 @@
|
|
|
1
|
+
# This code is part of Qiskit.
|
|
2
|
+
#
|
|
3
|
+
# (C) Copyright IBM 2017, 2019, 2020, 2021, 2022.
|
|
4
|
+
#
|
|
5
|
+
# This code is licensed under the Apache License, Version 2.0. You may
|
|
6
|
+
# obtain a copy of this license in the LICENSE.txt file in the root directory
|
|
7
|
+
# of this source tree or at http://www.apache.org/licenses/LICENSE-2.0.
|
|
8
|
+
#
|
|
9
|
+
# Any modifications or derivative works of this code must retain this
|
|
10
|
+
# copyright notice, and modified files need to carry a notice indicating
|
|
11
|
+
# that they have been altered from the originals.
|
|
12
|
+
|
|
13
|
+
"""
|
|
14
|
+
Statevector quantum state class.
|
|
15
|
+
"""
|
|
16
|
+
import copy
|
|
17
|
+
import numpy as np
|
|
18
|
+
|
|
19
|
+
from qiskit.circuit import QuantumCircuit, Instruction
|
|
20
|
+
from qiskit.quantum_info.states import Statevector
|
|
21
|
+
|
|
22
|
+
from qiskit_aer import AerSimulator
|
|
23
|
+
from .aer_state import AerState
|
|
24
|
+
from ...backends.aerbackend import AerError
|
|
25
|
+
from ...backends.backend_utils import BASIS_GATES
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
class AerStatevector(Statevector):
|
|
29
|
+
"""AerStatevector class
|
|
30
|
+
|
|
31
|
+
This class inherits :class:`Statevector`, which stores probability amplitudes
|
|
32
|
+
in its `ndarray`. class:`AerStatevector` generates this `ndarray` by using the
|
|
33
|
+
same runtime with :class:`AerSimulator`.
|
|
34
|
+
"""
|
|
35
|
+
|
|
36
|
+
def __init__(self, data, dims=None, **configs):
|
|
37
|
+
"""
|
|
38
|
+
Args:
|
|
39
|
+
data (np.array or list or Statevector or AerStatevector or QuantumCircuit or
|
|
40
|
+
qiskit.circuit.Instruction):
|
|
41
|
+
Data from which the statevector can be constructed. This can be either a complex
|
|
42
|
+
vector, another statevector or a ``QuantumCircuit`` or ``Instruction``
|
|
43
|
+
(``Operator`` is not supported in the current implementation). If the data is
|
|
44
|
+
a circuit or instruction, the statevector is constructed by assuming that all
|
|
45
|
+
qubits are initialized to the zero state.
|
|
46
|
+
dims (int or tuple or list): Optional. The subsystem dimension of
|
|
47
|
+
the state (See additional information).
|
|
48
|
+
configs (kwargs): configurations of :class:`AerSimulator`. `method` configuration must
|
|
49
|
+
be `statevector` or `matrix_product_state`.
|
|
50
|
+
|
|
51
|
+
Raises:
|
|
52
|
+
AerError: if input data is not valid.
|
|
53
|
+
|
|
54
|
+
Additional Information:
|
|
55
|
+
The ``dims`` kwarg is used to ``Statevector`` constructor.
|
|
56
|
+
|
|
57
|
+
"""
|
|
58
|
+
if "_aer_state" in configs:
|
|
59
|
+
self._aer_state = configs.pop("_aer_state")
|
|
60
|
+
else:
|
|
61
|
+
if "method" not in configs:
|
|
62
|
+
configs["method"] = "statevector"
|
|
63
|
+
elif configs["method"] not in ("statevector", "matrix_product_state"):
|
|
64
|
+
method = configs["method"]
|
|
65
|
+
raise AerError(f"Method {method} is not supported")
|
|
66
|
+
if isinstance(data, (QuantumCircuit, Instruction)):
|
|
67
|
+
data, aer_state = AerStatevector._from_instruction(data, None, configs)
|
|
68
|
+
elif isinstance(data, list):
|
|
69
|
+
data, aer_state = AerStatevector._from_ndarray(
|
|
70
|
+
np.array(data, dtype=complex), configs
|
|
71
|
+
)
|
|
72
|
+
elif isinstance(data, np.ndarray):
|
|
73
|
+
data, aer_state = AerStatevector._from_ndarray(data, configs)
|
|
74
|
+
elif isinstance(data, AerStatevector):
|
|
75
|
+
aer_state = data._aer_state
|
|
76
|
+
if dims is None:
|
|
77
|
+
dims = data._op_shape._dims_l
|
|
78
|
+
data = data._data.copy()
|
|
79
|
+
elif isinstance(data, Statevector):
|
|
80
|
+
data, aer_state = AerStatevector._from_ndarray(
|
|
81
|
+
np.array(data.data, dtype=complex), configs
|
|
82
|
+
)
|
|
83
|
+
else:
|
|
84
|
+
raise AerError(f"Input data is not supported: type={data.__class__}, data={data}")
|
|
85
|
+
|
|
86
|
+
self._aer_state = aer_state
|
|
87
|
+
|
|
88
|
+
super().__init__(data, dims=dims)
|
|
89
|
+
|
|
90
|
+
self._result = None
|
|
91
|
+
self._configs = configs
|
|
92
|
+
|
|
93
|
+
def seed(self, value=None):
|
|
94
|
+
"""Set the seed for the quantum state RNG."""
|
|
95
|
+
if value is None or isinstance(value, int):
|
|
96
|
+
self._aer_state.set_seed(value)
|
|
97
|
+
else:
|
|
98
|
+
raise AerError(f"This seed is not supported: type={value.__class__}, value={value}")
|
|
99
|
+
|
|
100
|
+
def _last_result(self):
|
|
101
|
+
if self._result is None:
|
|
102
|
+
self._result = self._aer_state.last_result()
|
|
103
|
+
return self._result
|
|
104
|
+
|
|
105
|
+
def metadata(self):
|
|
106
|
+
"""Return result metadata of an operation that executed lastly."""
|
|
107
|
+
if self._last_result() is None:
|
|
108
|
+
raise AerError("AerState was not used and metadata does not exist.")
|
|
109
|
+
return self._last_result()["metadata"]
|
|
110
|
+
|
|
111
|
+
def __copy__(self):
|
|
112
|
+
return copy.deepcopy(self)
|
|
113
|
+
|
|
114
|
+
def __deepcopy__(self, _memo=None):
|
|
115
|
+
ret = AerStatevector(self._data.copy(), **self._configs)
|
|
116
|
+
ret._op_shape = copy.deepcopy(self._op_shape)
|
|
117
|
+
ret._rng_generator = copy.deepcopy(self._rng_generator)
|
|
118
|
+
return ret
|
|
119
|
+
|
|
120
|
+
def conjugate(self):
|
|
121
|
+
return AerStatevector(np.conj(self._data), dims=self.dims())
|
|
122
|
+
|
|
123
|
+
def sample_memory(self, shots, qargs=None):
|
|
124
|
+
if qargs is None:
|
|
125
|
+
qubits = np.arange(self._aer_state.num_qubits)
|
|
126
|
+
else:
|
|
127
|
+
qubits = np.array(qargs)
|
|
128
|
+
self._aer_state.close()
|
|
129
|
+
|
|
130
|
+
self._aer_state.renew()
|
|
131
|
+
self._aer_state.initialize(self._data, copy=False)
|
|
132
|
+
samples = self._aer_state.sample_memory(qubits, shots)
|
|
133
|
+
self._data = self._aer_state.move_to_ndarray()
|
|
134
|
+
return samples
|
|
135
|
+
|
|
136
|
+
@staticmethod
|
|
137
|
+
def _from_ndarray(init_data, configs):
|
|
138
|
+
do_copy = True
|
|
139
|
+
if not init_data.flags["C_CONTIGUOUS"]:
|
|
140
|
+
init_data = np.ascontiguousarray(init_data)
|
|
141
|
+
do_copy = False
|
|
142
|
+
|
|
143
|
+
aer_state = AerState()
|
|
144
|
+
|
|
145
|
+
options = AerSimulator._default_options()
|
|
146
|
+
for config_key, config_value in configs.items():
|
|
147
|
+
if options.get(config_key):
|
|
148
|
+
aer_state.configure(config_key, config_value)
|
|
149
|
+
|
|
150
|
+
if len(init_data) == 0:
|
|
151
|
+
raise AerError("initial data must be larger than 0")
|
|
152
|
+
|
|
153
|
+
num_qubits = int(np.log2(len(init_data)))
|
|
154
|
+
|
|
155
|
+
aer_state.allocate_qubits(num_qubits)
|
|
156
|
+
aer_state.initialize(data=init_data, copy=do_copy)
|
|
157
|
+
|
|
158
|
+
return aer_state.move_to_ndarray(), aer_state
|
|
159
|
+
|
|
160
|
+
@classmethod
|
|
161
|
+
def from_instruction(cls, instruction):
|
|
162
|
+
return AerStatevector(instruction)
|
|
163
|
+
|
|
164
|
+
@staticmethod
|
|
165
|
+
def _from_instruction(inst, init_data, configs):
|
|
166
|
+
aer_state = AerState()
|
|
167
|
+
|
|
168
|
+
for config_key, config_value in configs.items():
|
|
169
|
+
aer_state.configure(config_key, config_value)
|
|
170
|
+
|
|
171
|
+
if "method" in configs:
|
|
172
|
+
method = configs["method"]
|
|
173
|
+
else:
|
|
174
|
+
method = "statevector"
|
|
175
|
+
aer_state.configure("method", method)
|
|
176
|
+
|
|
177
|
+
basis_gates = BASIS_GATES[method]
|
|
178
|
+
custom_insts = ["reset", "kraus", "barrier"]
|
|
179
|
+
if method == "statevector":
|
|
180
|
+
custom_insts.append("initialize")
|
|
181
|
+
|
|
182
|
+
aer_state.allocate_qubits(inst.num_qubits)
|
|
183
|
+
num_qubits = inst.num_qubits
|
|
184
|
+
|
|
185
|
+
if init_data is not None:
|
|
186
|
+
aer_state.initialize(data=init_data, copy=True)
|
|
187
|
+
else:
|
|
188
|
+
aer_state.initialize()
|
|
189
|
+
|
|
190
|
+
if isinstance(inst, QuantumCircuit) and inst.global_phase != 0:
|
|
191
|
+
aer_state.apply_global_phase(inst.global_phase)
|
|
192
|
+
|
|
193
|
+
if isinstance(inst, QuantumCircuit):
|
|
194
|
+
AerStatevector._aer_evolve_circuit(
|
|
195
|
+
aer_state, inst, range(num_qubits), basis_gates, custom_insts
|
|
196
|
+
)
|
|
197
|
+
else:
|
|
198
|
+
AerStatevector._aer_evolve_instruction(
|
|
199
|
+
aer_state, inst, range(num_qubits), basis_gates, custom_insts
|
|
200
|
+
)
|
|
201
|
+
|
|
202
|
+
return aer_state.move_to_ndarray(), aer_state
|
|
203
|
+
|
|
204
|
+
@staticmethod
|
|
205
|
+
def _aer_evolve_circuit(aer_state, circuit, qubits, basis_gates=None, custom_insts=None):
|
|
206
|
+
"""Apply circuit into aer_state"""
|
|
207
|
+
for instruction in circuit.data:
|
|
208
|
+
if instruction.clbits:
|
|
209
|
+
raise AerError(
|
|
210
|
+
f"Cannot apply instruction with classical bits: {instruction.operation.name}"
|
|
211
|
+
)
|
|
212
|
+
inst = instruction.operation
|
|
213
|
+
qargs = instruction.qubits
|
|
214
|
+
AerStatevector._aer_evolve_instruction(
|
|
215
|
+
aer_state,
|
|
216
|
+
inst,
|
|
217
|
+
[qubits[circuit.find_bit(qarg).index] for qarg in qargs],
|
|
218
|
+
basis_gates,
|
|
219
|
+
custom_insts,
|
|
220
|
+
)
|
|
221
|
+
|
|
222
|
+
@staticmethod
|
|
223
|
+
def _aer_evolve_instruction(aer_state, inst, qubits, basis_gates=None, custom_insts=None):
|
|
224
|
+
"""Apply instruction into aer_state"""
|
|
225
|
+
|
|
226
|
+
params = inst.params
|
|
227
|
+
applied = True
|
|
228
|
+
|
|
229
|
+
if basis_gates and inst.name in basis_gates:
|
|
230
|
+
if inst.name in ["u3", "u"]:
|
|
231
|
+
aer_state.apply_u(qubits[0], params[0], params[1], params[2])
|
|
232
|
+
elif inst.name == "h":
|
|
233
|
+
aer_state.apply_h(qubits[0])
|
|
234
|
+
elif inst.name == "x":
|
|
235
|
+
aer_state.apply_x(qubits[0])
|
|
236
|
+
elif inst.name == "cx":
|
|
237
|
+
aer_state.apply_cx(qubits[0], qubits[1])
|
|
238
|
+
elif inst.name == "y":
|
|
239
|
+
aer_state.apply_y(qubits[0])
|
|
240
|
+
elif inst.name == "cy":
|
|
241
|
+
aer_state.apply_cy(qubits[0], qubits[1])
|
|
242
|
+
elif inst.name == "z":
|
|
243
|
+
aer_state.apply_z(qubits[0])
|
|
244
|
+
elif inst.name == "cz":
|
|
245
|
+
aer_state.apply_cz(qubits[0], qubits[1])
|
|
246
|
+
elif inst.name == "unitary":
|
|
247
|
+
aer_state.apply_unitary(qubits, inst.params[0])
|
|
248
|
+
elif inst.name == "diagonal":
|
|
249
|
+
aer_state.apply_diagonal(qubits, inst.params)
|
|
250
|
+
elif inst.name == "cu":
|
|
251
|
+
aer_state.apply_cu(qubits[0], qubits[1], params[0], params[1], params[2], params[3])
|
|
252
|
+
elif inst.name == "mcu":
|
|
253
|
+
aer_state.apply_mcu(
|
|
254
|
+
qubits[0 : len(qubits) - 1],
|
|
255
|
+
qubits[len(qubits) - 1],
|
|
256
|
+
params[0],
|
|
257
|
+
params[1],
|
|
258
|
+
params[2],
|
|
259
|
+
params[3],
|
|
260
|
+
)
|
|
261
|
+
elif inst.name in "mcx":
|
|
262
|
+
aer_state.apply_mcx(qubits[0 : len(qubits) - 1], qubits[len(qubits) - 1])
|
|
263
|
+
elif inst.name in "mcy":
|
|
264
|
+
aer_state.apply_mcy(qubits[0 : len(qubits) - 1], qubits[len(qubits) - 1])
|
|
265
|
+
elif inst.name in "mcz":
|
|
266
|
+
aer_state.apply_mcz(qubits[0 : len(qubits) - 1], qubits[len(qubits) - 1])
|
|
267
|
+
elif inst.name == "id":
|
|
268
|
+
pass
|
|
269
|
+
else:
|
|
270
|
+
applied = False
|
|
271
|
+
elif custom_insts and inst.name in custom_insts:
|
|
272
|
+
if inst.name == "initialize":
|
|
273
|
+
aer_state.apply_initialize(qubits, inst.params)
|
|
274
|
+
elif inst.name == "reset":
|
|
275
|
+
aer_state.apply_reset(qubits)
|
|
276
|
+
elif inst.name == "kraus":
|
|
277
|
+
aer_state.apply_kraus(qubits, inst.params)
|
|
278
|
+
elif inst.name == "barrier":
|
|
279
|
+
pass
|
|
280
|
+
else:
|
|
281
|
+
applied = False
|
|
282
|
+
else:
|
|
283
|
+
applied = False
|
|
284
|
+
|
|
285
|
+
if not applied:
|
|
286
|
+
definition = inst.definition
|
|
287
|
+
if definition is inst or definition is None:
|
|
288
|
+
raise AerError("cannot decompose " + inst.name)
|
|
289
|
+
AerStatevector._aer_evolve_circuit(
|
|
290
|
+
aer_state, definition, qubits, basis_gates, custom_insts
|
|
291
|
+
)
|
|
292
|
+
|
|
293
|
+
@classmethod
|
|
294
|
+
def from_label(cls, label):
|
|
295
|
+
return AerStatevector(Statevector.from_label(label)._data)
|
|
296
|
+
|
|
297
|
+
@staticmethod
|
|
298
|
+
def from_int(i, dims):
|
|
299
|
+
size = np.prod(dims)
|
|
300
|
+
state = np.zeros(size, dtype=complex)
|
|
301
|
+
state[i] = 1.0
|
|
302
|
+
return AerStatevector(state, dims=dims)
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
# This code is part of Qiskit.
|
|
2
|
+
#
|
|
3
|
+
# (C) Copyright IBM 2018, 2019.
|
|
4
|
+
#
|
|
5
|
+
# This code is licensed under the Apache License, Version 2.0. You may
|
|
6
|
+
# obtain a copy of this license in the LICENSE.txt file in the root directory
|
|
7
|
+
# of this source tree or at http://www.apache.org/licenses/LICENSE-2.0.
|
|
8
|
+
#
|
|
9
|
+
# Any modifications or derivative works of this code must retain this
|
|
10
|
+
# copyright notice, and modified files need to carry a notice indicating
|
|
11
|
+
# that they have been altered from the originals.
|
|
12
|
+
|
|
13
|
+
"""
|
|
14
|
+
=============================================
|
|
15
|
+
Utilities (:mod:`qiskit_aer.utils`)
|
|
16
|
+
=============================================
|
|
17
|
+
|
|
18
|
+
.. currentmodule:: qiskit_aer.utils
|
|
19
|
+
|
|
20
|
+
This module contains utility functions for modifying
|
|
21
|
+
:class:`~qiskit_aer.noise.NoiseModel` objects and ``QuantumCircuits``
|
|
22
|
+
using noise models.
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
Functions
|
|
26
|
+
=========
|
|
27
|
+
|
|
28
|
+
.. autosummary::
|
|
29
|
+
:toctree: ../stubs/
|
|
30
|
+
|
|
31
|
+
insert_noise
|
|
32
|
+
approximate_quantum_error
|
|
33
|
+
approximate_noise_model
|
|
34
|
+
transform_noise_model
|
|
35
|
+
transpile_noise_model
|
|
36
|
+
transpile_quantum_error
|
|
37
|
+
"""
|
|
38
|
+
|
|
39
|
+
from .noise_model_inserter import insert_noise
|
|
40
|
+
from .noise_transformation import approximate_noise_model
|
|
41
|
+
from .noise_transformation import approximate_quantum_error
|
|
42
|
+
from .noise_transformation import transform_noise_model
|
|
43
|
+
from .noise_transformation import transpile_noise_model
|
|
44
|
+
from .noise_transformation import transpile_quantum_error
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
# This code is part of Qiskit.
|
|
2
|
+
#
|
|
3
|
+
# (C) Copyright IBM 2019.
|
|
4
|
+
#
|
|
5
|
+
# This code is licensed under the Apache License, Version 2.0. You may
|
|
6
|
+
# obtain a copy of this license in the LICENSE.txt file in the root directory
|
|
7
|
+
# of this source tree or at http://www.apache.org/licenses/LICENSE-2.0.
|
|
8
|
+
#
|
|
9
|
+
# Any modifications or derivative works of this code must retain this
|
|
10
|
+
# copyright notice, and modified files need to carry a notice indicating
|
|
11
|
+
# that they have been altered from the originals.
|
|
12
|
+
"""
|
|
13
|
+
Noise model inserter module
|
|
14
|
+
The goal of this module is to add QuantumError gates (Kraus gates) to a circuit
|
|
15
|
+
based on a given noise model.
|
|
16
|
+
"""
|
|
17
|
+
import qiskit.compiler
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
def insert_noise(circuits, noise_model, transpile=False):
|
|
21
|
+
"""Return a noisy version of a QuantumCircuit.
|
|
22
|
+
|
|
23
|
+
Args:
|
|
24
|
+
circuits (QuantumCircuit or list[QuantumCircuit]): Input noise-free circuits.
|
|
25
|
+
noise_model (NoiseModel): The noise model containing the errors to add
|
|
26
|
+
transpile (Boolean): Should the circuit be transpiled into the noise model basis gates
|
|
27
|
+
|
|
28
|
+
Returns:
|
|
29
|
+
QuantumCircuit: The new circuit with the Kraus noise instructions inserted.
|
|
30
|
+
|
|
31
|
+
Additional Information:
|
|
32
|
+
The noisy circuit return by this function will consist of the
|
|
33
|
+
original circuit with ``Kraus`` instructions inserted after all
|
|
34
|
+
instructions referenced in the ``noise_model``. The resulting circuit
|
|
35
|
+
cannot be ran on a quantum computer but can be executed on the
|
|
36
|
+
:class:`~qiskit_aer.QasmSimulator`.
|
|
37
|
+
"""
|
|
38
|
+
is_circuits_list = isinstance(circuits, (list, tuple))
|
|
39
|
+
circuits = circuits if is_circuits_list else [circuits]
|
|
40
|
+
result_circuits = []
|
|
41
|
+
local_errors = noise_model._local_quantum_errors
|
|
42
|
+
default_errors = noise_model._default_quantum_errors
|
|
43
|
+
for circuit in circuits:
|
|
44
|
+
if transpile:
|
|
45
|
+
transpiled_circuit = qiskit.compiler.transpile(
|
|
46
|
+
circuit, basis_gates=noise_model.basis_gates
|
|
47
|
+
)
|
|
48
|
+
else:
|
|
49
|
+
transpiled_circuit = circuit
|
|
50
|
+
qubit_indices = {bit: index for index, bit in enumerate(transpiled_circuit.qubits)}
|
|
51
|
+
result_circuit = transpiled_circuit.copy(name=transpiled_circuit.name + "_with_noise")
|
|
52
|
+
result_circuit.data = []
|
|
53
|
+
for inst in transpiled_circuit.data:
|
|
54
|
+
result_circuit.data.append(inst)
|
|
55
|
+
qubits = tuple(qubit_indices[q] for q in inst.qubits)
|
|
56
|
+
# Priority for error model used:
|
|
57
|
+
# local error > default error
|
|
58
|
+
name = inst.operation.name
|
|
59
|
+
if name in local_errors and qubits in local_errors[name]:
|
|
60
|
+
error = local_errors[name][qubits]
|
|
61
|
+
result_circuit.append(error.to_instruction(), inst.qubits)
|
|
62
|
+
elif name in default_errors.keys():
|
|
63
|
+
error = default_errors[name]
|
|
64
|
+
result_circuit.append(error.to_instruction(), inst.qubits)
|
|
65
|
+
result_circuits.append(result_circuit)
|
|
66
|
+
return result_circuits if is_circuits_list else result_circuits[0]
|