Skip to content

Commit

Permalink
Add serialization support for DoubleSliceSpan
Browse files Browse the repository at this point in the history
  • Loading branch information
ihincks committed Oct 22, 2024
1 parent 1b6a3fc commit 5d1c87c
Show file tree
Hide file tree
Showing 2 changed files with 47 additions and 12 deletions.
22 changes: 21 additions & 1 deletion qiskit_ibm_runtime/utils/json.py
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,11 @@
from qiskit_ibm_runtime.options.zne_options import ( # pylint: disable=ungrouped-imports
ExtrapolatorType,
)
from qiskit_ibm_runtime.execution_span import SliceSpan, ExecutionSpans
from qiskit_ibm_runtime.execution_span.execution_span import (
DoubleSliceSpan,
SliceSpan,
ExecutionSpans,
)

from .noise_learner_result import NoiseLearnerResult

Expand Down Expand Up @@ -327,6 +331,16 @@ def default(self, obj: Any) -> Any: # pylint: disable=arguments-differ
if isinstance(obj, NoiseLearnerResult):
out_val = {"data": obj.data, "metadata": obj.metadata}
return {"__type__": "NoiseLearnerResult", "__value__": out_val}
if isinstance(obj, DoubleSliceSpan):
out_val = {
"start": obj.start,
"stop": obj.stop,
"data_slices": {
idx: (shape, arg_sl.start, arg_sl.stop, shot_sl.start, shot_sl.stop)
for idx, (shape, arg_sl, shot_sl) in obj._data_slices.items()
},
}
return {"__type__": "DoubleSliceSpan", "__value__": out_val}
if isinstance(obj, SliceSpan):
out_val = {
"start": obj.start,
Expand Down Expand Up @@ -450,6 +464,12 @@ def object_hook(self, obj: Any) -> Any:
return PrimitiveResult(**obj_val)
if obj_type == "NoiseLearnerResult":
return NoiseLearnerResult(**obj_val)
if obj_type == "DoubleSliceSpan":
obj_val["data_slices"] = {
int(idx): (tuple(shape), slice(arg0, arg1), slice(shot0, shot1))
for idx, (shape, arg0, arg1, shot0, shot1) in obj_val["data_slices"].items()
}
return DoubleSliceSpan(**obj_val)
if obj_type == "ExecutionSpan":
new_slices = {
int(idx): (tuple(shape), slice(*sl_args))
Expand Down
37 changes: 26 additions & 11 deletions test/unit/test_data_serialization.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,8 +46,12 @@
LayerError,
NoiseLearnerResult,
)
from qiskit_ibm_runtime.fake_provider import FakeNairobiV2
from qiskit_ibm_runtime.execution_span import SliceSpan, ExecutionSpans
from qiskit_ibm_runtime.fake_provider import FakeNairobi
from qiskit_ibm_runtime.execution_span.execution_span import (
DoubleSliceSpan,
SliceSpan,
ExecutionSpans,
)

from .mock.fake_runtime_client import CustomResultRuntimeJob
from .mock.fake_runtime_service import FakeRuntimeService
Expand Down Expand Up @@ -138,7 +142,7 @@ def test_coder_operators(self):

def test_coder_noise_model(self):
"""Test encoding and decoding a noise model."""
noise_model = NoiseModel.from_backend(FakeNairobiV2())
noise_model = NoiseModel.from_backend(FakeNairobi())
self.assertIsInstance(noise_model, NoiseModel)
encoded = json.dumps(noise_model, cls=RuntimeEncoder)
self.assertIsInstance(encoded, str)
Expand Down Expand Up @@ -340,9 +344,8 @@ def assert_primitive_results_equal(self, primitive_result1, primitive_result2):

def assert_pauli_lindblad_error_equal(self, error1, error2):
"""Tests that two PauliLindbladError objects are equal"""
if error1 or error2:
self.assertEqual(error1.generators, error2.generators)
self.assertEqual(error1.rates.tolist(), error2.rates.tolist())
self.assertEqual(error1.generators, error2.generators)
self.assertEqual(error1.rates.tolist(), error2.rates.tolist())

def assert_layer_errors_equal(self, layer_error1, layer_error2):
"""Tests that two LayerError objects are equal"""
Expand Down Expand Up @@ -451,6 +454,19 @@ def make_test_primitive_results(self):
SliceSpan(
datetime(2024, 8, 20), datetime(2024, 8, 21), {0: ((14,), slice(2, 3))}
),
DoubleSliceSpan(
datetime(2022, 1, 1),
datetime(2023, 1, 1),
{
1: ((100,), slice(4, 9), slice(1, 2)),
0: ((2, 5), slice(5, 7), slice(3, 4)),
},
),
DoubleSliceSpan(
datetime(2024, 8, 20),
datetime(2024, 8, 21),
{0: ((14,), slice(2, 3), slice(1, 9))},
),
]
)
}
Expand All @@ -460,13 +476,13 @@ def make_test_primitive_results(self):
primitive_results.append(result)
return primitive_results

def make_test_noise_learner_results(self, unknown_err=False):
def make_test_noise_learner_results(self):
"""Generates test data for NoiseLearnerResult test"""
noise_learner_results = []
circuit = QuantumCircuit(2)
circuit.cx(0, 1)
circuit.measure_all()
error = None if unknown_err else PauliLindbladError(PauliList(["XX", "ZZ"]), [0.1, 0.2])
error = PauliLindbladError(PauliList(["XX", "ZZ"]), [0.1, 0.2])
layer_error = LayerError(circuit, [3, 5], error)

noise_learner_result = NoiseLearnerResult([layer_error])
Expand Down Expand Up @@ -597,10 +613,9 @@ def test_primitive_result(self):
self.assertIsInstance(decoded, PrimitiveResult)
self.assert_primitive_results_equal(primitive_result, decoded)

@data(True, False)
def test_noise_learner_result(self, unknown_err):
def test_noise_learner_result(self):
"""Test encoding and decoding NoiseLearnerResult"""
for noise_learner_result in self.make_test_noise_learner_results(unknown_err):
for noise_learner_result in self.make_test_noise_learner_results():
payload = {"noise_learner_result": noise_learner_result}
encoded = json.dumps(payload, cls=RuntimeEncoder)
decoded = json.loads(encoded, cls=RuntimeDecoder)["noise_learner_result"]
Expand Down

0 comments on commit 5d1c87c

Please sign in to comment.