-
Notifications
You must be signed in to change notification settings - Fork 66
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Fix SPAM errors introducing overhead #529
Conversation
dakk
commented
May 30, 2023
•
edited
Loading
edited
- Fixes SPAM errors introduce large simulation overhead #352
- Handle eps_p = eps = 0 case
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good start, but I think the improvement from this alone will be quite small. The main goal is to avoid unecessarily repeating the time-consuming part where the flips
are calculated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is already quite a nice optimization, but I think we can go further. I'll write up another comment detailing how
A question for you @dakk : How is the runtime scaling with |
Indeed, I made a new optimization in the last commit, by using tuple instead of strings for sample_dict indexing. Please take a look. (I removed the screenshot from the issue, since I noticed there was an error in my profiling script) |
Now scales sub-linearly; this is a test run with different import time
import sys
import numpy as np
from pulser import Register, Pulse, Sequence, waveforms, devices
from pulser_simulation import Simulation, SimConfig
reg = Register.square(side=2)
pulse = Pulse.ConstantDetuning(waveforms.BlackmanWaveform(duration=1000, area=np.pi),0,0)
seq = Sequence(reg, devices.MockDevice)
seq.declare_channel('ch', 'rydberg_global')
seq.add(pulse, 'ch')
sim = Simulation(seq)
def run(r):
noise_config = SimConfig(noise=('SPAM', 'doppler', 'amplitude') if spam else ('doppler', 'amplitude'),
eta=0.005, epsilon=0.03, epsilon_prime=0.08,
temperature=30, laser_waist=148,
runs=10, samples_per_run=r)
sim.set_config(noise_config)
#sim.show_config()
t = time.time()
res = sim.run(False)
tt = time.time() - t
print(f'Samples_per_run: {r}\tElapsed: {tt} seconds')
for x in [1, 10, 100, 500, 1000, 2000, 5000, 10000]:
run(x) |
Ok, here is the alternative that I think it's worth investigating: when The potential downside of this approach is that calculating the density matrix is expensive, as you go from a state of size N to a matrix of size N**2, so I'm not sure it will be benefitial. I have a feeling this is the conclusion I arrived at a while ago, but I can't remember with certainty anymore. On the other hand, I suspect that calculating the full pseudo-density matrix might even not be necessary as we are only using the N elements in its diagonal. |
Let's take this step by step:
def get_samples(self, n_samples: int) -> Counter[str]:
"""Takes multiple samples from the sampling distribution.
Args:
n_samples: Number of samples to return.
Returns:
Samples of bitstrings corresponding to measured quantum states.
"""
return self.get_samples_from_weights(n_samples, self._weights())
@staticmethod
def get_samples_from_weights(n_samples: int, weights: np.ndarray):
# TODO: Docstring
dist = np.random.multinomial(n_samples, weights)
return Counter(
{
np.binary_repr(i, self._size): dist[i]
for i in np.nonzero(dist)[0]
}
)
...
if eps_p == 0.0 and eps == 0.0:
return sampled_state
t_index = self._get_index_from_time(t, t_tol)
custom_weights = np.abs(self._calc_pseudo_density(t_index).diag())
return Result.get_samples_from_weights(n_samples, custom_weights)
My guess is that there will be regimes where this performs better (ie large number of PS: It's very likely that there are bugs in the code above, I just wanted to give some pointers so feel free to adjust it as you see fit |
I integrated your code into Pulser, but it takes way more time to run simulations; for way more I mean several minutes instead of seconds even with the smallest samples_per_run. Maybe I'm missing something |
Your implementation seems correct, it's very likely that |
Sure; this is before:
and after:
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hey @dakk !
This is already a nice accelleration !
I have another idea, that would be to vectorize the code.
I let you have a look to it, I hope it will be understoodable 😄
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Very nice, thank your for your work!
It was a pleasure! |