emu-base 2.2.1__py3-none-any.whl → 2.3.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
emu_base/__init__.py CHANGED
@@ -5,6 +5,7 @@ from .math.krylov_exp import krylov_exp, DEFAULT_MAX_KRYLOV_DIM
5
5
  from .jump_lindblad_operators import compute_noise_from_lindbladians
6
6
  from .math.matmul import matmul_2x2_with_batched
7
7
  from .aggregators import AggregationType, aggregate
8
+ from .utils import apply_measurement_errors
8
9
 
9
10
  __all__ = [
10
11
  "__version__",
@@ -18,6 +19,7 @@ __all__ = [
18
19
  "HamiltonianType",
19
20
  "DEFAULT_MAX_KRYLOV_DIM",
20
21
  "DEVICE_COUNT",
22
+ "apply_measurement_errors",
21
23
  ]
22
24
 
23
- __version__ = "2.2.1"
25
+ __version__ = "2.3.0"
emu_base/noise.py ADDED
@@ -0,0 +1,11 @@
1
+ import torch
2
+
3
+
4
+ def pick_dark_qubits(eta: float, n: int) -> torch.Tensor:
5
+ """
6
+ Randomly pick n booleans such that ℙ(True) = eta
7
+
8
+ Returns:
9
+ A BoolTensor of shape (n,) where each element is True with probability eta.
10
+ """
11
+ return torch.rand(n) < eta
@@ -294,6 +294,26 @@ def _get_all_lindblad_noise_operators(
294
294
  ]
295
295
 
296
296
 
297
+ def _get_target_times(
298
+ sequence: pulser.Sequence, config: EmulationConfig, dt: int
299
+ ) -> list[int]:
300
+ sequence_duration = sequence.get_duration(include_fall_time=config.with_modulation)
301
+ # the end value is exclusive, so add +1
302
+ observable_times = set(range(0, sequence_duration + 1, dt))
303
+ observable_times.add(sequence_duration)
304
+ for obs in config.observables:
305
+ times: Sequence[float]
306
+ if obs.evaluation_times is not None:
307
+ times = obs.evaluation_times
308
+ elif config.default_evaluation_times != "Full":
309
+ times = config.default_evaluation_times.tolist() # type: ignore[union-attr,assignment]
310
+ observable_times |= set([round(time * sequence_duration) for time in times])
311
+
312
+ target_times: list[int] = list(observable_times)
313
+ target_times.sort()
314
+ return target_times
315
+
316
+
297
317
  class PulserData:
298
318
  slm_end_time: float
299
319
  full_interaction_matrix: torch.Tensor
@@ -308,22 +328,7 @@ class PulserData:
308
328
  def __init__(self, *, sequence: pulser.Sequence, config: EmulationConfig, dt: int):
309
329
  self.qubit_ids = sequence.register.qubit_ids
310
330
  self.qubit_count = len(self.qubit_ids)
311
- sequence_duration = sequence.get_duration()
312
- # the end value is exclusive, so add +1
313
- observable_times = set(torch.arange(0, sequence.get_duration() + 1, dt).tolist())
314
- observable_times.add(sequence.get_duration())
315
- for obs in config.observables:
316
- times: Sequence[float]
317
- if obs.evaluation_times is not None:
318
- times = obs.evaluation_times
319
- elif config.default_evaluation_times != "Full":
320
- times = (
321
- config.default_evaluation_times.tolist() # type: ignore[union-attr,assignment]
322
- )
323
- observable_times |= set([round(time * sequence_duration) for time in times])
324
-
325
- self.target_times: list[int] = list(observable_times)
326
- self.target_times.sort()
331
+ self.target_times = _get_target_times(sequence=sequence, config=config, dt=dt)
327
332
 
328
333
  laser_waist = config.noise_model.laser_waist
329
334
  amp_sigma = config.noise_model.amp_sigma
emu_base/utils.py CHANGED
@@ -1,3 +1,5 @@
1
+ from collections import Counter
2
+ import random
1
3
  import torch
2
4
 
3
5
 
@@ -33,3 +35,39 @@ def deallocate_tensor(t: torch.Tensor) -> None:
33
35
  if t._base is not None:
34
36
  t._base.resize_(0)
35
37
  t._base.set_(source=replacement_storage)
38
+
39
+
40
+ def readout_with_error(c: str, *, p_false_pos: float, p_false_neg: float) -> str:
41
+ # p_false_pos = false positive, p_false_neg = false negative
42
+ r = random.random()
43
+ if c == "0" and r < p_false_pos:
44
+ return "1"
45
+
46
+ if c == "1" and r < p_false_neg:
47
+ return "0"
48
+
49
+ return c
50
+
51
+
52
+ def apply_measurement_errors(
53
+ bitstrings: Counter[str], *, p_false_pos: float, p_false_neg: float
54
+ ) -> Counter[str]:
55
+ """
56
+ Given a bag of sampled bitstrings, returns another bag of bitstrings
57
+ sampled with readout/measurement errors.
58
+
59
+ p_false_pos: probability of false positive
60
+ p_false_neg: probability of false negative
61
+ """
62
+
63
+ result: Counter[str] = Counter()
64
+ for bitstring, count in bitstrings.items():
65
+ for _ in range(count):
66
+ bitstring_with_error = "".join(
67
+ readout_with_error(c, p_false_pos=p_false_pos, p_false_neg=p_false_neg)
68
+ for c in bitstring
69
+ )
70
+
71
+ result[bitstring_with_error] += 1
72
+
73
+ return result
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: emu-base
3
- Version: 2.2.1
3
+ Version: 2.3.0
4
4
  Summary: Pasqal base classes for emulators
5
5
  Project-URL: Documentation, https://pasqal-io.github.io/emulators/
6
6
  Project-URL: Repository, https://github.com/pasqal-io/emulators
@@ -1,15 +1,16 @@
1
- emu_base/__init__.py,sha256=lXgYx3VbA0qNMwDZyV4HpFcr6aUDxhqWjy8Um73JXrs,681
1
+ emu_base/__init__.py,sha256=wD_KJ7LfcWPbEbnskS46DOhToP4r6D_y2EyztecGMqg,757
2
2
  emu_base/aggregators.py,sha256=bB-rldoDAErxQMpL715K5lpiabGOpkCY0GyxW7mfHuc,5000
3
3
  emu_base/constants.py,sha256=41LYkKLUCz-oxPbd-j7nUDZuhIbUrnez6prT0uR0jcE,56
4
4
  emu_base/jump_lindblad_operators.py,sha256=Y30f8emVFS4Dazljc_Rh4lX9qU4QQY_AxPNahnzcsfY,2101
5
- emu_base/pulser_adapter.py,sha256=WJX8y6iBYg8FX--q0Y10haz-35TbmUGoHbMDQEDuZIY,14534
6
- emu_base/utils.py,sha256=-nIoJuu1pOxkPc2tiJTLjQ0ONsPR43CCB6vOJqdWaUc,1425
5
+ emu_base/noise.py,sha256=h47DhEsFdAN783VnisJ50QJIiAPeRPKpU0SYtt8bAEQ,273
6
+ emu_base/pulser_adapter.py,sha256=NlZ1nNuNdU7D8S0XJqtjgu1b-qW2jFVzXOCAroH4Vuk,14660
7
+ emu_base/utils.py,sha256=17gca5uQfPaXiH3z4Leqd_rAJEZKQUqlSHj7OzFvCkU,2495
7
8
  emu_base/math/__init__.py,sha256=6BbIytYV5uC-e5jLMtIErkcUl_PvfSNnhmVFY9Il8uQ,97
8
9
  emu_base/math/brents_root_finding.py,sha256=AVx6L1Il6rpPJWrLJ7cn6oNmJyZOPRgEaaZaubC9lsU,3711
9
10
  emu_base/math/double_krylov.py,sha256=X16dyCbyzdP7fFK-hmKS03Q-DJtC6TZ8sJrGTJ6akIc,3708
10
11
  emu_base/math/krylov_energy_min.py,sha256=hm_B5qtBXHY1hl-r_LgDUKNDsdqVCDBHprQB3D-UFR8,4009
11
12
  emu_base/math/krylov_exp.py,sha256=mGFddVQ8mEbwypbZtnlRPFpi4Nf8JZT6OKLHloIwCDQ,3934
12
13
  emu_base/math/matmul.py,sha256=lEAnV0b5z_f1xEA-9p-WXxA8bM3QbShiHdXQ3ZkZFcQ,877
13
- emu_base-2.2.1.dist-info/METADATA,sha256=Rs1xk1Xu4iB3-sWXgq0ASiM2bULwk0DVEfC-AclHIGs,3604
14
- emu_base-2.2.1.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
15
- emu_base-2.2.1.dist-info/RECORD,,
14
+ emu_base-2.3.0.dist-info/METADATA,sha256=AAanXBVpBx2__3ojtFYDqPjgLF-9WqNmKcXH4V3JiJA,3604
15
+ emu_base-2.3.0.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
16
+ emu_base-2.3.0.dist-info/RECORD,,