Skip to content

Commit

Permalink
Fix for Service Serialization (Qiskit-Extensions#796)
Browse files Browse the repository at this point in the history
* Added warning for saving service class.

* Added tests for experiment data serialization and bug fix

* Serialization of numpy.number in json file

Co-authored-by: Christopher J. Wood <cjwood@us.ibm.com>
  • Loading branch information
ItamarGoldman and chriseclectic committed May 18, 2022
1 parent 2ef87ae commit 8718aab
Show file tree
Hide file tree
Showing 6 changed files with 135 additions and 3 deletions.
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 @@ -1835,8 +1835,6 @@ def __json_encode__(self):
for att in [
"_metadata",
"_source",
"_service",
"_backend",
"_id",
"_parent_id",
"_type",
Expand All @@ -1861,6 +1859,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 @@ -160,4 +160,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

Expand Down Expand Up @@ -51,3 +52,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 @@ -95,3 +95,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

0 comments on commit 8718aab

Please sign in to comment.