• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

Qiskit / qiskit / 13904336911

17 Mar 2025 04:12PM UTC coverage: 88.094% (-0.03%) from 88.12%
13904336911

Pull #14005

github

web-flow
Merge d415bef59 into 219dec704
Pull Request #14005: Create a secure internal path for custom prefixes in registers.

16 of 17 new or added lines in 3 files covered. (94.12%)

744 existing lines in 11 files now uncovered.

72747 of 82579 relevant lines covered (88.09%)

357550.35 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

83.68
/qiskit/qpy/binary_io/value.py
1
# This code is part of Qiskit.
2
#
3
# (C) Copyright IBM 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
"""Binary IO for any value objects, such as numbers, string, parameters."""
14

15
from __future__ import annotations
1✔
16

17
import collections.abc
1✔
18
import io
1✔
19
import struct
1✔
20
import uuid
1✔
21

22
import numpy as np
1✔
23
import symengine
1✔
24

25

26
from qiskit.circuit import CASE_DEFAULT, Clbit, ClassicalRegister, Duration
1✔
27
from qiskit.circuit.classical import expr, types
1✔
28
from qiskit.circuit.parameter import Parameter
1✔
29
from qiskit.circuit.parameterexpression import (
1✔
30
    ParameterExpression,
31
    op_code_to_method,
32
    _OPCode,
33
    _SUBS,
34
)
35
from qiskit.circuit.parametervector import ParameterVector, ParameterVectorElement
1✔
36
from qiskit.qpy import common, formats, exceptions, type_keys
1✔
37
from qiskit.qpy.binary_io.parse_sympy_repr import parse_sympy_repr
1✔
38

39

40
def _write_parameter(file_obj, obj):
1✔
41
    name_bytes = obj.name.encode(common.ENCODE)
1✔
42
    file_obj.write(struct.pack(formats.PARAMETER_PACK, len(name_bytes), obj.uuid.bytes))
1✔
43
    file_obj.write(name_bytes)
1✔
44

45

46
def _write_parameter_vec(file_obj, obj):
1✔
47
    name_bytes = obj._vector._name.encode(common.ENCODE)
1✔
48
    file_obj.write(
1✔
49
        struct.pack(
50
            formats.PARAMETER_VECTOR_ELEMENT_PACK,
51
            len(name_bytes),
52
            len(obj._vector),
53
            obj.uuid.bytes,
54
            obj._index,
55
        )
56
    )
57
    file_obj.write(name_bytes)
1✔
58

59

60
def _encode_replay_entry(inst, file_obj, version, r_side=False):
1✔
61
    inst_type = None
1✔
62
    inst_data = None
1✔
63
    if inst is None:
1✔
64
        inst_type = "n"
1✔
65
        inst_data = b"\x00"
1✔
66
    elif isinstance(inst, Parameter):
1✔
67
        inst_type = "p"
1✔
68
        inst_data = inst.uuid.bytes
1✔
69
    elif isinstance(inst, complex):
1✔
70
        inst_type = "c"
×
UNCOV
71
        inst_data = struct.pack("!dd", inst.real, inst.imag)
×
72
    elif isinstance(inst, float):
1✔
73
        inst_type = "f"
1✔
74
        inst_data = struct.pack("!Qd", 0, inst)
1✔
75
    elif isinstance(inst, int):
1✔
76
        inst_type = "i"
1✔
77
        inst_data = struct.pack("!Qq", 0, inst)
1✔
78
    elif isinstance(inst, ParameterExpression):
1✔
79
        if not r_side:
1✔
UNCOV
80
            entry = struct.pack(
×
81
                formats.PARAM_EXPR_ELEM_V13_PACK,
82
                255,
83
                "s".encode("utf8"),
84
                b"\x00",
85
                "n".encode("utf8"),
86
                b"\x00",
87
            )
88
        else:
89
            entry = struct.pack(
1✔
90
                formats.PARAM_EXPR_ELEM_V13_PACK,
91
                255,
92
                "n".encode("utf8"),
93
                b"\x00",
94
                "s".encode("utf8"),
95
                b"\x00",
96
            )
97
        file_obj.write(entry)
1✔
98
        _write_parameter_expression_v13(file_obj, inst, version)
1✔
99
        if not r_side:
1✔
UNCOV
100
            entry = struct.pack(
×
101
                formats.PARAM_EXPR_ELEM_V13_PACK,
102
                255,
103
                "e".encode("utf8"),
104
                b"\x00",
105
                "n".encode("utf8"),
106
                b"\x00",
107
            )
108
        else:
109
            entry = struct.pack(
1✔
110
                formats.PARAM_EXPR_ELEM_V13_PACK,
111
                255,
112
                "n".encode("utf8"),
113
                b"\x00",
114
                "e".encode("utf8"),
115
                b"\x00",
116
            )
117
        file_obj.write(entry)
1✔
118
        inst_type = "n"
1✔
119
        inst_data = b"\x00"
1✔
120
    else:
UNCOV
121
        raise exceptions.QpyError("Invalid parameter expression type")
×
122
    return inst_type, inst_data
1✔
123

124

125
def _encode_replay_subs(subs, file_obj, version):
1✔
126
    with io.BytesIO() as mapping_buf:
1✔
127
        subs_dict = {k.name: v for k, v in subs.binds.items()}
1✔
128
        common.write_mapping(
1✔
129
            mapping_buf, mapping=subs_dict, serializer=dumps_value, version=version
130
        )
131
        data = mapping_buf.getvalue()
1✔
132
    entry = struct.pack(
1✔
133
        formats.PARAM_EXPR_ELEM_V13_PACK,
134
        subs.op,
135
        "u".encode("utf8"),
136
        struct.pack("!QQ", len(data), 0),
137
        "n".encode("utf8"),
138
        b"\x00",
139
    )
140
    file_obj.write(entry)
1✔
141
    file_obj.write(data)
1✔
142
    return subs.binds
1✔
143

144

145
def _write_parameter_expression_v13(file_obj, obj, version):
1✔
146
    # A symbol is `Parameter` or `ParameterVectorElement`.
147
    # `symbol_map` maps symbols to ParameterExpression (which may be a symbol).
148
    symbol_map = {}
1✔
149
    for inst in obj._qpy_replay:
1✔
150
        if isinstance(inst, _SUBS):
1✔
151
            symbol_map.update(_encode_replay_subs(inst, file_obj, version))
1✔
152
            continue
1✔
153
        lhs_type, lhs = _encode_replay_entry(inst.lhs, file_obj, version)
1✔
154
        rhs_type, rhs = _encode_replay_entry(inst.rhs, file_obj, version, True)
1✔
155
        entry = struct.pack(
1✔
156
            formats.PARAM_EXPR_ELEM_V13_PACK,
157
            inst.op,
158
            lhs_type.encode("utf8"),
159
            lhs,
160
            rhs_type.encode("utf8"),
161
            rhs,
162
        )
163
        file_obj.write(entry)
1✔
164
    return symbol_map
1✔
165

166

167
def _write_parameter_expression(file_obj, obj, use_symengine, *, version):
1✔
168
    extra_symbols = None
1✔
169
    with io.BytesIO() as buf:
1✔
170
        extra_symbols = _write_parameter_expression_v13(buf, obj, version)
1✔
171
        expr_bytes = buf.getvalue()
1✔
172
    symbol_table_len = len(obj._parameter_symbols)
