From 847e14269e45a623ae8af6376720c45a2d906f8e Mon Sep 17 00:00:00 2001 From: a_corni Date: Wed, 14 Feb 2024 10:18:49 +0100 Subject: [PATCH 1/3] Fix: SPAM noise in XY --- VERSION.txt | 2 +- .../pulser_simulation/simulation.py | 4 +- tests/test_simulation.py | 143 +++++++++++------- 3 files changed, 96 insertions(+), 53 deletions(-) diff --git a/VERSION.txt b/VERSION.txt index c5523bd09..7cca7711a 100644 --- a/VERSION.txt +++ b/VERSION.txt @@ -1 +1 @@ -0.17.0 +0.17.1 diff --git a/pulser-simulation/pulser_simulation/simulation.py b/pulser-simulation/pulser_simulation/simulation.py index 4cf8a4c2b..e6121d8c6 100644 --- a/pulser-simulation/pulser_simulation/simulation.py +++ b/pulser-simulation/pulser_simulation/simulation.py @@ -514,7 +514,9 @@ def run( } if self.config.eta > 0 and self.initial_state != qutip.tensor( [ - self._hamiltonian.basis["g"] + self._hamiltonian.basis[ + "u" if self._hamiltonian._interaction == "XY" else "g" + ] for _ in range(self._hamiltonian._size) ] ): diff --git a/tests/test_simulation.py b/tests/test_simulation.py index 5839232c3..b9123a194 100644 --- a/tests/test_simulation.py +++ b/tests/test_simulation.py @@ -734,39 +734,18 @@ def test_noise_with_zero_epsilons(seq, matrices): assert sim.run().sample_final_state() == sim2.run().sample_final_state() -def test_dephasing(): - np.random.seed(123) - reg = Register.from_coordinates([(0, 0)], prefix="q") - seq = Sequence(reg, DigitalAnalogDevice) - seq.declare_channel("ch0", "rydberg_global") - duration = 2500 - pulse = Pulse.ConstantPulse(duration, np.pi, 0, 0) - seq.add(pulse, "ch0") - sim = QutipEmulator.from_sequence( - seq, sampling_rate=0.01, config=SimConfig(noise="dephasing") - ) - assert sim.run().sample_final_state() == Counter({"0": 595, "1": 405}) - assert len(sim._hamiltonian._collapse_ops) != 0 - - -def test_depolarizing(): - np.random.seed(123) - reg = Register.from_coordinates([(0, 0)], prefix="q") - seq = Sequence(reg, DigitalAnalogDevice) - seq.declare_channel("ch0", "rydberg_global") - duration = 2500 - pulse = Pulse.ConstantPulse(duration, np.pi, 0, 0) - seq.add(pulse, "ch0") - sim = QutipEmulator.from_sequence( - seq, sampling_rate=0.01, config=SimConfig(noise="depolarizing") - ) - assert sim.run().sample_final_state() == Counter({"0": 587, "1": 413}) - trace_2 = sim.run().states[-1] ** 2 - assert np.trace(trace_2) < 1 and not np.isclose(np.trace(trace_2), 1) - assert len(sim._hamiltonian._collapse_ops) != 0 - - -def test_eff_noise(matrices): +@pytest.mark.parametrize( + "noise_results_collapse_ops", + [ + ("dephasing", {"0": 595, "1": 405}, 1), + ("eff_noise", {"0": 595, "1": 405}, 1), + ("depolarizing", {"0": 587, "1": 413}, 3), + (("dephasing", "depolarizing"), {"0": 587, "1": 413}, 4), + (("eff_noise", "dephasing"), {"0": 595, "1": 405}, 2), + ], +) +def test_dephasing(matrices, noise_results_collapse_ops): + noise, samples, n_collapse_ops = noise_results_collapse_ops np.random.seed(123) reg = Register.from_coordinates([(0, 0)], prefix="q") seq = Sequence(reg, DigitalAnalogDevice) @@ -778,19 +757,17 @@ def test_eff_noise(matrices): seq, sampling_rate=0.01, config=SimConfig( - noise="eff_noise", + noise=noise, eff_noise_opers=[matrices["Z"]], eff_noise_rates=[0.025], ), ) - sim_dph = QutipEmulator.from_sequence( - seq, sampling_rate=0.01, config=SimConfig(noise="dephasing") - ) - assert ( - sim._hamiltonian._collapse_ops == sim_dph._hamiltonian._collapse_ops - and sim.run().states[-1] == sim_dph.run().states[-1] - ) - assert len(sim._hamiltonian._collapse_ops) != 0 + res = sim.run() + res_samples = res.sample_final_state() + assert res_samples == Counter(samples) + assert len(sim._hamiltonian._collapse_ops) == n_collapse_ops + trace_2 = res.states[-1] ** 2 + assert np.trace(trace_2) < 1 and not np.isclose(np.trace(trace_2), 1) def test_add_config(matrices): @@ -934,17 +911,58 @@ def test_run_xy(): assert sim.samples_obj._measurement == "XY" -def test_noisy_xy(): +@pytest.mark.parametrize( + "masked_qubit", + [ + ( + None, + { + "0000": 837, + "0100": 62, + "0001": 42, + "0010": 28, + "1000": 19, + "0101": 12, + }, + ), + ( + "atom0", + { + "0000": 792, + "0001": 79, + "0100": 50, + "0010": 29, + "0110": 27, + "1000": 13, + "0101": 10, + }, + ), + ( + "atom1", + { + "0000": 648, + "0001": 214, + "0010": 78, + "0011": 24, + "1001": 23, + "1000": 13, + }, + ), + ], +) +def test_noisy_xy(matrices, masked_qubit): np.random.seed(15092021) simple_reg = Register.square(2, prefix="atom") detun = 1.0 amp = 3.0 rise = Pulse.ConstantPulse(1500, amp, detun, 0.0) - simple_seq = Sequence(simple_reg, MockDevice) - simple_seq.declare_channel("ch0", "mw_global") - simple_seq.add(rise, "ch0") + seq = Sequence(simple_reg, MockDevice) + seq.declare_channel("ch0", "mw_global") + if masked_qubit[0] is not None: + seq.config_slm_mask([masked_qubit[0]]) + seq.add(rise, "ch0") - sim = QutipEmulator.from_sequence(simple_seq, sampling_rate=0.01) + sim = QutipEmulator.from_sequence(seq, sampling_rate=0.01) with pytest.raises( NotImplementedError, match="mode 'XY' does not support simulation of" ): @@ -958,6 +976,32 @@ def test_noisy_xy(): sim._hamiltonian.set_config( SimConfig(("SPAM", "doppler")).to_noise_model() ) + with pytest.raises( + NotImplementedError, match="simulation of noise types: amplitude" + ): + sim.add_config(SimConfig("amplitude")) + + with pytest.raises( + NotImplementedError, match="simulation of noise types: dephasing" + ): + sim.add_config(SimConfig("dephasing")) + + with pytest.raises( + NotImplementedError, match="simulation of noise types: depolarizing" + ): + sim.add_config(SimConfig("depolarizing")) + + with pytest.raises( + NotImplementedError, match="simulation of noise types: eff_noise" + ): + sim.add_config( + config=SimConfig( + noise="eff_noise", + eff_noise_opers=[matrices["Z"]], + eff_noise_rates=[0.025], + ), + ) + # SPAM simulation is implemented: sim.set_config(SimConfig("SPAM", eta=0.4)) assert sim._hamiltonian._bad_atoms == { "atom0": True, @@ -965,10 +1009,7 @@ def test_noisy_xy(): "atom2": True, "atom3": False, } - with pytest.raises( - NotImplementedError, match="simulation of noise types: amplitude" - ): - sim.add_config(SimConfig("amplitude")) + assert sim.run().sample_final_state() == Counter(masked_qubit[1]) def test_mask_nopulses(): From 5e3a3ca953d02bd878c6345d961b165691dffacf Mon Sep 17 00:00:00 2001 From: a_corni Date: Wed, 14 Feb 2024 10:19:10 +0100 Subject: [PATCH 2/3] FIX: Slope in RampWaveform --- pulser-core/pulser/waveforms.py | 6 +++--- tests/test_waveforms.py | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/pulser-core/pulser/waveforms.py b/pulser-core/pulser/waveforms.py index fe6a493d9..0a7bdfbb0 100644 --- a/pulser-core/pulser/waveforms.py +++ b/pulser-core/pulser/waveforms.py @@ -532,8 +532,8 @@ class RampWaveform(Waveform): Args: duration: The waveform duration (in ns). - start: The initial value (in rad/µs). - stop: The final value (in rad/µs). + start: The value (in rad/µs) at the initial sample. + stop: The value (in rad/µs) at the final sample. """ def __init__( @@ -566,7 +566,7 @@ def _samples(self) -> np.ndarray: @property def slope(self) -> float: r"""Slope of the ramp, in :math:`s^{-15}`.""" - return (self._stop - self._start) / self._duration + return (self._stop - self._start) / (self._duration - 1) def change_duration(self, new_duration: int) -> RampWaveform: """Returns a new waveform with modified duration. diff --git a/tests/test_waveforms.py b/tests/test_waveforms.py index 06dd291b6..31bbb4a37 100644 --- a/tests/test_waveforms.py +++ b/tests/test_waveforms.py @@ -162,7 +162,7 @@ def test_custom(): def test_ramp(): - assert ramp.slope == 7e-3 + assert np.isclose(ramp.slope, 7e-3, atol=1e-5) def test_blackman(): From da18b52913b0e5614c48a5faed28f3e50dad8491 Mon Sep 17 00:00:00 2001 From: a_corni Date: Wed, 14 Feb 2024 10:38:38 +0100 Subject: [PATCH 3/3] Fix syntax in tests --- tests/test_simulation.py | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-) diff --git a/tests/test_simulation.py b/tests/test_simulation.py index b9123a194..d002c9a6d 100644 --- a/tests/test_simulation.py +++ b/tests/test_simulation.py @@ -735,17 +735,14 @@ def test_noise_with_zero_epsilons(seq, matrices): @pytest.mark.parametrize( - "noise_results_collapse_ops", + "noise, result, n_collapse_ops", [ ("dephasing", {"0": 595, "1": 405}, 1), ("eff_noise", {"0": 595, "1": 405}, 1), ("depolarizing", {"0": 587, "1": 413}, 3), - (("dephasing", "depolarizing"), {"0": 587, "1": 413}, 4), - (("eff_noise", "dephasing"), {"0": 595, "1": 405}, 2), ], ) -def test_dephasing(matrices, noise_results_collapse_ops): - noise, samples, n_collapse_ops = noise_results_collapse_ops +def test_dephasing(matrices, noise, result, n_collapse_ops): np.random.seed(123) reg = Register.from_coordinates([(0, 0)], prefix="q") seq = Sequence(reg, DigitalAnalogDevice) @@ -764,7 +761,7 @@ def test_dephasing(matrices, noise_results_collapse_ops): ) res = sim.run() res_samples = res.sample_final_state() - assert res_samples == Counter(samples) + assert res_samples == Counter(result) assert len(sim._hamiltonian._collapse_ops) == n_collapse_ops trace_2 = res.states[-1] ** 2 assert np.trace(trace_2) < 1 and not np.isclose(np.trace(trace_2), 1) @@ -912,7 +909,7 @@ def test_run_xy(): @pytest.mark.parametrize( - "masked_qubit", + "masked_qubit, result", [ ( None, @@ -950,7 +947,7 @@ def test_run_xy(): ), ], ) -def test_noisy_xy(matrices, masked_qubit): +def test_noisy_xy(matrices, masked_qubit, result): np.random.seed(15092021) simple_reg = Register.square(2, prefix="atom") detun = 1.0 @@ -958,8 +955,8 @@ def test_noisy_xy(matrices, masked_qubit): rise = Pulse.ConstantPulse(1500, amp, detun, 0.0) seq = Sequence(simple_reg, MockDevice) seq.declare_channel("ch0", "mw_global") - if masked_qubit[0] is not None: - seq.config_slm_mask([masked_qubit[0]]) + if masked_qubit is not None: + seq.config_slm_mask([masked_qubit]) seq.add(rise, "ch0") sim = QutipEmulator.from_sequence(seq, sampling_rate=0.01) @@ -1009,7 +1006,7 @@ def test_noisy_xy(matrices, masked_qubit): "atom2": True, "atom3": False, } - assert sim.run().sample_final_state() == Counter(masked_qubit[1]) + assert sim.run().sample_final_state() == Counter(result) def test_mask_nopulses():