tensorcircuit-nightly 1.2.1.dev20250724__py3-none-any.whl → 1.2.1.dev20250726__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 CHANGED
@@ -1,4 +1,4 @@
1
- __version__ = "1.2.1.dev20250724"
1
+ __version__ = "1.2.1.dev20250726"
2
2
  __author__ = "TensorCircuit Authors"
3
3
  __creator__ = "refraction-ray"
4
4
 
@@ -442,7 +442,14 @@ class JaxBackend(jax_backend.JaxBackend, ExtendedBackend): # type: ignore
442
442
  def to_dlpack(self, a: Tensor) -> Any:
443
443
  import jax.dlpack
444
444
 
445
- return jax.dlpack.to_dlpack(a)
445
+ try:
446
+ return jax.dlpack.to_dlpack(a) # type: ignore
447
+ except AttributeError: # jax >v0.7
448
+ # jax.dlpack.to_dlpack was deprecated in JAX v0.6.0 and removed in JAX v0.7.0.
449
+ # Please use the newer DLPack API based on __dlpack__ and __dlpack_device__ instead.
450
+ # Typically, you can pass a JAX array directly to the `from_dlpack` function of
451
+ # another framework without using `to_dlpack`.
452
+ return a.__dlpack__()
446
453
 
447
454
  def set_random_state(
448
455
  self, seed: Optional[Union[int, PRNGKeyArray]] = None, get_only: bool = False
tensorcircuit/circuit.py CHANGED
@@ -231,6 +231,25 @@ class Circuit(BaseCircuit):
231
231
  pz: float,
232
232
  status: Optional[float] = None,
233
233
  ) -> float:
234
+ """
235
+ Apply a depolarizing channel to the circuit in a Monte Carlo way.
236
+ For each call, one of the Pauli gates (X, Y, Z) or an Identity gate is applied to the qubit
237
+ at the given index based on the probabilities `px`, `py`, and `pz`.
238
+
239
+ :param index: The index of the qubit to apply the depolarizing channel on.
240
+ :type index: int
241
+ :param px: The probability of applying an X gate.
242
+ :type px: float
243
+ :param py: The probability of applying a Y gate.
244
+ :type py: float
245
+ :param pz: The probability of applying a Z gate.
246
+ :type pz: float
247
+ :param status: A random number between 0 and 1 to determine which gate to apply. If None,
248
+ a random number is generated automatically. Defaults to None.
249
+ :type status: Optional[float], optional
250
+ :return: Returns 0.0. The function modifies the circuit in place.
251
+ :rtype: float
252
+ """
234
253
  if status is None:
235
254
  status = backend.implicit_randu()[0]
236
255
  g = backend.cond(
@@ -323,6 +342,35 @@ class Circuit(BaseCircuit):
323
342
  status: Optional[float] = None,
324
343
  name: Optional[str] = None,
325
344
  ) -> Tensor:
345
+ """
346
+ Apply a unitary Kraus channel to the circuit using a Monte Carlo approach. This method is functionally
347
+ similar to `unitary_kraus` but uses `backend.switch` for selecting the Kraus operator, which can have
348
+ different performance characteristics on some backends.
349
+
350
+ A random Kraus operator from the provided list is applied to the circuit based on the given probabilities.
351
+ This method is jittable and suitable for simulating noisy quantum circuits where the noise is represented
352
+ by unitary Kraus operators.
353
+
354
+ .. warning::
355
+ This method may have issues with `vmap` due to potential concurrent access locks, potentially related with
356
+ `backend.switch`. `unitary_kraus` is generally recommended.
357
+
358
+ :param kraus: A sequence of `Gate` objects representing the unitary Kraus operators.
359
+ :type kraus: Sequence[Gate]
360
+ :param index: The qubit indices on which to apply the Kraus channel.
361
+ :type index: int
362
+ :param prob: A sequence of probabilities corresponding to each Kraus operator. If None, probabilities
363
+ are derived from the operators themselves. Defaults to None.
364
+ :type prob: Optional[Sequence[float]], optional
365
+ :param status: A random number between 0 and 1 to determine which Kraus operator to apply. If None,
366
+ a random number is generated automatically. Defaults to None.
367
+ :type status: Optional[float], optional
368
+ :param name: An optional name for the operation. Defaults to None.
369
+ :type name: Optional[str], optional
370
+ :return: A tensor indicating which Kraus operator was applied.
371
+ :rtype: Tensor
372
+ """
373
+
326
374
  # dont use, has issue conflicting with vmap, concurrent access lock emerged
327
375
  # potential issue raised from switch
328
376
  # general impl from Monte Carlo trajectory depolarizing above
