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.

Files changed (76) hide show
  1. tensorcircuit/__init__.py +18 -2
  2. tensorcircuit/about.py +46 -0
  3. tensorcircuit/abstractcircuit.py +4 -0
  4. tensorcircuit/analogcircuit.py +413 -0
  5. tensorcircuit/applications/layers.py +1 -1
  6. tensorcircuit/applications/van.py +1 -1
  7. tensorcircuit/backends/abstract_backend.py +320 -7
  8. tensorcircuit/backends/cupy_backend.py +3 -1
  9. tensorcircuit/backends/jax_backend.py +102 -4
  10. tensorcircuit/backends/jax_ops.py +110 -1
  11. tensorcircuit/backends/numpy_backend.py +49 -3
  12. tensorcircuit/backends/pytorch_backend.py +92 -3
  13. tensorcircuit/backends/tensorflow_backend.py +102 -3
  14. tensorcircuit/basecircuit.py +157 -98
  15. tensorcircuit/circuit.py +115 -57
  16. tensorcircuit/cloud/local.py +1 -1
  17. tensorcircuit/cloud/quafu_provider.py +1 -1
  18. tensorcircuit/cloud/tencent.py +1 -1
  19. tensorcircuit/compiler/simple_compiler.py +2 -2
  20. tensorcircuit/cons.py +142 -21
  21. tensorcircuit/densitymatrix.py +43 -14
  22. tensorcircuit/experimental.py +387 -129
  23. tensorcircuit/fgs.py +282 -81
  24. tensorcircuit/gates.py +66 -22
  25. tensorcircuit/interfaces/__init__.py +1 -3
  26. tensorcircuit/interfaces/jax.py +189 -0
  27. tensorcircuit/keras.py +3 -3
  28. tensorcircuit/mpscircuit.py +154 -65
  29. tensorcircuit/quantum.py +868 -152
  30. tensorcircuit/quditcircuit.py +733 -0
  31. tensorcircuit/quditgates.py +618 -0
  32. tensorcircuit/results/counts.py +147 -20
  33. tensorcircuit/results/readout_mitigation.py +4 -1
  34. tensorcircuit/shadows.py +1 -1
  35. tensorcircuit/simplify.py +3 -1
  36. tensorcircuit/stabilizercircuit.py +479 -0
  37. tensorcircuit/templates/__init__.py +2 -0
  38. tensorcircuit/templates/blocks.py +2 -2
  39. tensorcircuit/templates/hamiltonians.py +174 -0
  40. tensorcircuit/templates/lattice.py +1789 -0
  41. tensorcircuit/timeevol.py +896 -0
  42. tensorcircuit/translation.py +10 -3
  43. tensorcircuit/utils.py +7 -0
  44. {tensorcircuit_nightly-1.0.2.dev20250108.dist-info → tensorcircuit_nightly-1.4.0.dev20251103.dist-info}/METADATA +73 -23
  45. tensorcircuit_nightly-1.4.0.dev20251103.dist-info/RECORD +96 -0
  46. {tensorcircuit_nightly-1.0.2.dev20250108.dist-info → tensorcircuit_nightly-1.4.0.dev20251103.dist-info}/WHEEL +1 -1
  47. {tensorcircuit_nightly-1.0.2.dev20250108.dist-info → tensorcircuit_nightly-1.4.0.dev20251103.dist-info}/top_level.txt +0 -1
  48. tensorcircuit_nightly-1.0.2.dev20250108.dist-info/RECORD +0 -115
  49. tests/__init__.py +0 -0
  50. tests/conftest.py +0 -67
  51. tests/test_backends.py +0 -1031
  52. tests/test_calibrating.py +0 -149
  53. tests/test_channels.py +0 -365
  54. tests/test_circuit.py +0 -1699
  55. tests/test_cloud.py +0 -219
  56. tests/test_compiler.py +0 -147
  57. tests/test_dmcircuit.py +0 -555
  58. tests/test_ensemble.py +0 -72
  59. tests/test_fgs.py +0 -310
  60. tests/test_gates.py +0 -156
  61. tests/test_interfaces.py +0 -429
  62. tests/test_keras.py +0 -160
  63. tests/test_miscs.py +0 -277
  64. tests/test_mpscircuit.py +0 -341
  65. tests/test_noisemodel.py +0 -156
  66. tests/test_qaoa.py +0 -86
  67. tests/test_qem.py +0 -152
  68. tests/test_quantum.py +0 -526
  69. tests/test_quantum_attr.py +0 -42
  70. tests/test_results.py +0 -347
  71. tests/test_shadows.py +0 -160
  72. tests/test_simplify.py +0 -46
  73. tests/test_templates.py +0 -218
  74. tests/test_torchnn.py +0 -99
  75. tests/test_van.py +0 -102
  76. {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
- main refs: https://arxiv.org/pdf/2306.16595.pdf,
38
- https://arxiv.org/abs/2209.06945,
39
- https://scipost.org/SciPostPhysLectNotes.54/pdf
40
-
41
- convention:
42
- for Hamiltonian (c^dagger, c)H(c, c^\dagger)
43
- for correlation <(c, c^\dagger)(c^\dagger, c)>
44
- c' = \alpha^\dagger (c, c^\dagger)
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
- _summary_
75
+ Initializes the Fermion Gaussian State (FGS) simulator.
57
76
 
58
- :param L: system size
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: the fermion site that is fully occupied, defaults to None
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: directly specify the alpha tensor as the input
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: the input is given as the ground state of quadratic Hamiltonian ``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: only used for debug, defaults to None
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
- get reduced correlation matrix by tracing out subsystems
274
+ Calculates the reduced correlation matrix by tracing out specified subsystems.
181
275
 
182
- :param subsystems_to_trace_out: list of sites to be traced out
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 density matrix
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
- compute renyi_entropy of order ``n`` for the fermion state
299
+ Computes the Renyi entropy of order n for a given subsystem.
206
300
 
207
- :param n: _description_
301
+ :param n: The order of the Renyi entropy.
208
302
  :type n: int
209
- :param subsystems_to_trace_out: system sites to be traced 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: _description_
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-6
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: to be integrated
329
+ :param alpha: The alpha parameter for the charge moment calculation.
234
330
  :type alpha: Tensor
235
- :param n: n-order, Renyi-n
331
+ :param n: The order of the charge moment (Renyi-n).
236
332
  :type n: int
237
- :param subsystems_to_trace_out: _description_
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: _description_
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: _description_
380
+ :param n: The order of the Renyi entanglement asymmetry.
283
381
  :type n: int
284
- :param subsystems_to_trace_out: _description_
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: sample number, defaults 100
287
- :type batch: int
288
- :param status: random number for the sample, -pi to pi,
289
- with shape [batch, n]
290
- :type status: Optional[Tensor]
291
- :return: _description_
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
- compute von Neumann entropy for the fermion state
438
+ Computes the von Neumann entropy of a subsystem.
338
439
 
339
- :param subsystems_to_trace_out: _description_, defaults to None
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: _description_
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-6
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
- Evolve as :math:`e^{-i/2 \hat{h}}`
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: _description_
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
- Evolve as :math:`e^{-1/2 \hat{h}}`
474
+ Evolves the state with a given Hamiltonian using imaginary time evolution.
371
475
 
372
- :param h: _description_
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
- Evolve as :math:`e^{-1/2 i \hat{h}}` with h generally non-Hermitian
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: _description_
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
- The evolve Hamiltonian is :math:`\chi c_i^\dagger c_j +h.c.`
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: _description_
541
+ :param i: The index of the first site.
415
542
  :type i: int
416
- :param j: _description_
543
+ :param j: The index of the second site.
417
544
  :type j: int
418
- :param chi: _description_, defaults to 0
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
- The evolve Hamiltonian is :math:`chi c_i^\dagger c_j^\dagger +h.c.`
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: _description_
603
+ :param i: The index of the first site.
446
604
  :type i: int
447
- :param j: _description_
605
+ :param j: The index of the second site.
448
606
  :type j: int
449
- :param chi: _description_, defaults to 0
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
- The evolve Hamiltonian is :math:`chi c_i^\dagger c_i`
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: _description_
618
+ :param i: The index of the site.
459
619
  :type i: int
460
- :param chi: _description_, defaults to 0
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
- The evolve Hamiltonian is :math:`chi c_i^\dagger c_i` with :math:`\exp^{-H/2}`
627
+ Evolves the state with a chemical potential Hamiltonian using imaginary time evolution.
468
628
 
469
- :param i: _description_
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: _description_, defaults to 0
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 defined in majorana basis
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
- :return: _description_
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 fermion terms
508
- convention: (c, c^\dagger)
509
- for i>L, c_{i-L}^\dagger is assumed
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: _description_
694
+ :param i: The index of the first fermion operator.
512
695
  :type i: int
513
- :param j: _description_
696
+ :param j: The index of the second fermion operator.
514
697
  :type j: int
515
- :return: _description_
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 fermion terms using Wick Thm
523
- convention: (c, c^\dagger)
524
- for i>L, c_{i-L}^\dagger is assumed
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: _description_
713
+ :param i: The index of the first fermion operator.
527
714
  :type i: int
528
- :param j: _description_
715
+ :param j: The index of the second fermion operator.
529
716
  :type j: int
530
- :param k: _description_
717
+ :param k: The index of the third fermion operator.
531
718
  :type k: int
532
- :param l: _description_
719
+ :param l: The index of the fourth fermion operator.
533
720
  :type l: int
534
- :return: _description_
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
- post select (project) the fermion state to occupation eigenstate
547
- <n_i> = ``keep``
733
+ Post-selects the state based on the occupation of a specific site.
548
734
 
549
- :param i: _description_
735
+ :param i: The index of the site to post-select on.
550
736
  :type i: int
551
- :param keep: _description_, defaults to 1
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)