1✔
173
    if extra_symbols:
1✔
174
        symbol_table_len += 2 * len(extra_symbols)
1✔
175
    param_expr_header_raw = struct.pack(
1✔
176
        formats.PARAMETER_EXPR_PACK, symbol_table_len, len(expr_bytes)
177
    )
178
    file_obj.write(param_expr_header_raw)
1✔
179
    file_obj.write(expr_bytes)
1✔
180
    for symbol, value in obj._parameter_symbols.items():
1✔
181
        symbol_key = type_keys.Value.assign(symbol)
1✔
182

183
        # serialize key
184
        if symbol_key == type_keys.Value.PARAMETER_VECTOR:
1✔
185
            symbol_data = common.data_to_binary(symbol, _write_parameter_vec)
1✔
186
        else:
187
            symbol_data = common.data_to_binary(symbol, _write_parameter)
1✔
188

189
        # serialize value
190
        if value == symbol._symbol_expr:
1✔
191
            value_key = symbol_key
1✔
192
            value_data = bytes()
1✔
193
        else:
UNCOV
194
            value_key, value_data = dumps_value(value, version=version, use_symengine=use_symengine)
×
195

196
        elem_header = struct.pack(
1✔
197
            formats.PARAM_EXPR_MAP_ELEM_V3_PACK,
198
            symbol_key,
199
            value_key,
200
            len(value_data),
201
        )
202
        file_obj.write(elem_header)
1✔
203
        file_obj.write(symbol_data)
1✔
204
        file_obj.write(value_data)
1✔
205
    if extra_symbols:
1✔
206
        for symbol in extra_symbols:
1✔
207
            symbol_key = type_keys.Value.assign(symbol)
1✔
208
            # serialize key
209
            if symbol_key == type_keys.Value.PARAMETER_VECTOR:
1✔
210
                symbol_data = common.data_to_binary(symbol, _write_parameter_vec)
1✔
211
            else:
212
                symbol_data = common.data_to_binary(symbol, _write_parameter)
1✔
213
            # serialize value
214
            value_key, value_data = dumps_value(
1✔
215
                symbol, version=version, use_symengine=use_symengine
216
            )
217

218
            elem_header = struct.pack(
1✔
219
                formats.PARAM_EXPR_MAP_ELEM_V3_PACK,
220
                symbol_key,
221
                value_key,
222
                len(value_data),
223
            )
224
            file_obj.write(elem_header)
1✔
225
            file_obj.write(symbol_data)
1✔
226
            file_obj.write(value_data)
1✔
227
        for symbol in extra_symbols.values():
1✔
228
            symbol_key = type_keys.Value.assign(symbol)
1✔
229
            # serialize key
230
            if symbol_key == type_keys.Value.PARAMETER_VECTOR:
1✔
231
                symbol_data = common.data_to_binary(symbol, _write_parameter_vec)
1✔
232
            elif symbol_key == type_keys.Value.PARAMETER_EXPRESSION:
1✔
233
                symbol_data = common.data_to_binary(
1✔
234
                    symbol,
235
                    _write_parameter_expression,
236
                    use_symengine=use_symengine,
237
                    version=version,
238
                )
239
            else:
240
                symbol_data = common.data_to_binary(symbol, _write_parameter)
1✔
241
            # serialize value
242

243
            value_key, value_data = dumps_value(
1✔
244
                symbol, version=version, use_symengine=use_symengine
245
            )
246

247
            elem_header = struct.pack(
1✔
248
                formats.PARAM_EXPR_MAP_ELEM_V3_PACK,
249
                symbol_key,
250
                value_key,
251
                len(value_data),
252
            )
253
            file_obj.write(elem_header)
1✔
254
            file_obj.write(symbol_data)
1✔
255
            file_obj.write(value_data)
1✔
256

257

258
class _ExprWriter(expr.ExprVisitor[None]):
1✔
259
    __slots__ = ("file_obj", "clbit_indices", "standalone_var_indices", "version")
1✔
260

261
    def __init__(self, file_obj, clbit_indices, standalone_var_indices, version):
1✔
262
        self.file_obj = file_obj
1✔
263
        self.clbit_indices = clbit_indices
1✔
264
        self.standalone_var_indices = standalone_var_indices
1✔
265
        self.version = version
1✔
266

267
    def _write_expr_type(self, type_, /):
1✔
268
        _write_expr_type(self.file_obj, type_, self.version)
1✔
269

270
    def visit_generic(self, node, /):
1✔
UNCOV
271
        raise exceptions.QpyError(f"unhandled Expr object '{node}'")
×
272

273
    def visit_var(self, node, /):
1✔
274
        self.file_obj.write(type_keys.Expression.VAR)
1✔
275
        self._write_expr_type(node.type)
1✔
276
        if node.standalone:
1✔
277
            self.file_obj.write(type_keys.ExprVar.UUID)
1✔
278
            self.file_obj.write(
1✔
279
                struct.pack(
280
                    formats.EXPR_VAR_UUID_PACK,
281
                    *formats.EXPR_VAR_UUID(self.standalone_var_indices[node]),
282
                )
283
            )
284
        elif isinstance(node.var, Clbit):
1✔
285
            self.file_obj.write(type_keys.ExprVar.CLBIT)
1✔
286
            self.file_obj.write(
1✔
287
                struct.pack(
288
                    formats.EXPR_VAR_CLBIT_PACK,
289
                    *formats.EXPR_VAR_CLBIT(self.clbit_indices[node.var]),
290
                )
291
            )
292
        elif isinstance(node.var, ClassicalRegister):
1✔
293
            self.file_obj.write(type_keys.ExprVar.REGISTER)
1✔
294
            self.file_obj.write(
1✔
295
                struct.pack(
296
                    formats.EXPR_VAR_REGISTER_PACK, *formats.EXPR_VAR_REGISTER(len(node.var.name))
297
                )
298
            )
299
            self.file_obj.write(node.var.name.encode(common.ENCODE))
1✔
300
        else:
UNCOV
301
            raise exceptions.QpyError(f"unhandled Var object '{node.var}'")
×
302

303
    def visit_stretch(self, node, /):
1✔
304
        self.file_obj.write(type_keys.Expression.STRETCH)
1✔
305
        self._write_expr_type(node.type)
1✔
306
        self.file_obj.write(
1✔
307
            struct.pack(
308
                formats.EXPRESSION_STRETCH_PACK,
309
                *formats.EXPRESSION_STRETCH(self.standalone_var_indices[node]),
310
            )
311
        )
312

313
    def visit_value(self, node, /):
1✔
314
        self.file_obj.write(type_keys.Expression.VALUE)
1✔
315
        self._write_expr_type(node.type)
1✔
316
        if node.value is True or node.value is False:
1✔
317
            self.file_obj.write(type_keys.ExprValue.BOOL)
1✔
318
            self.file_obj.write(
1✔
319
                struct.pack(formats.EXPR_VALUE_BOOL_PACK, *formats.EXPR_VALUE_BOOL(node.value))
320
            )
321
        elif isinstance(node.value, int):
1✔
322
            self.file_obj.write(type_keys.ExprValue.INT)
1✔
323
            if node.value == 0:
1✔
324
                num_bytes = 0
1✔
325
                buffer = b""
1✔
326
            else:
327
                # This wastes a byte for `-(2 ** (8*n - 1))` for natural `n`, but they'll still
