17
17
import warnings
18
18
from collections import defaultdict
19
19
from dataclasses import dataclass
20
- from typing import Iterable
20
+ from typing import Any , Iterable
21
21
22
22
import numpy as np
23
23
from numpy .typing import NDArray
24
24
25
25
from qiskit .circuit import QuantumCircuit
26
+ from qiskit .exceptions import QiskitError
26
27
from qiskit .primitives .backend_estimator import _run_circuits
27
28
from qiskit .primitives .base import BaseSamplerV2
28
29
from qiskit .primitives .containers import (
@@ -53,6 +54,21 @@ class Options:
53
54
Default: None.
54
55
"""
55
56
57
+ noise_model : Any | None = None
58
+ """A ``NoiseModel`` to pass to pass through a simulator backend (like ones from qiskit-aer)
59
+ Default: None (option not passed to backend's ``run`` method)
60
+ """
61
+
62
+ meas_level : int | None = None
63
+ """Measurement level for the backend to return.
64
+ Default: None (option not passed to backend's ``run`` method)
65
+ """
66
+
67
+ meas_return : str | None = None
68
+ """Measurement return format for the backend to return.
69
+ Default: None (option not passed to backend's ``run`` method)
70
+ """
71
+
56
72
57
73
@dataclass
58
74
class _MeasureInfo :
@@ -165,13 +181,21 @@ def _run_pubs(self, pubs: list[SamplerPub], shots: int) -> list[SamplerPubResult
165
181
for circuits in bound_circuits :
166
182
flatten_circuits .extend (np .ravel (circuits ).tolist ())
167
183
184
+ # Put options in dict to unpacked below so that unset options are left
185
+ # out rather than being passed as None
186
+ run_opts = {
187
+ k : getattr (self ._options , k )
188
+ for k in ("noise_model" , "meas_return" , "meas_level" )
189
+ if getattr (self ._options , k ) is not None
190
+ }
168
191
# run circuits
169
192
results , _ = _run_circuits (
170
193
flatten_circuits ,
171
194
self ._backend ,
172
195
memory = True ,
173
196
shots = shots ,
174
197
seed_simulator = self ._options .seed_simulator ,
198
+ ** run_opts ,
175
199
)
176
200
result_memory = _prepare_memory (results )
177
201
@@ -189,6 +213,7 @@ def _run_pubs(self, pubs: list[SamplerPub], shots: int) -> list[SamplerPubResult
189
213
meas_info ,
190
214
max_num_bytes ,
191
215
pub .circuit .metadata ,
216
+ meas_level = self ._options .meas_level ,
192
217
)
193
218
)
194
219
start = end
@@ -203,22 +228,36 @@ def _postprocess_pub(
203
228
meas_info : list [_MeasureInfo ],
204
229
max_num_bytes : int ,
205
230
circuit_metadata : dict ,
231
+ meas_level : int | None = None ,
206
232
) -> SamplerPubResult :
207
- """Converts the memory data into an array of bit arrays with the shape of the pub."""
208
- arrays = {
209
- item .creg_name : np .zeros (shape + (shots , item .num_bytes ), dtype = np .uint8 )
210
- for item in meas_info
211
- }
212
- memory_array = _memory_array (result_memory , max_num_bytes )
213
-
214
- for samples , index in zip (memory_array , np .ndindex (* shape )):
215
- for item in meas_info :
216
- ary = _samples_to_packed_array (samples , item .num_bits , item .start )
217
- arrays [item .creg_name ][index ] = ary
233
+ """Converts the memory data into a sampler pub result
218
234
219
- meas = {
220
- item .creg_name : BitArray (arrays [item .creg_name ], item .num_bits ) for item in meas_info
221
- }
235
+ For level 2 data, the memory data are stored in an array of bit arrays
236
+ with the shape of the pub. For level 1 data, the data are stored in a
237
+ complex numpy array.
238
+ """
239
+ if meas_level == 2 or meas_level is None :
240
+ arrays = {
241
+ item .creg_name : np .zeros (shape + (shots , item .num_bytes ), dtype = np .uint8 )
242
+ for item in meas_info
243
+ }
244
+ memory_array = _memory_array (result_memory , max_num_bytes )
245
+
246
+ for samples , index in zip (memory_array , np .ndindex (* shape )):
247
+ for item in meas_info :
248
+ ary = _samples_to_packed_array (samples , item .num_bits , item .start )
249
+ arrays [item .creg_name ][index ] = ary
250
+
251
+ meas = {
252
+ item .creg_name : BitArray (arrays [item .creg_name ], item .num_bits ) for item in meas_info
253
+ }
254
+ elif meas_level == 1 :
255
+ raw = np .array (result_memory )
256
+ cplx = raw [..., 0 ] + 1j * raw [..., 1 ]
257
+ cplx = np .reshape (cplx , (* shape , * cplx .shape [1 :]))
258
+ meas = {item .creg_name : cplx for item in meas_info }
259
+ else :
260
+ raise QiskitError (f"Unsupported meas_level: { meas_level } " )
222
261
return SamplerPubResult (
223
262
DataBin (** meas , shape = shape ),
224
263
metadata = {"shots" : shots , "circuit_metadata" : circuit_metadata },
0 commit comments