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 CHANGED
@@ -38,4 +38,4 @@ __all__ = [
38
38
  "DensityMatrix",
39
39
  ]
40
40
 
41
- __version__ = "2.2.0"
41
+ __version__ = "2.2.1"
@@ -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 energy_sv_impl(
154
- self: Energy,
173
+ def energy_second_moment_den_mat_impl(
174
+ self: EnergyVariance,
155
175
  *,
156
176
  config: EmulationConfig,
157
- state: StateVector,
158
- hamiltonian: RydbergHamiltonian,
177
+ state: DensityMatrix,
178
+ hamiltonian: RydbergLindbladian,
159
179
  ) -> torch.Tensor:
160
180
  """
161
- Custom implementation of the energy ❬ψ|H|ψ❭ for the state vector solver.
181
+ Custom implementation of the second moment of energy tr(ρH²) for the
182
+ lindblad equation solver.
162
183
  """
163
- en: torch.Tensor = hamiltonian.expect(state)
164
- return en
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)
@@ -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
- # apply all local terms: Ωⱼ σₓ - δⱼ n - 0.5i (∑ₖ Lₖ† Lₖ) to each qubit
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
- energy_variance_sv_impl, obs_copy
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
- energy_second_moment_sv_impl, obs_copy
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.0
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.0
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=vVU7zIUsHPgFXUBWMn1lUtkWUg-avdFRqLUrtbmPvDI,771
2
- emu_sv/custom_callback_implementations.py,sha256=j_G5x-xSnFSyKE81QN_DKoiTaF9JvNWaM1N6k2_t0Oo,5501
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=Rlxh24dXVUAutSrSacNO2ilNVlxKix8pfFt7h2CfVOg,7893
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=ixMTgDXKll4bXsYtAe4a_9Gng0bhwCgS42KKMwZCFHI,6308
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.0.dist-info/METADATA,sha256=aw71GDNhy2P9-zjXjXszkLyaOY95qCpPkOmG2lAmYZg,3595
14
- emu_sv-2.2.0.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
15
- emu_sv-2.2.0.dist-info/RECORD,,
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