emu-sv 2.2.0__py3-none-any.whl → 2.2.1__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_sv/__init__.py +1 -1
- emu_sv/custom_callback_implementations.py +33 -8
- emu_sv/lindblad_operator.py +56 -36
- emu_sv/sv_config.py +14 -7
- {emu_sv-2.2.0.dist-info → emu_sv-2.2.1.dist-info}/METADATA +2 -2
- {emu_sv-2.2.0.dist-info → emu_sv-2.2.1.dist-info}/RECORD +7 -7
- {emu_sv-2.2.0.dist-info → emu_sv-2.2.1.dist-info}/WHEEL +0 -0
emu_sv/__init__.py
CHANGED
|
@@ -6,12 +6,12 @@ from pulser.backend import (
|
|
|
6
6
|
EnergySecondMoment,
|
|
7
7
|
EnergyVariance,
|
|
8
8
|
Occupation,
|
|
9
|
-
Energy,
|
|
10
9
|
)
|
|
11
10
|
from emu_sv.density_matrix_state import DensityMatrix
|
|
12
11
|
from emu_sv.state_vector import StateVector
|
|
13
12
|
from emu_sv.dense_operator import DenseOperator
|
|
14
13
|
from emu_sv.hamiltonian import RydbergHamiltonian
|
|
14
|
+
from emu_sv.lindblad_operator import RydbergLindbladian
|
|
15
15
|
|
|
16
16
|
dtype = torch.float64
|
|
17
17
|
|
|
@@ -134,6 +134,26 @@ def energy_variance_sv_impl(
|
|
|
134
134
|
return en_var.cpu()
|
|
135
135
|
|
|
136
136
|
|
|
137
|
+
def energy_variance_sv_den_mat_impl(
|
|
138
|
+
self: EnergyVariance,
|
|
139
|
+
*,
|
|
140
|
+
config: EmulationConfig,
|
|
141
|
+
state: DensityMatrix,
|
|
142
|
+
hamiltonian: RydbergLindbladian,
|
|
143
|
+
) -> torch.Tensor:
|
|
144
|
+
"""
|
|
145
|
+
Custom implementation of the energy variance tr(ρH²)-tr(ρH)² for the
|
|
146
|
+
lindblad equation solver.
|
|
147
|
+
"""
|
|
148
|
+
h_dense_matrix = hamiltonian.h_eff(state.matrix) # Hρ
|
|
149
|
+
gpu = state.matrix.is_cuda
|
|
150
|
+
h_squared_dense_mat = hamiltonian.expect(
|
|
151
|
+
DensityMatrix(h_dense_matrix, gpu=gpu)
|
|
152
|
+
) # tr(ρH²)
|
|
153
|
+
en_var: torch.Tensor = h_squared_dense_mat - hamiltonian.expect(state) ** 2 # tr(ρH)²
|
|
154
|
+
return en_var.cpu()
|
|
155
|
+
|
|
156
|
+
|
|
137
157
|
def energy_second_moment_sv_impl(
|
|
138
158
|
self: EnergySecondMoment,
|
|
139
159
|
*,
|
|
@@ -150,15 +170,20 @@ def energy_second_moment_sv_impl(
|
|
|
150
170
|
return en_2_mom.cpu()
|
|
151
171
|
|
|
152
172
|
|
|
153
|
-
def
|
|
154
|
-
self:
|
|
173
|
+
def energy_second_moment_den_mat_impl(
|
|
174
|
+
self: EnergyVariance,
|
|
155
175
|
*,
|
|
156
176
|
config: EmulationConfig,
|
|
157
|
-
state:
|
|
158
|
-
hamiltonian:
|
|
177
|
+
state: DensityMatrix,
|
|
178
|
+
hamiltonian: RydbergLindbladian,
|
|
159
179
|
) -> torch.Tensor:
|
|
160
180
|
"""
|
|
161
|
-
Custom implementation of the energy
|
|
181
|
+
Custom implementation of the second moment of energy tr(ρH²) for the
|
|
182
|
+
lindblad equation solver.
|
|
162
183
|
"""
|
|
163
|
-
|
|
164
|
-
|
|
184
|
+
h_dense_matrix = hamiltonian.h_eff(state.matrix) # Hρ
|
|
185
|
+
gpu = state.matrix.is_cuda
|
|
186
|
+
|
|
187
|
+
return hamiltonian.expect(
|
|
188
|
+
DensityMatrix(h_dense_matrix, gpu=gpu)
|
|
189
|
+
).cpu() # tr(ρH²) = tr(ρ H H)
|
emu_sv/lindblad_operator.py
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import torch
|
|
2
2
|
from emu_base import compute_noise_from_lindbladians, matmul_2x2_with_batched
|
|
3
|
-
|
|
3
|
+
from emu_sv.density_matrix_state import DensityMatrix
|
|
4
4
|
|
|
5
5
|
dtype = torch.complex128
|
|
6
6
|
sigmax = torch.tensor([[0.0, 1.0], [1.0, 0.0]], dtype=dtype)
|
|
@@ -129,6 +129,52 @@ class RydbergLindbladian:
|
|
|
129
129
|
|
|
130
130
|
return density_matrix.view(orignal_shape)
|
|
131
131
|
|
|
132
|
+
def h_eff(
|
|
133
|
+
self,
|
|
134
|
+
density_matrix: torch.Tensor,
|
|
135
|
+
lindblad_ops: torch.Tensor = torch.zeros(2, 2, dtype=dtype),
|
|
136
|
+
) -> torch.Tensor:
|
|
137
|
+
"""Compute the effective Hamiltonian, Heff = Hρ -0.5i ∑ₖ Lₖ† Lₖ ρ, applied
|
|
138
|
+
to a density matrix ρ.
|
|
139
|
+
- libdlad_ops by default are 2x2 zero matrix"""
|
|
140
|
+
H_den_matrix = torch.zeros_like(density_matrix, dtype=dtype, device=self.device)
|
|
141
|
+
|
|
142
|
+
for qubit in range(len(self.omegas)):
|
|
143
|
+
H_q = self._local_terms_hamiltonian(qubit, lindblad_ops.to(self.device))
|
|
144
|
+
H_den_matrix += self.apply_local_op_to_density_matrix(
|
|
145
|
+
density_matrix, H_q, qubit
|
|
146
|
+
)
|
|
147
|
+
|
|
148
|
+
H_den_matrix += self._apply_interaction_terms(density_matrix)
|
|
149
|
+
return H_den_matrix
|
|
150
|
+
|
|
151
|
+
def _local_terms_hamiltonian(
|
|
152
|
+
self, qubit: int, lindblad_ops: torch.Tensor
|
|
153
|
+
) -> torch.Tensor:
|
|
154
|
+
"""Construct the Hamiltonian for single qubit terms:
|
|
155
|
+
∑ᵢ 𝛺ᵢ /2 𝜎ₓ^ i − 𝛿ⁱ nᵢ + jump operators terms , including the sum
|
|
156
|
+
of Lindblad terms, when 𝜙ᵢ equals to 0.0.
|
|
157
|
+
When 𝜙ᵢ not equals to 0.0:
|
|
158
|
+
∑ᵢ 𝛺ᵢ /2 (cos (𝜙ᵢ) 𝜎ₓ^ i + sin(𝜙ᵢ)𝜎_yⁱ) − 𝛿ⁱ nᵢ + jump operators terms
|
|
159
|
+
"""
|
|
160
|
+
omega = self.omegas[qubit]
|
|
161
|
+
delta = self.deltas[qubit]
|
|
162
|
+
|
|
163
|
+
sigma_x = sigmax.to(device=self.device)
|
|
164
|
+
n = n_op.to(device=self.device)
|
|
165
|
+
|
|
166
|
+
if not self.complex:
|
|
167
|
+
return omega * sigma_x - delta * n + lindblad_ops.to(self.device)
|
|
168
|
+
|
|
169
|
+
phi = self.phis[qubit]
|
|
170
|
+
sigma_y = sigmay.to(device=self.device)
|
|
171
|
+
complex_part = torch.cos(phi) * sigma_x + torch.sin(phi) * sigma_y
|
|
172
|
+
return omega * complex_part - delta * n + lindblad_ops.to(self.device)
|
|
173
|
+
|
|
174
|
+
def _apply_interaction_terms(self, density_matrix: torch.Tensor) -> torch.Tensor:
|
|
175
|
+
"""Apply the interaction terms ∑ᵢⱼ Uᵢⱼ nᵢ nⱼ to the density matrix."""
|
|
176
|
+
return self.diag.view(-1, 1) * density_matrix
|
|
177
|
+
|
|
132
178
|
def __matmul__(self, density_matrix: torch.Tensor) -> torch.Tensor:
|
|
133
179
|
"""Apply the i*RydbergLindbladian operator to the density matrix ρ
|
|
134
180
|
in the following way:
|
|
@@ -142,41 +188,8 @@ class RydbergLindbladian:
|
|
|
142
188
|
sum_lindblad_local = compute_noise_from_lindbladians(self.pulser_linblads).to(
|
|
143
189
|
self.device
|
|
144
190
|
)
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
H_den_matrix = torch.zeros_like(density_matrix, dtype=dtype, device=self.device)
|
|
148
|
-
|
|
149
|
-
if not self.complex:
|
|
150
|
-
for qubit, (omega, delta) in enumerate(zip(self.omegas, self.deltas)):
|
|
151
|
-
H_q = (
|
|
152
|
-
omega * sigmax.to(device=self.device)
|
|
153
|
-
- delta * n_op.to(device=self.device)
|
|
154
|
-
+ sum_lindblad_local
|
|
155
|
-
)
|
|
156
|
-
H_den_matrix += self.apply_local_op_to_density_matrix(
|
|
157
|
-
density_matrix, H_q, qubit
|
|
158
|
-
)
|
|
159
|
-
else:
|
|
160
|
-
for qubit, (omega, delta, phi) in enumerate(
|
|
161
|
-
zip(self.omegas, self.deltas, self.phis)
|
|
162
|
-
):
|
|
163
|
-
H_q = (
|
|
164
|
-
omega
|
|
165
|
-
* (
|
|
166
|
-
(
|
|
167
|
-
torch.cos(phi) * sigmax.to(device=self.device)
|
|
168
|
-
+ torch.sin(phi) * sigmay.to(device=self.device)
|
|
169
|
-
)
|
|
170
|
-
)
|
|
171
|
-
- delta * n_op.to(device=self.device)
|
|
172
|
-
+ sum_lindblad_local
|
|
173
|
-
)
|
|
174
|
-
H_den_matrix += self.apply_local_op_to_density_matrix(
|
|
175
|
-
density_matrix, H_q, qubit
|
|
176
|
-
)
|
|
177
|
-
|
|
178
|
-
# apply the interaction terms ∑ᵢⱼ Uᵢⱼ nᵢ nⱼ
|
|
179
|
-
H_den_matrix += self.diag.view(-1, 1) * density_matrix
|
|
191
|
+
# Heff = Hρ -0.5i ∑ₖ Lₖ† Lₖ ρ
|
|
192
|
+
H_den_matrix = self.h_eff(density_matrix, sum_lindblad_local)
|
|
180
193
|
|
|
181
194
|
# Heff - Heff^†= [H, ρ] - 0.5i ∑ₖ Lₖ† Lₖρ - ρ 0.5i ∑ₖ Lₖ† Lₖρ
|
|
182
195
|
H_den_matrix = H_den_matrix - H_den_matrix.conj().T
|
|
@@ -195,3 +208,10 @@ class RydbergLindbladian:
|
|
|
195
208
|
)
|
|
196
209
|
|
|
197
210
|
return H_den_matrix + 1.0j * L_den_matrix_Ldag
|
|
211
|
+
|
|
212
|
+
def expect(self, state: DensityMatrix) -> torch.Tensor:
|
|
213
|
+
"""Return the energy expectation value E=tr(H𝜌)"""
|
|
214
|
+
en = (self.h_eff(state.matrix)).trace()
|
|
215
|
+
|
|
216
|
+
assert torch.allclose(en.imag, torch.zeros_like(en.imag), atol=1e-8)
|
|
217
|
+
return en.real
|
emu_sv/sv_config.py
CHANGED
|
@@ -9,7 +9,9 @@ from emu_sv.custom_callback_implementations import (
|
|
|
9
9
|
correlation_matrix_sv_impl,
|
|
10
10
|
correlation_matrix_sv_den_mat_impl,
|
|
11
11
|
energy_second_moment_sv_impl,
|
|
12
|
+
energy_second_moment_den_mat_impl,
|
|
12
13
|
energy_variance_sv_impl,
|
|
14
|
+
energy_variance_sv_den_mat_impl,
|
|
13
15
|
qubit_occupation_sv_impl,
|
|
14
16
|
qubit_occupation_sv_den_mat_impl,
|
|
15
17
|
)
|
|
@@ -144,17 +146,22 @@ class SVConfig(EmulationConfig):
|
|
|
144
146
|
obs_copy,
|
|
145
147
|
)
|
|
146
148
|
if isinstance(obs, EnergyVariance):
|
|
147
|
-
if self.noise_model.noise_types != ():
|
|
148
|
-
raise Exception("Not implemented for density matrix")
|
|
149
149
|
obs_copy.apply = MethodType( # type: ignore[method-assign]
|
|
150
|
-
|
|
150
|
+
(
|
|
151
|
+
energy_variance_sv_impl
|
|
152
|
+
if self.noise_model.noise_types == ()
|
|
153
|
+
else energy_variance_sv_den_mat_impl
|
|
154
|
+
),
|
|
155
|
+
obs_copy,
|
|
151
156
|
)
|
|
152
157
|
elif isinstance(obs, EnergySecondMoment):
|
|
153
|
-
if self.noise_model.noise_types != ():
|
|
154
|
-
raise Exception("Not implemented for density matrix")
|
|
155
|
-
|
|
156
158
|
obs_copy.apply = MethodType( # type: ignore[method-assign]
|
|
157
|
-
|
|
159
|
+
(
|
|
160
|
+
energy_second_moment_sv_impl
|
|
161
|
+
if self.noise_model.noise_types == ()
|
|
162
|
+
else energy_second_moment_den_mat_impl
|
|
163
|
+
),
|
|
164
|
+
obs_copy,
|
|
158
165
|
)
|
|
159
166
|
obs_list.append(obs_copy)
|
|
160
167
|
self.observables = tuple(obs_list)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: emu-sv
|
|
3
|
-
Version: 2.2.
|
|
3
|
+
Version: 2.2.1
|
|
4
4
|
Summary: Pasqal State Vector 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.
|
|
28
|
+
Requires-Dist: emu-base==2.2.1
|
|
29
29
|
Description-Content-Type: text/markdown
|
|
30
30
|
|
|
31
31
|
<div align="center">
|
|
@@ -1,15 +1,15 @@
|
|
|
1
|
-
emu_sv/__init__.py,sha256=
|
|
2
|
-
emu_sv/custom_callback_implementations.py,sha256=
|
|
1
|
+
emu_sv/__init__.py,sha256=sREepAk-h3a3-e7PGexVNmYmj5hf4fVIrKk78vnDKiE,771
|
|
2
|
+
emu_sv/custom_callback_implementations.py,sha256=_7XLIDzJ-p3DVqz-Jyv0eYbl8nih2x2p-pM4cBCLumA,6367
|
|
3
3
|
emu_sv/dense_operator.py,sha256=NfgzVpnNitc5ZSM4RlfpAc5Ls2wFPNsTxdeFdhJSg1o,6909
|
|
4
4
|
emu_sv/density_matrix_state.py,sha256=5W_UKIAYHb0k3ryRLQ2dbFUgrb5ju5jceDGAekM2gNE,7035
|
|
5
5
|
emu_sv/hamiltonian.py,sha256=CqNGuWJlO2ZljK47wt130s-5uKiOldQUsC3tjwk1mKA,6106
|
|
6
|
-
emu_sv/lindblad_operator.py,sha256=
|
|
6
|
+
emu_sv/lindblad_operator.py,sha256=pgjRNLBcvEM2-qxM8uy9wL74OtrD4A8trQeERi_AXH8,8892
|
|
7
7
|
emu_sv/state_vector.py,sha256=zKHCdgl_eRIOPE4qVKO53ig9UyYTQ7a_guNFXgynU7g,9753
|
|
8
8
|
emu_sv/sv_backend.py,sha256=-soOkSEzEBK1dCKnYnbtvYjmNZtZra1_4jP3H1ROOtM,737
|
|
9
9
|
emu_sv/sv_backend_impl.py,sha256=mdPWBLDwH0q7EEwQTmLNLLx5tycMmsCQbUifIHvciMk,8059
|
|
10
|
-
emu_sv/sv_config.py,sha256=
|
|
10
|
+
emu_sv/sv_config.py,sha256=0geciKkrF3h8pU_UAQ8R-G6WxfYb_X5XIrxZavGxK5Q,6511
|
|
11
11
|
emu_sv/time_evolution.py,sha256=_VH4f2RF6lGKzO08WxTYJ5Aw8_pTTMRKcyMnIuxH03I,13382
|
|
12
12
|
emu_sv/utils.py,sha256=-axfQ2tqw0C7I9yw-28g7lytyk373DNBjDALh4kLBrM,302
|
|
13
|
-
emu_sv-2.2.
|
|
14
|
-
emu_sv-2.2.
|
|
15
|
-
emu_sv-2.2.
|
|
13
|
+
emu_sv-2.2.1.dist-info/METADATA,sha256=_NvCSEGYdw9ZXATsZKME-GX0ECeiJcDy8MthY9C5ZUU,3595
|
|
14
|
+
emu_sv-2.2.1.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
|
15
|
+
emu_sv-2.2.1.dist-info/RECORD,,
|
|
File without changes
|