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/results/counts.py
CHANGED
|
@@ -6,14 +6,26 @@ from typing import Any, Dict, Optional, Sequence
|
|
|
6
6
|
|
|
7
7
|
import numpy as np
|
|
8
8
|
|
|
9
|
+
from ..quantum import _decode_basis_label
|
|
9
10
|
|
|
10
11
|
Tensor = Any
|
|
11
12
|
ct = Dict[str, int]
|
|
12
13
|
|
|
13
|
-
# TODO(@refraction-ray): merge_count
|
|
14
|
-
|
|
15
14
|
|
|
16
15
|
def reverse_count(count: ct) -> ct:
|
|
16
|
+
"""
|
|
17
|
+
Reverse the bit string keys in a count dictionary.
|
|
18
|
+
|
|
19
|
+
:param count: A dictionary mapping bit strings to counts
|
|
20
|
+
:type count: ct
|
|
21
|
+
:return: A new dictionary with reversed bit string keys
|
|
22
|
+
:rtype: ct
|
|
23
|
+
|
|
24
|
+
:Example:
|
|
25
|
+
|
|
26
|
+
>>> reverse_count({"01": 10, "10": 20})
|
|
27
|
+
{'10': 10, '01': 20}
|
|
28
|
+
"""
|
|
17
29
|
ncount = {}
|
|
18
30
|
for k, v in count.items():
|
|
19
31
|
ncount[k[::-1]] = v
|
|
@@ -21,15 +33,56 @@ def reverse_count(count: ct) -> ct:
|
|
|
21
33
|
|
|
22
34
|
|
|
23
35
|
def sort_count(count: ct) -> ct:
|
|
36
|
+
"""
|
|
37
|
+
Sort the count dictionary by counts in descending order.
|
|
38
|
+
|
|
39
|
+
:param count: A dictionary mapping bit strings to counts
|
|
40
|
+
:type count: ct
|
|
41
|
+
:return: A new dictionary sorted by count values (descending)
|
|
42
|
+
:rtype: ct
|
|
43
|
+
|
|
44
|
+
:Example:
|
|
45
|
+
|
|
46
|
+
>>> sort_count({"00": 5, "01": 15, "10": 10})
|
|
47
|
+
{'01': 15, '10': 10, '00': 5}
|
|
48
|
+
"""
|
|
24
49
|
return {k: v for k, v in sorted(count.items(), key=lambda item: -item[1])}
|
|
25
50
|
|
|
26
51
|
|
|
27
52
|
def normalized_count(count: ct) -> Dict[str, float]:
|
|
53
|
+
"""
|
|
54
|
+
Normalize the count dictionary to represent probabilities.
|
|
55
|
+
|
|
56
|
+
:param count: A dictionary mapping bit strings to counts
|
|
57
|
+
:type count: ct
|
|
58
|
+
:return: A new dictionary with probabilities instead of counts
|
|
59
|
+
:rtype: Dict[str, float]
|
|
60
|
+
|
|
61
|
+
:Example:
|
|
62
|
+
|
|
63
|
+
>>> normalized_count({"00": 5, "01": 15})
|
|
64
|
+
{'00': 0.25, '01': 0.75}
|
|
65
|
+
"""
|
|
28
66
|
shots = sum([v for k, v in count.items()])
|
|
29
67
|
return {k: v / shots for k, v in count.items()}
|
|
30
68
|
|
|
31
69
|
|
|
32
70
|
def marginal_count(count: ct, keep_list: Sequence[int]) -> ct:
|
|
71
|
+
"""
|
|
72
|
+
Compute the marginal distribution of a count dictionary over specified qubits.
|
|
73
|
+
|
|
74
|
+
:param count: A dictionary mapping bit strings to counts
|
|
75
|
+
:type count: ct
|
|
76
|
+
:param keep_list: List of qubit indices to keep in the marginal distribution
|
|
77
|
+
:type keep_list: Sequence[int]
|
|
78
|
+
:return: A new count dictionary with marginal distribution
|
|
79
|
+
:rtype: ct
|
|
80
|
+
|
|
81
|
+
:Example:
|
|
82
|
+
|
|
83
|
+
>>> marginal_count({"001": 10, "110": 20}, [0, 2])
|
|
84
|
+
{'01': 10, '10': 20}
|
|
85
|
+
"""
|
|
33
86
|
import qiskit
|
|
34
87
|
|
|
35
88
|
count = reverse_count(count)
|
|
@@ -37,34 +90,87 @@ def marginal_count(count: ct, keep_list: Sequence[int]) -> ct:
|
|
|
37
90
|
return reverse_count(ncount)
|
|
38
91
|
|
|
39
92
|
|
|
40
|
-
def count2vec(
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
93
|
+
def count2vec(
|
|
94
|
+
count: ct, normalization: bool = True, dim: Optional[int] = None
|
|
95
|
+
) -> Tensor:
|
|
96
|
+
"""
|
|
97
|
+
Convert a dictionary of counts (with string keys) to a probability/count vector.
|
|
98
|
+
|
|
99
|
+
Support:
|
|
100
|
+
- base-d string (d <= 36), characters taken from 0-9A-Z (case-insensitive)
|
|
101
|
+
For example:
|
|
102
|
+
qubit: '0101'
|
|
103
|
+
qudit: '012' or '09A' (A represents 10, which means [0, 9, 10])
|
|
104
|
+
|
|
105
|
+
:param count: A dictionary mapping bit strings to counts
|
|
106
|
+
:type count: ct
|
|
107
|
+
:param normalization: Whether to normalize the counts to probabilities, defaults to True
|
|
108
|
+
:type normalization: bool, optional
|
|
109
|
+
:param dim: Dimensionality of the vector, defaults to 2
|
|
110
|
+
:type dim: int, optional
|
|
111
|
+
:return: Probability vector as numpy array
|
|
112
|
+
:rtype: Tensor
|
|
113
|
+
|
|
114
|
+
:Example:
|
|
115
|
+
|
|
116
|
+
>>> count2vec({"00": 2, "10": 3, "11": 5})
|
|
117
|
+
array([0.2, 0. , 0.3, 0.5])
|
|
118
|
+
"""
|
|
119
|
+
|
|
120
|
+
if not count:
|
|
121
|
+
return np.array([], dtype=float)
|
|
122
|
+
|
|
123
|
+
dim = 2 if dim is None else dim
|
|
124
|
+
|
|
125
|
+
n = len(next(iter(count)).upper())
|
|
126
|
+
prob = np.zeros(dim**n, dtype=float)
|
|
127
|
+
shots = float(sum(count.values())) if normalization else 1.0
|
|
128
|
+
if shots == 0:
|
|
129
|
+
return prob
|
|
130
|
+
|
|
131
|
+
powers = [dim**p for p in range(n)][::-1]
|
|
44
132
|
for k, v in count.items():
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
return np.array(probability)
|
|
133
|
+
digits = _decode_basis_label(k, n, dim)
|
|
134
|
+
idx = sum(dig * p for dig, p in zip(digits, powers))
|
|
135
|
+
prob[idx] = (v / shots) if normalization else v
|
|
49
136
|
|
|
137
|
+
return prob
|
|
138
|
+
|
|
139
|
+
|
|
140
|
+
def vec2count(vec: Tensor, prune: bool = False, dim: Optional[int] = None) -> ct:
|
|
141
|
+
"""
|
|
142
|
+
Map a count/probability vector of length D to a dictionary with base-d string keys (0-9A-Z).
|
|
143
|
+
Only generate string keys when d <= 36; if d is inferred to be > 36, raise a NotImplementedError.
|
|
50
144
|
|
|
51
|
-
|
|
52
|
-
|
|
145
|
+
:param vec: A one-dimensional vector of length D = d**n
|
|
146
|
+
:param prune: Whether to prune near-zero elements (threshold 1e-8)
|
|
147
|
+
:param dim: Dimensionality of the vector, defaults to 2
|
|
148
|
+
:return: {base-d string key: value}, key length n
|
|
149
|
+
"""
|
|
150
|
+
from ..quantum import count_vector2dict, _infer_num_sites
|
|
53
151
|
|
|
152
|
+
dim = 2 if dim is None else dim
|
|
54
153
|
if isinstance(vec, list):
|
|
55
154
|
vec = np.array(vec)
|
|
56
|
-
n = int(
|
|
57
|
-
c = count_vector2dict(vec, n, key="bin")
|
|
58
|
-
if prune
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
if np.abs(v) < 1e-8:
|
|
62
|
-
del nc[k]
|
|
63
|
-
return nc
|
|
155
|
+
n = _infer_num_sites(int(vec.shape[0]), dim)
|
|
156
|
+
c: ct = count_vector2dict(vec, n, key="bin", dim=dim) # type: ignore
|
|
157
|
+
if prune:
|
|
158
|
+
c = {k: v for k, v in c.items() if np.abs(v) >= 1e-8}
|
|
159
|
+
|
|
64
160
|
return c
|
|
65
161
|
|
|
66
162
|
|
|
67
163
|
def kl_divergence(c1: ct, c2: ct) -> float:
|
|
164
|
+
"""
|
|
165
|
+
Compute the Kullback-Leibler divergence between two count distributions.
|
|
166
|
+
|
|
167
|
+
:param c1: First count dictionary
|
|
168
|
+
:type c1: ct
|
|
169
|
+
:param c2: Second count dictionary
|
|
170
|
+
:type c2: ct
|
|
171
|
+
:return: KL divergence value
|
|
172
|
+
:rtype: float
|
|
173
|
+
"""
|
|
68
174
|
eps = 1e-4 # typical value for inverse of the total shots
|
|
69
175
|
c1 = normalized_count(c1) # type: ignore
|
|
70
176
|
c2 = normalized_count(c2) # type: ignore
|
|
@@ -107,6 +213,27 @@ def expectation(
|
|
|
107
213
|
return r / shots
|
|
108
214
|
|
|
109
215
|
|
|
216
|
+
def merge_count(*counts: ct) -> ct:
|
|
217
|
+
"""
|
|
218
|
+
Merge multiple count dictionaries by summing up their counts
|
|
219
|
+
|
|
220
|
+
:param counts: Variable number of count dictionaries
|
|
221
|
+
:type counts: ct
|
|
222
|
+
:return: Merged count dictionary
|
|
223
|
+
:rtype: ct
|
|
224
|
+
|
|
225
|
+
:Example:
|
|
226
|
+
|
|
227
|
+
>>> merge_count({"00": 10, "01": 20}, {"00": 5, "10": 15})
|
|
228
|
+
{'00': 15, '01': 20, '10': 15}
|
|
229
|
+
"""
|
|
230
|
+
merged: ct = {}
|
|
231
|
+
for count in counts:
|
|
232
|
+
for k, v in count.items():
|
|
233
|
+
merged[k] = merged.get(k, 0) + v
|
|
234
|
+
return merged
|
|
235
|
+
|
|
236
|
+
|
|
110
237
|
def plot_histogram(data: Any, **kws: Any) -> Any:
|
|
111
238
|
"""
|
|
112
239
|
See ``qiskit.visualization.plot_histogram``:
|
|
@@ -723,7 +723,10 @@ class ReadoutMit:
|
|
|
723
723
|
cals = self._form_cals(qubits)
|
|
724
724
|
M = M3MatVec(dict(counts), cals, distance)
|
|
725
725
|
L = spla.LinearOperator(
|
|
726
|
-
(M.num_elems, M.num_elems),
|
|
726
|
+
(M.num_elems, M.num_elems),
|
|
727
|
+
matvec=M.matvec,
|
|
728
|
+
rmatvec=M.rmatvec,
|
|
729
|
+
dtype=np.float64,
|
|
727
730
|
)
|
|
728
731
|
diags = M.get_diagonal()
|
|
729
732
|
|
tensorcircuit/shadows.py
CHANGED
|
@@ -334,7 +334,7 @@ def entropy_shadow(
|
|
|
334
334
|
|
|
335
335
|
def renyi_entropy_2(snapshots: Tensor, sub: Optional[Sequence[int]] = None) -> Tensor:
|
|
336
336
|
r"""To calculate the second order Renyi entropy of a subsystem from snapshot, please refer to
|
|
337
|
-
Brydges, T. et al. Science 364, 260
|
|
337
|
+
Brydges, T. et al. Science 364, 260-263 (2019). This function is not jitable.
|
|
338
338
|
|
|
339
339
|
:param snapshots: shape = (ns, repeat, nq)
|
|
340
340
|
:type: Tensor
|
tensorcircuit/simplify.py
CHANGED
|
@@ -121,7 +121,9 @@ def _split_two_qubit_gate(
|
|
|
121
121
|
if fixed_choice == 2: # swap one
|
|
122
122
|
return n3, n4, True # swap
|
|
123
123
|
s2 = n3.tensor.shape[-1]
|
|
124
|
-
if (s1 >=
|
|
124
|
+
if (s1 >= n[0].dimension * n[2].dimension) and (
|
|
125
|
+
s2 >= n[1].dimension * n[3].dimension
|
|
126
|
+
):
|
|
125
127
|
# jax jit unspport split_node with trun_err anyway
|
|
126
128
|
# tf function doesn't work either, though I believe it may work on tf side
|
|
127
129
|
# CANNOT DONE(@refraction-ray): tf.function version with trun_err set
|