Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion samplomatic/serialization/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,9 @@
- Added :class:`~.C1Register` serialization; updated :class:`~.BasisChange` format.
* - 3
- 0.16.0
- Added :class:`~.BalancedUniformPauli` distribution support in twirl nodes.
- Added :class:`~.BalancedUniformPauli` distribution support in twirl nodes; switched
parameter expression table serialization from circuit-wrapped QPY to direct
``write_values``/``read_values``.

Backwards compatibility
^^^^^^^^^^^^^^^^^^^^^^^
Expand Down
27 changes: 27 additions & 0 deletions samplomatic/serialization/parameter_expression_serializer.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ class ParameterExpressionTableSerializer(TypeSerializer[ParameterExpressionTable

class SSV1(DataSerializer[ParameterExpressionTable]):
MIN_SSV = 1
MAX_SSV = 2

@classmethod
def serialize(cls, obj, ssv):
Expand All @@ -55,3 +56,29 @@ def deserialize(cls, data):
for instr in circuit:
param_table.append(instr.operation.params[0])
return param_table

class SSV3(DataSerializer[ParameterExpressionTable]):
MIN_SSV = 3

@classmethod
def serialize(cls, obj, ssv):
from qiskit._accelerate import qpy as qpy_rust
from qiskit.qpy.common import QPY_VERSION

with io.BytesIO() as buf:
qpy_rust.write_values(buf, list(obj._expressions)) # noqa: SLF001
values_base64 = pybase64.b64encode_as_string(buf.getvalue())

return {"qpy": str(QPY_VERSION), "values_base64": values_base64}

@classmethod
def deserialize(cls, data):
from qiskit._accelerate import qpy as qpy_rust

with io.BytesIO(pybase64.b64decode(data["values_base64"])) as buf:
expressions = qpy_rust.read_values(buf)

param_table = ParameterExpressionTable()
for expr in expressions:
param_table.append(expr)
return param_table
14 changes: 9 additions & 5 deletions test/performance/test_serialization.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# This code is a Qiskit project.
#
# (C) Copyright IBM 2025.
# (C) Copyright IBM 2025, 2026.
#
# 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
Expand All @@ -21,6 +21,7 @@
from .utils import make_layered_circuit


@pytest.mark.parametrize("ssv", [2, 3])
@pytest.mark.parametrize(
("num_qubits", "num_gates"),
[
Expand All @@ -40,15 +41,17 @@
),
],
)
def test_serialize_noisy_circuit(rng, benchmark, num_qubits, num_gates):
def test_serialize_noisy_circuit(rng, benchmark, num_qubits, num_gates, ssv):
"""Test the speed of serializing a samplex."""
num_boxes = num_gates // (num_qubits // 2)
circuit = make_layered_circuit(num_qubits, num_boxes, inject_noise=True)

_, samplex = build(circuit)
benchmark(samplex_to_json, samplex)
result = benchmark(samplex_to_json, samplex, ssv=ssv)
benchmark.extra_info["payload_bytes"] = len(result)


@pytest.mark.parametrize("ssv", [2, 3])
@pytest.mark.parametrize(
("num_qubits", "num_gates"),
[
Expand All @@ -68,11 +71,12 @@ def test_serialize_noisy_circuit(rng, benchmark, num_qubits, num_gates):
),
],
)
def test_deserialize_noisy_circuit(rng, benchmark, num_qubits, num_gates):
def test_deserialize_noisy_circuit(rng, benchmark, num_qubits, num_gates, ssv):
"""Test the speed of deserializing a samplex."""
num_boxes = num_gates // (num_qubits // 2)
circuit = make_layered_circuit(num_qubits, num_boxes, inject_noise=True)

_, samplex = build(circuit)
samplex_json = samplex_to_json(samplex, None)
samplex_json = samplex_to_json(samplex, None, ssv=ssv)
benchmark.extra_info["payload_bytes"] = len(samplex_json)
benchmark(samplex_from_json, samplex_json)
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# This code is a Qiskit project.
#
# (C) Copyright IBM 2025.
# (C) Copyright IBM 2025, 2026.
#
# 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
Expand Down Expand Up @@ -29,3 +29,14 @@ def test_change_basis_serializer_round_trip(ssv):
data = ParameterExpressionTableSerializer.serialize(table, ssv)
orjson.dumps(data)
assert table == TypeSerializer.deserialize(data)


def test_ssv3_format():
"""Test that SSV3 uses values_base64 (not circuit_base64) and includes qpy version."""
table = ParameterExpressionTable()
table.append(Parameter("x") + Parameter("y"))
data = ParameterExpressionTableSerializer.serialize(table, ssv=3)
assert "values_base64" in data
assert "circuit_base64" not in data
assert "qpy" in data
assert int(data["qpy"]) > 0
Loading