diff --git a/qiskit_ibm_runtime/utils/json.py b/qiskit_ibm_runtime/utils/json.py index efde27fc0..9b9ab9aef 100644 --- a/qiskit_ibm_runtime/utils/json.py +++ b/qiskit_ibm_runtime/utils/json.py @@ -71,7 +71,6 @@ PrimitiveResult, ) from qiskit_ibm_runtime.options.zne_options import ExtrapolatorType -from qiskit_ibm_runtime.utils.noise_learner_result import LayerError, PauliLindbladError _TERRA_VERSION = tuple( int(x) for x in re.match(r"\d+\.\d+\.\d", _terra_version_string).group(0).split(".")[:3] @@ -157,6 +156,27 @@ def _deserialize_from_settings(mod_name: str, class_name: str, settings: Dict) - raise ValueError(f"Unable to find class {class_name} in module {mod_name}") +def _deserialize_from_json(mod_name: str, class_name: str, json_dict: Dict) -> Any: + """Deserialize an object from its ``_json`` dictionary. + + Args: + mod_name: Name of the module. + class_name: Name of the class. + json_dict: json dictionary. + + Returns: + Deserialized object. + + Raises: + ValueError: If unable to find the class. + """ + mod = importlib.import_module(mod_name) + for name, clz in inspect.getmembers(mod, inspect.isclass): + if name == class_name: + return clz(**json_dict) + raise ValueError(f"Unable to find class {class_name} in module {mod_name}") + + def _set_int_keys_flag(obj: Dict) -> Union[Dict, List]: """Recursively sets '__int_keys__' flag if dictionary uses integer keys @@ -307,6 +327,13 @@ def default(self, obj: Any) -> Any: # pylint: disable=arguments-differ "__class__": obj.__class__.__name__, "__value__": _set_int_keys_flag(copy.deepcopy(obj.settings)), } + if hasattr(obj, "_json"): + return { + "__type__": "_json", + "__module__": obj.__class__.__module__, + "__class__": obj.__class__.__name__, + "__value__": _set_int_keys_flag(copy.deepcopy(obj._json())), + } if callable(obj): warnings.warn(f"Callable {obj} is not JSON serializable and will be set to None.") return None @@ -353,16 +380,20 @@ def object_hook(self, obj: Any) -> Any: return circuit.data[0][0] if obj_type == "settings": if obj["__module__"].startswith( - ( - "qiskit.quantum_info.operators", - "qiskit_ibm_runtime.utils.noise_learner_result", - ) + "qiskit.quantum_info.operators", ): return _deserialize_from_settings( mod_name=obj["__module__"], class_name=obj["__class__"], settings=_cast_strings_keys_to_int(obj_val), ) + if obj_type == "_json": + if obj["__module__"] == "qiskit.quantum_info.operators": + return _deserialize_from_json( + mod_name=obj["__module__"], + class_name=obj["__class__"], + settings=_cast_strings_keys_to_int(obj_val), + ) if obj_type == "Result": return Result.from_dict(obj_val) if obj_type == "spmatrix": @@ -389,10 +420,6 @@ def object_hook(self, obj: Any) -> Any: if shape is not None and isinstance(shape, list): shape = tuple(shape) return DataBin(shape=shape, **obj_val["fields"]) - if obj_type == "LayerError": - return LayerError(**obj_val) - if obj_type == "PauliLindbladError": - return PauliLindbladError(**obj_val) if obj_type == "SamplerPubResult": return SamplerPubResult(**obj_val) if obj_type == "PubResult": diff --git a/qiskit_ibm_runtime/utils/noise_learner_result.py b/qiskit_ibm_runtime/utils/noise_learner_result.py index b9ff59ba6..e59b6313d 100644 --- a/qiskit_ibm_runtime/utils/noise_learner_result.py +++ b/qiskit_ibm_runtime/utils/noise_learner_result.py @@ -91,9 +91,8 @@ def num_qubits(self) -> int: """ return self.generators.num_qubits - @property - def settings(self) -> dict: - """Return settings.""" + def _json(self) -> dict: + """Return a dictionary containing all the information to re-initialize this object.""" return {"generators": self.generators, "rates": self.rates} def __repr__(self) -> str: @@ -176,9 +175,8 @@ def num_qubits(self) -> int: """ return len(self.qubits) - @property - def settings(self) -> dict: - """Return settings.""" + def _json(self) -> dict: + """Return a dictionary containing all the information to re-initialize this object.""" return {"circuit": self.circuit, "qubits": self.qubits, "error": self.error} def __repr__(self) -> str: