Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix for Service Serialization #796

Merged
merged 12 commits into from
May 18, 2022
11 changes: 9 additions & 2 deletions qiskit_experiments/database_service/db_experiment_data.py
Original file line number Diff line number Diff line change
Expand Up @@ -1831,8 +1831,6 @@ def __json_encode__(self):
for att in [
"_metadata",
"_source",
"_service",
ItamarGoldman marked this conversation as resolved.
Show resolved Hide resolved
"_backend",
"_id",
"_parent_id",
"_type",
Expand All @@ -1857,6 +1855,15 @@ def __json_encode__(self):
# Handle non-serializable objects
json_value["_jobs"] = self._safe_serialize_jobs()

# the attribute self._service in charge of the connection and communication with the
# experiment db. It doesn't have meaning in the json format so there is no need to serialize
# it.
for att in ["_service", "_backend"]:
json_value[att] = None
value = getattr(self, att)
if value is not None:
LOG.info("%s cannot be JSON serialized", str(type(value)))

return json_value

@classmethod
Expand Down
2 changes: 2 additions & 0 deletions qiskit_experiments/framework/json.py
Original file line number Diff line number Diff line change
Expand Up @@ -456,6 +456,8 @@ def default(self, obj: Any) -> Any: # pylint: disable=arguments-differ
return {"__type__": "spmatrix", "__value__": value}
if isinstance(obj, bytes):
return _serialize_bytes(obj)
if isinstance(obj, np.number):
return obj.item()
if dataclasses.is_dataclass(obj):
return _serialize_object(obj, settings=dataclasses.asdict(obj))
if isinstance(obj, uncertainties.UFloat):
Expand Down
53 changes: 53 additions & 0 deletions test/test_qubit_spectroscopy.py
Original file line number Diff line number Diff line change
Expand Up @@ -151,4 +151,57 @@ def test_experiment_config(self):
def test_roundtrip_serializable(self):
"""Test round trip JSON serialization"""
exp = QubitSpectroscopy(1, np.linspace(int(100e6), int(150e6), int(20e6)))
# Checking serialization of the experiment
self.assertRoundTripSerializable(exp, self.json_equiv)

def test_expdata_serialization(self):
"""Test experiment data and analysis data JSON serialization"""
exp_helper = SpectroscopyHelper(line_width=2e6)
backend = MockIQBackend(
experiment_helper=exp_helper,
iq_cluster_centers=[((-1.0, -1.0), (1.0, 1.0))],
iq_cluster_width=[0.2],
)
backend._configuration.basis_gates = ["x"]
backend._configuration.timing_constraints = {"granularity": 16}

qubit = 1
freq01 = backend.defaults().qubit_freq_est[qubit]
frequencies = np.linspace(freq01 - 10.0e6, freq01 + 10.0e6, 21)
exp = QubitSpectroscopy(qubit, frequencies)

exp.set_run_options(meas_level=MeasLevel.CLASSIFIED, shots=1024)
expdata = exp.run(backend).block_for_results()
self.assertExperimentDone(expdata)

# Checking serialization of the experiment data
self.assertRoundTripSerializable(expdata, self.experiment_data_equiv)

# Checking serialization of the analysis
self.assertRoundTripSerializable(expdata.analysis_results(1), self.analysis_result_equiv)

def test_kerneled_expdata_serialization(self):
"""Test experiment data and analysis data JSON serialization"""
exp_helper = SpectroscopyHelper(line_width=2e6)
backend = MockIQBackend(
experiment_helper=exp_helper,
iq_cluster_centers=[((-1.0, -1.0), (1.0, 1.0))],
iq_cluster_width=[0.2],
)
backend._configuration.basis_gates = ["x"]
backend._configuration.timing_constraints = {"granularity": 16}

qubit = 1
freq01 = backend.defaults().qubit_freq_est[qubit]
frequencies = np.linspace(freq01 - 10.0e6, freq01 + 10.0e6, 21)
exp = QubitSpectroscopy(qubit, frequencies)

exp.set_run_options(meas_level=MeasLevel.KERNELED, shots=1024)
expdata = exp.run(backend).block_for_results()
self.assertExperimentDone(expdata)

# Checking serialization of the experiment data
self.assertRoundTripSerializable(expdata, self.experiment_data_equiv)

# Checking serialization of the analysis
self.assertRoundTripSerializable(expdata.analysis_results(1), self.analysis_result_equiv)
19 changes: 19 additions & 0 deletions test/test_readout_angle.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
from test.base import QiskitExperimentsTestCase
import numpy as np

from qiskit.qobj.utils import MeasLevel
from qiskit_experiments.library import ReadoutAngle
from qiskit_experiments.test.mock_iq_backend import MockIQBackend
from qiskit_experiments.test.mock_iq_helpers import MockIQReadoutAngleHelper
Expand Down Expand Up @@ -48,3 +49,21 @@ def test_readout_angle_end2end(self):
self.assertExperimentDone(expdata)
res = expdata.analysis_results(0)
self.assertAlmostEqual(res.value % (2 * np.pi), 15 * np.pi / 8, places=2)

def test_kerneled_expdata_serialization(self):
"""Test experiment data and analysis data JSON serialization"""
backend = MockIQBackend(
MockIQReadoutAngleHelper(), iq_cluster_centers=[((-3.0, 3.0), (5.0, 5.0))]
)

exp = ReadoutAngle(0)

exp.set_run_options(meas_level=MeasLevel.KERNELED, shots=1024)
expdata = exp.run(backend).block_for_results()
self.assertExperimentDone(expdata)

# Checking serialization of the experiment data
self.assertRoundTripSerializable(expdata, self.experiment_data_equiv)

# Checking serialization of the analysis
self.assertRoundTripSerializable(expdata.analysis_results(0), self.analysis_result_equiv)
29 changes: 29 additions & 0 deletions test/test_resonator_spectroscopy.py
Original file line number Diff line number Diff line change
Expand Up @@ -65,3 +65,32 @@ def test_roundtrip_serializable(self):
"""Test round trip JSON serialization"""
exp = ResonatorSpectroscopy(1, frequencies=np.linspace(int(100e6), int(150e6), int(20e6)))
self.assertRoundTripSerializable(exp, self.json_equiv)

@data(-5e6, 0, 3e6)
def test_kerneled_expdata_serialization(self, freq_shift):
"""Test experiment data and analysis data JSON serialization"""
qubit = 1
backend = MockIQBackend(
experiment_helper=ResonatorSpectroscopyHelper(
gate_name="measure", freq_offset=freq_shift
),
iq_cluster_centers=[((0.0, 0.0), (-1.0, 0.0))],
iq_cluster_width=[0.2],
)
backend._configuration.timing_constraints = {"granularity": 16}

res_freq = backend.defaults().meas_freq_est[qubit]

frequencies = np.linspace(res_freq - 20e6, res_freq + 20e6, 51)
exp = ResonatorSpectroscopy(qubit, backend=backend, frequencies=frequencies)

expdata = exp.run(backend).block_for_results()
self.assertExperimentDone(expdata)

# since under _experiment in kwargs there is an argument of the backend which isn't serializable.
expdata._experiment = None
# Checking serialization of the experiment data
self.assertRoundTripSerializable(expdata, self.experiment_data_equiv)

# Checking serialization of the analysis
self.assertRoundTripSerializable(expdata.analysis_results(1), self.analysis_result_equiv)
24 changes: 23 additions & 1 deletion test/test_t2hahn.py
Original file line number Diff line number Diff line change
Expand Up @@ -166,9 +166,31 @@ def test_experiment_config(self):

def test_roundtrip_serializable(self):
"""Test round trip JSON serialization"""
exp = T2Hahn(0, [1, 2, 3, 4, 5])

delays0 = list(range(1, 60, 2))

exp = T2Hahn(0, delays0)
self.assertRoundTripSerializable(exp, self.json_equiv)

osc_freq = 0.08
estimated_t2hahn = 30
backend = T2HahnBackend(
t2hahn=[estimated_t2hahn],
frequency=[osc_freq],
initialization_error=[0.0],
readout0to1=[0.02],
readout1to0=[0.02],
)
exp.analysis.set_options(p0={"amp": 0.5, "tau": estimated_t2hahn, "base": 0.5}, plot=False)
expdata = exp.run(backend=backend, shots=1000).block_for_results()
self.assertExperimentDone(expdata)

# Checking serialization of the experiment data
self.assertRoundTripSerializable(expdata, self.experiment_data_equiv)

# Checking serialization of the analysis
self.assertRoundTripSerializable(expdata.analysis_results(1), self.analysis_result_equiv)

def test_analysis_config(self):
""" "Test converting analysis to and from config works"""
analysis = T2HahnAnalysis()
Expand Down