emu-mps 1.2.6__py3-none-any.whl → 1.2.7__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 +1 -1
- emu_mps/mps.py +52 -41
- emu_mps/mps_backend_impl.py +33 -23
- emu_mps/tdvp.py +1 -0
- emu_mps/utils.py +7 -2
- {emu_mps-1.2.6.dist-info → emu_mps-1.2.7.dist-info}/METADATA +2 -2
- {emu_mps-1.2.6.dist-info → emu_mps-1.2.7.dist-info}/RECORD +8 -8
- {emu_mps-1.2.6.dist-info → emu_mps-1.2.7.dist-info}/WHEEL +0 -0
emu_mps/__init__.py
CHANGED
emu_mps/mps.py
CHANGED
|
@@ -189,11 +189,58 @@ class MPS(State):
|
|
|
189
189
|
"""
|
|
190
190
|
self.orthogonalize(0)
|
|
191
191
|
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
bitstrings = Counter(
|
|
195
|
-
|
|
196
|
-
|
|
192
|
+
rnd_matrix = torch.rand(num_shots, self.num_sites).to(self.factors[0].device)
|
|
193
|
+
|
|
194
|
+
bitstrings: Counter[str] = Counter()
|
|
195
|
+
|
|
196
|
+
# Shots are performed in batches.
|
|
197
|
+
# Larger max_batch_size is faster but uses more memory.
|
|
198
|
+
max_batch_size = 32
|
|
199
|
+
|
|
200
|
+
shots_done = 0
|
|
201
|
+
while shots_done < num_shots:
|
|
202
|
+
batch_size = min(max_batch_size, num_shots - shots_done)
|
|
203
|
+
batched_accumulator = torch.ones(
|
|
204
|
+
batch_size, 1, dtype=torch.complex128, device=self.factors[0].device
|
|
205
|
+
)
|
|
206
|
+
|
|
207
|
+
batch_outcomes = torch.empty(batch_size, self.num_sites, dtype=torch.bool)
|
|
208
|
+
|
|
209
|
+
for qubit, factor in enumerate(self.factors):
|
|
210
|
+
batched_accumulator = torch.tensordot(
|
|
211
|
+
batched_accumulator.to(factor.device), factor, dims=1
|
|
212
|
+
)
|
|
213
|
+
|
|
214
|
+
# Probability of measuring qubit == 0 for each shot in the batch
|
|
215
|
+
probas = (
|
|
216
|
+
torch.linalg.vector_norm(batched_accumulator[:, 0, :], dim=1) ** 2
|
|
217
|
+
)
|
|
218
|
+
|
|
219
|
+
outcomes = (
|
|
220
|
+
rnd_matrix[shots_done : shots_done + batch_size, qubit].to(
|
|
221
|
+
factor.device
|
|
222
|
+
)
|
|
223
|
+
> probas
|
|
224
|
+
)
|
|
225
|
+
batch_outcomes[:, qubit] = outcomes
|
|
226
|
+
|
|
227
|
+
# Batch collapse qubit
|
|
228
|
+
tmp = torch.stack((~outcomes, outcomes), dim=1).to(dtype=torch.complex128)
|
|
229
|
+
|
|
230
|
+
batched_accumulator = (
|
|
231
|
+
torch.tensordot(batched_accumulator, tmp, dims=([1], [1]))
|
|
232
|
+
.diagonal(dim1=0, dim2=2)
|
|
233
|
+
.transpose(1, 0)
|
|
234
|
+
)
|
|
235
|
+
batched_accumulator /= torch.sqrt(
|
|
236
|
+
(~outcomes) * probas + outcomes * (1 - probas)
|
|
237
|
+
).unsqueeze(1)
|
|
238
|
+
|
|
239
|
+
shots_done += batch_size
|
|
240
|
+
|
|
241
|
+
for outcome in batch_outcomes:
|
|
242
|
+
bitstrings.update(["".join("0" if x == 0 else "1" for x in outcome)])
|
|
243
|
+
|
|
197
244
|
if p_false_neg > 0 or p_false_pos > 0:
|
|
198
245
|
bitstrings = apply_measurement_errors(
|
|
199
246
|
bitstrings,
|
|
@@ -214,42 +261,6 @@ class MPS(State):
|
|
|
214
261
|
torch.linalg.norm(self.factors[orthogonality_center].to("cpu")).item()
|
|
215
262
|
)
|
|
216
263
|
|
|
217
|
-
def _sample_implementation(self, rnd_vector: torch.Tensor) -> str:
|
|
218
|
-
"""
|
|
219
|
-
Samples this MPS once, returning the resulting bitstring.
|
|
220
|
-
"""
|
|
221
|
-
assert rnd_vector.shape == (self.num_sites,)
|
|
222
|
-
assert self.orthogonality_center == 0
|
|
223
|
-
|
|
224
|
-
num_qubits = len(self.factors)
|
|
225
|
-
|
|
226
|
-
bitstring = ""
|
|
227
|
-
acc_mps_j: torch.Tensor = self.factors[0]
|
|
228
|
-
|
|
229
|
-
for qubit in range(num_qubits):
|
|
230
|
-
# comp_basis is a projector: 0 is for ket |0> and 1 for ket |1>
|
|
231
|
-
comp_basis = 0 # check if the qubit is in |0>
|
|
232
|
-
# Measure the qubit j by applying the projector onto nth comp basis state
|
|
233
|
-
tensorj_projected_n = acc_mps_j[:, comp_basis, :]
|
|
234
|
-
probability_n = (tensorj_projected_n.norm() ** 2).item()
|
|
235
|
-
|
|
236
|
-
if rnd_vector[qubit] > probability_n:
|
|
237
|
-
# the qubit is in |1>
|
|
238
|
-
comp_basis = 1
|
|
239
|
-
tensorj_projected_n = acc_mps_j[:, comp_basis, :]
|
|
240
|
-
probability_n = 1 - probability_n
|
|
241
|
-
|
|
242
|
-
bitstring += str(comp_basis)
|
|
243
|
-
if qubit < num_qubits - 1:
|
|
244
|
-
acc_mps_j = torch.tensordot(
|
|
245
|
-
tensorj_projected_n.to(device=self.factors[qubit + 1].device),
|
|
246
|
-
self.factors[qubit + 1],
|
|
247
|
-
dims=1,
|
|
248
|
-
)
|
|
249
|
-
acc_mps_j /= math.sqrt(probability_n)
|
|
250
|
-
|
|
251
|
-
return bitstring
|
|
252
|
-
|
|
253
264
|
def inner(self, other: State) -> float | complex:
|
|
254
265
|
"""
|
|
255
266
|
Compute the inner product between this state and other.
|
emu_mps/mps_backend_impl.py
CHANGED
|
@@ -54,7 +54,8 @@ class MPSBackendImpl:
|
|
|
54
54
|
|
|
55
55
|
def __init__(self, mps_config: MPSConfig, pulser_data: PulserData):
|
|
56
56
|
self.config = mps_config
|
|
57
|
-
self.
|
|
57
|
+
self.target_times = pulser_data.target_times
|
|
58
|
+
self.target_time = self.target_times[1]
|
|
58
59
|
self.pulser_data = pulser_data
|
|
59
60
|
self.qubit_count = pulser_data.qubit_count
|
|
60
61
|
assert self.qubit_count >= 2
|
|
@@ -94,18 +95,16 @@ class MPSBackendImpl:
|
|
|
94
95
|
return pathlib.Path(os.getcwd()) / (autosave_prefix + str(uuid.uuid1()) + ".dat")
|
|
95
96
|
|
|
96
97
|
def init_dark_qubits(self) -> None:
|
|
97
|
-
has_state_preparation_error
|
|
98
|
+
# has_state_preparation_error
|
|
99
|
+
if (
|
|
98
100
|
self.config.noise_model is not None
|
|
99
101
|
and self.config.noise_model.state_prep_error > 0.0
|
|
100
|
-
)
|
|
101
|
-
|
|
102
|
-
self.well_prepared_qubits_filter = (
|
|
103
|
-
pick_well_prepared_qubits(
|
|
102
|
+
):
|
|
103
|
+
self.well_prepared_qubits_filter = pick_well_prepared_qubits(
|
|
104
104
|
self.config.noise_model.state_prep_error, self.qubit_count
|
|
105
105
|
)
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
)
|
|
106
|
+
else:
|
|
107
|
+
self.well_prepared_qubits_filter = None
|
|
109
108
|
|
|
110
109
|
if self.well_prepared_qubits_filter is not None:
|
|
111
110
|
self.qubit_count = sum(1 for x in self.well_prepared_qubits_filter if x)
|
|
@@ -152,9 +151,11 @@ class MPSBackendImpl:
|
|
|
152
151
|
too many factors are put in the Hamiltonian
|
|
153
152
|
"""
|
|
154
153
|
self.hamiltonian = make_H(
|
|
155
|
-
interaction_matrix=
|
|
156
|
-
|
|
157
|
-
|
|
154
|
+
interaction_matrix=(
|
|
155
|
+
self.masked_interaction_matrix
|
|
156
|
+
if self.is_masked
|
|
157
|
+
else self.full_interaction_matrix
|
|
158
|
+
),
|
|
158
159
|
hamiltonian_type=self.hamiltonian_type,
|
|
159
160
|
num_gpus_to_use=self.config.num_gpus_to_use,
|
|
160
161
|
)
|
|
@@ -176,6 +177,12 @@ class MPSBackendImpl:
|
|
|
176
177
|
self.right_baths = right_baths(self.state, self.hamiltonian, final_qubit=2)
|
|
177
178
|
assert len(self.right_baths) == self.qubit_count - 1
|
|
178
179
|
|
|
180
|
+
def get_current_right_bath(self) -> torch.Tensor:
|
|
181
|
+
return self.right_baths[-1]
|
|
182
|
+
|
|
183
|
+
def get_current_left_bath(self) -> torch.Tensor:
|
|
184
|
+
return self.left_baths[-1]
|
|
185
|
+
|
|
179
186
|
def init(self) -> None:
|
|
180
187
|
self.init_dark_qubits()
|
|
181
188
|
self.init_initial_state(self.config.initial_state)
|
|
@@ -196,7 +203,7 @@ class MPSBackendImpl:
|
|
|
196
203
|
"""
|
|
197
204
|
assert 1 <= len(indices) <= 2
|
|
198
205
|
|
|
199
|
-
baths = (self.
|
|
206
|
+
baths = (self.get_current_left_bath(), self.get_current_right_bath())
|
|
200
207
|
|
|
201
208
|
if len(indices) == 1:
|
|
202
209
|
assert orth_center_right is None
|
|
@@ -268,10 +275,10 @@ class MPSBackendImpl:
|
|
|
268
275
|
)
|
|
269
276
|
self.left_baths.append(
|
|
270
277
|
new_left_bath(
|
|
271
|
-
self.
|
|
278
|
+
self.get_current_left_bath(),
|
|
272
279
|
self.state.factors[self.tdvp_index],
|
|
273
280
|
self.hamiltonian.factors[self.tdvp_index],
|
|
274
|
-
)
|
|
281
|
+
).to(self.state.factors[self.tdvp_index + 1].device)
|
|
275
282
|
)
|
|
276
283
|
self._evolve(self.tdvp_index + 1, dt=-delta_time / 2)
|
|
277
284
|
self.right_baths.pop()
|
|
@@ -297,10 +304,10 @@ class MPSBackendImpl:
|
|
|
297
304
|
assert self.tdvp_index <= self.qubit_count - 2
|
|
298
305
|
self.right_baths.append(
|
|
299
306
|
new_right_bath(
|
|
300
|
-
self.
|
|
307
|
+
self.get_current_right_bath(),
|
|
301
308
|
self.state.factors[self.tdvp_index + 1],
|
|
302
309
|
self.hamiltonian.factors[self.tdvp_index + 1],
|
|
303
|
-
)
|
|
310
|
+
).to(self.state.factors[self.tdvp_index].device)
|
|
304
311
|
)
|
|
305
312
|
if not self.has_lindblad_noise:
|
|
306
313
|
# Free memory because it won't be used anymore
|
|
@@ -333,7 +340,6 @@ class MPSBackendImpl:
|
|
|
333
340
|
def timestep_complete(self) -> None:
|
|
334
341
|
self.fill_results()
|
|
335
342
|
self.timestep_index += 1
|
|
336
|
-
self.target_time = float((self.timestep_index + 1) * self.config.dt)
|
|
337
343
|
if self.is_masked and self.current_time >= self.slm_end_time:
|
|
338
344
|
self.is_masked = False
|
|
339
345
|
self.hamiltonian = make_H(
|
|
@@ -343,6 +349,7 @@ class MPSBackendImpl:
|
|
|
343
349
|
)
|
|
344
350
|
|
|
345
351
|
if not self.is_finished():
|
|
352
|
+
self.target_time = self.target_times[self.timestep_index + 1]
|
|
346
353
|
update_H(
|
|
347
354
|
hamiltonian=self.hamiltonian,
|
|
348
355
|
omega=self.omega[self.timestep_index, :],
|
|
@@ -479,12 +486,15 @@ class NoisyMPSBackendImpl(MPSBackendImpl):
|
|
|
479
486
|
self.aggregated_lindblad_ops = stacked.conj().transpose(1, 2) @ stacked
|
|
480
487
|
|
|
481
488
|
self.lindblad_noise = compute_noise_from_lindbladians(self.lindblad_ops)
|
|
482
|
-
|
|
489
|
+
|
|
490
|
+
def set_jump_threshold(self, bound: float) -> None:
|
|
491
|
+
self.jump_threshold = random.uniform(0.0, bound)
|
|
483
492
|
self.norm_gap_before_jump = self.state.norm() ** 2 - self.jump_threshold
|
|
484
493
|
|
|
485
494
|
def init(self) -> None:
|
|
486
|
-
super().init()
|
|
487
495
|
self.init_lindblad_noise()
|
|
496
|
+
super().init()
|
|
497
|
+
self.set_jump_threshold(1.0)
|
|
488
498
|
|
|
489
499
|
def tdvp_complete(self) -> None:
|
|
490
500
|
previous_time = self.current_time
|
|
@@ -515,7 +525,7 @@ class NoisyMPSBackendImpl(MPSBackendImpl):
|
|
|
515
525
|
|
|
516
526
|
if self.root_finder.is_converged(tolerance=1):
|
|
517
527
|
self.do_random_quantum_jump()
|
|
518
|
-
self.target_time =
|
|
528
|
+
self.target_time = self.target_times[self.timestep_index + 1]
|
|
519
529
|
self.root_finder = None
|
|
520
530
|
else:
|
|
521
531
|
self.target_time = self.root_finder.get_next_abscissa()
|
|
@@ -534,11 +544,11 @@ class NoisyMPSBackendImpl(MPSBackendImpl):
|
|
|
534
544
|
self.state.apply(jumped_qubit_index, jump_operator)
|
|
535
545
|
self.state.orthogonalize(0)
|
|
536
546
|
self.state *= 1 / self.state.norm()
|
|
547
|
+
self.init_baths()
|
|
537
548
|
|
|
538
549
|
norm_after_normalizing = self.state.norm()
|
|
539
550
|
assert math.isclose(norm_after_normalizing, 1, abs_tol=1e-10)
|
|
540
|
-
self.
|
|
541
|
-
self.norm_gap_before_jump = norm_after_normalizing**2 - self.jump_threshold
|
|
551
|
+
self.set_jump_threshold(norm_after_normalizing**2)
|
|
542
552
|
|
|
543
553
|
def fill_results(self) -> None:
|
|
544
554
|
# Remove the noise from self.hamiltonian for the callbacks.
|
emu_mps/tdvp.py
CHANGED
|
@@ -117,6 +117,7 @@ def evolve_pair(
|
|
|
117
117
|
|
|
118
118
|
left_ham_factor = left_ham_factor.to(left_device)
|
|
119
119
|
right_ham_factor = right_ham_factor.to(left_device)
|
|
120
|
+
right_bath = right_bath.to(left_device)
|
|
120
121
|
|
|
121
122
|
combined_hamiltonian_factors = (
|
|
122
123
|
torch.tensordot(left_ham_factor, right_ham_factor, dims=1)
|
emu_mps/utils.py
CHANGED
|
@@ -130,13 +130,18 @@ def extended_mps_factors(
|
|
|
130
130
|
bond_dimension = mps_factors[factor_index].shape[2]
|
|
131
131
|
factor_index += 1
|
|
132
132
|
elif factor_index == len(mps_factors):
|
|
133
|
-
factor = torch.zeros(
|
|
133
|
+
factor = torch.zeros(
|
|
134
|
+
bond_dimension, 2, 1, dtype=torch.complex128
|
|
135
|
+
) # FIXME: assign device
|
|
134
136
|
factor[:, 0, :] = torch.eye(bond_dimension, 1)
|
|
135
137
|
bond_dimension = 1
|
|
136
138
|
result.append(factor)
|
|
137
139
|
else:
|
|
138
140
|
factor = torch.zeros(
|
|
139
|
-
bond_dimension,
|
|
141
|
+
bond_dimension,
|
|
142
|
+
2,
|
|
143
|
+
bond_dimension,
|
|
144
|
+
dtype=torch.complex128, # FIXME: assign device
|
|
140
145
|
)
|
|
141
146
|
factor[:, 0, :] = torch.eye(bond_dimension, bond_dimension)
|
|
142
147
|
result.append(factor)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: emu-mps
|
|
3
|
-
Version: 1.2.
|
|
3
|
+
Version: 1.2.7
|
|
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==1.2.
|
|
28
|
+
Requires-Dist: emu-base==1.2.7
|
|
29
29
|
Description-Content-Type: text/markdown
|
|
30
30
|
|
|
31
31
|
<div align="center">
|
|
@@ -1,17 +1,17 @@
|
|
|
1
|
-
emu_mps/__init__.py,sha256=
|
|
1
|
+
emu_mps/__init__.py,sha256=KSTZWIZSKHhjt0yt8-fS23rFFcFVQciNiXBgHS0pnHU,646
|
|
2
2
|
emu_mps/algebra.py,sha256=ngPtTH-j2ZCBWoaJZXlkUyIlug7dY7Q92gzfnRlpPMA,5485
|
|
3
3
|
emu_mps/hamiltonian.py,sha256=LcBs6CKBb643a1e9AAVtQoUfa4L_0dIhLOKecx5OOWs,15864
|
|
4
4
|
emu_mps/mpo.py,sha256=H5vkJvz4AfXfnPbvgWznBWpMUO8LnGL3_NAP3IhxZzQ,8740
|
|
5
|
-
emu_mps/mps.py,sha256=
|
|
5
|
+
emu_mps/mps.py,sha256=J0I4oQP_F1woEKmnOqnXPOWxx2Y1addxNjosL3yhYAY,18214
|
|
6
6
|
emu_mps/mps_backend.py,sha256=6fVaq-D4xyicYRjGjhqMEieC7---90LpfpbV7ZD7zkQ,2192
|
|
7
|
-
emu_mps/mps_backend_impl.py,sha256=
|
|
7
|
+
emu_mps/mps_backend_impl.py,sha256=XT2HccHWd6Y1gIAs070pBxjPUPIHBl-hFCuqXJaPS-E,21256
|
|
8
8
|
emu_mps/mps_config.py,sha256=ydKN0OOaWCBcNd9V-4CU5ZZ4w1FRT-bbKyZQD2WCaME,3317
|
|
9
9
|
emu_mps/noise.py,sha256=h4X2EFjoC_Ok0gZ8I9wN77RANXaVehTBbjkcbY_GAmY,784
|
|
10
|
-
emu_mps/tdvp.py,sha256=
|
|
11
|
-
emu_mps/utils.py,sha256=
|
|
10
|
+
emu_mps/tdvp.py,sha256=pIQ2NXA2Mrkp3elhqQbX3pdJVbtKkG3c5r9fFlJo7pI,5755
|
|
11
|
+
emu_mps/utils.py,sha256=BqRJYAcXqprtZVJ0V_j954ON2bhTdtZiaTojsYyrWrg,8193
|
|
12
12
|
emu_mps/optimatrix/__init__.py,sha256=lHWYNeThHp57ZrwTwXd0p8bNvcCv0w_AZ31iCWflBUo,226
|
|
13
13
|
emu_mps/optimatrix/optimiser.py,sha256=cVMdm2r_4OpbthcQuFMrJ9rNR9WEJRga9c_lHrJFkhw,6687
|
|
14
14
|
emu_mps/optimatrix/permutations.py,sha256=JRXGont8B4QgbkV9CzrA0w7uzLgBrmZ1J9aa0G52hPo,1979
|
|
15
|
-
emu_mps-1.2.
|
|
16
|
-
emu_mps-1.2.
|
|
17
|
-
emu_mps-1.2.
|
|
15
|
+
emu_mps-1.2.7.dist-info/METADATA,sha256=-yHfBZrLmNsmc-tA-Yb0KfmxULGgVrcLVUbx4F37oA4,3505
|
|
16
|
+
emu_mps-1.2.7.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
|
17
|
+
emu_mps-1.2.7.dist-info/RECORD,,
|
|
File without changes
|