tensorcircuit/cons.py CHANGED
@@ -516,8 +516,8 @@ def _get_path_cache_friendly(
516
516
  nodes = list(nodes)
517
517
 
518
518
  nodes_new = sorted(nodes, key=lambda node: getattr(node, "_stable_id_", -1))
519
- if isinstance(algorithm, list):
520
- return algorithm, nodes_new
519
+ # if isinstance(algorithm, list):
520
+ # return algorithm, [nodes_new]
521
521
 
522
522
  all_edges = tn.get_all_edges(nodes_new)
523
523
  all_edges_sorted = sorted_edges(all_edges)
@@ -693,6 +693,51 @@ def _base(
693
693
  return final_node
694
694
 
695
695
 
696
+ class NodesReturn(Exception):
697
+ """
698
+ Intentionally stop execution to return a value.
699
+ """
700
+
701
+ def __init__(self, value_to_return: Any):
702
+ self.value = value_to_return
703
+ super().__init__(
704
+ f"Intentionally stopping execution to return: {value_to_return}"
705
+ )
706
+
707
+
708
+ def _get_sorted_nodes(nodes: List[Any], *args: Any, **kws: Any) -> Any:
709
+ nodes_new = sorted(nodes, key=lambda node: getattr(node, "_stable_id_", -1))
710
+ raise NodesReturn(nodes_new)
711
+
712
+
713
+ def function_nodes_capture(func: Callable[[Any], Any]) -> Callable[[Any], Any]:
714
+ @wraps(func)
715
+ def wrapper(*args: Any, **kwargs: Any) -> Any:
716
+ with runtime_contractor(method="before"):
717
+ try:
718
+ result = func(*args, **kwargs)
719
+ return result
720
+ except NodesReturn as e:
721
+ return e.value
722
+
723
+ return wrapper
724
+
725
+
726
+ @contextmanager
727
+ def runtime_nodes_capture(key: str = "nodes") -> Iterator[Any]:
728
+ old_contractor = getattr(thismodule, "contractor")
729
+ set_contractor(method="before")
730
+ captured_value: Dict[str, List[tn.Node]] = {}
731
+ try:
732
+ yield captured_value
733
+ except NodesReturn as e:
734
+ captured_value[key] = e.value
735
+ finally:
736
+ for module in sys.modules:
737
+ if module.startswith(package_name):
738
+ setattr(sys.modules[module], "contractor", old_contractor)
739
+
740
+
696
741
  def custom(
697
742
  nodes: List[Any],
698
743
  optimizer: Any,
@@ -763,6 +808,16 @@ def custom_stateful(
763
808
 
764
809
  # only work for custom
765
810
  def contraction_info_decorator(algorithm: Callable[..., Any]) -> Callable[..., Any]:
811
+ """Decorator to add contraction information logging to an optimizer.
812
+
813
+ This decorator wraps an optimization algorithm and prints detailed information
814
+ about the contraction cost (FLOPs, size, write) and path finding time.
815
+
816
+ :param algorithm: The optimization algorithm to decorate.
817
+ :type algorithm: Callable[..., Any]
818
+ :return: The decorated optimization algorithm.
819
+ :rtype: Callable[..., Any]
820
+ """
766
821
  from cotengra import ContractionTree
767
822
 
768
823
  def new_algorithm(
@@ -869,6 +924,9 @@ def set_contractor(
869
924
  **kws,
870
925
  )
871
926
 
927
+ elif method == "before": # a hack way to get the nodes
928
+ cf = _get_sorted_nodes
929
+
872
930
  else:
873
931
  # cf = getattr(tn.contractors, method, None)
874
932
  # if not cf:
tensorcircuit/fgs.py CHANGED
@@ -73,17 +73,26 @@ class FGSSimulator:
73
73
  cmatrix: Optional[Tensor] = None,
74
74
  ):
75
75
  """
76
- _summary_
76
+ Initializes the Fermion Gaussian State (FGS) simulator.
77
77
 
78
- :param L: system size
78
+ The state can be initialized in one of four ways:
79
+ 1. By specifying the system size `L` and a list of `filled` sites, creating a product state.
80
+ 2. By providing a quadratic Hamiltonian `hc`, the ground state of which is used as the initial state.
81
+ 3. By directly providing the `alpha` matrix, which defines the Bogoliubov transformation.
82
+ 4. For debugging, by providing a pre-computed correlation matrix `cmatrix`.
83
+
84
+ :param L: The number of fermionic sites (system size).
79
85
  :type L: int
80
- :param filled: the fermion site that is fully occupied, defaults to None
86
+ :param filled: A list of site indices that are occupied by fermions in the initial state.
87
+ Defaults to None (no sites filled).
81
88
  :type filled: Optional[List[int]], optional
82
- :param alpha: directly specify the alpha tensor as the input
89
+ :param alpha: The matrix defining the Bogoliubov transformation from the vacuum state, of shape `(2L, L)`.
90
+ If provided, it directly specifies the initial state. Defaults to None.
83
91
  :type alpha: Optional[Tensor], optional
84
- :param hc: the input is given as the ground state of quadratic Hamiltonian ``hc``
92
+ :param hc: A quadratic Hamiltonian. The ground state of this Hamiltonian will be used as the initial state.
93
+ Defaults to None.
85
94
  :type hc: Optional[Tensor], optional
86
- :param cmatrix: only used for debug, defaults to None
95
+ :param cmatrix: A pre-computed correlation matrix, primarily for debugging purposes. Defaults to None.
87
96
  :type cmatrix: Optional[Tensor], optional
88
97
  """
89
98
  if filled is None:
@@ -105,6 +114,19 @@ class FGSSimulator:
105
114
  def fermion_diagonalization(
106
115
  cls, hc: Tensor, L: int
107
116
  ) -> Tuple[Tensor, Tensor, Tensor]:
117
+ """
118
+ Diagonalizes a quadratic fermionic Hamiltonian.
119
+
120
+ This method computes the eigenvalues, eigenvectors, and the alpha matrix for a given
121
+ quadratic Hamiltonian `hc`.
122
+
123
+ :param hc: The quadratic Hamiltonian to be diagonalized.
124
+ :type hc: Tensor
125
+ :param L: The number of fermionic sites.
126
+ :type L: int
127
+ :return: A tuple containing the eigenvalues, eigenvectors, and the alpha matrix.
128
+ :rtype: Tuple[Tensor, Tensor, Tensor]
129
+ """
108
130
  es, u = backend.eigh(hc)
109
131
  es = es[::-1]
110
132
  u = u[:, ::-1]
@@ -115,6 +137,19 @@ class FGSSimulator:
115
137
  def fermion_diagonalization_2(
116
138
  cls, hc: Tensor, L: int
117
139
  ) -> Tuple[Tensor, Tensor, Tensor]:
140
+ """
141
+ Alternative method for diagonalizing a quadratic fermionic Hamiltonian.
142
+
143
+ This method uses a different approach based on the Schur decomposition to diagonalize
144
+ the Hamiltonian.
145
+
146
+ :param hc: The quadratic Hamiltonian to be diagonalized.
147
+ :type hc: Tensor
148
+ :param L: The number of fermionic sites.
149
+ :type L: int
150
+ :return: A tuple containing the eigenvalues, eigenvectors, and the alpha matrix.
151
+ :rtype: Tuple[Tensor, Tensor, Tensor]
152
+ """
118
153
  w = cls.wmatrix(L)
119
154
  hm = 0.25 * w @ hc @ backend.adjoint(w)
120
155
  hm = backend.real((-1.0j) * hm)
@@ -140,6 +175,16 @@ class FGSSimulator:
140
175
 
141
176
  @staticmethod
142
177
  def wmatrix(L: int) -> Tensor:
178
+ """
179
+ Constructs the transformation matrix W.
180
+
181
+ This matrix transforms from the fermionic basis to the Majorana basis.
182
+
183
+ :param L: The number of fermionic sites.
184
+ :type L: int
185
+ :return: The transformation matrix W.
186
+ :rtype: Tensor
187
+ """
143
188
  w = np.zeros([2 * L, 2 * L], dtype=complex)
144
189
  for i in range(2 * L):
145
190
  if i % 2 == 1:
@@ -152,6 +197,16 @@ class FGSSimulator:
152
197
 
153
198
  @staticmethod
154
199
  def init_alpha(filled: List[int], L: int) -> Tensor:
200
+ """
201
+ Initializes the alpha matrix for a given set of filled sites.
202
+
203
+ :param filled: A list of site indices that are occupied by fermions.
204
+ :type filled: List[int]
205
+ :param L: The number of fermionic sites.
206
+ :type L: int
207
+ :return: The initialized alpha matrix.
208
+ :rtype: Tensor
209
+ """
155
210
  alpha = np.zeros([2 * L, L])
156
211
  for i in range(L):
157
212
  if i not in filled:
@@ -163,9 +218,29 @@ class FGSSimulator:
163
218
  return alpha
164
219
 
165
220
  def get_alpha(self) -> Tensor:
221
+ """
222
+ Returns the current alpha matrix of the FGS.
223
+
224
+ :return: The alpha matrix.
225
+ :rtype: Tensor
226
+ """
166
227
  return self.alpha
167
228
 
168
229
  def get_cmatrix(self, now_i: bool = True, now_j: bool = True) -> Tensor:
230
+ """
231
+ Calculates the correlation matrix.
232
+
233
+ The correlation matrix is defined as :math:`C_{ij} = \langle c_i^\dagger c_j \rangle`.
234
+ This method can also compute out-of-time-ordered correlators (OTOC) by specifying
235
+ whether to use the current or initial state for the `i` and `j` indices.
236
+
237
+ :param now_i: If True, use the current state for the `i` index. Defaults to True.
238
+ :type now_i: bool, optional
239
+ :param now_j: If True, use the current state for the `j` index. Defaults to True.
240
+ :type now_j: bool, optional
241
+ :return: The correlation matrix.
242
+ :rtype: Tensor
243
+ """
169
244
  # otoc in FGS language, see: https://arxiv.org/pdf/1908.03292.pdf
170
245
  # https://journals.aps.org/prb/pdf/10.1103/PhysRevB.99.054205
171
246
  # otoc for non=hermitian system is more subtle due to the undefined normalization
@@ -197,11 +272,11 @@ class FGSSimulator:
197
272
 
198
273
  def get_reduced_cmatrix(self, subsystems_to_trace_out: List[int]) -> Tensor:
199
274
  """
200
- get reduced correlation matrix by tracing out subsystems
275
+ Calculates the reduced correlation matrix by tracing out specified subsystems.
201
276
 
202
- :param subsystems_to_trace_out: list of sites to be traced out
277
+ :param subsystems_to_trace_out: A list of site indices to be traced out.
203
278
  :type subsystems_to_trace_out: List[int]
204
- :return: reduced density matrix
279
+ :return: The reduced correlation matrix.
205
280
  :rtype: Tensor
206
281
  """
207
282
  m = self.get_cmatrix()
@@ -222,13 +297,13 @@ class FGSSimulator:
222
297
 
223
298
  def renyi_entropy(self, n: int, subsystems_to_trace_out: List[int]) -> Tensor:
224
299
  """
225
- compute renyi_entropy of order ``n`` for the fermion state
300
+ Computes the Renyi entropy of order n for a given subsystem.
226
301
 
227
- :param n: _description_
302
+ :param n: The order of the Renyi entropy.
228
303
  :type n: int
229
- :param subsystems_to_trace_out: system sites to be traced out
304
+ :param subsystems_to_trace_out: A list of site indices to be traced out, defining the subsystem.
230
305
  :type subsystems_to_trace_out: List[int]
231
- :return: _description_
306
+ :return: The Renyi entropy of order n.
232
307
  :rtype: Tensor
233
308
  """
234
309
  m = self.get_reduced_cmatrix(subsystems_to_trace_out)
@@ -248,15 +323,17 @@ class FGSSimulator:
248
323
  subsystems_to_trace_out: List[int],
249
324
  ) -> Tensor:
250
325
  """
326
+ Computes the charge moment of order n.
327
+
251
328
  Ref: https://arxiv.org/abs/2302.03330
252
329
 
253
- :param alpha: to be integrated
330
+ :param alpha: The alpha parameter for the charge moment calculation.
254
331
  :type alpha: Tensor
255
- :param n: n-order, Renyi-n
332
+ :param n: The order of the charge moment (Renyi-n).
256
333
  :type n: int
257
- :param subsystems_to_trace_out: _description_
334
+ :param subsystems_to_trace_out: A list of site indices to be traced out.
258
335
  :type subsystems_to_trace_out: List[int]
259
- :return: _description_
336
+ :return: The charge moment.
260
337
  :rtype: Tensor
261
338
  """
262
339
  m = self.get_reduced_cmatrix(subsystems_to_trace_out)
@@ -297,18 +374,23 @@ class FGSSimulator:
297
374
  with_std: bool = False,
298
375
  ) -> Tensor:
299
376
  """
377
+ Computes the Renyi entanglement asymmetry.
378
+
300
379
  Ref: https://arxiv.org/abs/2302.03330
301
380
 
302
- :param n: _description_
381
+ :param n: The order of the Renyi entanglement asymmetry.
303
382
  :type n: int
304
- :param subsystems_to_trace_out: _description_
383
+ :param subsystems_to_trace_out: A list of site indices to be traced out.
305
384
  :type subsystems_to_trace_out: List[int]
306
- :param batch: sample number, defaults 100
307
- :type batch: int
308
- :param status: random number for the sample, -pi to pi,
309
- with shape [batch, n]
310
- :type status: Optional[Tensor]
311
- :return: _description_
385
+ :param batch: The number of samples to use for the Monte Carlo estimation. Defaults to 100.
386
+ :type batch: int, optional
387
+ :param status: A tensor of random numbers for the sampling. If None, it will be generated internally.
388
+ Defaults to None.
389
+ :type status: Optional[Tensor], optional
390
+ :param with_std: If True, also return the standard deviation of the estimation. Defaults to False.
391
+ :type with_std: bool, optional
392
+ :return: The Renyi entanglement asymmetry.
393
+ If `with_std` is True, a tuple containing the asymmetry and its standard deviation is returned.
312
394
  :rtype: Tensor
313
395
  """
314
396
  r = []
@@ -354,11 +436,12 @@ class FGSSimulator:
354
436
 
355
437
  def entropy(self, subsystems_to_trace_out: Optional[List[int]] = None) -> Tensor:
356
438
  """
357
- compute von Neumann entropy for the fermion state
439
+ Computes the von Neumann entropy of a subsystem.
358
440
 
359
- :param subsystems_to_trace_out: _description_, defaults to None
441
+ :param subsystems_to_trace_out: A list of site indices to be traced out, defining the subsystem.
442
+ If None, the entropy of the entire system is computed. Defaults to None.
360
443
  :type subsystems_to_trace_out: Optional[List[int]], optional
361
- :return: _description_
444
+ :return: The von Neumann entropy.
362
445
  :rtype: Tensor
363
446
  """
364
447
  m = self.get_reduced_cmatrix(subsystems_to_trace_out) # type: ignore
@@ -374,9 +457,11 @@ class FGSSimulator:
374
457
 
375
458
  def evol_hamiltonian(self, h: Tensor) -> None:
376
459
  r"""
377
- Evolve as :math:`e^{-i/2 \hat{h}}`
460
+ Evolves the state with a given Hamiltonian.
461
+
462
+ The evolution is given by :math:`e^{-i/2 \hat{h}}`.
378
463
 
379
- :param h: _description_
464
+ :param h: The Hamiltonian for the evolution.
380
465
  :type h: Tensor
381
466
  """
382
467
  # e^{-i/2 H}
@@ -387,9 +472,11 @@ class FGSSimulator:
387
472
 
388
473
  def evol_ihamiltonian(self, h: Tensor) -> None:
389
474
  r"""
390
- Evolve as :math:`e^{-1/2 \hat{h}}`
475
+ Evolves the state with a given Hamiltonian using imaginary time evolution.
391
476
 
392
- :param h: _description_
477
+ The evolution is given by :math:`e^{-1/2 \hat{h}}`.
478
+
479
+ :param h: The Hamiltonian for the evolution.
393
480
  :type h: Tensor
394
481
  """
395
482
  # e^{-1/2 H}
@@ -401,9 +488,11 @@ class FGSSimulator:
401
488
 
402
489
  def evol_ghamiltonian(self, h: Tensor) -> None:
403
490
  r"""
404
- Evolve as :math:`e^{-1/2 i \hat{h}}` with h generally non-Hermitian
491
+ Evolves the state with a general non-Hermitian Hamiltonian.
492
+
493
+ The evolution is given by :math:`e^{-1/2 i \hat{h}}`.
405
494
 
406
- :param h: _description_
495
+ :param h: The non-Hermitian Hamiltonian for the evolution.
407
496
  :type h: Tensor
408
497
  """
409
498
  # e^{-1/2 H}
@@ -414,11 +503,28 @@ class FGSSimulator:
414
503
  self.otcmatrix = {}
415
504
 
416
505
  def orthogonal(self) -> None:
506
+ """Orthogonalizes the alpha matrix using QR decomposition."""
417
507
  q, _ = backend.qr(self.alpha)
418
508
  self.alpha = q
419
509
 
420
510
  @staticmethod
421
511
  def hopping(chi: Tensor, i: int, j: int, L: int) -> Tensor:
512
+ """
513
+ Constructs the hopping Hamiltonian between two sites.
514
+
515
+ The hopping Hamiltonian is given by :math:`\chi c_i^\dagger c_j + h.c.`.
516
+
517
+ :param chi: The hopping strength.
518
+ :type chi: Tensor
519
+ :param i: The index of the first site.
520
+ :type i: int
521
+ :param j: The index of the second site.
522
+ :type j: int
523
+ :param L: The number of fermionic sites.
524
+ :type L: int
525
+ :return: The hopping Hamiltonian.
526
+ :rtype: Tensor
527
+ """
422
528
  # chi * ci dagger cj + hc.
423
529
  chi = backend.convert_to_tensor(chi)
424
530
  chi = backend.cast(chi, dtypestr)
@@ -429,19 +535,35 @@ class FGSSimulator:
429
535
 
430
536
  def evol_hp(self, i: int, j: int, chi: Tensor = 0) -> None:
431
537
  r"""
432
- The evolve Hamiltonian is :math:`\chi c_i^\dagger c_j +h.c.`
538
+ Evolves the state with a hopping Hamiltonian.
539
+
540
+ The evolution is governed by the Hamiltonian :math:`\chi c_i^\dagger c_j + h.c.`.
433
541
 
434
- :param i: _description_
542
+ :param i: The index of the first site.
435
543
  :type i: int
436
- :param j: _description_
544
+ :param j: The index of the second site.
437
545
  :type j: int
438
- :param chi: _description_, defaults to 0
546
+ :param chi: The hopping strength. Defaults to 0.
439
547
  :type chi: Tensor, optional
440
548
  """
441
549
  self.evol_hamiltonian(self.hopping(chi, i, j, self.L))
442
550
 
443
551
  @staticmethod
444
552
  def chemical_potential(chi: Tensor, i: int, L: int) -> Tensor:
553
+ """
554
+ Constructs the chemical potential Hamiltonian for a single site.
555
+
556
+ The chemical potential Hamiltonian is given by :math:`\chi c_i^\dagger c_i`.
557
+
558
+ :param chi: The chemical potential strength.
559
+ :type chi: Tensor
560
+ :param i: The index of the site.
561
+ :type i: int
562
+ :param L: The number of fermionic sites.
563
+ :type L: int
564
+ :return: The chemical potential Hamiltonian.
565
+ :rtype: Tensor
566
+ """
445
567
  chi = backend.convert_to_tensor(chi)
446
568
  chi = backend.cast(chi, dtypestr)
447
569
  m = chi / 2 * onehot_matrix(i, i, 2 * L)
@@ -450,6 +572,22 @@ class FGSSimulator:
450
572
 
451
573
  @staticmethod
452
574
  def sc_pairing(chi: Tensor, i: int, j: int, L: int) -> Tensor:
575
+ """
576
+ Constructs the superconducting pairing Hamiltonian between two sites.
577
+
578
+ The superconducting pairing Hamiltonian is given by :math:`\chi c_i^\dagger c_j^\dagger + h.c.`.
579
+
580
+ :param chi: The pairing strength.
581
+ :type chi: Tensor
582
+ :param i: The index of the first site.
583
+ :type i: int
584
+ :param j: The index of the second site.
585
+ :type j: int
586
+ :param L: The number of fermionic sites.
587
+ :type L: int
588
+ :return: The superconducting pairing Hamiltonian.
589
+ :rtype: Tensor
590
+ """
453
591
  chi = backend.convert_to_tensor(chi)
454
592
  chi = backend.cast(chi, dtypestr)
455
593
  m = chi / 2 * onehot_matrix(i, j + L, 2 * L)
@@ -459,41 +597,57 @@ class FGSSimulator:
459
597
 
460
598
  def evol_sp(self, i: int, j: int, chi: Tensor = 0) -> None:
461
599
  r"""
462
- The evolve Hamiltonian is :math:`chi c_i^\dagger c_j^\dagger +h.c.`
600
+ Evolves the state with a superconducting pairing Hamiltonian.
463
601
 
602
+ The evolution is governed by the Hamiltonian :math:`\chi c_i^\dagger c_j^\dagger + h.c.`.
464
603
 
465
- :param i: _description_
604
+ :param i: The index of the first site.
466
605
  :type i: int
467
- :param j: _description_
606
+ :param j: The index of the second site.
468
607
  :type j: int
469
- :param chi: _description_, defaults to 0
608
+ :param chi: The pairing strength. Defaults to 0.
470
609
  :type chi: Tensor, optional
471
610
  """
472
611
  self.evol_hamiltonian(self.sc_pairing(chi, i, j, self.L))
473
612
 
474
613
  def evol_cp(self, i: int, chi: Tensor = 0) -> None:
475
614
  r"""
476
- The evolve Hamiltonian is :math:`chi c_i^\dagger c_i`
615
+ Evolves the state with a chemical potential Hamiltonian.
477
616
 
478
- :param i: _description_
617
+ The evolution is governed by the Hamiltonian :math:`\chi c_i^\dagger c_i`.
618
+
619
+ :param i: The index of the site.
479
620
  :type i: int
480
- :param chi: _description_, defaults to 0
621
+ :param chi: The chemical potential strength. Defaults to 0.
481
622
  :type chi: Tensor, optional
482
623
  """
483
624
  self.evol_hamiltonian(self.chemical_potential(chi, i, self.L))
484
625
 
485
626
  def evol_icp(self, i: int, chi: Tensor = 0) -> None:
486
627
  r"""
487
- The evolve Hamiltonian is :math:`chi c_i^\dagger c_i` with :math:`\exp^{-H/2}`
628
+ Evolves the state with a chemical potential Hamiltonian using imaginary time evolution.
629
+
630
+ The evolution is governed by :math:`e^{-H/2}` where :math:`H = \chi c_i^\dagger c_i`.
488
631
 
489
- :param i: _description_
632
+ :param i: The index of the site.
490
633
  :type i: int
491
- :param chi: _description_, defaults to 0
634
+ :param chi: The chemical potential strength. Defaults to 0.
492
635
  :type chi: Tensor, optional
493
636
  """
494
637
  self.evol_ihamiltonian(self.chemical_potential(chi, i, self.L))
495
638
 
496
639
  def get_bogoliubov_uv(self) -> Tuple[Tensor, Tensor]:
640
+ """
641
+ Returns the u and v matrices of the Bogoliubov transformation.
642
+
643
+ The Bogoliubov transformation is defined as:
644
+ :math:`b_k = u_{k,i} a_i + v_{k,i} a_i^\dagger`
645
+
646
+ where :math:`b_k` are the new fermionic operators and :math:`a_i` are the original ones.
647
+
648
+ :return: A tuple containing the u and v matrices.
649
+ :rtype: Tuple[Tensor, Tensor]
650
+ """
497
651
  return (
498
652
  backend.gather1d(
499
653
  self.alpha, backend.convert_to_tensor([i for i in range(self.L)])
@@ -506,17 +660,27 @@ class FGSSimulator:
506
660
 
507
661
  def get_cmatrix_majorana(self) -> Tensor:
508
662
  r"""
509
- correlation matrix defined in majorana basis
510
- convention: :math:`gamma_0 = c_0 + c_0^\dagger`
511
- :math:`gamma_1 = i(c_0 - c_0^\dagger)`
663
+ Calculates the correlation matrix in the Majorana basis.
512
664
 
513
- :return: _description_
665
+ The Majorana operators are defined as:
666
+ :math:`\gamma_{2i} = c_i + c_i^\dagger`
667
+ :math:`\gamma_{2i+1} = -i(c_i - c_i^\dagger)`
668
+
669
+ :return: The correlation matrix in the Majorana basis.
514
670
  :rtype: Tensor
515
671
  """
516
672
  c = self.get_cmatrix()
517
673
  return self.wtransform @ c @ backend.adjoint(self.wtransform)
518
674
 
519
675
  def get_covariance_matrix(self) -> Tensor:
676
+ """
677
+ Calculates the covariance matrix.
678
+
679
+ The covariance matrix is defined from the Majorana correlation matrix.
680
+
681
+ :return: The covariance matrix.
682
+ :rtype: Tensor
683
+ """
520
684
  m = self.get_cmatrix_majorana()
521
685
  return -1.0j * (2 * m - backend.eye(self.L * 2))
522
686
 
@@ -524,34 +688,38 @@ class FGSSimulator:
524
688
  self, i: int, j: int, now_i: bool = True, now_j: bool = True
525
689
  ) -> Tensor:
526
690
  r"""
527
- expectation of two fermion terms
528
- convention: (c, c^\dagger)
529
- for i>L, c_{i-L}^\dagger is assumed
691
+ Calculates the expectation value of a two-fermion term.
530
692
 
531
- :param i: _description_
693
+ The convention for the operators is (c, c^\dagger). For i >= L, the operator is c_{i-L}^\dagger.
694
+
695
+ :param i: The index of the first fermion operator.
532
696
  :type i: int
533
- :param j: _description_
697
+ :param j: The index of the second fermion operator.
534
698
  :type j: int
535
- :return: _description_
699
+ :param now_i: Whether to use the current state for the first operator. Defaults to True.
700
+ :type now_i: bool, optional
701
+ :param now_j: Whether to use the current state for the second operator. Defaults to True.
702
+ :type now_j: bool, optional
703
+ :return: The expectation value of the two-fermion term.
536
704
  :rtype: Tensor
537
705
  """
538
706
  return self.get_cmatrix(now_i, now_j)[i][(j + self.L) % (2 * self.L)]
539
707
 
540
708
  def expectation_4body(self, i: int, j: int, k: int, l: int) -> Tensor:
541
709
  r"""
542
- expectation of four fermion terms using Wick Thm
543
- convention: (c, c^\dagger)
544
- for i>L, c_{i-L}^\dagger is assumed
710
+ Calculates the expectation value of a four-fermion term using Wick's theorem.
545
711
 
546
- :param i: _description_
712
+ The convention for the operators is (c, c^\dagger). For an index m >= L, the operator is c_{m-L}^\dagger.
713
+
714
+ :param i: The index of the first fermion operator.
547
715
  :type i: int
548
- :param j: _description_
716
+ :param j: The index of the second fermion operator.
549
717
  :type j: int
550
- :param k: _description_
718
+ :param k: The index of the third fermion operator.
551
719
  :type k: int
552
- :param l: _description_
720
+ :param l: The index of the fourth fermion operator.
553
721
  :type l: int
554
- :return: _description_
722
+ :return: The expectation value of the four-fermion term.
555
723
  :rtype: Tensor
556
724
  """
557
725
  e = (
@@ -563,12 +731,11 @@ class FGSSimulator:
563
731
 
564
732
  def post_select(self, i: int, keep: int = 1) -> None:
565
733
  """
566
- post select (project) the fermion state to occupation eigenstate
567
- <n_i> = ``keep``
734
+ Post-selects the state based on the occupation of a specific site.
568
735
 
569
- :param i: _description_
736
+ :param i: The index of the site to post-select on.
570
737
  :type i: int
571
- :param keep: _description_, defaults to 1
738
+ :param keep: The desired occupation number (0 or 1). Defaults to 1.
572
739
  :type keep: int, optional
573
740
  """
574
741
  # i is not jittable, keep is jittable
@@ -628,6 +795,20 @@ class FGSSimulator:
628
795
  self.alpha = q
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)
@@ -260,6 +260,17 @@ class MPSCircuit(AbstractCircuit):
260
260
  index_to: int,
261
261
  split: Optional[Dict[str, Any]] = None,
262
262
  ) -> None:
263
+ """
264
+ Apply a series of SWAP gates to move a qubit from ``index_from`` to ``index_to``.
265
+
266
+ :param index_from: The starting index of the qubit.
267
+ :type index_from: int
268
+ :param index_to: The destination index of the qubit.
269
+ :type index_to: int
270
+ :param split: Truncation options for the SWAP gates. Defaults to None.
271
+ consistent with the split option of the class.
272
+ :type split: Optional[Dict[str, Any]], optional
273
+ """
263
274
  if split is None:
264
275
  split = self.split
265
276
  self.position(index_from)
@@ -437,7 +448,15 @@ class MPSCircuit(AbstractCircuit):
437
448
  split: Optional[Dict[str, Any]] = None,
438
449
  ) -> None:
439
450
  """
440
- Reduce the bond dimension between two adjacent sites by SVD
451
+ Reduce the bond dimension between two adjacent sites using SVD.
452
+
453
+ :param index_left: The index of the left tensor of the bond to be truncated.
454
+ :type index_left: int
455
+ :param center_left: If True, the orthogonality center will be on the left tensor after truncation.
456
+ Otherwise, it will be on the right tensor. Defaults to True.
457
+ :type center_left: bool, optional
458
+ :param split: Truncation options for the SVD. Defaults to None.
459
+ :type split: Optional[Dict[str, Any]], optional
441
460
  """
442
461
  if split is None:
443
462
  split = self.split
@@ -463,7 +482,22 @@ class MPSCircuit(AbstractCircuit):
463
482
  split: Optional[Dict[str, Any]] = None,
464
483
  ) -> None:
