tensorcircuit-nightly 1.2.0.dev20250326__py3-none-any.whl → 1.4.0.dev20251128__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.
Potentially problematic release.
This version of tensorcircuit-nightly might be problematic. Click here for more details.
- tensorcircuit/__init__.py +5 -1
- tensorcircuit/abstractcircuit.py +4 -0
- tensorcircuit/analogcircuit.py +413 -0
- tensorcircuit/applications/layers.py +1 -1
- tensorcircuit/applications/van.py +1 -1
- tensorcircuit/backends/abstract_backend.py +312 -5
- tensorcircuit/backends/cupy_backend.py +3 -1
- tensorcircuit/backends/jax_backend.py +100 -4
- tensorcircuit/backends/jax_ops.py +108 -0
- tensorcircuit/backends/numpy_backend.py +49 -3
- tensorcircuit/backends/pytorch_backend.py +92 -3
- tensorcircuit/backends/tensorflow_backend.py +102 -3
- tensorcircuit/basecircuit.py +157 -98
- tensorcircuit/circuit.py +115 -57
- tensorcircuit/cloud/local.py +1 -1
- tensorcircuit/cloud/quafu_provider.py +1 -1
- tensorcircuit/cloud/tencent.py +1 -1
- tensorcircuit/compiler/simple_compiler.py +2 -2
- tensorcircuit/cons.py +105 -23
- tensorcircuit/densitymatrix.py +16 -11
- tensorcircuit/experimental.py +733 -153
- tensorcircuit/fgs.py +254 -73
- tensorcircuit/gates.py +66 -22
- tensorcircuit/interfaces/jax.py +5 -3
- tensorcircuit/interfaces/tensortrans.py +6 -2
- tensorcircuit/interfaces/torch.py +14 -4
- tensorcircuit/keras.py +3 -3
- tensorcircuit/mpscircuit.py +154 -65
- tensorcircuit/quantum.py +698 -134
- tensorcircuit/quditcircuit.py +733 -0
- tensorcircuit/quditgates.py +618 -0
- tensorcircuit/results/counts.py +131 -18
- tensorcircuit/results/readout_mitigation.py +4 -1
- tensorcircuit/shadows.py +1 -1
- tensorcircuit/simplify.py +3 -1
- tensorcircuit/stabilizercircuit.py +29 -17
- tensorcircuit/templates/__init__.py +2 -0
- tensorcircuit/templates/blocks.py +2 -2
- tensorcircuit/templates/hamiltonians.py +174 -0
- tensorcircuit/templates/lattice.py +1789 -0
- tensorcircuit/timeevol.py +896 -0
- tensorcircuit/translation.py +10 -3
- tensorcircuit/utils.py +7 -0
- {tensorcircuit_nightly-1.2.0.dev20250326.dist-info → tensorcircuit_nightly-1.4.0.dev20251128.dist-info}/METADATA +66 -29
- tensorcircuit_nightly-1.4.0.dev20251128.dist-info/RECORD +96 -0
- {tensorcircuit_nightly-1.2.0.dev20250326.dist-info → tensorcircuit_nightly-1.4.0.dev20251128.dist-info}/WHEEL +1 -1
- {tensorcircuit_nightly-1.2.0.dev20250326.dist-info → tensorcircuit_nightly-1.4.0.dev20251128.dist-info}/top_level.txt +0 -1
- tensorcircuit_nightly-1.2.0.dev20250326.dist-info/RECORD +0 -118
- tests/__init__.py +0 -0
- tests/conftest.py +0 -67
- tests/test_backends.py +0 -1035
- tests/test_calibrating.py +0 -149
- tests/test_channels.py +0 -409
- tests/test_circuit.py +0 -1699
- tests/test_cloud.py +0 -219
- tests/test_compiler.py +0 -147
- tests/test_dmcircuit.py +0 -555
- tests/test_ensemble.py +0 -72
- tests/test_fgs.py +0 -310
- tests/test_gates.py +0 -156
- tests/test_interfaces.py +0 -562
- tests/test_keras.py +0 -160
- tests/test_miscs.py +0 -282
- tests/test_mpscircuit.py +0 -341
- tests/test_noisemodel.py +0 -156
- tests/test_qaoa.py +0 -86
- tests/test_qem.py +0 -152
- tests/test_quantum.py +0 -549
- tests/test_quantum_attr.py +0 -42
- tests/test_results.py +0 -380
- tests/test_shadows.py +0 -160
- tests/test_simplify.py +0 -46
- tests/test_stabilizer.py +0 -217
- tests/test_templates.py +0 -218
- tests/test_torchnn.py +0 -99
- tests/test_van.py +0 -102
- {tensorcircuit_nightly-1.2.0.dev20250326.dist-info → tensorcircuit_nightly-1.4.0.dev20251128.dist-info}/licenses/LICENSE +0 -0
tensorcircuit/fgs.py
CHANGED
|
@@ -28,7 +28,6 @@ def onehot_matrix(i: int, j: int, N: int) -> Tensor:
|
|
|
28
28
|
|
|
29
29
|
# TODO(@refraction-ray): efficiency benchmark with jit
|
|
30
30
|
# TODO(@refraction-ray): FGS mixed state support?
|
|
31
|
-
# TODO(@refraction-ray): overlap?
|
|
32
31
|
# TODO(@refraction-ray): fermionic logarithmic negativity
|
|
33
32
|
|
|
34
33
|
|
|
@@ -73,17 +72,26 @@ class FGSSimulator:
|
|
|
73
72
|
cmatrix: Optional[Tensor] = None,
|
|
74
73
|
):
|
|
75
74
|
"""
|
|
76
|
-
|
|
75
|
+
Initializes the Fermion Gaussian State (FGS) simulator.
|
|
77
76
|
|
|
78
|
-
|
|
77
|
+
The state can be initialized in one of four ways:
|
|
78
|
+
1. By specifying the system size `L` and a list of `filled` sites, creating a product state.
|
|
79
|
+
2. By providing a quadratic Hamiltonian `hc`, the ground state of which is used as the initial state.
|
|
80
|
+
3. By directly providing the `alpha` matrix, which defines the Bogoliubov transformation.
|
|
81
|
+
4. For debugging, by providing a pre-computed correlation matrix `cmatrix`.
|
|
82
|
+
|
|
83
|
+
:param L: The number of fermionic sites (system size).
|
|
79
84
|
:type L: int
|
|
80
|
-
:param filled:
|
|
85
|
+
:param filled: A list of site indices that are occupied by fermions in the initial state.
|
|
86
|
+
Defaults to None (no sites filled).
|
|
81
87
|
:type filled: Optional[List[int]], optional
|
|
82
|
-
:param alpha:
|
|
88
|
+
:param alpha: The matrix defining the Bogoliubov transformation from the vacuum state, of shape `(2L, L)`.
|
|
89
|
+
If provided, it directly specifies the initial state. Defaults to None.
|
|
83
90
|
:type alpha: Optional[Tensor], optional
|
|
84
|
-
:param hc:
|
|
91
|
+
:param hc: A quadratic Hamiltonian. The ground state of this Hamiltonian will be used as the initial state.
|
|
92
|
+
Defaults to None.
|
|
85
93
|
:type hc: Optional[Tensor], optional
|
|
86
|
-
:param cmatrix:
|
|
94
|
+
:param cmatrix: A pre-computed correlation matrix, primarily for debugging purposes. Defaults to None.
|
|
87
95
|
:type cmatrix: Optional[Tensor], optional
|
|
88
96
|
"""
|
|
89
97
|
if filled is None:
|
|
@@ -105,6 +113,19 @@ class FGSSimulator:
|
|
|
105
113
|
def fermion_diagonalization(
|
|
106
114
|
cls, hc: Tensor, L: int
|
|
107
115
|
) -> Tuple[Tensor, Tensor, Tensor]:
|
|
116
|
+
"""
|
|
117
|
+
Diagonalizes a quadratic fermionic Hamiltonian.
|
|
118
|
+
|
|
119
|
+
This method computes the eigenvalues, eigenvectors, and the alpha matrix for a given
|
|
120
|
+
quadratic Hamiltonian `hc`.
|
|
121
|
+
|
|
122
|
+
:param hc: The quadratic Hamiltonian to be diagonalized.
|
|
123
|
+
:type hc: Tensor
|
|
124
|
+
:param L: The number of fermionic sites.
|
|
125
|
+
:type L: int
|
|
126
|
+
:return: A tuple containing the eigenvalues, eigenvectors, and the alpha matrix.
|
|
127
|
+
:rtype: Tuple[Tensor, Tensor, Tensor]
|
|
128
|
+
"""
|
|
108
129
|
es, u = backend.eigh(hc)
|
|
109
130
|
es = es[::-1]
|
|
110
131
|
u = u[:, ::-1]
|
|
@@ -115,6 +136,19 @@ class FGSSimulator:
|
|
|
115
136
|
def fermion_diagonalization_2(
|
|
116
137
|
cls, hc: Tensor, L: int
|
|
117
138
|
) -> Tuple[Tensor, Tensor, Tensor]:
|
|
139
|
+
"""
|
|
140
|
+
Alternative method for diagonalizing a quadratic fermionic Hamiltonian.
|
|
141
|
+
|
|
142
|
+
This method uses a different approach based on the Schur decomposition to diagonalize
|
|
143
|
+
the Hamiltonian.
|
|
144
|
+
|
|
145
|
+
:param hc: The quadratic Hamiltonian to be diagonalized.
|
|
146
|
+
:type hc: Tensor
|
|
147
|
+
:param L: The number of fermionic sites.
|
|
148
|
+
:type L: int
|
|
149
|
+
:return: A tuple containing the eigenvalues, eigenvectors, and the alpha matrix.
|
|
150
|
+
:rtype: Tuple[Tensor, Tensor, Tensor]
|
|
151
|
+
"""
|
|
118
152
|
w = cls.wmatrix(L)
|
|
119
153
|
hm = 0.25 * w @ hc @ backend.adjoint(w)
|
|
120
154
|
hm = backend.real((-1.0j) * hm)
|
|
@@ -140,6 +174,16 @@ class FGSSimulator:
|
|
|
140
174
|
|
|
141
175
|
@staticmethod
|
|
142
176
|
def wmatrix(L: int) -> Tensor:
|
|
177
|
+
"""
|
|
178
|
+
Constructs the transformation matrix W.
|
|
179
|
+
|
|
180
|
+
This matrix transforms from the fermionic basis to the Majorana basis.
|
|
181
|
+
|
|
182
|
+
:param L: The number of fermionic sites.
|
|
183
|
+
:type L: int
|
|
184
|
+
:return: The transformation matrix W.
|
|
185
|
+
:rtype: Tensor
|
|
186
|
+
"""
|
|
143
187
|
w = np.zeros([2 * L, 2 * L], dtype=complex)
|
|
144
188
|
for i in range(2 * L):
|
|
145
189
|
if i % 2 == 1:
|
|
@@ -152,6 +196,16 @@ class FGSSimulator:
|
|
|
152
196
|
|
|
153
197
|
@staticmethod
|
|
154
198
|
def init_alpha(filled: List[int], L: int) -> Tensor:
|
|
199
|
+
"""
|
|
200
|
+
Initializes the alpha matrix for a given set of filled sites.
|
|
201
|
+
|
|
202
|
+
:param filled: A list of site indices that are occupied by fermions.
|
|
203
|
+
:type filled: List[int]
|
|
204
|
+
:param L: The number of fermionic sites.
|
|
205
|
+
:type L: int
|
|
206
|
+
:return: The initialized alpha matrix.
|
|
207
|
+
:rtype: Tensor
|
|
208
|
+
"""
|
|
155
209
|
alpha = np.zeros([2 * L, L])
|
|
156
210
|
for i in range(L):
|
|
157
211
|
if i not in filled:
|
|
@@ -163,9 +217,29 @@ class FGSSimulator:
|
|
|
163
217
|
return alpha
|
|
164
218
|
|
|
165
219
|
def get_alpha(self) -> Tensor:
|
|
220
|
+
"""
|
|
221
|
+
Returns the current alpha matrix of the FGS.
|
|
222
|
+
|
|
223
|
+
:return: The alpha matrix.
|
|
224
|
+
:rtype: Tensor
|
|
225
|
+
"""
|
|
166
226
|
return self.alpha
|
|
167
227
|
|
|
168
228
|
def get_cmatrix(self, now_i: bool = True, now_j: bool = True) -> Tensor:
|
|
229
|
+
r"""
|
|
230
|
+
Calculates the correlation matrix.
|
|
231
|
+
|
|
232
|
+
The correlation matrix is defined as :math:`C_{ij} = \langle c_i^\dagger c_j \rangle`.
|
|
233
|
+
This method can also compute out-of-time-ordered correlators (OTOC) by specifying
|
|
234
|
+
whether to use the current or initial state for the `i` and `j` indices.
|
|
235
|
+
|
|
236
|
+
:param now_i: If True, use the current state for the `i` index. Defaults to True.
|
|
237
|
+
:type now_i: bool, optional
|
|
238
|
+
:param now_j: If True, use the current state for the `j` index. Defaults to True.
|
|
239
|
+
:type now_j: bool, optional
|
|
240
|
+
:return: The correlation matrix.
|
|
241
|
+
:rtype: Tensor
|
|
242
|
+
"""
|
|
169
243
|
# otoc in FGS language, see: https://arxiv.org/pdf/1908.03292.pdf
|
|
170
244
|
# https://journals.aps.org/prb/pdf/10.1103/PhysRevB.99.054205
|
|
171
245
|
# otoc for non=hermitian system is more subtle due to the undefined normalization
|
|
@@ -197,11 +271,11 @@ class FGSSimulator:
|
|
|
197
271
|
|
|
198
272
|
def get_reduced_cmatrix(self, subsystems_to_trace_out: List[int]) -> Tensor:
|
|
199
273
|
"""
|
|
200
|
-
|
|
274
|
+
Calculates the reduced correlation matrix by tracing out specified subsystems.
|
|
201
275
|
|
|
202
|
-
:param subsystems_to_trace_out: list of
|
|
276
|
+
:param subsystems_to_trace_out: A list of site indices to be traced out.
|
|
203
277
|
:type subsystems_to_trace_out: List[int]
|
|
204
|
-
:return: reduced
|
|
278
|
+
:return: The reduced correlation matrix.
|
|
205
279
|
:rtype: Tensor
|
|
206
280
|
"""
|
|
207
281
|
m = self.get_cmatrix()
|
|
@@ -222,20 +296,20 @@ class FGSSimulator:
|
|
|
222
296
|
|
|
223
297
|
def renyi_entropy(self, n: int, subsystems_to_trace_out: List[int]) -> Tensor:
|
|
224
298
|
"""
|
|
225
|
-
|
|
299
|
+
Computes the Renyi entropy of order n for a given subsystem.
|
|
226
300
|
|
|
227
|
-
:param n:
|
|
301
|
+
:param n: The order of the Renyi entropy.
|
|
228
302
|
:type n: int
|
|
229
|
-
:param subsystems_to_trace_out:
|
|
303
|
+
:param subsystems_to_trace_out: A list of site indices to be traced out, defining the subsystem.
|
|
230
304
|
:type subsystems_to_trace_out: List[int]
|
|
231
|
-
:return:
|
|
305
|
+
:return: The Renyi entropy of order n.
|
|
232
306
|
:rtype: Tensor
|
|
233
307
|
"""
|
|
234
308
|
m = self.get_reduced_cmatrix(subsystems_to_trace_out)
|
|
235
309
|
lbd, _ = backend.eigh(m)
|
|
236
310
|
lbd = backend.real(lbd)
|
|
237
311
|
lbd = backend.relu(lbd)
|
|
238
|
-
eps = 1e-
|
|
312
|
+
eps = 1e-9
|
|
239
313
|
|
|
240
314
|
entropy = backend.sum(backend.log(lbd**n + (1 - lbd) ** n + eps))
|
|
241
315
|
s = 1 / (2 * (1 - n)) * entropy
|
|
@@ -248,15 +322,17 @@ class FGSSimulator:
|
|
|
248
322
|
subsystems_to_trace_out: List[int],
|
|
249
323
|
) -> Tensor:
|
|
250
324
|
"""
|
|
325
|
+
Computes the charge moment of order n.
|
|
326
|
+
|
|
251
327
|
Ref: https://arxiv.org/abs/2302.03330
|
|
252
328
|
|
|
253
|
-
:param alpha:
|
|
329
|
+
:param alpha: The alpha parameter for the charge moment calculation.
|
|
254
330
|
:type alpha: Tensor
|
|
255
|
-
:param n:
|
|
331
|
+
:param n: The order of the charge moment (Renyi-n).
|
|
256
332
|
:type n: int
|
|
257
|
-
:param subsystems_to_trace_out:
|
|
333
|
+
:param subsystems_to_trace_out: A list of site indices to be traced out.
|
|
258
334
|
:type subsystems_to_trace_out: List[int]
|
|
259
|
-
:return:
|
|
335
|
+
:return: The charge moment.
|
|
260
336
|
:rtype: Tensor
|
|
261
337
|
"""
|
|
262
338
|
m = self.get_reduced_cmatrix(subsystems_to_trace_out)
|
|
@@ -297,18 +373,23 @@ class FGSSimulator:
|
|
|
297
373
|
with_std: bool = False,
|
|
298
374
|
) -> Tensor:
|
|
299
375
|
"""
|
|
376
|
+
Computes the Renyi entanglement asymmetry.
|
|
377
|
+
|
|
300
378
|
Ref: https://arxiv.org/abs/2302.03330
|
|
301
379
|
|
|
302
|
-
:param n:
|
|
380
|
+
:param n: The order of the Renyi entanglement asymmetry.
|
|
303
381
|
:type n: int
|
|
304
|
-
:param subsystems_to_trace_out:
|
|
382
|
+
:param subsystems_to_trace_out: A list of site indices to be traced out.
|
|
305
383
|
:type subsystems_to_trace_out: List[int]
|
|
306
|
-
:param batch:
|
|
307
|
-
:type batch: int
|
|
308
|
-
:param status: random
|
|
309
|
-
|
|
310
|
-
:type status: Optional[Tensor]
|
|
311
|
-
:
|
|
384
|
+
:param batch: The number of samples to use for the Monte Carlo estimation. Defaults to 100.
|
|
385
|
+
:type batch: int, optional
|
|
386
|
+
:param status: A tensor of random numbers for the sampling. If None, it will be generated internally.
|
|
387
|
+
Defaults to None.
|
|
388
|
+
:type status: Optional[Tensor], optional
|
|
389
|
+
:param with_std: If True, also return the standard deviation of the estimation. Defaults to False.
|
|
390
|
+
:type with_std: bool, optional
|
|
391
|
+
:return: The Renyi entanglement asymmetry.
|
|
392
|
+
If `with_std` is True, a tuple containing the asymmetry and its standard deviation is returned.
|
|
312
393
|
:rtype: Tensor
|
|
313
394
|
"""
|
|
314
395
|
r = []
|
|
@@ -354,11 +435,12 @@ class FGSSimulator:
|
|
|
354
435
|
|
|
355
436
|
def entropy(self, subsystems_to_trace_out: Optional[List[int]] = None) -> Tensor:
|
|
356
437
|
"""
|
|
357
|
-
|
|
438
|
+
Computes the von Neumann entropy of a subsystem.
|
|
358
439
|
|
|
359
|
-
:param subsystems_to_trace_out:
|
|
440
|
+
:param subsystems_to_trace_out: A list of site indices to be traced out, defining the subsystem.
|
|
441
|
+
If None, the entropy of the entire system is computed. Defaults to None.
|
|
360
442
|
:type subsystems_to_trace_out: Optional[List[int]], optional
|
|
361
|
-
:return:
|
|
443
|
+
:return: The von Neumann entropy.
|
|
362
444
|
:rtype: Tensor
|
|
363
445
|
"""
|
|
364
446
|
m = self.get_reduced_cmatrix(subsystems_to_trace_out) # type: ignore
|
|
@@ -366,7 +448,7 @@ class FGSSimulator:
|
|
|
366
448
|
lbd = backend.real(lbd)
|
|
367
449
|
lbd = backend.relu(lbd)
|
|
368
450
|
# lbd /= backend.sum(lbd)
|
|
369
|
-
eps = 1e-
|
|
451
|
+
eps = 1e-9
|
|
370
452
|
entropy = -backend.sum(
|
|
371
453
|
lbd * backend.log(lbd + eps) + (1 - lbd) * backend.log(1 - lbd + eps)
|
|
372
454
|
)
|
|
@@ -374,9 +456,11 @@ class FGSSimulator:
|
|
|
374
456
|
|
|
375
457
|
def evol_hamiltonian(self, h: Tensor) -> None:
|
|
376
458
|
r"""
|
|
377
|
-
|
|
459
|
+
Evolves the state with a given Hamiltonian.
|
|
460
|
+
|
|
461
|
+
The evolution is given by :math:`e^{-i/2 \hat{h}}`.
|
|
378
462
|
|
|
379
|
-
:param h:
|
|
463
|
+
:param h: The Hamiltonian for the evolution.
|
|
380
464
|
:type h: Tensor
|
|
381
465
|
"""
|
|
382
466
|
# e^{-i/2 H}
|
|
@@ -387,9 +471,11 @@ class FGSSimulator:
|
|
|
387
471
|
|
|
388
472
|
def evol_ihamiltonian(self, h: Tensor) -> None:
|
|
389
473
|
r"""
|
|
390
|
-
|
|
474
|
+
Evolves the state with a given Hamiltonian using imaginary time evolution.
|
|
391
475
|
|
|
392
|
-
:
|
|
476
|
+
The evolution is given by :math:`e^{-1/2 \hat{h}}`.
|
|
477
|
+
|
|
478
|
+
:param h: The Hamiltonian for the evolution.
|
|
393
479
|
:type h: Tensor
|
|
394
480
|
"""
|
|
395
481
|
# e^{-1/2 H}
|
|
@@ -401,9 +487,11 @@ class FGSSimulator:
|
|
|
401
487
|
|
|
402
488
|
def evol_ghamiltonian(self, h: Tensor) -> None:
|
|
403
489
|
r"""
|
|
404
|
-
|
|
490
|
+
Evolves the state with a general non-Hermitian Hamiltonian.
|
|
491
|
+
|
|
492
|
+
The evolution is given by :math:`e^{-1/2 i \hat{h}}`.
|
|
405
493
|
|
|
406
|
-
:param h:
|
|
494
|
+
:param h: The non-Hermitian Hamiltonian for the evolution.
|
|
407
495
|
:type h: Tensor
|
|
408
496
|
"""
|
|
409
497
|
# e^{-1/2 H}
|
|
@@ -414,11 +502,28 @@ class FGSSimulator:
|
|
|
414
502
|
self.otcmatrix = {}
|
|
415
503
|
|
|
416
504
|
def orthogonal(self) -> None:
|
|
505
|
+
"""Orthogonalizes the alpha matrix using QR decomposition."""
|
|
417
506
|
q, _ = backend.qr(self.alpha)
|
|
418
507
|
self.alpha = q
|
|
419
508
|
|
|
420
509
|
@staticmethod
|
|
421
510
|
def hopping(chi: Tensor, i: int, j: int, L: int) -> Tensor:
|
|
511
|
+
r"""
|
|
512
|
+
Constructs the hopping Hamiltonian between two sites.
|
|
513
|
+
|
|
514
|
+
The hopping Hamiltonian is given by :math:`\chi c_i^\dagger c_j + h.c.`.
|
|
515
|
+
|
|
516
|
+
:param chi: The hopping strength.
|
|
517
|
+
:type chi: Tensor
|
|
518
|
+
:param i: The index of the first site.
|
|
519
|
+
:type i: int
|
|
520
|
+
:param j: The index of the second site.
|
|
521
|
+
:type j: int
|
|
522
|
+
:param L: The number of fermionic sites.
|
|
523
|
+
:type L: int
|
|
524
|
+
:return: The hopping Hamiltonian.
|
|
525
|
+
:rtype: Tensor
|
|
526
|
+
"""
|
|
422
527
|
# chi * ci dagger cj + hc.
|
|
423
528
|
chi = backend.convert_to_tensor(chi)
|
|
424
529
|
chi = backend.cast(chi, dtypestr)
|
|
@@ -429,19 +534,35 @@ class FGSSimulator:
|
|
|
429
534
|
|
|
430
535
|
def evol_hp(self, i: int, j: int, chi: Tensor = 0) -> None:
|
|
431
536
|
r"""
|
|
432
|
-
|
|
537
|
+
Evolves the state with a hopping Hamiltonian.
|
|
538
|
+
|
|
539
|
+
The evolution is governed by the Hamiltonian :math:`\chi c_i^\dagger c_j + h.c.`.
|
|
433
540
|
|
|
434
|
-
:param i:
|
|
541
|
+
:param i: The index of the first site.
|
|
435
542
|
:type i: int
|
|
436
|
-
:param j:
|
|
543
|
+
:param j: The index of the second site.
|
|
437
544
|
:type j: int
|
|
438
|
-
:param chi:
|
|
545
|
+
:param chi: The hopping strength. Defaults to 0.
|
|
439
546
|
:type chi: Tensor, optional
|
|
440
547
|
"""
|
|
441
548
|
self.evol_hamiltonian(self.hopping(chi, i, j, self.L))
|
|
442
549
|
|
|
443
550
|
@staticmethod
|
|
444
551
|
def chemical_potential(chi: Tensor, i: int, L: int) -> Tensor:
|
|
552
|
+
r"""
|
|
553
|
+
Constructs the chemical potential Hamiltonian for a single site.
|
|
554
|
+
|
|
555
|
+
The chemical potential Hamiltonian is given by :math:`\chi c_i^\dagger c_i`.
|
|
556
|
+
|
|
557
|
+
:param chi: The chemical potential strength.
|
|
558
|
+
:type chi: Tensor
|
|
559
|
+
:param i: The index of the site.
|
|
560
|
+
:type i: int
|
|
561
|
+
:param L: The number of fermionic sites.
|
|
562
|
+
:type L: int
|
|
563
|
+
:return: The chemical potential Hamiltonian.
|
|
564
|
+
:rtype: Tensor
|
|
565
|
+
"""
|
|
445
566
|
chi = backend.convert_to_tensor(chi)
|
|
446
567
|
chi = backend.cast(chi, dtypestr)
|
|
447
568
|
m = chi / 2 * onehot_matrix(i, i, 2 * L)
|
|
@@ -450,6 +571,22 @@ class FGSSimulator:
|
|
|
450
571
|
|
|
451
572
|
@staticmethod
|
|
452
573
|
def sc_pairing(chi: Tensor, i: int, j: int, L: int) -> Tensor:
|
|
574
|
+
r"""
|
|
575
|
+
Constructs the superconducting pairing Hamiltonian between two sites.
|
|
576
|
+
|
|
577
|
+
The superconducting pairing Hamiltonian is given by :math:`\chi c_i^\dagger c_j^\dagger + h.c.`.
|
|
578
|
+
|
|
579
|
+
:param chi: The pairing strength.
|
|
580
|
+
:type chi: Tensor
|
|
581
|
+
:param i: The index of the first site.
|
|
582
|
+
:type i: int
|
|
583
|
+
:param j: The index of the second site.
|
|
584
|
+
:type j: int
|
|
585
|
+
:param L: The number of fermionic sites.
|
|
586
|
+
:type L: int
|
|
587
|
+
:return: The superconducting pairing Hamiltonian.
|
|
588
|
+
:rtype: Tensor
|
|
589
|
+
"""
|
|
453
590
|
chi = backend.convert_to_tensor(chi)
|
|
454
591
|
chi = backend.cast(chi, dtypestr)
|
|
455
592
|
m = chi / 2 * onehot_matrix(i, j + L, 2 * L)
|
|
@@ -459,41 +596,57 @@ class FGSSimulator:
|
|
|
459
596
|
|
|
460
597
|
def evol_sp(self, i: int, j: int, chi: Tensor = 0) -> None:
|
|
461
598
|
r"""
|
|
462
|
-
|
|
599
|
+
Evolves the state with a superconducting pairing Hamiltonian.
|
|
463
600
|
|
|
601
|
+
The evolution is governed by the Hamiltonian :math:`\chi c_i^\dagger c_j^\dagger + h.c.`.
|
|
464
602
|
|
|
465
|
-
:param i:
|
|
603
|
+
:param i: The index of the first site.
|
|
466
604
|
:type i: int
|
|
467
|
-
:param j:
|
|
605
|
+
:param j: The index of the second site.
|
|
468
606
|
:type j: int
|
|
469
|
-
:param chi:
|
|
607
|
+
:param chi: The pairing strength. Defaults to 0.
|
|
470
608
|
:type chi: Tensor, optional
|
|
471
609
|
"""
|
|
472
610
|
self.evol_hamiltonian(self.sc_pairing(chi, i, j, self.L))
|
|
473
611
|
|
|
474
612
|
def evol_cp(self, i: int, chi: Tensor = 0) -> None:
|
|
475
613
|
r"""
|
|
476
|
-
|
|
614
|
+
Evolves the state with a chemical potential Hamiltonian.
|
|
615
|
+
|
|
616
|
+
The evolution is governed by the Hamiltonian :math:`\chi c_i^\dagger c_i`.
|
|
477
617
|
|
|
478
|
-
:param i:
|
|
618
|
+
:param i: The index of the site.
|
|
479
619
|
:type i: int
|
|
480
|
-
:param chi:
|
|
620
|
+
:param chi: The chemical potential strength. Defaults to 0.
|
|
481
621
|
:type chi: Tensor, optional
|
|
482
622
|
"""
|
|
483
623
|
self.evol_hamiltonian(self.chemical_potential(chi, i, self.L))
|
|
484
624
|
|
|
485
625
|
def evol_icp(self, i: int, chi: Tensor = 0) -> None:
|
|
486
626
|
r"""
|
|
487
|
-
|
|
627
|
+
Evolves the state with a chemical potential Hamiltonian using imaginary time evolution.
|
|
488
628
|
|
|
489
|
-
:
|
|
629
|
+
The evolution is governed by :math:`e^{-H/2}` where :math:`H = \chi c_i^\dagger c_i`.
|
|
630
|
+
|
|
631
|
+
:param i: The index of the site.
|
|
490
632
|
:type i: int
|
|
491
|
-
:param chi:
|
|
633
|
+
:param chi: The chemical potential strength. Defaults to 0.
|
|
492
634
|
:type chi: Tensor, optional
|
|
493
635
|
"""
|
|
494
636
|
self.evol_ihamiltonian(self.chemical_potential(chi, i, self.L))
|
|
495
637
|
|
|
496
638
|
def get_bogoliubov_uv(self) -> Tuple[Tensor, Tensor]:
|
|
639
|
+
r"""
|
|
640
|
+
Returns the u and v matrices of the Bogoliubov transformation.
|
|
641
|
+
|
|
642
|
+
The Bogoliubov transformation is defined as:
|
|
643
|
+
:math:`b_k = u_{k,i} a_i + v_{k,i} a_i^\dagger`
|
|
644
|
+
|
|
645
|
+
where :math:`b_k` are the new fermionic operators and :math:`a_i` are the original ones.
|
|
646
|
+
|
|
647
|
+
:return: A tuple containing the u and v matrices.
|
|
648
|
+
:rtype: Tuple[Tensor, Tensor]
|
|
649
|
+
"""
|
|
497
650
|
return (
|
|
498
651
|
backend.gather1d(
|
|
499
652
|
self.alpha, backend.convert_to_tensor([i for i in range(self.L)])
|
|
@@ -506,17 +659,27 @@ class FGSSimulator:
|
|
|
506
659
|
|
|
507
660
|
def get_cmatrix_majorana(self) -> Tensor:
|
|
508
661
|
r"""
|
|
509
|
-
correlation matrix
|
|
510
|
-
convention: :math:`gamma_0 = c_0 + c_0^\dagger`
|
|
511
|
-
:math:`gamma_1 = i(c_0 - c_0^\dagger)`
|
|
662
|
+
Calculates the correlation matrix in the Majorana basis.
|
|
512
663
|
|
|
513
|
-
:
|
|
664
|
+
The Majorana operators are defined as:
|
|
665
|
+
:math:`\gamma_{2i} = c_i + c_i^\dagger`
|
|
666
|
+
:math:`\gamma_{2i+1} = -i(c_i - c_i^\dagger)`
|
|
667
|
+
|
|
668
|
+
:return: The correlation matrix in the Majorana basis.
|
|
514
669
|
:rtype: Tensor
|
|
515
670
|
"""
|
|
516
671
|
c = self.get_cmatrix()
|
|
517
672
|
return self.wtransform @ c @ backend.adjoint(self.wtransform)
|
|
518
673
|
|
|
519
674
|
def get_covariance_matrix(self) -> Tensor:
|
|
675
|
+
"""
|
|
676
|
+
Calculates the covariance matrix.
|
|
677
|
+
|
|
678
|
+
The covariance matrix is defined from the Majorana correlation matrix.
|
|
679
|
+
|
|
680
|
+
:return: The covariance matrix.
|
|
681
|
+
:rtype: Tensor
|
|
682
|
+
"""
|
|
520
683
|
m = self.get_cmatrix_majorana()
|
|
521
684
|
return -1.0j * (2 * m - backend.eye(self.L * 2))
|
|
522
685
|
|
|
@@ -524,34 +687,38 @@ class FGSSimulator:
|
|
|
524
687
|
self, i: int, j: int, now_i: bool = True, now_j: bool = True
|
|
525
688
|
) -> Tensor:
|
|
526
689
|
r"""
|
|
527
|
-
expectation of two
|
|
528
|
-
|
|
529
|
-
for i
|
|
690
|
+
Calculates the expectation value of a two-fermion term.
|
|
691
|
+
|
|
692
|
+
The convention for the operators is (c, c^\dagger). For i >= L, the operator is c_{i-L}^\dagger.
|
|
530
693
|
|
|
531
|
-
:param i:
|
|
694
|
+
:param i: The index of the first fermion operator.
|
|
532
695
|
:type i: int
|
|
533
|
-
:param j:
|
|
696
|
+
:param j: The index of the second fermion operator.
|
|
534
697
|
:type j: int
|
|
535
|
-
:
|
|
698
|
+
:param now_i: Whether to use the current state for the first operator. Defaults to True.
|
|
699
|
+
:type now_i: bool, optional
|
|
700
|
+
:param now_j: Whether to use the current state for the second operator. Defaults to True.
|
|
701
|
+
:type now_j: bool, optional
|
|
702
|
+
:return: The expectation value of the two-fermion term.
|
|
536
703
|
:rtype: Tensor
|
|
537
704
|
"""
|
|
538
705
|
return self.get_cmatrix(now_i, now_j)[i][(j + self.L) % (2 * self.L)]
|
|
539
706
|
|
|
540
707
|
def expectation_4body(self, i: int, j: int, k: int, l: int) -> Tensor:
|
|
541
708
|
r"""
|
|
542
|
-
expectation of four
|
|
543
|
-
|
|
544
|
-
for
|
|
709
|
+
Calculates the expectation value of a four-fermion term using Wick's theorem.
|
|
710
|
+
|
|
711
|
+
The convention for the operators is (c, c^\dagger). For an index m >= L, the operator is c_{m-L}^\dagger.
|
|
545
712
|
|
|
546
|
-
:param i:
|
|
713
|
+
:param i: The index of the first fermion operator.
|
|
547
714
|
:type i: int
|
|
548
|
-
:param j:
|
|
715
|
+
:param j: The index of the second fermion operator.
|
|
549
716
|
:type j: int
|
|
550
|
-
:param k:
|
|
717
|
+
:param k: The index of the third fermion operator.
|
|
551
718
|
:type k: int
|
|
552
|
-
:param l:
|
|
719
|
+
:param l: The index of the fourth fermion operator.
|
|
553
720
|
:type l: int
|
|
554
|
-
:return:
|
|
721
|
+
:return: The expectation value of the four-fermion term.
|
|
555
722
|
:rtype: Tensor
|
|
556
723
|
"""
|
|
557
724
|
e = (
|
|
@@ -563,12 +730,11 @@ class FGSSimulator:
|
|
|
563
730
|
|
|
564
731
|
def post_select(self, i: int, keep: int = 1) -> None:
|
|
565
732
|
"""
|
|
566
|
-
|
|
567
|
-
<n_i> = ``keep``
|
|
733
|
+
Post-selects the state based on the occupation of a specific site.
|
|
568
734
|
|
|
569
|
-
:param i:
|
|
735
|
+
:param i: The index of the site to post-select on.
|
|
570
736
|
:type i: int
|
|
571
|
-
:param keep:
|
|
737
|
+
:param keep: The desired occupation number (0 or 1). Defaults to 1.
|
|
572
738
|
:type keep: int, optional
|
|
573
739
|
"""
|
|
574
740
|
# i is not jittable, keep is jittable
|
|
@@ -626,8 +792,23 @@ class FGSSimulator:
|
|
|
626
792
|
alpha1 = alpha1 * mask02d + backend.tile(newcol[:, None], [1, self.L]) * mask12d
|
|
627
793
|
q, _ = backend.qr(alpha1)
|
|
628
794
|
self.alpha = q
|
|
795
|
+
self.cmatrix = None
|
|
629
796
|
|
|
630
797
|
def cond_measure(self, ind: int, status: float, with_prob: bool = False) -> Tensor:
|
|
798
|
+
"""
|
|
799
|
+
Performs a conditional measurement on a specific site.
|
|
800
|
+
The fermion Gaussian state is collapsed in the consistent way accordingly.
|
|
801
|
+
|
|
802
|
+
:param ind: The index of the site to measure.
|
|
803
|
+
:type ind: int
|
|
804
|
+
:param status: A random number between 0 and 1 to determine the measurement outcome.
|
|
805
|
+
:type status: float
|
|
806
|
+
:param with_prob: If True, also return the probabilities of the measurement outcomes. Defaults to False.
|
|
807
|
+
:type with_prob: bool, optional
|
|
808
|
+
:return: The measurement outcome (0 or 1). If `with_prob` is True,
|
|
809
|
+
a tuple containing the outcome and the probabilities is returned.
|
|
810
|
+
:rtype: Tensor
|
|
811
|
+
"""
|
|
631
812
|
p0 = backend.real(self.get_cmatrix()[ind, ind])
|
|
632
813
|
prob = backend.convert_to_tensor([p0, 1 - p0])
|
|
633
814
|
status = backend.convert_to_tensor(status)
|