tensorcircuit-nightly 1.0.2.dev20250108__py3-none-any.whl → 1.4.0.dev20251103__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 +18 -2
- tensorcircuit/about.py +46 -0
- 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 +320 -7
- tensorcircuit/backends/cupy_backend.py +3 -1
- tensorcircuit/backends/jax_backend.py +102 -4
- tensorcircuit/backends/jax_ops.py +110 -1
- 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 +142 -21
- tensorcircuit/densitymatrix.py +43 -14
- tensorcircuit/experimental.py +387 -129
- tensorcircuit/fgs.py +282 -81
- tensorcircuit/gates.py +66 -22
- tensorcircuit/interfaces/__init__.py +1 -3
- tensorcircuit/interfaces/jax.py +189 -0
- tensorcircuit/keras.py +3 -3
- tensorcircuit/mpscircuit.py +154 -65
- tensorcircuit/quantum.py +868 -152
- tensorcircuit/quditcircuit.py +733 -0
- tensorcircuit/quditgates.py +618 -0
- tensorcircuit/results/counts.py +147 -20
- tensorcircuit/results/readout_mitigation.py +4 -1
- tensorcircuit/shadows.py +1 -1
- tensorcircuit/simplify.py +3 -1
- tensorcircuit/stabilizercircuit.py +479 -0
- 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.0.2.dev20250108.dist-info → tensorcircuit_nightly-1.4.0.dev20251103.dist-info}/METADATA +73 -23
- tensorcircuit_nightly-1.4.0.dev20251103.dist-info/RECORD +96 -0
- {tensorcircuit_nightly-1.0.2.dev20250108.dist-info → tensorcircuit_nightly-1.4.0.dev20251103.dist-info}/WHEEL +1 -1
- {tensorcircuit_nightly-1.0.2.dev20250108.dist-info → tensorcircuit_nightly-1.4.0.dev20251103.dist-info}/top_level.txt +0 -1
- tensorcircuit_nightly-1.0.2.dev20250108.dist-info/RECORD +0 -115
- tests/__init__.py +0 -0
- tests/conftest.py +0 -67
- tests/test_backends.py +0 -1031
- tests/test_calibrating.py +0 -149
- tests/test_channels.py +0 -365
- 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 -429
- tests/test_keras.py +0 -160
- tests/test_miscs.py +0 -277
- 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 -526
- tests/test_quantum_attr.py +0 -42
- tests/test_results.py +0 -347
- tests/test_shadows.py +0 -160
- tests/test_simplify.py +0 -46
- tests/test_templates.py +0 -218
- tests/test_torchnn.py +0 -99
- tests/test_van.py +0 -102
- {tensorcircuit_nightly-1.0.2.dev20250108.dist-info → tensorcircuit_nightly-1.4.0.dev20251103.dist-info/licenses}/LICENSE +0 -0
tensorcircuit/fgs.py
CHANGED
|
@@ -28,20 +28,39 @@ 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
|
|
|
35
34
|
class FGSSimulator:
|
|
36
35
|
r"""
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
36
|
+
Fermion Gaussian State (FGS) simulator for efficient simulation of non-interacting fermionic systems.
|
|
37
|
+
|
|
38
|
+
This simulator implements methods for:
|
|
39
|
+
1. State initialization and evolution
|
|
40
|
+
2. Correlation matrix calculations
|
|
41
|
+
3. Entanglement measures
|
|
42
|
+
4. Out-of-time-ordered correlators (OTOC)
|
|
43
|
+
5. Post-selection and measurements
|
|
44
|
+
|
|
45
|
+
Main references:
|
|
46
|
+
- Gaussian formalism: https://arxiv.org/pdf/2306.16595.pdf
|
|
47
|
+
- Quantum circuits: https://arxiv.org/abs/2209.06945
|
|
48
|
+
- Theory background: https://scipost.org/SciPostPhysLectNotes.54/pdf
|
|
49
|
+
|
|
50
|
+
Conventions:
|
|
51
|
+
- Hamiltonian form: (c^dagger, c)H(c, c^\dagger)
|
|
52
|
+
- Correlation form: <(c, c^\dagger)(c^\dagger, c)>
|
|
53
|
+
- Bogoliubov transformation: c' = \alpha^\dagger (c, c^\dagger)
|
|
54
|
+
|
|
55
|
+
:Example:
|
|
56
|
+
|
|
57
|
+
>>> import tensorcircuit as tc
|
|
58
|
+
>>> # Initialize a 4-site system with sites 0 and 2 occupied
|
|
59
|
+
>>> sim = tc.FGSSimulator(L=4, filled=[0, 2])
|
|
60
|
+
>>> # Apply hopping between sites 0 and 1
|
|
61
|
+
>>> sim.evol_hp(i=0, j=1, chi=1.0)
|
|
62
|
+
>>> # Calculate entanglement entropy for first two sites
|
|
63
|
+
>>> entropy = sim.entropy([2, 3])
|
|
45
64
|
"""
|
|
46
65
|
|
|
47
66
|
def __init__(
|
|
@@ -53,17 +72,26 @@ class FGSSimulator:
|
|
|
53
72
|
cmatrix: Optional[Tensor] = None,
|
|
54
73
|
):
|
|
55
74
|
"""
|
|
56
|
-
|
|
75
|
+
Initializes the Fermion Gaussian State (FGS) simulator.
|
|
57
76
|
|
|
58
|
-
|
|
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).
|
|
59
84
|
:type L: int
|
|
60
|
-
: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).
|
|
61
87
|
:type filled: Optional[List[int]], optional
|
|
62
|
-
: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.
|
|
63
90
|
:type alpha: Optional[Tensor], optional
|
|
64
|
-
: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.
|
|
65
93
|
:type hc: Optional[Tensor], optional
|
|
66
|
-
:param cmatrix:
|
|
94
|
+
:param cmatrix: A pre-computed correlation matrix, primarily for debugging purposes. Defaults to None.
|
|
67
95
|
:type cmatrix: Optional[Tensor], optional
|
|
68
96
|
"""
|
|
69
97
|
if filled is None:
|
|
@@ -85,6 +113,19 @@ class FGSSimulator:
|
|
|
85
113
|
def fermion_diagonalization(
|
|
86
114
|
cls, hc: Tensor, L: int
|
|
87
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
|
+
"""
|
|
88
129
|
es, u = backend.eigh(hc)
|
|
89
130
|
es = es[::-1]
|
|
90
131
|
u = u[:, ::-1]
|
|
@@ -95,6 +136,19 @@ class FGSSimulator:
|
|
|
95
136
|
def fermion_diagonalization_2(
|
|
96
137
|
cls, hc: Tensor, L: int
|
|
97
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
|
+
"""
|
|
98
152
|
w = cls.wmatrix(L)
|
|
99
153
|
hm = 0.25 * w @ hc @ backend.adjoint(w)
|
|
100
154
|
hm = backend.real((-1.0j) * hm)
|
|
@@ -120,6 +174,16 @@ class FGSSimulator:
|
|
|
120
174
|
|
|
121
175
|
@staticmethod
|
|
122
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
|
+
"""
|
|
123
187
|
w = np.zeros([2 * L, 2 * L], dtype=complex)
|
|
124
188
|
for i in range(2 * L):
|
|
125
189
|
if i % 2 == 1:
|
|
@@ -132,6 +196,16 @@ class FGSSimulator:
|
|
|
132
196
|
|
|
133
197
|
@staticmethod
|
|
134
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
|
+
"""
|
|
135
209
|
alpha = np.zeros([2 * L, L])
|
|
136
210
|
for i in range(L):
|
|
137
211
|
if i not in filled:
|
|
@@ -143,9 +217,29 @@ class FGSSimulator:
|
|
|
143
217
|
return alpha
|
|
144
218
|
|
|
145
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
|
+
"""
|
|
146
226
|
return self.alpha
|
|
147
227
|
|
|
148
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
|
+
"""
|
|
149
243
|
# otoc in FGS language, see: https://arxiv.org/pdf/1908.03292.pdf
|
|
150
244
|
# https://journals.aps.org/prb/pdf/10.1103/PhysRevB.99.054205
|
|
151
245
|
# otoc for non=hermitian system is more subtle due to the undefined normalization
|
|
@@ -177,11 +271,11 @@ class FGSSimulator:
|
|
|
177
271
|
|
|
178
272
|
def get_reduced_cmatrix(self, subsystems_to_trace_out: List[int]) -> Tensor:
|
|
179
273
|
"""
|
|
180
|
-
|
|
274
|
+
Calculates the reduced correlation matrix by tracing out specified subsystems.
|
|
181
275
|
|
|
182
|
-
:param subsystems_to_trace_out: list of
|
|
276
|
+
:param subsystems_to_trace_out: A list of site indices to be traced out.
|
|
183
277
|
:type subsystems_to_trace_out: List[int]
|
|
184
|
-
:return: reduced
|
|
278
|
+
:return: The reduced correlation matrix.
|
|
185
279
|
:rtype: Tensor
|
|
186
280
|
"""
|
|
187
281
|
m = self.get_cmatrix()
|
|
@@ -202,20 +296,20 @@ class FGSSimulator:
|
|
|
202
296
|
|
|
203
297
|
def renyi_entropy(self, n: int, subsystems_to_trace_out: List[int]) -> Tensor:
|
|
204
298
|
"""
|
|
205
|
-
|
|
299
|
+
Computes the Renyi entropy of order n for a given subsystem.
|
|
206
300
|
|
|
207
|
-
:param n:
|
|
301
|
+
:param n: The order of the Renyi entropy.
|
|
208
302
|
:type n: int
|
|
209
|
-
:param subsystems_to_trace_out:
|
|
303
|
+
:param subsystems_to_trace_out: A list of site indices to be traced out, defining the subsystem.
|
|
210
304
|
:type subsystems_to_trace_out: List[int]
|
|
211
|
-
:return:
|
|
305
|
+
:return: The Renyi entropy of order n.
|
|
212
306
|
:rtype: Tensor
|
|
213
307
|
"""
|
|
214
308
|
m = self.get_reduced_cmatrix(subsystems_to_trace_out)
|
|
215
309
|
lbd, _ = backend.eigh(m)
|
|
216
310
|
lbd = backend.real(lbd)
|
|
217
311
|
lbd = backend.relu(lbd)
|
|
218
|
-
eps = 1e-
|
|
312
|
+
eps = 1e-9
|
|
219
313
|
|
|
220
314
|
entropy = backend.sum(backend.log(lbd**n + (1 - lbd) ** n + eps))
|
|
221
315
|
s = 1 / (2 * (1 - n)) * entropy
|
|
@@ -228,15 +322,17 @@ class FGSSimulator:
|
|
|
228
322
|
subsystems_to_trace_out: List[int],
|
|
229
323
|
) -> Tensor:
|
|
230
324
|
"""
|
|
325
|
+
Computes the charge moment of order n.
|
|
326
|
+
|
|
231
327
|
Ref: https://arxiv.org/abs/2302.03330
|
|
232
328
|
|
|
233
|
-
:param alpha:
|
|
329
|
+
:param alpha: The alpha parameter for the charge moment calculation.
|
|
234
330
|
:type alpha: Tensor
|
|
235
|
-
:param n:
|
|
331
|
+
:param n: The order of the charge moment (Renyi-n).
|
|
236
332
|
:type n: int
|
|
237
|
-
:param subsystems_to_trace_out:
|
|
333
|
+
:param subsystems_to_trace_out: A list of site indices to be traced out.
|
|
238
334
|
:type subsystems_to_trace_out: List[int]
|
|
239
|
-
:return:
|
|
335
|
+
:return: The charge moment.
|
|
240
336
|
:rtype: Tensor
|
|
241
337
|
"""
|
|
242
338
|
m = self.get_reduced_cmatrix(subsystems_to_trace_out)
|
|
@@ -277,18 +373,23 @@ class FGSSimulator:
|
|
|
277
373
|
with_std: bool = False,
|
|
278
374
|
) -> Tensor:
|
|
279
375
|
"""
|
|
376
|
+
Computes the Renyi entanglement asymmetry.
|
|
377
|
+
|
|
280
378
|
Ref: https://arxiv.org/abs/2302.03330
|
|
281
379
|
|
|
282
|
-
:param n:
|
|
380
|
+
:param n: The order of the Renyi entanglement asymmetry.
|
|
283
381
|
:type n: int
|
|
284
|
-
:param subsystems_to_trace_out:
|
|
382
|
+
:param subsystems_to_trace_out: A list of site indices to be traced out.
|
|
285
383
|
:type subsystems_to_trace_out: List[int]
|
|
286
|
-
:param batch:
|
|
287
|
-
:type batch: int
|
|
288
|
-
:param status: random
|
|
289
|
-
|
|
290
|
-
:type status: Optional[Tensor]
|
|
291
|
-
:
|
|
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.
|
|
292
393
|
:rtype: Tensor
|
|
293
394
|
"""
|
|
294
395
|
r = []
|
|
@@ -334,11 +435,12 @@ class FGSSimulator:
|
|
|
334
435
|
|
|
335
436
|
def entropy(self, subsystems_to_trace_out: Optional[List[int]] = None) -> Tensor:
|
|
336
437
|
"""
|
|
337
|
-
|
|
438
|
+
Computes the von Neumann entropy of a subsystem.
|
|
338
439
|
|
|
339
|
-
: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.
|
|
340
442
|
:type subsystems_to_trace_out: Optional[List[int]], optional
|
|
341
|
-
:return:
|
|
443
|
+
:return: The von Neumann entropy.
|
|
342
444
|
:rtype: Tensor
|
|
343
445
|
"""
|
|
344
446
|
m = self.get_reduced_cmatrix(subsystems_to_trace_out) # type: ignore
|
|
@@ -346,7 +448,7 @@ class FGSSimulator:
|
|
|
346
448
|
lbd = backend.real(lbd)
|
|
347
449
|
lbd = backend.relu(lbd)
|
|
348
450
|
# lbd /= backend.sum(lbd)
|
|
349
|
-
eps = 1e-
|
|
451
|
+
eps = 1e-9
|
|
350
452
|
entropy = -backend.sum(
|
|
351
453
|
lbd * backend.log(lbd + eps) + (1 - lbd) * backend.log(1 - lbd + eps)
|
|
352
454
|
)
|
|
@@ -354,9 +456,11 @@ class FGSSimulator:
|
|
|
354
456
|
|
|
355
457
|
def evol_hamiltonian(self, h: Tensor) -> None:
|
|
356
458
|
r"""
|
|
357
|
-
|
|
459
|
+
Evolves the state with a given Hamiltonian.
|
|
460
|
+
|
|
461
|
+
The evolution is given by :math:`e^{-i/2 \hat{h}}`.
|
|
358
462
|
|
|
359
|
-
:param h:
|
|
463
|
+
:param h: The Hamiltonian for the evolution.
|
|
360
464
|
:type h: Tensor
|
|
361
465
|
"""
|
|
362
466
|
# e^{-i/2 H}
|
|
@@ -367,9 +471,11 @@ class FGSSimulator:
|
|
|
367
471
|
|
|
368
472
|
def evol_ihamiltonian(self, h: Tensor) -> None:
|
|
369
473
|
r"""
|
|
370
|
-
|
|
474
|
+
Evolves the state with a given Hamiltonian using imaginary time evolution.
|
|
371
475
|
|
|
372
|
-
:
|
|
476
|
+
The evolution is given by :math:`e^{-1/2 \hat{h}}`.
|
|
477
|
+
|
|
478
|
+
:param h: The Hamiltonian for the evolution.
|
|
373
479
|
:type h: Tensor
|
|
374
480
|
"""
|
|
375
481
|
# e^{-1/2 H}
|
|
@@ -381,9 +487,11 @@ class FGSSimulator:
|
|
|
381
487
|
|
|
382
488
|
def evol_ghamiltonian(self, h: Tensor) -> None:
|
|
383
489
|
r"""
|
|
384
|
-
|
|
490
|
+
Evolves the state with a general non-Hermitian Hamiltonian.
|
|
491
|
+
|
|
492
|
+
The evolution is given by :math:`e^{-1/2 i \hat{h}}`.
|
|
385
493
|
|
|
386
|
-
:param h:
|
|
494
|
+
:param h: The non-Hermitian Hamiltonian for the evolution.
|
|
387
495
|
:type h: Tensor
|
|
388
496
|
"""
|
|
389
497
|
# e^{-1/2 H}
|
|
@@ -394,11 +502,28 @@ class FGSSimulator:
|
|
|
394
502
|
self.otcmatrix = {}
|
|
395
503
|
|
|
396
504
|
def orthogonal(self) -> None:
|
|
505
|
+
"""Orthogonalizes the alpha matrix using QR decomposition."""
|
|
397
506
|
q, _ = backend.qr(self.alpha)
|
|
398
507
|
self.alpha = q
|
|
399
508
|
|
|
400
509
|
@staticmethod
|
|
401
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
|
+
"""
|
|
402
527
|
# chi * ci dagger cj + hc.
|
|
403
528
|
chi = backend.convert_to_tensor(chi)
|
|
404
529
|
chi = backend.cast(chi, dtypestr)
|
|
@@ -409,19 +534,35 @@ class FGSSimulator:
|
|
|
409
534
|
|
|
410
535
|
def evol_hp(self, i: int, j: int, chi: Tensor = 0) -> None:
|
|
411
536
|
r"""
|
|
412
|
-
|
|
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.`.
|
|
413
540
|
|
|
414
|
-
:param i:
|
|
541
|
+
:param i: The index of the first site.
|
|
415
542
|
:type i: int
|
|
416
|
-
:param j:
|
|
543
|
+
:param j: The index of the second site.
|
|
417
544
|
:type j: int
|
|
418
|
-
:param chi:
|
|
545
|
+
:param chi: The hopping strength. Defaults to 0.
|
|
419
546
|
:type chi: Tensor, optional
|
|
420
547
|
"""
|
|
421
548
|
self.evol_hamiltonian(self.hopping(chi, i, j, self.L))
|
|
422
549
|
|
|
423
550
|
@staticmethod
|
|
424
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
|
+
"""
|
|
425
566
|
chi = backend.convert_to_tensor(chi)
|
|
426
567
|
chi = backend.cast(chi, dtypestr)
|
|
427
568
|
m = chi / 2 * onehot_matrix(i, i, 2 * L)
|
|
@@ -430,6 +571,22 @@ class FGSSimulator:
|
|
|
430
571
|
|
|
431
572
|
@staticmethod
|
|
432
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
|
+
"""
|
|
433
590
|
chi = backend.convert_to_tensor(chi)
|
|
434
591
|
chi = backend.cast(chi, dtypestr)
|
|
435
592
|
m = chi / 2 * onehot_matrix(i, j + L, 2 * L)
|
|
@@ -439,41 +596,57 @@ class FGSSimulator:
|
|
|
439
596
|
|
|
440
597
|
def evol_sp(self, i: int, j: int, chi: Tensor = 0) -> None:
|
|
441
598
|
r"""
|
|
442
|
-
|
|
599
|
+
Evolves the state with a superconducting pairing Hamiltonian.
|
|
443
600
|
|
|
601
|
+
The evolution is governed by the Hamiltonian :math:`\chi c_i^\dagger c_j^\dagger + h.c.`.
|
|
444
602
|
|
|
445
|
-
:param i:
|
|
603
|
+
:param i: The index of the first site.
|
|
446
604
|
:type i: int
|
|
447
|
-
:param j:
|
|
605
|
+
:param j: The index of the second site.
|
|
448
606
|
:type j: int
|
|
449
|
-
:param chi:
|
|
607
|
+
:param chi: The pairing strength. Defaults to 0.
|
|
450
608
|
:type chi: Tensor, optional
|
|
451
609
|
"""
|
|
452
610
|
self.evol_hamiltonian(self.sc_pairing(chi, i, j, self.L))
|
|
453
611
|
|
|
454
612
|
def evol_cp(self, i: int, chi: Tensor = 0) -> None:
|
|
455
613
|
r"""
|
|
456
|
-
|
|
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`.
|
|
457
617
|
|
|
458
|
-
:param i:
|
|
618
|
+
:param i: The index of the site.
|
|
459
619
|
:type i: int
|
|
460
|
-
:param chi:
|
|
620
|
+
:param chi: The chemical potential strength. Defaults to 0.
|
|
461
621
|
:type chi: Tensor, optional
|
|
462
622
|
"""
|
|
463
623
|
self.evol_hamiltonian(self.chemical_potential(chi, i, self.L))
|
|
464
624
|
|
|
465
625
|
def evol_icp(self, i: int, chi: Tensor = 0) -> None:
|
|
466
626
|
r"""
|
|
467
|
-
|
|
627
|
+
Evolves the state with a chemical potential Hamiltonian using imaginary time evolution.
|
|
468
628
|
|
|
469
|
-
:
|
|
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.
|
|
470
632
|
:type i: int
|
|
471
|
-
:param chi:
|
|
633
|
+
:param chi: The chemical potential strength. Defaults to 0.
|
|
472
634
|
:type chi: Tensor, optional
|
|
473
635
|
"""
|
|
474
636
|
self.evol_ihamiltonian(self.chemical_potential(chi, i, self.L))
|
|
475
637
|
|
|
476
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
|
+
"""
|
|
477
650
|
return (
|
|
478
651
|
backend.gather1d(
|
|
479
652
|
self.alpha, backend.convert_to_tensor([i for i in range(self.L)])
|
|
@@ -486,17 +659,27 @@ class FGSSimulator:
|
|
|
486
659
|
|
|
487
660
|
def get_cmatrix_majorana(self) -> Tensor:
|
|
488
661
|
r"""
|
|
489
|
-
correlation matrix
|
|
490
|
-
convention: :math:`gamma_0 = c_0 + c_0^\dagger`
|
|
491
|
-
:math:`gamma_1 = i(c_0 - c_0^\dagger)`
|
|
662
|
+
Calculates the correlation matrix in the Majorana basis.
|
|
492
663
|
|
|
493
|
-
:
|
|
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.
|
|
494
669
|
:rtype: Tensor
|
|
495
670
|
"""
|
|
496
671
|
c = self.get_cmatrix()
|
|
497
672
|
return self.wtransform @ c @ backend.adjoint(self.wtransform)
|
|
498
673
|
|
|
499
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
|
+
"""
|
|
500
683
|
m = self.get_cmatrix_majorana()
|
|
501
684
|
return -1.0j * (2 * m - backend.eye(self.L * 2))
|
|
502
685
|
|
|
@@ -504,34 +687,38 @@ class FGSSimulator:
|
|
|
504
687
|
self, i: int, j: int, now_i: bool = True, now_j: bool = True
|
|
505
688
|
) -> Tensor:
|
|
506
689
|
r"""
|
|
507
|
-
expectation of two
|
|
508
|
-
|
|
509
|
-
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.
|
|
510
693
|
|
|
511
|
-
:param i:
|
|
694
|
+
:param i: The index of the first fermion operator.
|
|
512
695
|
:type i: int
|
|
513
|
-
:param j:
|
|
696
|
+
:param j: The index of the second fermion operator.
|
|
514
697
|
:type j: int
|
|
515
|
-
:
|
|
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.
|
|
516
703
|
:rtype: Tensor
|
|
517
704
|
"""
|
|
518
705
|
return self.get_cmatrix(now_i, now_j)[i][(j + self.L) % (2 * self.L)]
|
|
519
706
|
|
|
520
707
|
def expectation_4body(self, i: int, j: int, k: int, l: int) -> Tensor:
|
|
521
708
|
r"""
|
|
522
|
-
expectation of four
|
|
523
|
-
|
|
524
|
-
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.
|
|
525
712
|
|
|
526
|
-
:param i:
|
|
713
|
+
:param i: The index of the first fermion operator.
|
|
527
714
|
:type i: int
|
|
528
|
-
:param j:
|
|
715
|
+
:param j: The index of the second fermion operator.
|
|
529
716
|
:type j: int
|
|
530
|
-
:param k:
|
|
717
|
+
:param k: The index of the third fermion operator.
|
|
531
718
|
:type k: int
|
|
532
|
-
:param l:
|
|
719
|
+
:param l: The index of the fourth fermion operator.
|
|
533
720
|
:type l: int
|
|
534
|
-
:return:
|
|
721
|
+
:return: The expectation value of the four-fermion term.
|
|
535
722
|
:rtype: Tensor
|
|
536
723
|
"""
|
|
537
724
|
e = (
|
|
@@ -543,12 +730,11 @@ class FGSSimulator:
|
|
|
543
730
|
|
|
544
731
|
def post_select(self, i: int, keep: int = 1) -> None:
|
|
545
732
|
"""
|
|
546
|
-
|
|
547
|
-
<n_i> = ``keep``
|
|
733
|
+
Post-selects the state based on the occupation of a specific site.
|
|
548
734
|
|
|
549
|
-
:param i:
|
|
735
|
+
:param i: The index of the site to post-select on.
|
|
550
736
|
:type i: int
|
|
551
|
-
:param keep:
|
|
737
|
+
:param keep: The desired occupation number (0 or 1). Defaults to 1.
|
|
552
738
|
:type keep: int, optional
|
|
553
739
|
"""
|
|
554
740
|
# i is not jittable, keep is jittable
|
|
@@ -606,8 +792,23 @@ class FGSSimulator:
|
|
|
606
792
|
alpha1 = alpha1 * mask02d + backend.tile(newcol[:, None], [1, self.L]) * mask12d
|
|
607
793
|
q, _ = backend.qr(alpha1)
|
|
608
794
|
self.alpha = q
|
|
795
|
+
self.cmatrix = None
|
|
609
796
|
|
|
610
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
|
+
"""
|
|
611
812
|
p0 = backend.real(self.get_cmatrix()[ind, ind])
|
|
612
813
|
prob = backend.convert_to_tensor([p0, 1 - p0])
|
|
613
814
|
status = backend.convert_to_tensor(status)
|