465
484
  """
466
- Apply a MPO to the MPS
485
+ Apply a Matrix Product Operator (MPO) to the MPS.
486
+
487
+ The application involves three main steps:
488
+ 1. Contract the MPO tensors with the corresponding MPS tensors.
489
+ 2. Canonicalize the resulting tensors by moving the orthogonality center.
490
+ 3. Truncate the bond dimensions to control complexity.
491
+
492
+ :param tensors: A sequence of tensors representing the MPO.
493
+ :type tensors: Sequence[Tensor]
494
+ :param index_left: The starting index on the MPS where the MPO is applied.
495
+ :type index_left: int
496
+ :param center_left: If True, the final orthogonality center will be at the left end of the MPO.
497
+ Otherwise, it will be at the right end. Defaults to True.
498
+ :type center_left: bool, optional
499
+ :param split: Truncation options for bond dimension reduction. Defaults to None.
500
+ :type split: Optional[Dict[str, Any]], optional
467
501
  """
468
502
  # step 1:
469
503
  # contract tensor
@@ -521,10 +555,17 @@ class MPSCircuit(AbstractCircuit):
521
555
  *index: int,
522
556
  split: Optional[Dict[str, Any]] = None,
523
557
  ) -> None:
524
- # TODO(@SUSYUSTC): jax autograd is wrong on this function
525
558
  """
526
- Apply a n-qubit gate by transforming the gate to MPO
559
+ Apply an n-qubit gate to the MPS by converting it to an MPO.
560
+
561
+ :param gate: The n-qubit gate to apply.
562
+ :type gate: Gate
563
+ :param index: The indices of the qubits to apply the gate to.
564
+ :type index: int
565
+ :param split: Truncation options for the MPO application. Defaults to None.
566
+ :type split: Optional[Dict[str, Any]], optional
527
567
  """
568
+ # TODO(@SUSYUSTC): jax autograd is wrong on this function
528
569
  ordered = np.all(np.diff(index) > 0)
529
570
  if not ordered:
530
571
  order = np.argsort(index)
@@ -147,14 +147,16 @@ class StabilizerCircuit(AbstractCircuit):
147
147
 
148
148
  def measure(self, *index: int, with_prob: bool = False) -> Tensor:
149
149
  """
150
- Measure qubits in Z basis.
150
+ Measure qubits in the Z basis.
151
151
 
152
- :param index: Indices of qubits to measure
152
+ :param index: Indices of the qubits to measure.
153
153
  :type index: int
154
- :param with_prob: Return probability of measurement outcome, defaults to False
154
+ :param with_prob: If True, returns the theoretical probability of the measurement outcome.
155
+ defaults to False
155
156
  :type with_prob: bool, optional
156
- :return: Measurement results and probability (if with_prob=True)
157
- :rtype: Union[np.ndarray, Tuple[np.ndarray, float]]
157
+ :return: A tensor containing the measurement results.
158
+ If `with_prob` is True, a tuple containing the results and the probability is returned.
159
+ :rtype: Tensor
158
160
  """
159
161
  # Convert negative indices
160
162
 
@@ -162,20 +164,29 @@ class StabilizerCircuit(AbstractCircuit):
162
164
 
163
165
  # Add measurement instructions
164
166
  s1 = self.current_simulator().copy()
165
- m = s1.measure_many(*index)
166
167
  # Sample once from the circuit using sampler
167
168
 
168
- # TODO(@refraction-ray): correct probability
169
+ if with_prob:
170
+ num_random_measurements = 0
171
+ for i in index:
172
+ print(i, s1.peek_z(i))
173
+ if s1.peek_z(i) == 0:
174
+ num_random_measurements += 1
175
+ probability = (0.5) ** num_random_measurements
176
+
177
+ m = s1.measure_many(*index)
178
+ if with_prob:
179
+ return m, probability
169
180
  return m
170
181
 
171
182
  def cond_measurement(self, index: int) -> Tensor:
172
183
  """
173
- Measure qubits in Z basis with state collapse.
184
+ Measure a single qubit in the Z basis and collapse the state.
174
185
 
175
- :param index: Index of qubit to measure
186
+ :param index: The index of the qubit to measure.
176
187
  :type index: int
177
- :return: Measurement results and probability (if with_prob=True)
178
- :rtype: Union[np.ndarray, Tuple[np.ndarray, float]]
188
+ :return: The measurement result (0 or 1).
189
+ :rtype: Tensor
179
190
  """
180
191
  # Convert negative indices
181
192
 
@@ -191,12 +202,12 @@ class StabilizerCircuit(AbstractCircuit):
191
202
 
192
203
  def cond_measure_many(self, *index: int) -> Tensor:
193
204
  """
194
- Measure qubits in Z basis with state collapse.
205
+ Measure multiple qubits in the Z basis and collapse the state.
195
206
 
196
- :param index: Index of qubit to measure
207
+ :param index: The indices of the qubits to measure.
197
208
  :type index: int
198
- :return: Measurement results and probability (if with_prob=True)
199
- :rtype: Union[np.ndarray, Tuple[np.ndarray, float]]
209
+ :return: A tensor containing the measurement results.
210
+ :rtype: Tensor
200
211
  """
201
212
  # Convert negative indices
202
213
 
@@ -13,8 +13,6 @@ logger = logging.getLogger(__name__)
13
13
 
14
14
  try:
15
15
  import qiskit.quantum_info as qi
16
- import symengine
17
- import sympy
18
16
  from qiskit import QuantumCircuit
19
17
  from qiskit.circuit import Parameter, ParameterExpression
20
18
  from qiskit.circuit.exceptions import CircuitError
@@ -28,6 +26,14 @@ except ImportError:
28
26
  CircuitInstruction = Any
29
27
  QuantumCircuit = Any
30
28
 
29
+ try:
30
+ import symengine
31
+ import sympy
32
+ except ImportError:
33
+ logger.info(
34
+ "Please first ``pip install -U sympy symengine`` to enable `qiskit2tc` in translation module"
35
+ )
36
+
31
37
  try:
32
38
  import cirq
33
39
  except ImportError:
