emu-mps 2.2.1__py3-none-any.whl → 2.4.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_mps/__init__.py CHANGED
@@ -9,12 +9,11 @@ from pulser.backend import (
9
9
  StateResult,
10
10
  EnergySecondMoment,
11
11
  )
12
- from .mps_config import MPSConfig
12
+ from .mps_config import MPSConfig, Solver
13
13
  from .mpo import MPO
14
14
  from .mps import MPS, inner
15
15
  from .mps_backend import MPSBackend
16
16
  from .observables import EntanglementEntropy
17
- from emu_base import aggregate
18
17
 
19
18
 
20
19
  __all__ = [
@@ -23,6 +22,7 @@ __all__ = [
23
22
  "MPS",
24
23
  "inner",
25
24
  "MPSConfig",
25
+ "Solver",
26
26
  "MPSBackend",
27
27
  "StateResult",
28
28
  "BitStrings",
@@ -33,8 +33,7 @@ __all__ = [
33
33
  "Energy",
34
34
  "EnergyVariance",
35
35
  "EnergySecondMoment",
36
- "aggregate",
37
36
  "EntanglementEntropy",
38
37
  ]
39
38
 
40
- __version__ = "2.2.1"
39
+ __version__ = "2.4.0"
emu_mps/mps.py CHANGED
@@ -7,11 +7,10 @@ from typing import List, Optional, Sequence, TypeVar, Mapping
7
7
  import torch
8
8
 
9
9
  from pulser.backend.state import State, Eigenstate
10
- from emu_base import DEVICE_COUNT
10
+ from emu_base import DEVICE_COUNT, apply_measurement_errors
11
11
  from emu_mps import MPSConfig
12
12
  from emu_mps.algebra import add_factors, scale_factors
13
13
  from emu_mps.utils import (
14
- apply_measurement_errors,
15
14
  assign_devices,
16
15
  truncate_impl,
17
16
  tensor_trace,
@@ -154,7 +153,7 @@ class MPS(State[complex, torch.Tensor]):
154
153
 
155
154
  for i in range(rl_swipe_start, desired_orthogonality_center, -1):
156
155
  q, r = torch.linalg.qr(
157
- self.factors[i].view(self.factors[i].shape[0], -1).mT,
156
+ self.factors[i].contiguous().view(self.factors[i].shape[0], -1).mT,
158
157
  )
159
158
  self.factors[i] = q.mT.view(-1, 2, self.factors[i].shape[2])
160
159
  self.factors[i - 1] = torch.tensordot(
@@ -10,7 +10,6 @@ import uuid
10
10
  from copy import deepcopy
11
11
  from collections import Counter
12
12
  from enum import Enum, auto
13
- from resource import RUSAGE_SELF, getrusage
14
13
  from types import MethodType
15
14
  from typing import Any, Optional
16
15
 
@@ -18,7 +17,7 @@ import torch
18
17
  from pulser import Sequence
19
18
  from pulser.backend import EmulationConfig, Observable, Results, State
20
19
 
21
- from emu_base import DEVICE_COUNT, PulserData
20
+ from emu_base import DEVICE_COUNT, PulserData, get_max_rss
22
21
  from emu_base.math.brents_root_finding import BrentsRootFinder
23
22
  from emu_base.utils import deallocate_tensor
24
23
 
@@ -26,12 +25,13 @@ from emu_mps.hamiltonian import make_H, update_H
26
25
  from emu_mps.mpo import MPO
27
26
  from emu_mps.mps import MPS
28
27
  from emu_mps.mps_config import MPSConfig
29
- from emu_mps.noise import pick_well_prepared_qubits
30
28
  from emu_base.jump_lindblad_operators import compute_noise_from_lindbladians
31
29
  import emu_mps.optimatrix as optimat
30
+ from emu_mps.solver import Solver
32
31
  from emu_mps.solver_utils import (
33
32
  evolve_pair,
34
33
  evolve_single,
34
+ minimize_energy_pair,
35
35
  new_right_bath,
36
36
  right_baths,
37
37
  )
@@ -68,14 +68,7 @@ class Statistics(Observable):
68
68
  """Calculates the observable to store in the Results."""
69
69
  assert isinstance(state, MPS)
70
70
  duration = self.data[-1]
71
- if state.factors[0].is_cuda:
72
- max_mem_per_device = (
73
- torch.cuda.max_memory_allocated(device) * 1e-6
74
- for device in range(torch.cuda.device_count())
75
- )
76
- max_mem = max(max_mem_per_device)
77
- else:
78
- max_mem = getrusage(RUSAGE_SELF).ru_maxrss * 1e-3
71
+ max_mem = get_max_rss(state.factors[0].is_cuda)
79
72
 
80
73
  config.logger.info(
81
74
  f"step = {len(self.data)}/{self.timestep_count}, "
@@ -102,11 +95,11 @@ class MPSBackendImpl:
102
95
  current_time: float = (
103
96
  0.0 # While dt is an integer, noisy collapse can happen at non-integer times.
104
97
  )
105
- well_prepared_qubits_filter: Optional[list[bool]]
98
+ well_prepared_qubits_filter: Optional[torch.Tensor]
106
99
  hamiltonian: MPO
107
100
  state: MPS
108
101
  right_baths: list[torch.Tensor]
109
- tdvp_index: int
102
+ sweep_index: int
110
103
  swipe_direction: SwipeDirection
111
104
  timestep_index: int
112
105
  target_time: float
@@ -142,7 +135,7 @@ class MPSBackendImpl:
142
135
  self.left_baths: list[torch.Tensor]
143
136
  self.time = time.time()
144
137
  self.swipe_direction = SwipeDirection.LEFT_TO_RIGHT
145
- self.tdvp_index = 0
138
+ self.sweep_index = 0
146
139
  self.timestep_index = 0
147
140
  self.results = Results(
148
141
  atom_order=optimat.permute_tuple(
@@ -192,8 +185,9 @@ class MPSBackendImpl:
192
185
  def init_dark_qubits(self) -> None:
193
186
  # has_state_preparation_error
194
187
  if self.config.noise_model.state_prep_error > 0.0:
195
- self.well_prepared_qubits_filter = pick_well_prepared_qubits(
196
- self.config.noise_model.state_prep_error, self.qubit_count
188
+ bad_atoms = self.pulser_data.hamiltonian.bad_atoms
189
+ self.well_prepared_qubits_filter = torch.logical_not(
190
+ torch.tensor(list(bool(x) for x in bad_atoms.values()))
197
191
  )
198
192
  else:
199
193
  self.well_prepared_qubits_filter = None
@@ -241,7 +235,7 @@ class MPSBackendImpl:
241
235
 
242
236
  initial_state = MPS(
243
237
  # Deep copy of every tensor of the initial state.
244
- [f.clone().detach() for f in initial_state.factors],
238
+ [f.detach().clone() for f in initial_state.factors],
245
239
  config=self.config,
246
240
  num_gpus_to_use=self.config.num_gpus_to_use,
247
241
  eigenstates=initial_state.eigenstates,
@@ -249,6 +243,7 @@ class MPSBackendImpl:
249
243
  initial_state.truncate()
250
244
  initial_state *= 1 / initial_state.norm()
251
245
  self.state = initial_state
246
+ self.state.orthogonalize(0)
252
247
 
253
248
  def init_hamiltonian(self) -> None:
254
249
  """
@@ -347,7 +342,7 @@ class MPSBackendImpl:
347
342
  """
348
343
  Do one unit of simulation work given the current state.
349
344
  Update the state accordingly.
350
- The state of the simulation is stored in self.tdvp_index and self.swipe_direction.
345
+ The state of the simulation is stored in self.sweep_index and self.swipe_direction.
351
346
  """
352
347
  if self.is_finished():
353
348
  return
@@ -358,79 +353,79 @@ class MPSBackendImpl:
358
353
  if 1 <= self.qubit_count <= 2:
359
354
  # Corner case: only 1 or 2 qubits
360
355
  assert self.swipe_direction == SwipeDirection.LEFT_TO_RIGHT
361
- assert self.tdvp_index == 0
356
+ assert self.sweep_index == 0
362
357
 
363
358
  if self.qubit_count == 1:
364
359
  self._evolve(0, dt=delta_time)
365
360
  else:
366
361
  self._evolve(0, 1, dt=delta_time, orth_center_right=False)
367
362
 
368
- self.tdvp_complete()
363
+ self.sweep_complete()
369
364
 
370
365
  elif (
371
- self.tdvp_index < self.qubit_count - 2
366
+ self.sweep_index < self.qubit_count - 2
372
367
  and self.swipe_direction == SwipeDirection.LEFT_TO_RIGHT
373
368
  ):
374
369
  # Left-to-right swipe of TDVP
375
370
  self._evolve(
376
- self.tdvp_index,
377
- self.tdvp_index + 1,
371
+ self.sweep_index,
372
+ self.sweep_index + 1,
378
373
  dt=delta_time / 2,
379
374
  orth_center_right=True,
380
375
  )
381
376
  self.left_baths.append(
382
377
  new_left_bath(
383
378
  self.get_current_left_bath(),
384
- self.state.factors[self.tdvp_index],
385
- self.hamiltonian.factors[self.tdvp_index],
386
- ).to(self.state.factors[self.tdvp_index + 1].device)
379
+ self.state.factors[self.sweep_index],
380
+ self.hamiltonian.factors[self.sweep_index],
381
+ ).to(self.state.factors[self.sweep_index + 1].device)
387
382
  )
388
- self._evolve(self.tdvp_index + 1, dt=-delta_time / 2)
383
+ self._evolve(self.sweep_index + 1, dt=-delta_time / 2)
389
384
  self.right_baths.pop()
390
- self.tdvp_index += 1
385
+ self.sweep_index += 1
391
386
 
392
387
  elif (
393
- self.tdvp_index == self.qubit_count - 2
388
+ self.sweep_index == self.qubit_count - 2
394
389
  and self.swipe_direction == SwipeDirection.LEFT_TO_RIGHT
395
390
  ):
396
391
  # Time-evolution of the rightmost 2 tensors
397
392
  self._evolve(
398
- self.tdvp_index,
399
- self.tdvp_index + 1,
393
+ self.sweep_index,
394
+ self.sweep_index + 1,
400
395
  dt=delta_time,
401
396
  orth_center_right=False,
402
397
  )
403
398
  self.swipe_direction = SwipeDirection.RIGHT_TO_LEFT
404
399
 
405
400
  elif (
406
- 1 <= self.tdvp_index and self.swipe_direction == SwipeDirection.RIGHT_TO_LEFT
401
+ 1 <= self.sweep_index and self.swipe_direction == SwipeDirection.RIGHT_TO_LEFT
407
402
  ):
408
403
  # Right-to-left swipe of TDVP
409
- assert self.tdvp_index <= self.qubit_count - 2
404
+ assert self.sweep_index <= self.qubit_count - 2
410
405
  self.right_baths.append(
411
406
  new_right_bath(
412
407
  self.get_current_right_bath(),
413
- self.state.factors[self.tdvp_index + 1],
414
- self.hamiltonian.factors[self.tdvp_index + 1],
415
- ).to(self.state.factors[self.tdvp_index].device)
408
+ self.state.factors[self.sweep_index + 1],
409
+ self.hamiltonian.factors[self.sweep_index + 1],
410
+ ).to(self.state.factors[self.sweep_index].device)
416
411
  )
417
412
  if not self.has_lindblad_noise:
418
413
  # Free memory because it won't be used anymore
419
414
  deallocate_tensor(self.right_baths[-2])
420
415
 
421
- self._evolve(self.tdvp_index, dt=-delta_time / 2)
416
+ self._evolve(self.sweep_index, dt=-delta_time / 2)
422
417
  self.left_baths.pop()
423
418
 
424
419
  self._evolve(
425
- self.tdvp_index - 1,
426
- self.tdvp_index,
420
+ self.sweep_index - 1,
421
+ self.sweep_index,
427
422
  dt=delta_time / 2,
428
423
  orth_center_right=False,
429
424
  )
430
- self.tdvp_index -= 1
425
+ self.sweep_index -= 1
431
426
 
432
- if self.tdvp_index == 0:
433
- self.tdvp_complete()
427
+ if self.sweep_index == 0:
428
+ self.sweep_complete()
434
429
  self.swipe_direction = SwipeDirection.LEFT_TO_RIGHT
435
430
 
436
431
  else:
@@ -438,7 +433,7 @@ class MPSBackendImpl:
438
433
 
439
434
  self.save_simulation()
440
435
 
441
- def tdvp_complete(self) -> None:
436
+ def sweep_complete(self) -> None:
442
437
  self.current_time = self.target_time
443
438
  self.timestep_complete()
444
439
 
@@ -623,7 +618,7 @@ class NoisyMPSBackendImpl(MPSBackendImpl):
623
618
  super().init()
624
619
  self.set_jump_threshold(1.0)
625
620
 
626
- def tdvp_complete(self) -> None:
621
+ def sweep_complete(self) -> None:
627
622
  previous_time = self.current_time
628
623
  self.current_time = self.target_time
629
624
  previous_norm_gap_before_jump = self.norm_gap_before_jump
@@ -690,10 +685,122 @@ class NoisyMPSBackendImpl(MPSBackendImpl):
690
685
  super().fill_results()
691
686
 
692
687
 
688
+ class DMRGBackendImpl(MPSBackendImpl):
689
+ def __init__(
690
+ self,
691
+ mps_config: MPSConfig,
692
+ pulser_data: PulserData,
693
+ energy_tolerance: float = 1e-5,
694
+ max_sweeps: int = 2000,
695
+ ):
696
+
697
+ if mps_config.noise_model.noise_types != ():
698
+ raise NotImplementedError(
699
+ "DMRG solver does not currently support noise types"
700
+ f"you are using: {mps_config.noise_model.noise_types}"
701
+ )
702
+ super().__init__(mps_config, pulser_data)
703
+ self.previous_energy: Optional[float] = None
704
+ self.current_energy: Optional[float] = None
705
+ self.sweep_count: int = 0
706
+ self.energy_tolerance: float = energy_tolerance
707
+ self.max_sweeps: int = max_sweeps
708
+
709
+ def convergence_check(self, energy_tolerance: float) -> bool:
710
+ if self.previous_energy is None or self.current_energy is None:
711
+ return False
712
+ return abs(self.current_energy - self.previous_energy) < energy_tolerance
713
+
714
+ def progress(self) -> None:
715
+ if self.is_finished():
716
+ return
717
+
718
+ # perform one two-site energy minimization and update
719
+ idx = self.sweep_index
720
+ assert self.swipe_direction in (
721
+ SwipeDirection.LEFT_TO_RIGHT,
722
+ SwipeDirection.RIGHT_TO_LEFT,
723
+ ), "Unknown Swipe direction"
724
+
725
+ orth_center_right = self.swipe_direction == SwipeDirection.LEFT_TO_RIGHT
726
+ new_L, new_R, energy = minimize_energy_pair(
727
+ state_factors=self.state.factors[idx : idx + 2],
728
+ ham_factors=self.hamiltonian.factors[idx : idx + 2],
729
+ baths=(self.left_baths[-1], self.right_baths[-1]),
730
+ orth_center_right=orth_center_right,
731
+ config=self.config,
732
+ residual_tolerance=self.config.precision,
733
+ )
734
+ self.state.factors[idx], self.state.factors[idx + 1] = new_L, new_R
735
+ self.state.orthogonality_center = idx + 1 if orth_center_right else idx
736
+ self.current_energy = energy
737
+
738
+ # updating baths and orthogonality center
739
+ if self.swipe_direction == SwipeDirection.LEFT_TO_RIGHT:
740
+ self._left_to_right_update(idx)
741
+ elif self.swipe_direction == SwipeDirection.RIGHT_TO_LEFT:
742
+ self._right_to_left_update(idx)
743
+ else:
744
+ raise Exception("Did not expect this")
745
+
746
+ self.save_simulation()
747
+
748
+ def _left_to_right_update(self, idx: int) -> None:
749
+ if idx < self.qubit_count - 2:
750
+ self.left_baths.append(
751
+ new_left_bath(
752
+ self.get_current_left_bath(),
753
+ self.state.factors[idx],
754
+ self.hamiltonian.factors[idx],
755
+ ).to(self.state.factors[idx + 1].device)
756
+ )
757
+ self.right_baths.pop()
758
+ self.sweep_index += 1
759
+
760
+ if self.sweep_index == self.qubit_count - 2:
761
+ self.swipe_direction = SwipeDirection.RIGHT_TO_LEFT
762
+
763
+ def _right_to_left_update(self, idx: int) -> None:
764
+ if idx > 0:
765
+ self.right_baths.append(
766
+ new_right_bath(
767
+ self.get_current_right_bath(),
768
+ self.state.factors[idx + 1],
769
+ self.hamiltonian.factors[idx + 1],
770
+ ).to(self.state.factors[idx].device)
771
+ )
772
+ self.left_baths.pop()
773
+ self.sweep_index -= 1
774
+
775
+ if self.sweep_index == 0:
776
+ self.state.orthogonalize(0)
777
+ self.swipe_direction = SwipeDirection.LEFT_TO_RIGHT
778
+ self.sweep_count += 1
779
+ self.sweep_complete()
780
+
781
+ def sweep_complete(self) -> None:
782
+ # This marks the end of one full sweep: checking convergence
783
+ if self.convergence_check(self.energy_tolerance):
784
+ self.current_time = self.target_time
785
+ self.timestep_complete()
786
+ elif self.sweep_count + 1 > self.max_sweeps:
787
+ # not converged
788
+ raise RuntimeError(f"DMRG did not converge after {self.max_sweeps} sweeps")
789
+ else:
790
+ # not converged for the current sweep. restart
791
+ self.previous_energy = self.current_energy
792
+
793
+ assert self.sweep_index == 0
794
+ assert self.state.orthogonality_center == 0
795
+ assert self.swipe_direction == SwipeDirection.LEFT_TO_RIGHT
796
+ self.current_energy = None
797
+
798
+
693
799
  def create_impl(sequence: Sequence, config: MPSConfig) -> MPSBackendImpl:
694
800
  pulser_data = PulserData(sequence=sequence, config=config, dt=config.dt)
695
801
 
696
802
  if pulser_data.has_lindblad_noise:
697
803
  return NoisyMPSBackendImpl(config, pulser_data)
698
-
804
+ if config.solver == Solver.DMRG:
805
+ return DMRGBackendImpl(config, pulser_data)
699
806
  return MPSBackendImpl(config, pulser_data)
emu_mps/mps_config.py CHANGED
@@ -4,6 +4,7 @@ from types import MethodType
4
4
  import copy
5
5
 
6
6
  from emu_base import DEVICE_COUNT
7
+ from emu_mps.solver import Solver
7
8
  from emu_mps.custom_callback_implementations import (
8
9
  energy_mps_impl,
9
10
  energy_second_moment_mps_impl,
@@ -53,6 +54,11 @@ class MPSConfig(EmulationConfig):
53
54
  autosave_dt: minimum time interval in seconds between two autosaves.
54
55
  Saving the simulation state is only possible at specific times,
55
56
  therefore this interval is only a lower bound.
57
+ solver: chooses the solver algorithm to run a sequence.
58
+ Two options are currently available:
59
+ ``TDVP``, which performs ordinary time evolution,
60
+ and ``DMRG``, which adiabatically follows the ground state
61
+ of a given adiabatic pulse.
56
62
  kwargs: arguments that are passed to the base class
57
63
 
58
64
  Examples:
@@ -81,6 +87,7 @@ class MPSConfig(EmulationConfig):
81
87
  log_file: pathlib.Path | None = None,
82
88
  autosave_prefix: str = "emu_mps_save_",
83
89
  autosave_dt: int = 600, # 10 minutes
90
+ solver: Solver = Solver.TDVP,
84
91
  **kwargs: Any,
85
92
  ):
86
93
  kwargs.setdefault("observables", [BitStrings(evaluation_times=[1.0])])
@@ -97,6 +104,7 @@ class MPSConfig(EmulationConfig):
97
104
  log_file=log_file,
98
105
  autosave_prefix=autosave_prefix,
99
106
  autosave_dt=autosave_dt,
107
+ solver=solver,
100
108
  **kwargs,
101
109
  )
102
110
  if self.optimize_qubit_ordering:
@@ -144,6 +152,7 @@ class MPSConfig(EmulationConfig):
144
152
  "log_file",
145
153
  "autosave_prefix",
146
154
  "autosave_dt",
155
+ "solver",
147
156
  }
148
157
 
149
158
  def monkeypatch_observables(self) -> None:
emu_mps/solver.py ADDED
@@ -0,0 +1,6 @@
1
+ from enum import Enum
2
+
3
+
4
+ class Solver(str, Enum):
5
+ TDVP = "tdvp"
6
+ DMRG = "dmrg"
emu_mps/solver_utils.py CHANGED
@@ -229,9 +229,9 @@ def evolve_single(
229
229
 
230
230
  def minimize_energy_pair(
231
231
  *,
232
- state_factors: tuple[torch.Tensor],
232
+ state_factors: Sequence[torch.Tensor],
233
233
  baths: tuple[torch.Tensor, torch.Tensor],
234
- ham_factors: tuple[torch.Tensor],
234
+ ham_factors: Sequence[torch.Tensor],
235
235
  orth_center_right: bool,
236
236
  config: MPSConfig,
237
237
  residual_tolerance: float,
emu_mps/utils.py CHANGED
@@ -1,7 +1,5 @@
1
1
  from typing import List, Optional
2
2
  import torch
3
- import random
4
- from collections import Counter
5
3
 
6
4
  from emu_mps import MPSConfig
7
5
 
@@ -111,7 +109,7 @@ def assign_devices(tensors: List[torch.Tensor], num_gpus_to_use: int) -> None:
111
109
 
112
110
 
113
111
  def extended_mps_factors(
114
- mps_factors: list[torch.Tensor], where: list[bool]
112
+ mps_factors: list[torch.Tensor], where: torch.Tensor
115
113
  ) -> list[torch.Tensor]:
116
114
  """
117
115
  Given a valid list of MPS factors, accounting for qubits marked as `True` in `where`,
@@ -149,7 +147,7 @@ def extended_mps_factors(
149
147
 
150
148
 
151
149
  def extended_mpo_factors(
152
- mpo_factors: list[torch.Tensor], where: list[bool]
150
+ mpo_factors: list[torch.Tensor], where: torch.Tensor
153
151
  ) -> list[torch.Tensor]:
154
152
  """
155
153
  Given a valid list of MPO factors, accounting for qubits marked as `True` in `where`,
@@ -184,7 +182,7 @@ def extended_mpo_factors(
184
182
 
185
183
 
186
184
  def get_extended_site_index(
187
- where: list[bool], desired_index: Optional[int]
185
+ where: torch.Tensor, desired_index: Optional[int]
188
186
  ) -> Optional[int]:
189
187
  """
190
188
  Returns the index in `where` that has `desired_index` preceding True elements.
@@ -210,42 +208,6 @@ def get_extended_site_index(
210
208
  raise ValueError(f"Index {desired_index} does not exist")
211
209
 
212
210
 
213
- def readout_with_error(c: str, *, p_false_pos: float, p_false_neg: float) -> str:
214
- # p_false_pos = false positive, p_false_neg = false negative
215
- r = random.random()
216
- if c == "0" and r < p_false_pos:
217
- return "1"
218
-
219
- if c == "1" and r < p_false_neg:
220
- return "0"
221
-
222
- return c
223
-
224
-
225
- def apply_measurement_errors(
226
- bitstrings: Counter[str], *, p_false_pos: float, p_false_neg: float
227
- ) -> Counter[str]:
228
- """
229
- Given a bag of sampled bitstrings, returns another bag of bitstrings
230
- sampled with readout/measurement errors.
231
-
232
- p_false_pos: probability of false positive
233
- p_false_neg: probability of false negative
234
- """
235
-
236
- result: Counter[str] = Counter()
237
- for bitstring, count in bitstrings.items():
238
- for _ in range(count):
239
- bitstring_with_error = "".join(
240
- readout_with_error(c, p_false_pos=p_false_pos, p_false_neg=p_false_neg)
241
- for c in bitstring
242
- )
243
-
244
- result[bitstring_with_error] += 1
245
-
246
- return result
247
-
248
-
249
211
  n_operator: torch.Tensor = torch.tensor(
250
212
  [
251
213
  [0, 0],
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: emu-mps
3
- Version: 2.2.1
3
+ Version: 2.4.0
4
4
  Summary: Pasqal MPS based pulse emulator built on PyTorch
5
5
  Project-URL: Documentation, https://pasqal-io.github.io/emulators/
6
6
  Project-URL: Repository, https://github.com/pasqal-io/emulators
@@ -25,7 +25,7 @@ Classifier: Programming Language :: Python :: 3.10
25
25
  Classifier: Programming Language :: Python :: Implementation :: CPython
26
26
  Classifier: Programming Language :: Python :: Implementation :: PyPy
27
27
  Requires-Python: >=3.10
28
- Requires-Dist: emu-base==2.2.1
28
+ Requires-Dist: emu-base==2.4.0
29
29
  Description-Content-Type: text/markdown
30
30
 
31
31
  <div align="center">
@@ -1,19 +1,19 @@
1
- emu_mps/__init__.py,sha256=iXV15aC4QkDT-W_pEv2vLF1vcZAUtb7GP6D4kBEYxYk,734
1
+ emu_mps/__init__.py,sha256=ySFn8SLcpsp1ndtvv38qg_gTlO9jt_jmwZVZd21hsg0,708
2
2
  emu_mps/algebra.py,sha256=78XP9HEbV3wGNUzIulcLU5HizW4XAYmcFdkCe1T1x-k,5489
3
3
  emu_mps/custom_callback_implementations.py,sha256=SZGKVyS8U5hy07L-3SqpWlCAqGGKFTlSlWexZwSmjrM,2408
4
4
  emu_mps/hamiltonian.py,sha256=gOPxNOBmk6jRPPjevERuCP_scGv0EKYeAJ0uxooihes,15622
5
5
  emu_mps/mpo.py,sha256=aWSVuEzZM-_7ZD5Rz3-tSJWX22ARP0tMIl3gUu-_4V4,7834
6
- emu_mps/mps.py,sha256=8i3Yz5C_cqHWeAJILOm7cz8P8cHDuNl6aBcLXtaO314,19964
6
+ emu_mps/mps.py,sha256=I7LAxoOPKr4me5ZFdL5AZMerg7go9I1fu-MAI0ZBMgU,19973
7
7
  emu_mps/mps_backend.py,sha256=bS83qFxvdoK-c12_1WaPw6O7xUc7vdWifZNHUzNP5sM,2091
8
- emu_mps/mps_backend_impl.py,sha256=SGqL2KiICE1fLviycrRdVlw3LOYRjpF5B0XgQlElSBs,26047
9
- emu_mps/mps_config.py,sha256=PoSKZxJMhG6zfzgEjj4tIvyiyYRQywxkRgidh8MRBsA,8222
10
- emu_mps/noise.py,sha256=5BXthepWLKnuSTJfIFuPl2AcYPxUeTJdRc2b28ekkhg,208
8
+ emu_mps/mps_backend_impl.py,sha256=JG4MlEsImc9izF-iwpgyw1t8q4M_20DxbbD4HDObSz0,30268
9
+ emu_mps/mps_config.py,sha256=58Y9HEExeHm8p7Zm5CVwku7Y1pQmkaBV7M_hKv4PQcA,8629
11
10
  emu_mps/observables.py,sha256=7GQDH5kyaVNrwckk2f8ZJRV9Ca4jKhWWDsOCqYWsoEk,1349
12
- emu_mps/solver_utils.py,sha256=NWwg6AeCCOrx8a5_ysSojdAOmg73W1202FtYx2JEHH0,8544
13
- emu_mps/utils.py,sha256=PRPIe9B8n-6caVcUYn3uTFSvb3jAMkXX-63f8KtX5-U,8196
11
+ emu_mps/solver.py,sha256=M9xkHhlEouTBvoPw2UYVu6kij7CO4Z1FXw_SiGFtdgo,85
12
+ emu_mps/solver_utils.py,sha256=VQ02_RxvPcjyXippuIY4Swpx4EdqtoJTt8Ie70GgdqU,8550
13
+ emu_mps/utils.py,sha256=hgtaRUtBAzk76ab-S_wTVkvqfVOmaUks38zWame9GRQ,7132
14
14
  emu_mps/optimatrix/__init__.py,sha256=fBXQ7-rgDro4hcaBijCGhx3J69W96qcw5_3mWc7tND4,364
15
15
  emu_mps/optimatrix/optimiser.py,sha256=k9suYmKLKlaZ7ozFuIqvXHyCBoCtGgkX1mpen9GOdOo,6977
16
16
  emu_mps/optimatrix/permutations.py,sha256=9DDMZtrGGZ01b9F3GkzHR3paX4qNtZiPoI7Z_Kia3Lc,3727
17
- emu_mps-2.2.1.dist-info/METADATA,sha256=FLJwfRKhNCuaThXQ39P92HcV4Fpz5KxPqyJMddrV-K8,3587
18
- emu_mps-2.2.1.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
19
- emu_mps-2.2.1.dist-info/RECORD,,
17
+ emu_mps-2.4.0.dist-info/METADATA,sha256=6eUzR_h7HcAVtC9Sy3umvCIw-w_bICX98VD-uXjRnxM,3587
18
+ emu_mps-2.4.0.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
19
+ emu_mps-2.4.0.dist-info/RECORD,,
emu_mps/noise.py DELETED
@@ -1,9 +0,0 @@
1
- import random
2
-
3
-
4
- def pick_well_prepared_qubits(eta: float, n: int) -> list[bool]:
5
- """
6
- Randomly pick n booleans such that ℙ(False) = eta.
7
- """
8
-
9
- return [random.random() > eta for _ in range(n)]