tensorcircuit-nightly 1.2.0.dev20250326__py3-none-any.whl → 1.4.0.dev20251128__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 +5 -1
- 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 +312 -5
- tensorcircuit/backends/cupy_backend.py +3 -1
- tensorcircuit/backends/jax_backend.py +100 -4
- tensorcircuit/backends/jax_ops.py +108 -0
- 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 +105 -23
- tensorcircuit/densitymatrix.py +16 -11
- tensorcircuit/experimental.py +733 -153
- tensorcircuit/fgs.py +254 -73
- tensorcircuit/gates.py +66 -22
- tensorcircuit/interfaces/jax.py +5 -3
- tensorcircuit/interfaces/tensortrans.py +6 -2
- tensorcircuit/interfaces/torch.py +14 -4
- tensorcircuit/keras.py +3 -3
- tensorcircuit/mpscircuit.py +154 -65
- tensorcircuit/quantum.py +698 -134
- tensorcircuit/quditcircuit.py +733 -0
- tensorcircuit/quditgates.py +618 -0
- tensorcircuit/results/counts.py +131 -18
- tensorcircuit/results/readout_mitigation.py +4 -1
- tensorcircuit/shadows.py +1 -1
- tensorcircuit/simplify.py +3 -1
- tensorcircuit/stabilizercircuit.py +29 -17
- 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.2.0.dev20250326.dist-info → tensorcircuit_nightly-1.4.0.dev20251128.dist-info}/METADATA +66 -29
- tensorcircuit_nightly-1.4.0.dev20251128.dist-info/RECORD +96 -0
- {tensorcircuit_nightly-1.2.0.dev20250326.dist-info → tensorcircuit_nightly-1.4.0.dev20251128.dist-info}/WHEEL +1 -1
- {tensorcircuit_nightly-1.2.0.dev20250326.dist-info → tensorcircuit_nightly-1.4.0.dev20251128.dist-info}/top_level.txt +0 -1
- tensorcircuit_nightly-1.2.0.dev20250326.dist-info/RECORD +0 -118
- tests/__init__.py +0 -0
- tests/conftest.py +0 -67
- tests/test_backends.py +0 -1035
- tests/test_calibrating.py +0 -149
- tests/test_channels.py +0 -409
- 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 -562
- tests/test_keras.py +0 -160
- tests/test_miscs.py +0 -282
- 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 -549
- tests/test_quantum_attr.py +0 -42
- tests/test_results.py +0 -380
- tests/test_shadows.py +0 -160
- tests/test_simplify.py +0 -46
- tests/test_stabilizer.py +0 -217
- tests/test_templates.py +0 -218
- tests/test_torchnn.py +0 -99
- tests/test_van.py +0 -102
- {tensorcircuit_nightly-1.2.0.dev20250326.dist-info → tensorcircuit_nightly-1.4.0.dev20251128.dist-info}/licenses/LICENSE +0 -0
tensorcircuit/__init__.py
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
__version__ = "1.
|
|
1
|
+
__version__ = "1.4.0.dev20251128"
|
|
2
2
|
__author__ = "TensorCircuit Authors"
|
|
3
3
|
__creator__ = "refraction-ray"
|
|
4
4
|
|
|
@@ -23,8 +23,11 @@ from .cons import (
|
|
|
23
23
|
runtime_contractor,
|
|
24
24
|
) # prerun of set hooks
|
|
25
25
|
from . import gates
|
|
26
|
+
from . import quditgates
|
|
26
27
|
from . import basecircuit
|
|
27
28
|
from .gates import Gate
|
|
29
|
+
from .quditcircuit import QuditCircuit
|
|
30
|
+
from .analogcircuit import AnalogCircuit
|
|
28
31
|
from .circuit import Circuit, expectation
|
|
29
32
|
from .mpscircuit import MPSCircuit
|
|
30
33
|
from .densitymatrix import DMCircuit as DMCircuit_reference
|
|
@@ -52,6 +55,7 @@ from . import compiler
|
|
|
52
55
|
from . import cloud
|
|
53
56
|
from . import fgs
|
|
54
57
|
from .fgs import FGSSimulator
|
|
58
|
+
from . import timeevol
|
|
55
59
|
|
|
56
60
|
FGSCircuit = FGSSimulator
|
|
57
61
|
|
tensorcircuit/abstractcircuit.py
CHANGED
|
@@ -53,6 +53,7 @@ vgates = [
|
|
|
53
53
|
"any",
|
|
54
54
|
"exp",
|
|
55
55
|
"exp1",
|
|
56
|
+
"su4",
|
|
56
57
|
]
|
|
57
58
|
mpogates = ["multicontrol", "mpo"]
|
|
58
59
|
gate_aliases = [
|
|
@@ -65,9 +66,12 @@ gate_aliases = [
|
|
|
65
66
|
["td", "tdg"],
|
|
66
67
|
]
|
|
67
68
|
|
|
69
|
+
defined_gates = sgates + vgates + mpogates + [alias[1] for alias in gate_aliases]
|
|
70
|
+
|
|
68
71
|
|
|
69
72
|
class AbstractCircuit:
|
|
70
73
|
_nqubits: int
|
|
74
|
+
_d: int = 2
|
|
71
75
|
_qir: List[Dict[str, Any]]
|
|
72
76
|
_extra_qir: List[Dict[str, Any]]
|
|
73
77
|
inputs: Tensor
|
|
@@ -0,0 +1,413 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Analog-Digital Hybrid Circuit class wrapper
|
|
3
|
+
only support jax backend
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
from typing import Any, List, Optional, Callable, Dict, Tuple, Union, Sequence
|
|
7
|
+
from dataclasses import dataclass
|
|
8
|
+
from functools import partial
|
|
9
|
+
|
|
10
|
+
import numpy as np
|
|
11
|
+
import tensornetwork as tn
|
|
12
|
+
|
|
13
|
+
from .cons import backend, rdtypestr
|
|
14
|
+
from .abstractcircuit import defined_gates
|
|
15
|
+
from .circuit import Circuit
|
|
16
|
+
from .quantum import QuOperator
|
|
17
|
+
from .timeevol import ode_evol_global, ode_evol_local
|
|
18
|
+
from .utils import arg_alias
|
|
19
|
+
|
|
20
|
+
Tensor = Any
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
@dataclass
|
|
24
|
+
class AnalogBlock:
|
|
25
|
+
"""
|
|
26
|
+
A data structure to hold information about an analog evolution block.
|
|
27
|
+
"""
|
|
28
|
+
|
|
29
|
+
hamiltonian_func: Callable[[Tensor], Tensor]
|
|
30
|
+
time: float
|
|
31
|
+
index: Optional[List[int]] = None
|
|
32
|
+
solver_options: Optional[Dict[str, Any]] = None
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
class AnalogCircuit:
|
|
36
|
+
"""
|
|
37
|
+
A class for hybrid digital-analog quantum simulation with time-dependent Hamiltonians.
|
|
38
|
+
"""
|
|
39
|
+
|
|
40
|
+
def __init__(
|
|
41
|
+
self,
|
|
42
|
+
nqubits: int,
|
|
43
|
+
inputs: Optional[Tensor] = None,
|
|
44
|
+
mps_inputs: Optional[QuOperator] = None,
|
|
45
|
+
split: Optional[Dict[str, Any]] = None,
|
|
46
|
+
dim: Optional[int] = None,
|
|
47
|
+
):
|
|
48
|
+
"""
|
|
49
|
+
Initializes the hybrid circuit.
|
|
50
|
+
|
|
51
|
+
:param nqubits: The number of qubits in the circuit.
|
|
52
|
+
:type nqubits: int
|
|
53
|
+
:param dim: The local Hilbert space dimension per site. Qudit is supported for 2 <= d <= 36.
|
|
54
|
+
:type dim: If None, the dimension of the circuit will be `2`, which is a qubit system.
|
|
55
|
+
:param inputs: If not None, the initial state of the circuit is taken as ``inputs``
|
|
56
|
+
instead of :math:`\vert 0 \rangle^n` qubits, defaults to None.
|
|
57
|
+
:type inputs: Optional[Tensor], optional
|
|
58
|
+
:param mps_inputs: QuVector for a MPS like initial wavefunction.
|
|
59
|
+
:type mps_inputs: Optional[QuOperator]
|
|
60
|
+
:param split: dict if two qubit gate is ready for split, including parameters for at least one of
|
|
61
|
+
``max_singular_values`` and ``max_truncation_err``.
|
|
62
|
+
:type split: Optional[Dict[str, Any]]
|
|
63
|
+
"""
|
|
64
|
+
self.num_qubits, self._nqubits = nqubits, nqubits
|
|
65
|
+
self.dim = 2**self.num_qubits
|
|
66
|
+
self.inputs = inputs
|
|
67
|
+
if inputs is None:
|
|
68
|
+
self.inputs = np.zeros([self.dim])
|
|
69
|
+
self.inputs[0] = 1.0
|
|
70
|
+
self.inputs = backend.convert_to_tensor(self.inputs)
|
|
71
|
+
|
|
72
|
+
# List of digital circuits, starting with one empty circuit.
|
|
73
|
+
self.digital_circuits: List[Circuit] = [
|
|
74
|
+
Circuit(self.num_qubits, inputs, mps_inputs, split, dim)
|
|
75
|
+
]
|
|
76
|
+
|
|
77
|
+
# List of analog blocks, each containing the Hamiltonian function, time, and solver options.
|
|
78
|
+
self.analog_blocks: List[AnalogBlock] = []
|
|
79
|
+
self._effective_circuit: Optional[Circuit] = None
|
|
80
|
+
self._solver_options: Dict[str, Any] = {}
|
|
81
|
+
|
|
82
|
+
def set_solver_options(self, **kws: Any) -> None:
|
|
83
|
+
"""
|
|
84
|
+
set solver options globally for this circuit object
|
|
85
|
+
"""
|
|
86
|
+
self._solver_options = kws
|
|
87
|
+
|
|
88
|
+
@property
|
|
89
|
+
def effective_circuit(self) -> Circuit:
|
|
90
|
+
"""
|
|
91
|
+
Returns the effective circuit after all blocks have been added.
|
|
92
|
+
"""
|
|
93
|
+
if self._effective_circuit is None:
|
|
94
|
+
self.state()
|
|
95
|
+
return self._effective_circuit # type: ignore
|
|
96
|
+
|
|
97
|
+
@property
|
|
98
|
+
def current_digital_circuit(self) -> Circuit:
|
|
99
|
+
"""
|
|
100
|
+
Returns the last (currently active) digital circuit.
|
|
101
|
+
"""
|
|
102
|
+
return self.digital_circuits[-1]
|
|
103
|
+
|
|
104
|
+
def add_analog_block(
|
|
105
|
+
self,
|
|
106
|
+
hamiltonian: Callable[[float], Tensor],
|
|
107
|
+
time: Union[float, List[Tensor]],
|
|
108
|
+
index: Optional[List[int]] = None,
|
|
109
|
+
**solver_options: Any,
|
|
110
|
+
) -> "AnalogCircuit":
|
|
111
|
+
"""
|
|
112
|
+
Adds a time-dependent analog evolution block to the circuit.
|
|
113
|
+
|
|
114
|
+
This finalizes the current digital block and prepares a new one for subsequent gates.
|
|
115
|
+
|
|
116
|
+
:param hamiltonian_func: A function H(t) that takes a time `t` (from 0 to `time`)
|
|
117
|
+
and returns the Hamiltonian matrix at that instant.
|
|
118
|
+
:type hamiltonian_func: Callable[[float], np.ndarray]
|
|
119
|
+
:param time: The total evolution time 'T'.
|
|
120
|
+
:type time: float
|
|
121
|
+
:param index: The indices of the qubits to apply the analog evolution to. Defaults None for
|
|
122
|
+
global application.
|
|
123
|
+
:type index: Optional[List[int]]
|
|
124
|
+
:param solver_options: Keyword arguments passed directly to `tc.timeevol.ode_evolve`
|
|
125
|
+
:type solver_options: Dict[str, Any]
|
|
126
|
+
"""
|
|
127
|
+
# Create and store the analog block information
|
|
128
|
+
time = backend.convert_to_tensor(time, dtype=rdtypestr)
|
|
129
|
+
time = backend.reshape(time, [-1])
|
|
130
|
+
if backend.shape_tuple(time)[0] == 1:
|
|
131
|
+
time = backend.stack([0.0, time[0]]) # type: ignore
|
|
132
|
+
elif backend.shape_tuple(time)[0] > 2:
|
|
133
|
+
raise ValueError(
|
|
134
|
+
"Time must be a scalar or a two elements array for the starting and end points."
|
|
135
|
+
)
|
|
136
|
+
combined_solver_options = self._solver_options.copy()
|
|
137
|
+
combined_solver_options.update(solver_options)
|
|
138
|
+
block = AnalogBlock(
|
|
139
|
+
hamiltonian_func=hamiltonian,
|
|
140
|
+
time=time, # type: ignore
|
|
141
|
+
index=index,
|
|
142
|
+
solver_options=combined_solver_options,
|
|
143
|
+
)
|
|
144
|
+
self.analog_blocks.append(block)
|
|
145
|
+
|
|
146
|
+
# After adding an analog block, we start a new digital block.
|
|
147
|
+
self.digital_circuits.append(Circuit(self.num_qubits, inputs=self.inputs))
|
|
148
|
+
self._effective_circuit = None
|
|
149
|
+
return self # Allow for chaining
|
|
150
|
+
|
|
151
|
+
def __getattr__(self, name: str) -> Any:
|
|
152
|
+
"""
|
|
153
|
+
Metaprogramming to forward gate calls to the current digital circuit.
|
|
154
|
+
This enables syntax like `analog_circuit.h(0)`.
|
|
155
|
+
"""
|
|
156
|
+
gate_method = getattr(self.current_digital_circuit, name, None)
|
|
157
|
+
|
|
158
|
+
if gate_method and callable(gate_method) and name.lower() in defined_gates:
|
|
159
|
+
|
|
160
|
+
def wrapper(*args, **kwargs): # type: ignore
|
|
161
|
+
gate_method(*args, **kwargs)
|
|
162
|
+
self._effective_circuit = None
|
|
163
|
+
return self
|
|
164
|
+
|
|
165
|
+
return wrapper
|
|
166
|
+
else:
|
|
167
|
+
raise AttributeError(
|
|
168
|
+
f"'{type(self).__name__}' object or its underlying '{type(self.current_digital_circuit).__name__}' "
|
|
169
|
+
f"object has no attribute '{name}'."
|
|
170
|
+
)
|
|
171
|
+
|
|
172
|
+
def state(self) -> Tensor:
|
|
173
|
+
"""
|
|
174
|
+
Executes the full digital-analog sequence.
|
|
175
|
+
|
|
176
|
+
:return: The final state vector after the full evolution
|
|
177
|
+
:rtype: Tensor
|
|
178
|
+
"""
|
|
179
|
+
# Propagate the state through the alternating circuit blocks
|
|
180
|
+
for i, analog_block in enumerate(self.analog_blocks):
|
|
181
|
+
# 1. Apply Digital Block i
|
|
182
|
+
digital_c = self.digital_circuits[i]
|
|
183
|
+
if i > 0:
|
|
184
|
+
digital_c.replace_inputs(psi) # type: ignore
|
|
185
|
+
psi = digital_c.wavefunction()
|
|
186
|
+
|
|
187
|
+
if analog_block.index is None:
|
|
188
|
+
psi = ode_evol_global( # type: ignore
|
|
189
|
+
hamiltonian=analog_block.hamiltonian_func,
|
|
190
|
+
initial_state=psi,
|
|
191
|
+
times=analog_block.time,
|
|
192
|
+
**analog_block.solver_options,
|
|
193
|
+
)
|
|
194
|
+
else:
|
|
195
|
+
psi = ode_evol_local( # type: ignore
|
|
196
|
+
hamiltonian=analog_block.hamiltonian_func,
|
|
197
|
+
initial_state=psi,
|
|
198
|
+
times=analog_block.time,
|
|
199
|
+
index=analog_block.index,
|
|
200
|
+
**analog_block.solver_options,
|
|
201
|
+
)
|
|
202
|
+
psi = psi[-1]
|
|
203
|
+
# TODO(@refraction-ray): support more time evol methods
|
|
204
|
+
|
|
205
|
+
# 3. Apply the final digital circuit
|
|
206
|
+
if self.analog_blocks:
|
|
207
|
+
self.digital_circuits[-1].replace_inputs(psi)
|
|
208
|
+
psi = self.digital_circuits[-1].wavefunction()
|
|
209
|
+
else:
|
|
210
|
+
psi = self.digital_circuits[-1].wavefunction()
|
|
211
|
+
self._effective_circuit = Circuit(self.num_qubits, inputs=psi)
|
|
212
|
+
|
|
213
|
+
return psi
|
|
214
|
+
|
|
215
|
+
wavefunction = state
|
|
216
|
+
|
|
217
|
+
def expectation(
|
|
218
|
+
self,
|
|
219
|
+
*ops: Tuple[tn.Node, List[int]],
|
|
220
|
+
reuse: bool = True,
|
|
221
|
+
enable_lightcone: bool = False,
|
|
222
|
+
nmc: int = 1000,
|
|
223
|
+
**kws: Any,
|
|
224
|
+
) -> Tensor:
|
|
225
|
+
"""
|
|
226
|
+
Compute expectation(s) of local operators.
|
|
227
|
+
|
|
228
|
+
:param ops: Pairs of `(operator_node, [sites])` specifying where each operator acts.
|
|
229
|
+
:type ops: Tuple[tn.Node, List[int]]
|
|
230
|
+
:param reuse: If True, then the wavefunction tensor is cached for further expectation evaluation,
|
|
231
|
+
defaults to be true.
|
|
232
|
+
:type reuse: bool, optional
|
|
233
|
+
:param enable_lightcone: whether enable light cone simplification, defaults to False
|
|
234
|
+
:type enable_lightcone: bool, optional
|
|
235
|
+
:param nmc: repetition time for Monte Carlo sampling for noisfy calculation, defaults to 1000
|
|
236
|
+
:type nmc: int, optional
|
|
237
|
+
:return: Tensor with one element
|
|
238
|
+
:rtype: Tensor
|
|
239
|
+
"""
|
|
240
|
+
return self.effective_circuit.expectation(
|
|
241
|
+
*ops,
|
|
242
|
+
reuse=reuse,
|
|
243
|
+
enable_lightcone=enable_lightcone,
|
|
244
|
+
noise_conf=None,
|
|
245
|
+
nmc=nmc,
|
|
246
|
+
**kws,
|
|
247
|
+
)
|
|
248
|
+
|
|
249
|
+
def measure_jit(
|
|
250
|
+
self, *index: int, with_prob: bool = False, status: Optional[Tensor] = None
|
|
251
|
+
) -> Tuple[Tensor, Tensor]:
|
|
252
|
+
"""
|
|
253
|
+
Take measurement on the given site indices (computational basis).
|
|
254
|
+
This method is jittable!
|
|
255
|
+
|
|
256
|
+
:param index: Measure on which site (wire) index.
|
|
257
|
+
:type index: int
|
|
258
|
+
:param with_prob: If true, theoretical probability is also returned.
|
|
259
|
+
:type with_prob: bool, optional
|
|
260
|
+
:param status: external randomness, with shape [index], defaults to None
|
|
261
|
+
:type status: Optional[Tensor]
|
|
262
|
+
:return: The sample output and probability (optional) of the quantum line.
|
|
263
|
+
:rtype: Tuple[Tensor, Tensor]
|
|
264
|
+
"""
|
|
265
|
+
return self.effective_circuit.measure_jit(
|
|
266
|
+
*index, with_prob=with_prob, status=status
|
|
267
|
+
)
|
|
268
|
+
|
|
269
|
+
measure = measure_jit
|
|
270
|
+
|
|
271
|
+
def amplitude(self, l: Union[str, Tensor]) -> Tensor:
|
|
272
|
+
r"""
|
|
273
|
+
Return the amplitude for a given bitstring `l`.
|
|
274
|
+
|
|
275
|
+
For state simulators, this computes :math:`\langle l \vert \psi \rangle`.
|
|
276
|
+
|
|
277
|
+
:param l: Bitstring in base-`d` using `0-9A-Z`.
|
|
278
|
+
:type l: Union[str, Tensor]
|
|
279
|
+
:return: Complex amplitude.
|
|
280
|
+
:rtype: Tensor
|
|
281
|
+
"""
|
|
282
|
+
return self.effective_circuit.amplitude(l)
|
|
283
|
+
|
|
284
|
+
def probability(self) -> Tensor:
|
|
285
|
+
"""
|
|
286
|
+
Get the length-`2^n` probability vector over the computational basis.
|
|
287
|
+
|
|
288
|
+
:return: Probability vector of shape `[dim^n]`.
|
|
289
|
+
:rtype: Tensor
|
|
290
|
+
"""
|
|
291
|
+
return self.effective_circuit.probability()
|
|
292
|
+
|
|
293
|
+
def expectation_ps(
|
|
294
|
+
self,
|
|
295
|
+
x: Optional[Sequence[int]] = None,
|
|
296
|
+
y: Optional[Sequence[int]] = None,
|
|
297
|
+
z: Optional[Sequence[int]] = None,
|
|
298
|
+
ps: Optional[Sequence[int]] = None,
|
|
299
|
+
reuse: bool = True,
|
|
300
|
+
noise_conf: Optional[Any] = None,
|
|
301
|
+
nmc: int = 1000,
|
|
302
|
+
status: Optional[Tensor] = None,
|
|
303
|
+
**kws: Any,
|
|
304
|
+
) -> Tensor:
|
|
305
|
+
"""
|
|
306
|
+
Shortcut for Pauli string expectation.
|
|
307
|
+
x, y, z list are for X, Y, Z positions
|
|
308
|
+
|
|
309
|
+
:Example:
|
|
310
|
+
|
|
311
|
+
>>> c = tc.Circuit(2)
|
|
312
|
+
>>> c.X(0)
|
|
313
|
+
>>> c.H(1)
|
|
314
|
+
>>> c.expectation_ps(x=[1], z=[0])
|
|
315
|
+
array(-0.99999994+0.j, dtype=complex64)
|
|
316
|
+
|
|
317
|
+
:param x: sites to apply X gate, defaults to None
|
|
318
|
+
:type x: Optional[Sequence[int]], optional
|
|
319
|
+
:param y: sites to apply Y gate, defaults to None
|
|
320
|
+
:type y: Optional[Sequence[int]], optional
|
|
321
|
+
:param z: sites to apply Z gate, defaults to None
|
|
322
|
+
:type z: Optional[Sequence[int]], optional
|
|
323
|
+
:param ps: or one can apply a ps structures instead of ``x``, ``y``, ``z``,
|
|
324
|
+
e.g. [0, 1, 3, 0, 2, 2] for X_1Z_2Y_4Y_5
|
|
325
|
+
defaults to None, ``ps`` can overwrite ``x``, ``y`` and ``z``
|
|
326
|
+
:type ps: Optional[Sequence[int]], optional
|
|
327
|
+
:param reuse: whether to cache and reuse the wavefunction, defaults to True
|
|
328
|
+
:type reuse: bool, optional
|
|
329
|
+
:param noise_conf: Noise Configuration, defaults to None
|
|
330
|
+
:type noise_conf: Optional[NoiseConf], optional
|
|
331
|
+
:param nmc: repetition time for Monte Carlo sampling for noisfy calculation, defaults to 1000
|
|
332
|
+
:type nmc: int, optional
|
|
333
|
+
:param status: external randomness given by tensor uniformly from [0, 1], defaults to None,
|
|
334
|
+
used for noisfy circuit sampling
|
|
335
|
+
:type status: Optional[Tensor], optional
|
|
336
|
+
:return: Expectation value
|
|
337
|
+
:rtype: Tensor
|
|
338
|
+
"""
|
|
339
|
+
return self.effective_circuit.expectation_ps(
|
|
340
|
+
x=x,
|
|
341
|
+
y=y,
|
|
342
|
+
z=z,
|
|
343
|
+
ps=ps,
|
|
344
|
+
reuse=reuse,
|
|
345
|
+
noise_conf=noise_conf,
|
|
346
|
+
nmc=nmc,
|
|
347
|
+
status=status,
|
|
348
|
+
**kws,
|
|
349
|
+
)
|
|
350
|
+
|
|
351
|
+
@partial(arg_alias, alias_dict={"format": ["format_"]})
|
|
352
|
+
def sample(
|
|
353
|
+
self,
|
|
354
|
+
batch: Optional[int] = None,
|
|
355
|
+
allow_state: bool = False,
|
|
356
|
+
readout_error: Optional[Sequence[Any]] = None,
|
|
357
|
+
format: Optional[str] = None,
|
|
358
|
+
random_generator: Optional[Any] = None,
|
|
359
|
+
status: Optional[Tensor] = None,
|
|
360
|
+
jittable: bool = True,
|
|
361
|
+
) -> Any:
|
|
362
|
+
r"""
|
|
363
|
+
Batched sampling from the circuit or final state.
|
|
364
|
+
|
|
365
|
+
:param batch: Number of samples. If `None`, returns a single draw.
|
|
366
|
+
:type batch: Optional[int]
|
|
367
|
+
:param allow_state: If `True`, sample from the final state (when memory allows). Prefer `True` for speed.
|
|
368
|
+
:type allow_state: bool
|
|
369
|
+
:param readout_error: Optional readout error model.
|
|
370
|
+
:type readout_error: Optional[Sequence[Any]]
|
|
371
|
+
:param format: Output format. See :py:meth:`tensorcircuit.quantum.measurement_results`.
|
|
372
|
+
:type format: Optional[str]
|
|
373
|
+
:param random_generator: random generator, defaults to None
|
|
374
|
+
:type random_generator: Optional[Any], optional
|
|
375
|
+
:param status: external randomness given by tensor uniformly from [0, 1],
|
|
376
|
+
if set, can overwrite random_generator, shape [batch] for `allow_state=True`
|
|
377
|
+
and shape [batch, nqudits] for `allow_state=False` using perfect sampling implementation
|
|
378
|
+
:type status: Optional[Tensor]
|
|
379
|
+
:param jittable: when converting to count, whether keep the full size. if false, may be conflict
|
|
380
|
+
external jit, if true, may fail for large scale system with actual limited count results
|
|
381
|
+
:type jittable: bool, defaults true
|
|
382
|
+
:return: List (if batch) of tuple (binary configuration tensor and corresponding probability)
|
|
383
|
+
if the format is None, and consistent with format when given
|
|
384
|
+
:rtype: Any
|
|
385
|
+
"""
|
|
386
|
+
return self.effective_circuit.sample(
|
|
387
|
+
batch=batch,
|
|
388
|
+
allow_state=allow_state,
|
|
389
|
+
readout_error=readout_error,
|
|
390
|
+
format=format,
|
|
391
|
+
random_generator=random_generator,
|
|
392
|
+
status=status,
|
|
393
|
+
jittable=jittable,
|
|
394
|
+
)
|
|
395
|
+
|
|
396
|
+
def __repr__(self) -> str:
|
|
397
|
+
s = f"AnalogCircuit(n={self.num_qubits}):\n"
|
|
398
|
+
s += "=" * 40 + "\n"
|
|
399
|
+
|
|
400
|
+
num_stages = len(self.analog_blocks) + 1
|
|
401
|
+
|
|
402
|
+
for i in range(num_stages):
|
|
403
|
+
# Print digital part
|
|
404
|
+
s += f"--- Digital Block {i} ---\n"
|
|
405
|
+
|
|
406
|
+
# Print analog part (if it exists)
|
|
407
|
+
if i < len(self.analog_blocks):
|
|
408
|
+
block = self.analog_blocks[i]
|
|
409
|
+
s += f"--- Analog Block {i} (T={block.time}) ---\n"
|
|
410
|
+
s += f" H(t) function: '{block.hamiltonian_func.__name__}'\n"
|
|
411
|
+
|
|
412
|
+
s += "=" * 40
|
|
413
|
+
return s
|
|
@@ -35,7 +35,7 @@ Symbol = Any # sympy.Symbol
|
|
|
35
35
|
|
|
36
36
|
def _resolve(symbol: Union[Symbol, Tensor], i: int = 0) -> Tensor:
|
|
37
37
|
"""
|
|
38
|
-
Make sure the layer is compatible with both multi-param and single param requirements
|
|
38
|
+
Make sure the layer is compatible with both multi-param and single param requirements
|
|
39
39
|
|
|
40
40
|
What could be the input: list/tuple of sympy.symbol, tf.tensor with 1D or 0D shape
|
|
41
41
|
"""
|
|
@@ -352,7 +352,7 @@ class NMF(Model): # type: ignore
|
|
|
352
352
|
spin_channel: int,
|
|
353
353
|
*dimensions: int,
|
|
354
354
|
_dtype: tf.DType = tf.float32,
|
|
355
|
-
probamp: Optional[tf.Tensor] = None
|
|
355
|
+
probamp: Optional[tf.Tensor] = None,
|
|
356
356
|
):
|
|
357
357
|
super().__init__()
|
|
358
358
|
self.w = self.add_weight(
|