Skip to content

Commit

Permalink
Adding QutipEmulator.draw (#546)
Browse files Browse the repository at this point in the history
* Adding QutipEmulator.draw, deprecating Simulation

* Changing Simulation to QutipEmulator in tests

* Fixing typo

* Fxing doc

* Fixing typo and adding asserts
  • Loading branch information
a-corni committed Jul 6, 2023
1 parent 5e36b3e commit 7ac6327
Show file tree
Hide file tree
Showing 18 changed files with 242 additions and 145 deletions.
48 changes: 47 additions & 1 deletion pulser-simulation/pulser_simulation/simulation.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@
from pulser.register.base_register import BaseRegister, QubitId
from pulser.result import SampledResult
from pulser.sampler.samples import SequenceSamples, _PulseTargetSlot
from pulser.sequence._seq_drawer import draw_sequence
from pulser.sequence._seq_drawer import draw_samples, draw_sequence
from pulser_simulation.qutip_result import QutipResult
from pulser_simulation.simconfig import SimConfig
from pulser_simulation.simresults import (
Expand Down Expand Up @@ -1042,6 +1042,44 @@ def _run_solver() -> CoherentResults:
n_measures,
)

def draw(
self,
draw_phase_area: bool = False,
draw_phase_shifts: bool = False,
draw_phase_curve: bool = False,
fig_name: str | None = None,
kwargs_savefig: dict = {},
) -> None:
"""Draws the samples of a sequence of operations used for simulation.
Args:
draw_phase_area: Whether phase and area values need
to be shown as text on the plot, defaults to False.
draw_phase_shifts: Whether phase shift and reference
information should be added to the plot, defaults to False.
draw_phase_curve: Draws the changes in phase in its own curve
(ignored if the phase doesn't change throughout the channel).
fig_name: The name on which to save the figure.
If None the figure will not be saved.
kwargs_savefig: Keywords arguments for
``matplotlib.pyplot.savefig``. Not applicable if `fig_name`
is ``None``.
See Also:
Sequence.draw(): Draws the sequence in its current state.
"""
draw_samples(
self.samples_obj,
self._register,
self._sampling_rate,
draw_phase_area=draw_phase_area,
draw_phase_shifts=draw_phase_shifts,
draw_phase_curve=draw_phase_curve,
)
if fig_name is not None:
plt.savefig(fig_name, **kwargs_savefig)
plt.show()

@classmethod
def from_sequence(
cls,
Expand Down Expand Up @@ -1150,6 +1188,14 @@ def __init__(
with_modulation: bool = False,
) -> None:
"""Instantiates a Simulation object."""
with warnings.catch_warnings():
warnings.simplefilter("always")
warnings.warn(
DeprecationWarning(
"The `Simulation` class is deprecated,"
" use `QutipEmulator.from_sequence` instead."
)
)
self._seq = sequence
self._modulated = with_modulation
self._emulator = QutipEmulator.from_sequence(
Expand Down
2 changes: 1 addition & 1 deletion tests/test_sequence_sampler.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@
def assert_same_samples_as_sim(seq: pulser.Sequence) -> None:
"""Check against the legacy sample extraction in the simulation module."""
got = sample(seq).to_nested_dict()
want = pulser_simulation.Simulation(seq).samples.copy()
want = pulser_simulation.QutipEmulator.from_sequence(seq).samples.copy()

def truncate_samples(samples_dict):
for key, value in samples_dict.items():
Expand Down
30 changes: 14 additions & 16 deletions tests/test_simresults.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
from pulser import Pulse, Register, Sequence
from pulser.devices import Chadoq2, MockDevice
from pulser.waveforms import BlackmanWaveform
from pulser_simulation import SimConfig, Simulation
from pulser_simulation import QutipEmulator, SimConfig
from pulser_simulation.simresults import CoherentResults, NoisyResults


Expand Down Expand Up @@ -52,7 +52,7 @@ def seq_no_meas(reg, pi_pulse):
def sim(seq_no_meas):
seq_no_meas.measure("ground-rydberg")
np.random.seed(123)
return Simulation(seq_no_meas)
return QutipEmulator.from_sequence(seq_no_meas)


@pytest.fixture
Expand Down Expand Up @@ -108,7 +108,7 @@ def test_initialization(results):

@pytest.mark.parametrize("noisychannel", [True, False])
def test_get_final_state(
noisychannel, sim: Simulation, results, reg, pi_pulse
noisychannel, sim: QutipEmulator, results, reg, pi_pulse
):
if noisychannel:
sim.add_config(SimConfig(noise="dephasing", dephasing_prob=0.01))
Expand Down Expand Up @@ -147,7 +147,7 @@ def test_get_final_state(
seq_.add(pi_pulse, "ram")
seq_.add(pi_pulse, "ryd")

sim_ = Simulation(seq_)
sim_ = QutipEmulator.from_sequence(seq_)
results_ = sim_.run()
results_ = cast(CoherentResults, results_)

Expand Down Expand Up @@ -180,7 +180,7 @@ def test_get_final_state_noisy(reg, pi_pulse):
seq_.declare_channel("ram", "raman_local", initial_target="A")
seq_.add(pi_pulse, "ram")
noisy_config = SimConfig(noise=("SPAM", "doppler"))
sim_noisy = Simulation(seq_, config=noisy_config)
sim_noisy = QutipEmulator.from_sequence(seq_, config=noisy_config)
res3 = sim_noisy.run()
res3._meas_basis = "digital"
final_state = res3.get_final_state()
Expand Down Expand Up @@ -229,7 +229,7 @@ def test_expect(results, pi_pulse, reg):
seq_single = Sequence(reg_single, Chadoq2)
seq_single.declare_channel("ryd", "rydberg_global")
seq_single.add(pi_pulse, "ryd")
sim_single = Simulation(seq_single)
sim_single = QutipEmulator.from_sequence(seq_single)
results_single = sim_single.run()
op = [qutip.basis(2, 0).proj()]
exp = results_single.expect(op)[0]
Expand All @@ -242,10 +242,6 @@ def test_expect(results, pi_pulse, reg):

config = SimConfig(noise="SPAM", eta=0)
sim_single.set_config(config)
with pytest.warns(
DeprecationWarning, match="Setting `evaluation_times` is deprecated"
):
sim_single.evaluation_times = "Minimal"
sim_single.set_evaluation_times("Minimal")
results_single = sim_single.run()
exp = results_single.expect(op)[0]
Expand All @@ -268,7 +264,7 @@ def test_expect(results, pi_pulse, reg):
seq3dim.declare_channel("ram", "raman_local", initial_target="A")
seq3dim.add(pi_pulse, "ram")
seq3dim.add(pi_pulse, "ryd")
sim3dim = Simulation(seq3dim)
sim3dim = QutipEmulator.from_sequence(seq3dim)
exp3dim = sim3dim.run().expect(
[qutip.tensor(qutip.basis(3, 0).proj(), qutip.qeye(3))]
)
Expand All @@ -293,7 +289,9 @@ def test_plot(results_noisy, results):

def test_sim_without_measurement(seq_no_meas):
assert not seq_no_meas.is_measured()
sim_no_meas = Simulation(seq_no_meas, config=SimConfig(runs=1))
sim_no_meas = QutipEmulator.from_sequence(
seq_no_meas, config=SimConfig(runs=1)
)
results_no_meas = sim_no_meas.run()
assert results_no_meas.sample_final_state() == Counter(
{"00": 80, "01": 164, "10": 164, "11": 592}
Expand All @@ -313,13 +311,13 @@ def test_sample_final_state(results):
def test_sample_final_state_three_level(seq_no_meas, pi_pulse):
seq_no_meas.declare_channel("raman", "raman_local", "B")
seq_no_meas.add(pi_pulse, "raman")
res_3level = Simulation(seq_no_meas).run()
res_3level = QutipEmulator.from_sequence(seq_no_meas).run()
# Raman pi pulse on one atom will not affect other,
# even with global pi on rydberg
assert len(res_3level.sample_final_state()) == 2

seq_no_meas.measure("ground-rydberg")
res_3level_gb = Simulation(seq_no_meas).run()
res_3level_gb = QutipEmulator.from_sequence(seq_no_meas).run()
sampling_three_levelB = res_3level_gb.sample_final_state()
# Rydberg will affect both:
assert len(sampling_three_levelB) == 4
Expand All @@ -330,7 +328,7 @@ def test_sample_final_state_noisy(seq_no_meas, results_noisy):
assert results_noisy.sample_final_state(N_samples=1234) == Counter(
{"11": 772, "10": 190, "01": 161, "00": 111}
)
res_3level = Simulation(
res_3level = QutipEmulator.from_sequence(
seq_no_meas, config=SimConfig(noise=("SPAM", "doppler"), runs=10)
)
final_state = res_3level.run().states[-1]
Expand All @@ -355,7 +353,7 @@ def test_results_xy(reg, pi_pulse):
seq_.add(pi_pulse, "ch0")
seq_.measure("XY")

sim_ = Simulation(seq_)
sim_ = QutipEmulator.from_sequence(seq_)
results_ = sim_.run()

assert results_._dim == 2
Expand Down
Loading

0 comments on commit 7ac6327

Please sign in to comment.