328
                # decode fine so it's not worth another special case.  They'll encode to
329
                # b"\xff\x80\x00\x00...", but we could encode them to b"\x80\x00\x00...".
330
                num_bytes = (node.value.bit_length() // 8) + 1
1✔
331
                buffer = node.value.to_bytes(num_bytes, "big", signed=True)
1✔
332
            self.file_obj.write(
1✔
333
                struct.pack(formats.EXPR_VALUE_INT_PACK, *formats.EXPR_VALUE_INT(num_bytes))
334
            )
335
            self.file_obj.write(buffer)
1✔
336
        elif isinstance(node.value, float):
1✔
337
            self.file_obj.write(type_keys.ExprValue.FLOAT)
1✔
338
            self.file_obj.write(
1✔
339
                struct.pack(formats.EXPR_VALUE_FLOAT_PACK, *formats.EXPR_VALUE_FLOAT(node.value))
340
            )
341
        elif isinstance(node.value, Duration):
1✔
342
            self.file_obj.write(type_keys.ExprValue.DURATION)
1✔
343
            _write_duration(self.file_obj, node.value)
1✔
344
        else:
UNCOV
345
            raise exceptions.QpyError(f"unhandled Value object '{node.value}'")
×
346

347
    def visit_cast(self, node, /):
1✔
348
        self.file_obj.write(type_keys.Expression.CAST)
1✔
349
        self._write_expr_type(node.type)
1✔
350
        self.file_obj.write(
1✔
351
            struct.pack(formats.EXPRESSION_CAST_PACK, *formats.EXPRESSION_CAST(node.implicit))
352
        )
353
        node.operand.accept(self)
1✔
354

355
    def visit_unary(self, node, /):
1✔
356
        self.file_obj.write(type_keys.Expression.UNARY)
1✔
357
        self._write_expr_type(node.type)
1✔
358
        self.file_obj.write(
1✔
359
            struct.pack(formats.EXPRESSION_UNARY_PACK, *formats.EXPRESSION_UNARY(node.op.value))
360
        )
361
        node.operand.accept(self)
1✔
362

363
    def visit_binary(self, node, /):
1✔
364
        self.file_obj.write(type_keys.Expression.BINARY)
1✔
365
        self._write_expr_type(node.type)
1✔
366
        self.file_obj.write(
1✔
367
            struct.pack(formats.EXPRESSION_BINARY_PACK, *formats.EXPRESSION_BINARY(node.op.value))
368
        )
369
        node.left.accept(self)
1✔
370
        node.right.accept(self)
1✔
371

372
    def visit_index(self, node, /):
1✔
373
        if self.version < 12:
1✔
UNCOV
374
            raise exceptions.UnsupportedFeatureForVersion(
×
375
                "the 'Index' expression", required=12, target=self.version
376
            )
377
        self.file_obj.write(type_keys.Expression.INDEX)
1✔
378
        self._write_expr_type(node.type)
1✔
379
        node.target.accept(self)
1✔
380
        node.index.accept(self)
1✔
381

382

383
def _write_expr(
1✔
384
    file_obj,
385
    node: expr.Expr,
386
    clbit_indices: collections.abc.Mapping[Clbit, int],
387
    standalone_var_indices: collections.abc.Mapping[expr.Var, int],
388
    version: int,
389
):
390
    node.accept(_ExprWriter(file_obj, clbit_indices, standalone_var_indices, version))
1✔
391

392

393
def _write_expr_type(file_obj, type_: types.Type, version: int):
1✔
394
    if type_.kind is types.Bool:
1✔
395
        file_obj.write(type_keys.ExprType.BOOL)
1✔
396
    elif type_.kind is types.Uint:
1✔
397
        file_obj.write(type_keys.ExprType.UINT)
1✔
398
        file_obj.write(
1✔
399
            struct.pack(formats.EXPR_TYPE_UINT_PACK, *formats.EXPR_TYPE_UINT(type_.width))
400
        )
401
    elif type_.kind is types.Float:
1✔
402
        if version < 14:
1✔
403
            raise exceptions.UnsupportedFeatureForVersion(
1✔
404
                "float-typed expressions", required=14, target=version
405
            )
406
        file_obj.write(type_keys.ExprType.FLOAT)
1✔
407
    elif type_.kind is types.Duration:
1✔
408
        if version < 14:
1✔
409
            raise exceptions.UnsupportedFeatureForVersion(
1✔
410
                "duration-typed expressions", required=14, target=version
411
            )
412
        file_obj.write(type_keys.ExprType.DURATION)
1✔
413
    else:
UNCOV
414
        raise exceptions.QpyError(f"unhandled Type object '{type_};")
×
415

416

417
def _write_duration(file_obj, duration: Duration):
1✔
418
    unit = duration.unit()
1✔
419
    if unit == "dt":
1✔
420
        file_obj.write(type_keys.CircuitDuration.DT)
1✔
421
        file_obj.write(
1✔
422
            struct.pack(formats.DURATION_DT_PACK, *formats.DURATION_DT(duration.value()))
423
        )
424
    elif unit == "ns":
1✔
425
        file_obj.write(type_keys.CircuitDuration.NS)
1✔
426
        file_obj.write(
1✔
427
            struct.pack(formats.DURATION_NS_PACK, *formats.DURATION_NS(duration.value()))
428
        )
429
    elif unit == "us":
1✔
430
        file_obj.write(type_keys.CircuitDuration.US)
1✔
431
        file_obj.write(
1✔
432
            struct.pack(formats.DURATION_US_PACK, *formats.DURATION_US(duration.value()))
433
        )
434
    elif unit == "ms":
1✔
435
        file_obj.write(type_keys.CircuitDuration.MS)
1✔
436
        file_obj.write(
1✔
437
            struct.pack(formats.DURATION_MS_PACK, *formats.DURATION_MS(duration.value()))
438
        )
439
    elif unit == "s":
1✔
440
        file_obj.write(type_keys.CircuitDuration.S)
1✔
441
        file_obj.write(struct.pack(formats.DURATION_S_PACK, *formats.DURATION_S(duration.value())))
1✔
442
    else:
UNCOV
443
        raise exceptions.QpyError(f"unhandled Duration object '{duration};")
×
444

445

446
def _read_parameter(file_obj):
1✔
447
    data = formats.PARAMETER(
1✔
448
        *struct.unpack(formats.PARAMETER_PACK, file_obj.read(formats.PARAMETER_SIZE))
449
    )
450
    param_uuid = uuid.UUID(bytes=data.uuid)
1✔
451
    name = file_obj.read(data.name_size).decode(common.ENCODE)
1✔
452
    return Parameter(name, uuid=param_uuid)
1✔
453

454

455
def _read_parameter_vec(file_obj, vectors):
1✔
456
    data = formats.PARAMETER_VECTOR_ELEMENT(
1✔
457
        *struct.unpack(
458
            formats.PARAMETER_VECTOR_ELEMENT_PACK,
459
            file_obj.read(formats.PARAMETER_VECTOR_ELEMENT_SIZE),
460
        ),
461
    )
462
    param_uuid = uuid.UUID(bytes=data.uuid)
1✔
463
    name = file_obj.read(data.vector_name_size).decode(common.ENCODE)
1✔
464
    if name not in vectors:
1✔
465
        vectors[name] = (ParameterVector(name, data.vector_size), set())
1✔
466
    vector = vectors[name][0]
1✔
467
    if vector[data.index].uuid != param_uuid:
1✔
468
        vectors[name][1].add(data.index)
1✔
469
        vector._params[data.index] = ParameterVectorElement(vector, data.index, uuid=param_uuid)
1✔
470
    return vector[data.index]
1✔
471

472

473
def _read_parameter_expression(file_obj):
1✔
UNCOV
474
    data = formats.PARAMETER_EXPR(
×
475
        *struct.unpack(formats.PARAMETER_EXPR_PACK, file_obj.read(formats.PARAMETER_EXPR_SIZE))
476
    )
477

478
    sympy_str = file_obj.read(data.expr_size).decode(common.ENCODE)
×
479
    expr_ = symengine.sympify(parse_sympy_repr(sympy_str))
×
480
    symbol_map = {}
×
481
    for _ in range(data.map_elements):
×
UNCOV
482
        elem_data = formats.PARAM_EXPR_MAP_ELEM(
×
483
            *struct.unpack(
484
                formats.PARAM_EXPR_MAP_ELEM_PACK,
485
                file_obj.read(formats.PARAM_EXPR_MAP_ELEM_SIZE),
486
            )
487
        )
UNCOV
488
        symbol = _read_parameter(file_obj)
×
489

490
        elem_key = type_keys.Value(elem_data.type)
×
491
        binary_data = file_obj.read(elem_data.size)
×
492
        if elem_key == type_keys.Value.INTEGER:
×
493
            value = struct.unpack("!q", binary_data)
×
494
        elif elem_key == type_keys.Value.FLOAT:
×
495
            value = struct.unpack("!d", binary_data)
×
496
        elif elem_key == type_keys.Value.COMPLEX:
×
497
            value = complex(*struct.unpack(formats.COMPLEX_PACK, binary_data))
×
498
        elif elem_key == type_keys.Value.PARAMETER:
×
499
            value = symbol._symbol_expr
×
500
        elif elem_key == type_keys.Value.PARAMETER_EXPRESSION:
×
UNCOV
501
            value = common.data_from_binary(binary_data, _read_parameter_expression)
×
502
        else:
503
            raise exceptions.QpyError(f"Invalid parameter expression map type: {elem_key}")
×
UNCOV
504
        symbol_map[symbol] = value
×
505

UNCOV
506
    return ParameterExpression(symbol_map, expr_)
×
507

508

509
def _read_parameter_expression_v3(file_obj, vectors, use_symengine):
1✔
UNCOV
510
    data = formats.PARAMETER_EXPR(
×
511
        *struct.unpack(formats.PARAMETER_EXPR_PACK, file_obj.read(formats.PARAMETER_EXPR_SIZE))
512
    )
513

514
    payload = file_obj.read(data.expr_size)
×
515
    if use_symengine:
×
UNCOV
516
        expr_ = common.load_symengine_payload(payload)
×
517
    else:
UNCOV
518
        sympy_str = payload.decode(common.ENCODE)
×
519
        expr_ = symengine.sympify(parse_sympy_repr(sympy_str))
×
520

521
    symbol_map = {}
×
522
    for _ in range(data.map_elements):
×
523
        elem_data = formats.PARAM_EXPR_MAP_ELEM_V3(
×
524
            *struct.unpack(
525
                formats.PARAM_EXPR_MAP_ELEM_V3_PACK,
526
                file_obj.read(formats.PARAM_EXPR_MAP_ELEM_V3_SIZE),
527
            )
528
        )
529
        symbol_key = type_keys.Value(elem_data.symbol_type)
×
530

531
        if symbol_key == type_keys.Value.PARAMETER:
×
532
            symbol = _read_parameter(file_obj)
×
533
        elif symbol_key == type_keys.Value.PARAMETER_VECTOR:
×
534
            symbol = _read_parameter_vec(file_obj, vectors)
×
535
        else:
536
            raise exceptions.QpyError(f"Invalid parameter expression map type: {symbol_key}")
×
537

538
        elem_key = type_keys.Value(elem_data.type)
×
539
        binary_data = file_obj.read(elem_data.size)
×
540
        if elem_key == type_keys.Value.INTEGER:
×
541
            value = struct.unpack("!q", binary_data)
×
542
        elif elem_key == type_keys.Value.FLOAT:
×
543
            value = struct.unpack("!d", binary_data)
×
544
        elif elem_key == type_keys.Value.COMPLEX:
×
545
            value = complex(*struct.unpack(formats.COMPLEX_PACK, binary_data))
×
546
        elif elem_key in (type_keys.Value.PARAMETER, type_keys.Value.PARAMETER_VECTOR):
×
547
            value = symbol._symbol_expr
×
548
        elif elem_key == type_keys.Value.PARAMETER_EXPRESSION:
×
549
            value = common.data_from_binary(
×
550
                binary_data,
551
                _read_parameter_expression_v3,
552
                vectors=vectors,
553
                use_symengine=use_symengine,
554
            )
555
        else:
556
            raise exceptions.QpyError(f"Invalid parameter expression map type: {elem_key}")
×
557
        symbol_map[symbol] = value
×
558

559
    return ParameterExpression(symbol_map, expr_)
×
560

561

562
def _read_parameter_expression_v13(file_obj, vectors, version):
1✔
563
    data = formats.PARAMETER_EXPR(
1✔
564
        *struct.unpack(formats.PARAMETER_EXPR_PACK, file_obj.read(formats.PARAMETER_EXPR_SIZE))
565
    )
566

567
    payload = file_obj.read(data.expr_size)
1✔
568

569
    symbol_map = {}
1✔
570
    for _ in range(data.map_elements):
1✔
571
        elem_data = formats.PARAM_EXPR_MAP_ELEM_V3(
1✔
572
            *struct.unpack(
573
                formats.PARAM_EXPR_MAP_ELEM_V3_PACK,
574
                file_obj.read(formats.PARAM_EXPR_MAP_ELEM_V3_SIZE),
575
            )
576
        )
577
        symbol_key = type_keys.Value(elem_data.symbol_type)
1✔
578

579
        if symbol_key == type_keys.Value.PARAMETER:
1✔
580
            symbol = _read_parameter(file_obj)
1✔
581
        elif symbol_key == type_keys.Value.PARAMETER_VECTOR:
1✔
582
            symbol = _read_parameter_vec(file_obj, vectors)
1✔
583
        elif symbol_key == type_keys.Value.PARAMETER_EXPRESSION:
1✔
584
            symbol = _read_parameter_expression_v13(file_obj, vectors, version)
1✔
585
        else:
586
            raise exceptions.QpyError(f"Invalid parameter expression map type: {symbol_key}")
×
587

588
        elem_key = type_keys.Value(elem_data.type)
1✔
589

590
        binary_data = file_obj.read(elem_data.size)
1✔
591
        if elem_key == type_keys.Value.INTEGER:
1✔
592
            value = struct.unpack("!q", binary_data)
×
593
        elif elem_key == type_keys.Value.FLOAT:
1✔
594
            value = struct.unpack("!d", binary_data)
×
595
        elif elem_key == type_keys.Value.COMPLEX:
1✔
596
            value = complex(*struct.unpack(formats.COMPLEX_PACK, binary_data))
×
597
        elif elem_key in (type_keys.Value.PARAMETER, type_keys.Value.PARAMETER_VECTOR):
1✔
598
            value = symbol._symbol_expr
1✔
599
        elif elem_key == type_keys.Value.PARAMETER_EXPRESSION:
1✔
600
            value = common.data_from_binary(
1✔
601
                binary_data,
602
                _read_parameter_expression_v13,
603
                vectors=vectors,
604
                version=version,
605
            )
606
        else:
607
            raise exceptions.QpyError(f"Invalid parameter expression map type: {elem_key}")
×
608
        symbol_map[symbol] = value
1✔
609
    with io.BytesIO(payload) as buf:
1✔
610
        return _read_parameter_expr_v13(buf, symbol_map, version, vectors)
1✔
611

612

613
def _read_parameter_expr_v13(buf, symbol_map, version, vectors):
1✔
614
    param_uuid_map = {symbol.uuid: symbol for symbol in symbol_map if isinstance(symbol, Parameter)}
1✔
615
    name_map = {str(v): k for k, v in symbol_map.items()}
1✔
616
    data = buf.read(formats.PARAM_EXPR_ELEM_V13_SIZE)
1✔
617
    stack = []
1✔
618
    while data:
1✔
619
        expression_data = formats.PARAM_EXPR_ELEM_V13._make(
1✔
620
            struct.unpack(formats.PARAM_EXPR_ELEM_V13_PACK, data)
621
        )
622
        # LHS
623
        if expression_data.LHS_TYPE == b"p":
1✔
624
            stack.append(param_uuid_map[uuid.UUID(bytes=expression_data.LHS)])
1✔
625
        elif expression_data.LHS_TYPE == b"f":
1✔
626
            stack.append(struct.unpack("!Qd", expression_data.LHS)[1])
×
627
        elif expression_data.LHS_TYPE == b"n":
1✔
628
            pass
1✔
629
        elif expression_data.LHS_TYPE == b"c":
1✔
630
            stack.append(complex(*struct.unpack("!dd", expression_data.LHS)))
×
631
        elif expression_data.LHS_TYPE == b"i":
1✔
632
            stack.append(struct.unpack("!Qq", expression_data.LHS)[1])
1✔
633
        elif expression_data.LHS_TYPE == b"s":
1✔
634
            data = buf.read(formats.PARAM_EXPR_ELEM_V13_SIZE)
×
635
            continue
×
636
        elif expression_data.LHS_TYPE == b"e":
1✔
637
            data = buf.read(formats.PARAM_EXPR_ELEM_V13_SIZE)
×
638
            continue
×
639
        elif expression_data.LHS_TYPE == b"u":
1✔
640
            size = struct.unpack_from("!QQ", expression_data.LHS)[0]
1✔
641
            subs_map_data = buf.read(size)
1✔
642
            with io.BytesIO(subs_map_data) as mapping_buf:
1✔
643
                mapping = common.read_mapping(
1✔
644
                    mapping_buf, deserializer=loads_value, version=version, vectors=vectors
645
                )
646
            stack.append({name_map[k]: v for k, v in mapping.items()})
1✔
647
        else:
648
            raise exceptions.QpyError(
×
649
                "Unknown ParameterExpression operation type {expression_data.LHS_TYPE}"
650
            )
651
        # RHS
652
        if expression_data.RHS_TYPE == b"p":
1✔
653
            stack.append(param_uuid_map[uuid.UUID(bytes=expression_data.RHS)])
1✔
654
        elif expression_data.RHS_TYPE == b"f":
1✔
655
            stack.append(struct.unpack("!Qd", expression_data.RHS)[1])
1✔
656
        elif expression_data.RHS_TYPE == b"n":
1✔
657
            pass
1✔
658
        elif expression_data.RHS_TYPE == b"c":
1✔
659
            stack.append(complex(*struct.unpack("!dd", expression_data.RHS)))
×
660
        elif expression_data.RHS_TYPE == b"i":
1✔
661
            stack.append(struct.unpack("!Qq", expression_data.RHS)[1])
1✔
662
        elif expression_data.RHS_TYPE == b"s":
1✔
663
            data = buf.read(formats.PARAM_EXPR_ELEM_V13_SIZE)
1✔
664
            continue
1✔
665
        elif expression_data.RHS_TYPE == b"e":
1✔
666
            data = buf.read(formats.PARAM_EXPR_ELEM_V13_SIZE)
1✔
667
            continue
1✔
668
        else:
669
            raise exceptions.QpyError(
×
670
                f"Unknown ParameterExpression operation type {expression_data.RHS_TYPE}"
671
            )
672
        if expression_data.OP_CODE == 255:
1✔
673
            continue
×
674
        method_str = op_code_to_method(_OPCode(expression_data.OP_CODE))
1✔
675
        if expression_data.OP_CODE in {0, 1, 2, 3, 4, 13, 15, 18, 19, 20}:
1✔
676
            rhs = stack.pop()
1✔
677
            lhs = stack.pop()
1✔
678
            # Reverse ops for commutative ops, which are add, mul (0 and 2 respectively)
679
            # op codes 13 and 15 can never be reversed and 18, 19, 20
680
            # are the reversed versions of non-commuative operations
681
            # so 1, 3, 4 and 18, 19, 20 handle this explicitly.
682
            if (
1✔
683
                not isinstance(lhs, ParameterExpression)
684
                and isinstance(rhs, ParameterExpression)
685
                and expression_data.OP_CODE in {0, 2}
686
            ):
687
                if expression_data.OP_CODE == 0:
1✔
688
                    method_str = "__radd__"
×
689
                elif expression_data.OP_CODE == 2:
1✔
690
                    method_str = "__rmul__"
1✔
691
                stack.append(getattr(rhs, method_str)(lhs))
1✔
692
            else:
693
                stack.append(getattr(lhs, method_str)(rhs))
1✔
694
        else:
695
            lhs = stack.pop()
1✔
696
            stack.append(getattr(lhs, method_str)())
1✔
697
        data = buf.read(formats.PARAM_EXPR_ELEM_V13_SIZE)
1✔
698
    return stack.pop()
1✔
699

700

701
def _read_expr(
1✔
702
    file_obj,
703
    clbits: collections.abc.Sequence[Clbit],
704
    cregs: collections.abc.Mapping[str, ClassicalRegister],
705
    standalone_vars: collections.abc.Sequence[expr.Var],
706
) -> expr.Expr:
707
    # pylint: disable=too-many-return-statements
708
    type_key = file_obj.read(formats.EXPRESSION_DISCRIMINATOR_SIZE)
1✔
709
    type_ = _read_expr_type(file_obj)
1✔
710
    if type_key == type_keys.Expression.VAR:
1✔
711
        var_type_key = file_obj.read(formats.EXPR_VAR_DISCRIMINATOR_SIZE)
1✔
712
        if var_type_key == type_keys.ExprVar.UUID:
1✔
713
            payload = formats.EXPR_VAR_UUID._make(
1✔
714
                struct.unpack(formats.EXPR_VAR_UUID_PACK, file_obj.read(formats.EXPR_VAR_UUID_SIZE))
715
            )
716
            return standalone_vars[payload.var_index]
1✔
717
        if var_type_key == type_keys.ExprVar.CLBIT:
1✔
718
            payload = formats.EXPR_VAR_CLBIT._make(
1✔
719
                struct.unpack(
720
                    formats.EXPR_VAR_CLBIT_PACK, file_obj.read(formats.EXPR_VAR_CLBIT_SIZE)
721
                )
722
            )
723
            return expr.Var(clbits[payload.index], type_)
1✔
724
        if var_type_key == type_keys.ExprVar.REGISTER:
1✔
725
            payload = formats.EXPR_VAR_REGISTER._make(
1✔
726
                struct.unpack(
727
                    formats.EXPR_VAR_REGISTER_PACK, file_obj.read(formats.EXPR_VAR_REGISTER_SIZE)
728
                )
729
            )
730
            name = file_obj.read(payload.reg_name_size).decode(common.ENCODE)
1✔
731
            return expr.Var(cregs[name], type_)
1✔
732
        raise exceptions.QpyError("Invalid classical-expression Var key '{var_type_key}'")
×
733
    if type_key == type_keys.Expression.STRETCH:
1✔
734
        payload = formats.EXPRESSION_STRETCH._make(
1✔
735
            struct.unpack(
736
                formats.EXPRESSION_STRETCH_PACK, file_obj.read(formats.EXPRESSION_STRETCH_SIZE)
737
            )
738
        )
739
        return standalone_vars[payload.var_index]
1✔
740
    if type_key == type_keys.Expression.VALUE:
1✔
741
        value_type_key = file_obj.read(formats.EXPR_VALUE_DISCRIMINATOR_SIZE)
1✔
742
        if value_type_key == type_keys.ExprValue.BOOL:
1✔
743
            payload = formats.EXPR_VALUE_BOOL._make(
1✔
744
                struct.unpack(
745
                    formats.EXPR_VALUE_BOOL_PACK, file_obj.read(formats.EXPR_VALUE_BOOL_SIZE)
746
                )
747
            )
748
            return expr.Value(payload.value, type_)
1✔
749
        if value_type_key == type_keys.ExprValue.INT:
1✔
750
            payload = formats.EXPR_VALUE_INT._make(
1✔
751
                struct.unpack(
752
                    formats.EXPR_VALUE_INT_PACK, file_obj.read(formats.EXPR_VALUE_INT_SIZE)
753
                )
754
            )
755
            return expr.Value(
1✔
756
                int.from_bytes(file_obj.read(payload.num_bytes), "big", signed=True), type_
757
            )
758
        if value_type_key == type_keys.ExprValue.FLOAT:
1✔
759
            payload = formats.EXPR_VALUE_FLOAT._make(
1✔
760
                struct.unpack(
761
                    formats.EXPR_VALUE_FLOAT_PACK, file_obj.read(formats.EXPR_VALUE_FLOAT_SIZE)
762
                )
763
            )
764
            return expr.Value(payload.value, type_)
1✔
765
        if value_type_key == type_keys.ExprValue.DURATION:
1✔
766
            value = _read_duration(file_obj)
1✔
767
            return expr.Value(value, type_)
1✔
768
        raise exceptions.QpyError("Invalid classical-expression Value key '{value_type_key}'")
×
769
    if type_key == type_keys.Expression.CAST:
1✔
770
        payload = formats.EXPRESSION_CAST._make(
1✔
771
            struct.unpack(formats.EXPRESSION_CAST_PACK, file_obj.read(formats.EXPRESSION_CAST_SIZE))
772
        )
773
        return expr.Cast(
1✔
774
            _read_expr(file_obj, clbits, cregs, standalone_vars), type_, implicit=payload.implicit
775
        )
776
    if type_key == type_keys.Expression.UNARY:
1✔
777
        payload = formats.EXPRESSION_UNARY._make(
1✔
778
            struct.unpack(
779
                formats.EXPRESSION_UNARY_PACK, file_obj.read(formats.EXPRESSION_UNARY_SIZE)
780
            )
781
        )
782
        return expr.Unary(
1✔
783
            expr.Unary.Op(payload.opcode),
784
            _read_expr(file_obj, clbits, cregs, standalone_vars),
785
            type_,
786
        )
787
    if type_key == type_keys.Expression.BINARY:
1✔
788
        payload = formats.EXPRESSION_BINARY._make(
1✔
789
            struct.unpack(
790
                formats.EXPRESSION_BINARY_PACK, file_obj.read(formats.EXPRESSION_BINARY_SIZE)
791
            )
792
        )
793
        return expr.Binary(
1✔
794
            expr.Binary.Op(payload.opcode),
795
            _read_expr(file_obj, clbits, cregs, standalone_vars),
796
            _read_expr(file_obj, clbits, cregs, standalone_vars),
797
            type_,
798
        )
799
    if type_key == type_keys.Expression.INDEX:
1✔
800
        return expr.Index(
1✔
801
            _read_expr(file_obj, clbits, cregs, standalone_vars),
802
            _read_expr(file_obj, clbits, cregs, standalone_vars),
803
            type_,
804
        )
805
    raise exceptions.QpyError(f"Invalid classical-expression Expr key '{type_key}'")
×
806

807

808
def _read_expr_type(file_obj) -> types.Type:
1✔
809
    type_key = file_obj.read(formats.EXPR_TYPE_DISCRIMINATOR_SIZE)
1✔
810
    if type_key == type_keys.ExprType.BOOL:
1✔
811
        return types.Bool()
1✔
812
    if type_key == type_keys.ExprType.UINT:
1✔
813
        elem = formats.EXPR_TYPE_UINT._make(
1✔
814
            struct.unpack(formats.EXPR_TYPE_UINT_PACK, file_obj.read(formats.EXPR_TYPE_UINT_SIZE))
815
        )
816
        return types.Uint(elem.width)
1✔
817
    if type_key == type_keys.ExprType.FLOAT:
1✔
818
        return types.Float()
1✔
819
    if type_key == type_keys.ExprType.DURATION:
1✔
820
        return types.Duration()
1✔
821
    raise exceptions.QpyError(f"Invalid classical-expression Type key '{type_key}'")
×
822

823

824
def _read_duration(file_obj) -> Duration:
1✔
825
    type_key = file_obj.read(formats.DURATION_DISCRIMINATOR_SIZE)
1✔
826
    if type_key == type_keys.CircuitDuration.DT:
1✔
827
        elem = formats.DURATION_DT._make(
1✔
828
            struct.unpack(formats.DURATION_DT_PACK, file_obj.read(formats.DURATION_DT_SIZE))
829
        )
830
        return Duration.dt(elem.value)
1✔
831
    if type_key == type_keys.CircuitDuration.NS:
1✔
832
        elem = formats.DURATION_NS._make(
1✔
833
            struct.unpack(formats.DURATION_NS_PACK, file_obj.read(formats.DURATION_NS_SIZE))
834
        )
835
        return Duration.ns(elem.value)
1✔
836
    if type_key == type_keys.CircuitDuration.US:
1✔
837
        elem = formats.DURATION_US._make(
1✔
838
            struct.unpack(formats.DURATION_US_PACK, file_obj.read(formats.DURATION_US_SIZE))
839
        )
840
        return Duration.us(elem.value)
1✔
841
    if type_key == type_keys.CircuitDuration.MS:
1✔
842
        elem = formats.DURATION_MS._make(
1✔
843
            struct.unpack(formats.DURATION_MS_PACK, file_obj.read(formats.DURATION_MS_SIZE))
844
        )
845
        return Duration.ms(elem.value)
1✔
846
    if type_key == type_keys.CircuitDuration.S:
1✔
847
        elem = formats.DURATION_S._make(
1✔
848
            struct.unpack(formats.DURATION_S_PACK, file_obj.read(formats.DURATION_S_SIZE))
849
        )
850
        return Duration.s(elem.value)
1✔
851
    raise exceptions.QpyError(f"Invalid duration Type key '{type_key}'")
×
852

853

854
def read_standalone_vars(file_obj, num_vars):
1✔
855
    """Read the ``num_vars`` standalone variable declarations from the file.
856

857
    Args:
858
        file_obj (File): a file-like object to read from.
859
        num_vars (int): the number of variables to read.
860

861
    Returns:
862
        tuple[dict, list]: the first item is a mapping of the ``ExprVarDeclaration`` type keys to
863
        the variables defined by that type key, and the second is the total order of variable
864
        declarations.
865
    """
866
    read_vars = {
1✔
867
        type_keys.ExprVarDeclaration.INPUT: [],
868
        type_keys.ExprVarDeclaration.CAPTURE: [],
869
        type_keys.ExprVarDeclaration.LOCAL: [],
870
        type_keys.ExprVarDeclaration.STRETCH_CAPTURE: [],
871
        type_keys.ExprVarDeclaration.STRETCH_LOCAL: [],
872
    }
873
    var_order = []
1✔
874
    for _ in range(num_vars):
1✔
875
        data = formats.EXPR_VAR_DECLARATION._make(
1✔
876
            struct.unpack(
877
                formats.EXPR_VAR_DECLARATION_PACK,
878
                file_obj.read(formats.EXPR_VAR_DECLARATION_SIZE),
879
            )
880
        )
881
        type_ = _read_expr_type(file_obj)
1✔
882
        name = file_obj.read(data.name_size).decode(common.ENCODE)
1✔
883
        if data.usage in {
1✔
884
            type_keys.ExprVarDeclaration.STRETCH_CAPTURE,
885
            type_keys.ExprVarDeclaration.STRETCH_LOCAL,
886
        }:
887
            var = expr.Stretch(uuid.UUID(bytes=data.uuid_bytes), name)
1✔
888
        else:
889
            var = expr.Var(uuid.UUID(bytes=data.uuid_bytes), type_, name=name)
1✔
890
        read_vars[data.usage].append(var)
1✔
891
        var_order.append(var)
1✔
892
    return read_vars, var_order
1✔
893

894

895
def _write_standalone_var(file_obj, var, type_key, version):
1✔
896
    name = var.name.encode(common.ENCODE)
1✔
897
    file_obj.write(
1✔
898
        struct.pack(
899
            formats.EXPR_VAR_DECLARATION_PACK,
900
            *formats.EXPR_VAR_DECLARATION(var.var.bytes, type_key, len(name)),
901
        )
902
    )
903
    _write_expr_type(file_obj, var.type, version)
1✔
904
    file_obj.write(name)
1✔
905

906

907
def write_standalone_vars(file_obj, circuit, version):
1✔
908
    """Write the standalone variables out from a circuit.
909

910
    Args:
911
        file_obj (File): the file-like object to write to.
912
        circuit (QuantumCircuit): the circuit to take the variables from.
913
        version (int): the QPY target version.
914

915
    Returns:
916
        dict[expr.Var | expr.Stretch, int]: a mapping of the variables written to the
917
            index that they were written at.
918
    """
919
    index = 0
1✔
920
    out = {}
1✔
921
    for var in circuit.iter_input_vars():
1✔
922
        _write_standalone_var(file_obj, var, type_keys.ExprVarDeclaration.INPUT, version)
1✔
923
        out[var] = index
1✔
924
        index += 1
1✔
925
    for var in circuit.iter_captured_vars():
1✔
926
        _write_standalone_var(file_obj, var, type_keys.ExprVarDeclaration.CAPTURE, version)
1✔
927
        out[var] = index
1✔
928
        index += 1
1✔
929
    for var in circuit.iter_declared_vars():
1✔
930
        _write_standalone_var(file_obj, var, type_keys.ExprVarDeclaration.LOCAL, version)
1✔
931
        out[var] = index
1✔
932
        index += 1
1✔
933
    if version < 14 and circuit.num_stretches:
1✔
934
        raise exceptions.UnsupportedFeatureForVersion(
1✔
935
            "circuits containing stretch variables", required=14, target=version
936
        )
937
    for var in circuit.iter_captured_stretches():
1✔
938
        _write_standalone_var(file_obj, var, type_keys.ExprVarDeclaration.STRETCH_CAPTURE, version)
×
939
        out[var] = index
×
940
        index += 1
×
941
    for var in circuit.iter_declared_stretches():
1✔
942
        _write_standalone_var(file_obj, var, type_keys.ExprVarDeclaration.STRETCH_LOCAL, version)
1✔
943
        out[var] = index
1✔
944
        index += 1
1✔
945
    return out
1✔
946

947

948
def dumps_value(
1✔
949
    obj,
950
    *,
951
    version,
952
    index_map=None,
953
    use_symengine=False,
954
    standalone_var_indices=None,
955
):
956
    """Serialize input value object.
957

958
    Args:
959
        obj (any): Arbitrary value object to serialize.
960
        version (int): the target QPY version for the dump.
961
        index_map (dict): Dictionary with two keys, "q" and "c".  Each key has a value that is a
962
            dictionary mapping :class:`.Qubit` or :class:`.Clbit` instances (respectively) to their
963
            integer indices.
964
        use_symengine (bool): If True, symbolic objects will be serialized using symengine's
965
            native mechanism. This is a faster serialization alternative, but not supported in all
966
            platforms. Please check that your target platform is supported by the symengine library
967
            before setting this option, as it will be required by qpy to deserialize the payload.
968
        standalone_var_indices (dict): Dictionary that maps standalone :class:`.expr.Var` entries to
969
            the index that should be used to refer to them.
970

971
    Returns:
972
        tuple: TypeKey and binary data.
973

974
    Raises:
975
        QpyError: Serializer for given format is not ready.
976
    """
977
    type_key = type_keys.Value.assign(obj)
1✔
978

979
    if type_key == type_keys.Value.INTEGER:
1✔
980
        binary_data = struct.pack("!q", obj)
×
981
    elif type_key == type_keys.Value.FLOAT:
1✔
982
        binary_data = struct.pack("!d", obj)
1✔
983
    elif type_key == type_keys.Value.COMPLEX:
1✔
984
        binary_data = struct.pack(formats.COMPLEX_PACK, obj.real, obj.imag)
1✔
985
    elif type_key == type_keys.Value.NUMPY_OBJ:
1✔
986
        binary_data = common.data_to_binary(obj, np.save)
1✔
987
    elif type_key == type_keys.Value.STRING:
1✔
988
        binary_data = obj.encode(common.ENCODE)
1✔
989
    elif type_key in (type_keys.Value.NULL, type_keys.Value.CASE_DEFAULT):
1✔
990
        binary_data = b""
1✔
991
    elif type_key == type_keys.Value.PARAMETER_VECTOR:
1✔
992
        binary_data = common.data_to_binary(obj, _write_parameter_vec)
1✔
993
    elif type_key == type_keys.Value.PARAMETER:
1✔
994
        binary_data = common.data_to_binary(obj, _write_parameter)
1✔
995
    elif type_key == type_keys.Value.PARAMETER_EXPRESSION:
1✔
996
        binary_data = common.data_to_binary(
1✔
997
            obj, _write_parameter_expression, use_symengine=use_symengine, version=version
998
        )
999
    elif type_key == type_keys.Value.EXPRESSION:
1✔
1000
        clbit_indices = {} if index_map is None else index_map["c"]
1✔
1001
        standalone_var_indices = {} if standalone_var_indices is None else standalone_var_indices
1✔
1002
        binary_data = common.data_to_binary(
1✔
1003
            obj,
1004
            _write_expr,
1005
            clbit_indices=clbit_indices,
1006
            standalone_var_indices=standalone_var_indices,
1007
            version=version,
1008
        )
1009
    else:
1010
        raise exceptions.QpyError(f"Serialization for {type_key} is not implemented in value I/O.")
×
1011

1012
    return type_key, binary_data
1✔
1013

1014

1015
def write_value(
1✔
1016
    file_obj, obj, *, version, index_map=None, use_symengine=False, standalone_var_indices=None
1017
):
1018
    """Write a value to the file like object.
1019

1020
    Args:
1021
        file_obj (File): A file like object to write data.
1022
        obj (any): Value to write.
1023
        version (int): the target QPY version for the dump.
1024
        index_map (dict): Dictionary with two keys, "q" and "c".  Each key has a value that is a
1025
            dictionary mapping :class:`.Qubit` or :class:`.Clbit` instances (respectively) to their
1026
            integer indices.
1027
        use_symengine (bool): If True, symbolic objects will be serialized using symengine's
1028
            native mechanism. This is a faster serialization alternative, but not supported in all
1029
            platforms. Please check that your target platform is supported by the symengine library
1030
            before setting this option, as it will be required by qpy to deserialize the payload.
1031
        standalone_var_indices (dict): Dictionary that maps standalone :class:`.expr.Var` entries to
1032
            the index that should be used to refer to them.
1033
    """
1034
    type_key, data = dumps_value(
1✔
1035
        obj,
1036
        version=version,
1037
        index_map=index_map,
1038
        use_symengine=use_symengine,
1039
        standalone_var_indices=standalone_var_indices,
1040
    )
1041
    common.write_generic_typed_data(file_obj, type_key, data)
1✔
1042

1043

1044
def loads_value(
1✔
1045
    type_key,
1046
    binary_data,
1047
    version,
1048
    vectors,
1049
    *,
1050
    clbits=(),
1051
    cregs=None,
1052
    use_symengine=False,
1053
    standalone_vars=(),
1054
):
1055
    """Deserialize input binary data to value object.
1056

1057
    Args:
1058
        type_key (ValueTypeKey): Type enum information.
1059
        binary_data (bytes): Data to deserialize.
1060
        version (int): QPY version.
1061
        vectors (dict): ParameterVector in current scope.
1062
        clbits (Sequence[Clbit]): Clbits in the current scope.
1063
        cregs (Mapping[str, ClassicalRegister]): Classical registers in the current scope.
1064
        use_symengine (bool): If True, symbolic objects will be de-serialized using symengine's
1065
            native mechanism. This is a faster serialization alternative, but not supported in all
1066
            platforms. Please check that your target platform is supported by the symengine library
1067
            before setting this option, as it will be required by qpy to deserialize the payload.
1068
        standalone_vars (Sequence[Var]): standalone :class:`.expr.Var` nodes in the order that they
1069
            were declared by the circuit header.
1070

1071
    Returns:
1072
        any: Deserialized value object.
1073

1074
    Raises:
1075
        QpyError: Serializer for given format is not ready.
1076
    """
1077
    # pylint: disable=too-many-return-statements
1078

1079
    if isinstance(type_key, bytes):
1✔
1080
        type_key = type_keys.Value(type_key)
1✔
1081

1082
    if type_key == type_keys.Value.INTEGER:
1✔
1083
        return struct.unpack("!q", binary_data)[0]
×
1084
    if type_key == type_keys.Value.FLOAT:
1✔
1085
        return struct.unpack("!d", binary_data)[0]
1✔
1086
    if type_key == type_keys.Value.COMPLEX:
1✔
1087
        return complex(*struct.unpack(formats.COMPLEX_PACK, binary_data))
1✔
1088
    if type_key == type_keys.Value.NUMPY_OBJ:
1✔
1089
        return common.data_from_binary(binary_data, np.load)
1✔
1090
    if type_key == type_keys.Value.STRING:
1✔
1091
        return binary_data.decode(common.ENCODE)
1✔
1092
    if type_key == type_keys.Value.NULL:
1✔
1093
        return None
1✔
1094
    if type_key == type_keys.Value.CASE_DEFAULT:
1✔
1095
        return CASE_DEFAULT
1✔
1096
    if type_key == type_keys.Value.PARAMETER_VECTOR:
1✔
1097
        return common.data_from_binary(binary_data, _read_parameter_vec, vectors=vectors)
1✔
1098
    if type_key == type_keys.Value.PARAMETER:
1✔
1099
        return common.data_from_binary(binary_data, _read_parameter)
1✔
1100
    if type_key == type_keys.Value.PARAMETER_EXPRESSION:
1✔
1101
        if version < 3:
1✔
1102
            return common.data_from_binary(binary_data, _read_parameter_expression)
×
1103
        elif version < 13:
1✔
1104
            return common.data_from_binary(
×
1105
                binary_data,
1106
                _read_parameter_expression_v3,
1107
                vectors=vectors,
1108
                use_symengine=use_symengine,
1109
            )
1110
        else:
1111
            return common.data_from_binary(
1✔
1112
                binary_data, _read_parameter_expression_v13, vectors=vectors, version=version
1113
            )
1114
    if type_key == type_keys.Value.EXPRESSION:
1✔
1115
        return common.data_from_binary(
1✔
1116
            binary_data,
1117
            _read_expr,
1118
            clbits=clbits,
1119
            cregs=cregs or {},
1120
            standalone_vars=standalone_vars,
1121
        )
1122

1123
    raise exceptions.QpyError(f"Serialization for {type_key} is not implemented in value I/O.")
×
1124

1125

1126
def read_value(
1✔
1127
    file_obj,
1128
    version,
1129
    vectors,
1130
    *,
1131
    clbits=(),
1132
    cregs=None,
1133
    use_symengine=False,
1134
    standalone_vars=(),
1135
):
1136
    """Read a value from the file like object.
1137

1138
    Args:
1139
        file_obj (File): A file like object to write data.
1140
        version (int): QPY version.
1141
        vectors (dict): ParameterVector in current scope.
1142
        clbits (Sequence[Clbit]): Clbits in the current scope.
1143
        cregs (Mapping[str, ClassicalRegister]): Classical registers in the current scope.
1144
        use_symengine (bool): If True, symbolic objects will be de-serialized using symengine's
1145
            native mechanism. This is a faster serialization alternative, but not supported in all
1146
            platforms. Please check that your target platform is supported by the symengine library
1147
            before setting this option, as it will be required by qpy to deserialize the payload.
1148
        standalone_vars (Sequence[expr.Var]): standalone variables in the order they were defined in
1149
            the QPY payload.
1150

1151
    Returns:
1152
        any: Deserialized value object.
1153
    """
1154
    type_key, data = common.read_generic_typed_data(file_obj)
1✔
1155

1156
    return loads_value(
1✔
1157
        type_key,
1158
        data,
1159
        version,
1160
        vectors,
1161
        clbits=clbits,
1162
        cregs=cregs,
1163
        use_symengine=use_symengine,
1164
        standalone_vars=standalone_vars,
1165
    )
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc