tensorcircuit-nightly 1.2.1.dev20250725__py3-none-any.whl → 1.3.0.dev20250727__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 +1 -1
- tensorcircuit/backends/jax_backend.py +8 -1
- tensorcircuit/circuit.py +48 -0
- tensorcircuit/cons.py +60 -2
- tensorcircuit/fgs.py +254 -72
- tensorcircuit/mpscircuit.py +45 -4
- tensorcircuit/results/counts.py +99 -0
- tensorcircuit/stabilizercircuit.py +25 -15
- tensorcircuit/templates/__init__.py +1 -0
- tensorcircuit/templates/hamiltonians.py +153 -0
- tensorcircuit/utils.py +7 -0
- {tensorcircuit_nightly-1.2.1.dev20250725.dist-info → tensorcircuit_nightly-1.3.0.dev20250727.dist-info}/METADATA +2 -2
- {tensorcircuit_nightly-1.2.1.dev20250725.dist-info → tensorcircuit_nightly-1.3.0.dev20250727.dist-info}/RECORD +22 -20
- tests/test_circuit.py +13 -0
- tests/test_dmcircuit.py +1 -1
- tests/test_fgs.py +8 -0
- tests/test_hamiltonians.py +159 -0
- tests/test_miscs.py +20 -0
- tests/test_stabilizer.py +9 -0
- {tensorcircuit_nightly-1.2.1.dev20250725.dist-info → tensorcircuit_nightly-1.3.0.dev20250727.dist-info}/WHEEL +0 -0
- {tensorcircuit_nightly-1.2.1.dev20250725.dist-info → tensorcircuit_nightly-1.3.0.dev20250727.dist-info}/licenses/LICENSE +0 -0
- {tensorcircuit_nightly-1.2.1.dev20250725.dist-info → tensorcircuit_nightly-1.3.0.dev20250727.dist-info}/top_level.txt +0 -0
tensorcircuit/__init__.py
CHANGED
|
@@ -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
|
-
|
|
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
|
-
|
|
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:
|