diff --git a/pulser-core/pulser/devices/_device_datacls.py b/pulser-core/pulser/devices/_device_datacls.py index 61629040..9a1d44bd 100644 --- a/pulser-core/pulser/devices/_device_datacls.py +++ b/pulser-core/pulser/devices/_device_datacls.py @@ -684,19 +684,21 @@ def _specs(self, for_docs: bool = False) -> str: ( "\t" + r"- Maximum :math:`\Omega`:" - + f" {ch.max_amp:.4g} rad/µs" + + f" {float(cast(float,ch.max_amp)):.4g} rad/µs" ), ( ( "\t" + r"- Maximum :math:`|\delta|`:" - + f" {ch.max_abs_detuning:.4g} rad/µs" + + f" {float(cast(float, ch.max_abs_detuning)):.4g}" + + " rad/µs" ) if not isinstance(ch, DMM) else ( "\t" + r"- Bottom :math:`|\delta|`:" - + f" {ch.bottom_detuning:.4g} rad/µs" + + f" {float(cast(float,ch.bottom_detuning)):.4g}" + + " rad/µs" ) ), f"\t- Minimum average amplitude: {ch.min_avg_amp} rad/µs", diff --git a/pulser-core/pulser/json/abstract_repr/deserializer.py b/pulser-core/pulser/json/abstract_repr/deserializer.py index 0f16c6dd..d4bcfd2a 100644 --- a/pulser-core/pulser/json/abstract_repr/deserializer.py +++ b/pulser-core/pulser/json/abstract_repr/deserializer.py @@ -436,8 +436,18 @@ def convert_complex(obj: Any) -> Any: noise_types = noise_model_obj.pop("noise_types") with_leakage = "leakage" in noise_types + relevant_params = pulser.NoiseModel._find_relevant_params( + noise_types, + noise_model_obj["state_prep_error"], + noise_model_obj["amp_sigma"], + noise_model_obj["laser_waist"], + ) - { # Handled separately + "eff_noise_rates", + "eff_noise_opers", + "with_leakage", + } noise_model = pulser.NoiseModel( - **noise_model_obj, + **{param: noise_model_obj[param] for param in relevant_params}, eff_noise_rates=tuple(eff_noise_rates), eff_noise_opers=tuple(eff_noise_opers), with_leakage=with_leakage, diff --git a/tests/test_abstract_repr.py b/tests/test_abstract_repr.py index 4a69c0eb..7ef0bd12 100644 --- a/tests/test_abstract_repr.py +++ b/tests/test_abstract_repr.py @@ -49,7 +49,7 @@ ) from pulser.json.abstract_repr.validation import validate_abstract_repr from pulser.json.exceptions import AbstractReprError, DeserializeDeviceError -from pulser.noise_model import NoiseModel +from pulser.noise_model import _LEGACY_DEFAULTS, NoiseModel from pulser.parametrized.decorators import parametrize from pulser.parametrized.paramobj import ParamObj from pulser.parametrized.variable import Variable, VariableItem @@ -194,7 +194,24 @@ def test_noise_model(noise_model: NoiseModel): re_noise_model = NoiseModel.from_abstract_repr(ser_noise_model_str) assert noise_model == re_noise_model + # Define parameters with defaults, like it was done before + # pulser-core < 0.20, and check deserialization still works ser_noise_model_obj = json.loads(ser_noise_model_str) + for param in ser_noise_model_obj: + if param in _LEGACY_DEFAULTS and ( + # Case where only laser_waist is defined and adding non-zero + # amp_sigma adds requirement for "runs" and "samples_per_run" + param != "amp_sigma" + or "amplitude" not in noise_model.noise_types + ): + ser_noise_model_obj[param] = ( + ser_noise_model_obj[param] or _LEGACY_DEFAULTS[param] + ) + assert ( + NoiseModel.from_abstract_repr(json.dumps(ser_noise_model_obj)) + == re_noise_model + ) + with pytest.raises(TypeError, match="must be given as a string"): NoiseModel.from_abstract_repr(ser_noise_model_obj)