@@ -325,7 +331,9 @@ def qir2qiskit(
325
331
  qiskit_circ.append(gate, index_reversed)
326
332
  elif gate_name == "multicontrol":
327
333
  unitary = backend.numpy(backend.convert_to_tensor(parameters["unitary"]))
334
+ k = int(np.log(unitary.shape[-1]) / np.log(2) + 1e-7)
328
335
  ctrl_str = "".join(map(str, parameters["ctrl"]))[::-1]
336
+ unitary = perm_matrix(k) @ unitary @ perm_matrix(k)
329
337
  gate = UnitaryGate(unitary, label=qis_name).control(
330
338
  len(ctrl_str), ctrl_state=ctrl_str
331
339
  )
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: tensorcircuit-nightly
3
- Version: 1.2.1.dev20250724
3
+ Version: 1.2.1.dev20250726
4
4
  Summary: nightly release for tensorcircuit
5
5
  Home-page: https://github.com/refraction-ray/tensorcircuit-dev
6
6
  Author: TensorCircuit Authors
@@ -1,25 +1,25 @@
1
- tensorcircuit/__init__.py,sha256=crGf_yKgxwxVS0dPKaNTaY7srmWi_K0oqt9Ixlj6CZ0,2032
1
+ tensorcircuit/__init__.py,sha256=f4VIGH0ZgN9St3QabFoG3CUJqNw3FwknLJRl8PU1nD8,2032
2
2
  tensorcircuit/about.py,sha256=DazTswU2nAwOmASTaDII3L04PVtaQ7oiWPty5YMI3Wk,5267
3
3
  tensorcircuit/abstractcircuit.py,sha256=0osacPqq7B1EJki-cI1aLYoVRmjFaG9q3XevWMs7SsA,44125
4
4
  tensorcircuit/asciiart.py,sha256=neY1OWFwtoW5cHPNwkQHgRPktDniQvdlP9QKHkk52fM,8236
5
5
  tensorcircuit/basecircuit.py,sha256=ipCg3J55sgkciUZ2qCZqpVqE00YIWRlACu509nktg3I,37203
6
6
  tensorcircuit/channels.py,sha256=CFQxWI-JmkIxexslCBdjp_RSxUbHs6eAJv4LvlXXXCY,28637
7
- tensorcircuit/circuit.py,sha256=jC1Bb9A06pt6XX7muC-Q72BR9HS6n0Ft6aMjOGcz9iM,36428
8
- tensorcircuit/cons.py,sha256=0fE9UY02TNI3FyQWGyGCKuYpwkMlV-a1cMbTZveFYmk,31125
7
+ tensorcircuit/circuit.py,sha256=mE4b_9xRu3ydoB8iDffdx35V9GZLhAQD_tkjZDLnLjg,39105
8
+ tensorcircuit/cons.py,sha256=uYKBeYKkDoJEqJTNrOZPRM31tBtkqe5aAg8GtVidJ1Y,33014
9
9
  tensorcircuit/densitymatrix.py,sha256=VqMBnWCxO5-OsOp6LOdc5RS2AzmB3U4-w40Vn_lqygo,14865
10
10
  tensorcircuit/experimental.py,sha256=RW97ncitCfO1QJLAUbKBvm2Tsc0hzKhqkC65ShA9-Q0,34456
11
- tensorcircuit/fgs.py,sha256=eIi38DnQBGxY4itxqzGVbi8cAjB3vCYAX87xcJVJmoo,40846
11
+ tensorcircuit/fgs.py,sha256=dBzRz0-9o8QQ6GkA1xzBZgZvqe_APp5jazJxzvbBVaY,49515
12
12
  tensorcircuit/gates.py,sha256=x-wA7adVpP7o0AQLt_xYUScFKj8tU_wUOV2mR1GyrPc,29322
13
13
  tensorcircuit/keras.py,sha256=5OF4dfhEeS8sRYglpqYtQsWPeqp7uK0i7-P-6RRJ7zQ,10126
14
14
  tensorcircuit/mps_base.py,sha256=UZ-v8vsr_rAsKrfun8prVgbXJ-qsdqKy2DZIHpq3sxo,15400
15
- tensorcircuit/mpscircuit.py,sha256=Jv4nsRyOhQxSHpDUJpb9OS6A5E3bTJoIHYGzwgs7NYU,34591
15
+ tensorcircuit/mpscircuit.py,sha256=COO9xzvA2Whe7Ncp6OqrgtXKmahHgTHxXTELAVHzFSY,36777
16
16
  tensorcircuit/noisemodel.py,sha256=vzxpoYEZbHVC4a6g7_Jk4dxsHi4wvhpRFwud8b616Qo,11878
17
17
  tensorcircuit/quantum.py,sha256=LNkIv5cJ2KG6puC18zTuXi-5cojW1Tnz-N-WjZ0Qu5Q,90217
18
18
  tensorcircuit/shadows.py,sha256=6XmWNubbuaxFNvZVWu-RXd0lN9Jkk-xwong_K8o8_KE,17014
19
19
  tensorcircuit/simplify.py,sha256=O11G3UYiVAc30GOfwXXmhLXwGZrQ8OVwLTMQMZp_XBc,9414
20
- tensorcircuit/stabilizercircuit.py,sha256=4gDeTgko04j4dwt7NdJvl8NhqmB8JH75nZjdbLU3Aw0,15178
20
+ tensorcircuit/stabilizercircuit.py,sha256=yoF03HfPYPhsoRrnp3JosoNde7eYluNbcM-PRYL-KfM,15504
21
21
  tensorcircuit/torchnn.py,sha256=z_QpM0QC3mydGyWpyp877j-tSFCPyzynCwqrTWaw-IA,4637
22
- tensorcircuit/translation.py,sha256=D0-JzhN8IxBlPerwDN4ImGbS4VQg-nFxGry9BhEc4xk,28330
22
+ tensorcircuit/translation.py,sha256=VnU7DnYmbk1cWjqa7N68WNLNDn3DwENrMzmbG4_CQco,28611
23
23
  tensorcircuit/utils.py,sha256=CH9gTV4iKIikSS8KajIu3ttyC8i_1tBPf5PAYH1fgxs,7060
24
24
  tensorcircuit/vis.py,sha256=O4hm050KKfOAoVyHsjpMg6NBNVoWhLSlv-xsCx4opsU,12196
25
25
  tensorcircuit/applications/__init__.py,sha256=nAX-Am6JoL9k53iJ_CjZJ2NcjIpaz21H87nrW4Op03k,246
@@ -42,7 +42,7 @@ tensorcircuit/backends/__init__.py,sha256=WiUmbUFzM29w3hKfhuKxVUk3PpqDFiXf4za9g0
42
42
  tensorcircuit/backends/abstract_backend.py,sha256=Ob8zp-AgovoY3uYFNEUA_WlJz9YtgnaJvugKUXWttAA,59018
43
43
  tensorcircuit/backends/backend_factory.py,sha256=Z0aQ-RnxOnQzp-SRw8sefAH8XyBSlj2NXZwOlHinbfY,1713
44
44
  tensorcircuit/backends/cupy_backend.py,sha256=4vgO3lnQnsvWL5hukhskjJp37EAHqio6z6TVXTQcdjs,15077
45
- tensorcircuit/backends/jax_backend.py,sha256=puBnoFZfFxxE5CRiy4QeTjdkRqnsXM4JmkoDn7lLBkE,25638
45
+ tensorcircuit/backends/jax_backend.py,sha256=dkDQ380CJHIdlt1fZvlN_g8DIowWPEcTTV_XBcs0YB0,26088
46
46
  tensorcircuit/backends/jax_ops.py,sha256=o7tLlQMRnaKWcr5rVnOMqwG6KZVpR8M8ryNQ-ceXVxs,4789
47
47
  tensorcircuit/backends/numpy_backend.py,sha256=sd1migp_E2FWjchvOeYRuyM47yexegT2_SW_ukSYSF8,14171
48
48
  tensorcircuit/backends/pytorch_backend.py,sha256=yhfZSrm99yNW-dmijk8t6zAkbVgLRd4b_aIWKrpT7bY,24230
@@ -84,23 +84,23 @@ tensorcircuit/templates/dataset.py,sha256=ldPvCUlwjHU_S98E2ISQp34KqJzJPpPHmDIKJ4
84
84
  tensorcircuit/templates/graphs.py,sha256=cPYrxjoem0xZ-Is9dZKAvEzWZL_FejfIRiCEOTA4qd4,3935
85
85
  tensorcircuit/templates/lattice.py,sha256=F35ebANk0DSmSHLR0-Q_hUbcznyCmZjb4fKmvCMywmA,58575
86
86
  tensorcircuit/templates/measurements.py,sha256=pzc5Aa9S416Ilg4aOY77Z6ZhUlYcXnAkQNQFTuHjFFs,10943
87
- tensorcircuit_nightly-1.2.1.dev20250724.dist-info/licenses/LICENSE,sha256=z8d0m5b2O9McPEK1xHG_dWgUBT6EfBDz6wA0F7xSPTA,11358
87
+ tensorcircuit_nightly-1.2.1.dev20250726.dist-info/licenses/LICENSE,sha256=z8d0m5b2O9McPEK1xHG_dWgUBT6EfBDz6wA0F7xSPTA,11358
88
88
  tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
89
89
  tests/conftest.py,sha256=J9nHlLE3Zspz1rMyzadEuBWhaS5I4Q9sq0lnWybcdIA,1457
90
90
  tests/test_backends.py,sha256=rClxb2gyAoGeXd_ZYVSAJ0zEvJ7z_2btAeFM_Iy_wwY,33925
91
91
  tests/test_calibrating.py,sha256=D1Tlv8mucUhg3ULvB5QlYyaDfw7aEERwq69-aGSb1A4,3805
92
92
  tests/test_channels.py,sha256=BL4CirU8ku9-_NrI6PZAS5xZ0wrL1UEC1S3wPI9dYQM,12628
93
- tests/test_circuit.py,sha256=DkyNJmG4-r9WHEPtRyZ1XrLeECCnjPGiMMlf3Y6yzxg,51866
93
+ tests/test_circuit.py,sha256=IsSIFEs7hUCSYexMb-ESt1ZUpztHtLA0qz0CZolGdc4,52240
94
94
  tests/test_cloud.py,sha256=241ng6LnG_o_2PKR-BuUFfmrj3V1aeFiI-_bcWuPFyo,5606
95
95
  tests/test_compiler.py,sha256=R1t0MDQR01uEbY2wxqzQEf-LkSehrfZWmLvPuguC2JI,3419
96
- tests/test_dmcircuit.py,sha256=Th5N6TCdGQ2MBWy8O3GNnMWshGui8XR_rUSeM2QlVcs,17232
96
+ tests/test_dmcircuit.py,sha256=ZtTS-Jcpt-oN3yafYee9ZZCFW8-2I0MaLpyaDPve0PA,17234
97
97
  tests/test_ensemble.py,sha256=0RzJkv-5D8LeZxS0Q0MwtEcgnXd2zefMquPHRNYT6RY,2109
98
98
  tests/test_fgs.py,sha256=nv3E_F_SAF4ChsoT8Ihm3FtSpOmTGJr_Jf2MoKXXceE,10162
99
99
  tests/test_gates.py,sha256=rAIV2QFpFsA5bT1QivTSkhdarvwu5t0N3IOz4SEDrzg,4593
100
100
  tests/test_interfaces.py,sha256=iJPmes8S8HkA9_PGjsu4Ike-vCXYyS1EMgnNKKXDNaU,16938
101
101
  tests/test_keras.py,sha256=U453jukavmx0RMeTSDEgPzrNdHNEfK1CW0CqO3XCNKo,4841
102
102
  tests/test_lattice.py,sha256=_ptDVK3EhS-X5fCQWiP8sHk3azdyGFuwqg6KMkBTkDE,65789
103
- tests/test_miscs.py,sha256=Wo2fZ-Co4-iPm7n3F9NTxnXuabWi_J6uvrOr0GIMqvY,9175
103
+ tests/test_miscs.py,sha256=mm6kv5LqLkwHxWrGzLxajyOp1RaaKoHxq2OT1J3DpIM,9741
104
104
  tests/test_mpscircuit.py,sha256=mDXX8oQeFeHr_PdZvwqyDs_tVcVAqLmCERqlTAU7590,10552
105
105
  tests/test_noisemodel.py,sha256=UYoMtCjwDaB-CCn5kLosofz-qTMiY4KGAFBjVtqqLPE,5637
106
106
  tests/test_qaoa.py,sha256=hEcC_XVmKBGt9XgUGtbTO8eQQK4mjorgTIrfqZCeQls,2616
@@ -110,11 +110,11 @@ tests/test_quantum_attr.py,sha256=Zl6WbkbnTWVp6FL2rR21qBGsLoheoIEZXqWZKxfpDRs,12
110
110
  tests/test_results.py,sha256=8cQO0ShkBc4_pB-fi9s35WJbuZl5ex5y1oElSV-GlRo,11882
111
111
  tests/test_shadows.py,sha256=1T3kJesVJ5XfZrSncL80xdq-taGCSnTDF3eL15UlavY,5160
112
112
  tests/test_simplify.py,sha256=35tbOu1QANsPvY1buLwNhqPnMkBOsnBtHn82qaukmgI,1175
113
- tests/test_stabilizer.py,sha256=HdVRbEshg02CaNsqni_nRYY7KL5vhRBp9k1KGzOSE9I,5252
113
+ tests/test_stabilizer.py,sha256=MivuZ5pY7GOcEPTanhtrflXostyLBToHyjfPqCU0tG0,5450
114
114
  tests/test_templates.py,sha256=Xm9otFFaaBWG9TZpgJ-nNh9MBfRipTzFWL8fBOnie2k,7192
115
115
  tests/test_torchnn.py,sha256=CHLTfWkF7Ses5_XnGFN_uv_JddfgenFEFzaDtSH8XYU,2848
116
116
  tests/test_van.py,sha256=kAWz860ivlb5zAJuYpzuBe27qccT-Yf0jatf5uXtTo4,3163
117
- tensorcircuit_nightly-1.2.1.dev20250724.dist-info/METADATA,sha256=zl0gksspBZ2l7gAYmvRyfOwclQEjtFkFy2k9cC46Fr8,34831
118
- tensorcircuit_nightly-1.2.1.dev20250724.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
119
- tensorcircuit_nightly-1.2.1.dev20250724.dist-info/top_level.txt,sha256=O_Iqeh2x02lasEYMI9iyPNNNtMzcpg5qvwMOkZQ7n4A,20
120
- tensorcircuit_nightly-1.2.1.dev20250724.dist-info/RECORD,,
117
+ tensorcircuit_nightly-1.2.1.dev20250726.dist-info/METADATA,sha256=rqna4H-ixz2BjdKLCDo3EUlJAoUr2XrJqs0V537BCfo,34831
118
+ tensorcircuit_nightly-1.2.1.dev20250726.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
119
+ tensorcircuit_nightly-1.2.1.dev20250726.dist-info/top_level.txt,sha256=O_Iqeh2x02lasEYMI9iyPNNNtMzcpg5qvwMOkZQ7n4A,20
120
+ tensorcircuit_nightly-1.2.1.dev20250726.dist-info/RECORD,,
tests/test_circuit.py CHANGED
@@ -889,6 +889,19 @@ def test_circuit_quoperator(backend):
889
889
  np.testing.assert_allclose(qo.eval_matrix(), c.matrix(), atol=1e-5)
890
890
 
891
891
 
892
+ def test_perm_matrix():
893
+ from tensorcircuit.translation import perm_matrix
894
+
895
+ p2 = perm_matrix(2)
896
+ np.testing.assert_allclose(
897
+ p2, np.array([[1, 0, 0, 0], [0, 0, 1, 0], [0, 1, 0, 0], [0, 0, 0, 1]])
898
+ )
899
+ p3 = perm_matrix(3)
900
+ v = np.arange(8)
901
+ vt = np.array([0, 4, 2, 6, 1, 5, 3, 7])
902
+ np.testing.assert_allclose(p3 @ v, vt)
903
+
904
+
892
905
  @pytest.mark.parametrize("backend", [lf("npb"), lf("tfb"), lf("jaxb")])
893
906
  def test_qir2cirq(backend):
894
907
  try:
@@ -1094,7 +1107,7 @@ def test_qiskit2tc():
1094
1107
  import qiskit.quantum_info as qi
1095
1108
  from qiskit import QuantumCircuit
1096
1109
  from qiskit.circuit.library import HamiltonianGate
1097
- from qiskit.circuit.library.standard_gates import MCXGate, SwapGate
1110
+ from qiskit.circuit.library.standard_gates import MCXGate, SwapGate, CXGate
1098
1111
 
1099
1112
  from tensorcircuit.translation import perm_matrix
1100
1113
  except ImportError:
@@ -1150,12 +1163,13 @@ def test_qiskit2tc():
1150
1163
  mcx_g = MCXGate(3, ctrl_state="010")
1151
1164
  qisc.append(mcx_g, [0, 1, 2, 3])
1152
1165
  qisc.ccx(0, 1, 2, ctrl_state="01")
1153
- CCCRX = SwapGate().control(2, ctrl_state="01")
1154
- qisc.append(CCCRX, [0, 1, 2, 3])
1166
+ CCswap = SwapGate().control(2, ctrl_state="01")
1167
+ qisc.append(CCswap, [0, 1, 2, 3])
1168
+ CCCX = CXGate().control(2, ctrl_state="01")
1169
+ qisc.append(CCCX, [1, 2, 3, 4])
1155
1170
 
1156
- c = tc.Circuit.from_qiskit(qisc, n, np.eye(2**n))
1157
- tc_unitary = c.wavefunction()
1158
- tc_unitary = np.reshape(tc_unitary, [2**n, 2**n])
1171
+ c = tc.Circuit.from_qiskit(qisc, n)
1172
+ tc_unitary = c.matrix()
1159
1173
  qis_unitary = qi.Operator(qisc)
1160
1174
  qis_unitary = np.reshape(qis_unitary, [2**n, 2**n])
1161
1175
  p_mat = perm_matrix(n)
tests/test_dmcircuit.py CHANGED
@@ -239,7 +239,7 @@ def test_measure(backend):
239
239
 
240
240
  key1, key2 = tc.backend.random_split(key)
241
241
  rs1, rs2 = r(key1), r(key2)
242
- assert rs1[0] != rs2[0]
242
+ # assert rs1[0] != rs2[0]
243
243
  print(rs1[1], rs2[1])
244
244
 
245
245
 
tests/test_miscs.py CHANGED
@@ -312,3 +312,23 @@ def test_distrubuted_contractor(jaxb):
312
312
  return c.expectation_ps(z=[-1])
313
313
 
314
314
  np.testing.assert_allclose(value, baseline(params), atol=1e-6)
315
+
316
+
317
+ @pytest.mark.parametrize("backend", [lf("npb"), lf("tfb"), lf("jaxb")])
318
+ def test_runtime_nodes_capture(backend):
319
+ with tc.cons.runtime_nodes_capture() as captured:
320
+ c = tc.Circuit(3)
321
+ c.h(0)
322
+ c.amplitude("010")
323
+ len(captured["nodes"]) == 7
324
+
325
+
326
+ @pytest.mark.parametrize("backend", [lf("npb"), lf("tfb"), lf("jaxb")])
327
+ def test_function_nodes_capture(backend):
328
+ @tc.cons.function_nodes_capture
329
+ def exp(theta):
330
+ c = tc.Circuit(3)
331
+ c.h(0)
332
+ return c.expectation_ps(z=[-3], reuse=False)
333
+
334
+ assert len(exp(0.3)) == 9
tests/test_stabilizer.py CHANGED
@@ -215,3 +215,12 @@ def test_mipt():
215
215
  return c.entanglement_entropy(list(range(n // 2)))
216
216
 
217
217
  print(ruc(50, 10, 0.1))
218
+
219
+
220
+ def test_measure_with_prob():
221
+ c = tc.StabilizerCircuit(3)
222
+ c.h(0)
223
+ c.cnot(0, 1)
224
+ m, p = c.measure(0, 2, with_prob=True)
225
+ np.testing.assert_allclose(p, 0.5, atol=1e-6)
226
+ print(m)