tensorcircuit-nightly 1.3.0.dev20250903__py3-none-any.whl → 1.3.0.dev20250904__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/abstractcircuit.py +1 -0
- tensorcircuit/backends/abstract_backend.py +33 -5
- tensorcircuit/backends/jax_backend.py +3 -0
- tensorcircuit/backends/numpy_backend.py +3 -0
- tensorcircuit/backends/pytorch_backend.py +3 -0
- tensorcircuit/backends/tensorflow_backend.py +3 -0
- tensorcircuit/basecircuit.py +127 -75
- tensorcircuit/circuit.py +54 -52
- tensorcircuit/cons.py +1 -0
- tensorcircuit/densitymatrix.py +13 -8
- tensorcircuit/gates.py +28 -22
- tensorcircuit/mpscircuit.py +89 -59
- tensorcircuit/quantum.py +274 -105
- tensorcircuit/results/counts.py +45 -31
- tensorcircuit/simplify.py +3 -1
- tensorcircuit/timeevol.py +42 -33
- {tensorcircuit_nightly-1.3.0.dev20250903.dist-info → tensorcircuit_nightly-1.3.0.dev20250904.dist-info}/METADATA +1 -1
- {tensorcircuit_nightly-1.3.0.dev20250903.dist-info → tensorcircuit_nightly-1.3.0.dev20250904.dist-info}/RECORD +22 -22
- {tensorcircuit_nightly-1.3.0.dev20250903.dist-info → tensorcircuit_nightly-1.3.0.dev20250904.dist-info}/WHEEL +0 -0
- {tensorcircuit_nightly-1.3.0.dev20250903.dist-info → tensorcircuit_nightly-1.3.0.dev20250904.dist-info}/licenses/LICENSE +0 -0
- {tensorcircuit_nightly-1.3.0.dev20250903.dist-info → tensorcircuit_nightly-1.3.0.dev20250904.dist-info}/top_level.txt +0 -0
tensorcircuit/__init__.py
CHANGED
tensorcircuit/abstractcircuit.py
CHANGED
|
@@ -865,7 +865,35 @@ class ExtendedBackend:
|
|
|
865
865
|
"Backend '{}' has not implemented `mod`.".format(self.name)
|
|
866
866
|
)
|
|
867
867
|
|
|
868
|
-
def
|
|
868
|
+
def floor_divide(self: Any, x: Tensor, y: Tensor) -> Tensor:
|
|
869
|
+
r"""
|
|
870
|
+
Compute the element-wise floor division of two tensors.
|
|
871
|
+
|
|
872
|
+
This operation returns a new tensor containing the result of
|
|
873
|
+
dividing `x` by `y` and rounding each element down towards
|
|
874
|
+
negative infinity. The semantics are equivalent to the Python
|
|
875
|
+
`//` operator:
|
|
876
|
+
|
|
877
|
+
result[i] = floor(x[i] / y[i])
|
|
878
|
+
|
|
879
|
+
Broadcasting is supported according to the backend's rules.
|
|
880
|
+
|
|
881
|
+
:param x: Dividend tensor.
|
|
882
|
+
:type x: Tensor
|
|
883
|
+
:param y: Divisor tensor, must be broadcastable with `x`.
|
|
884
|
+
:type y: Tensor
|
|
885
|
+
:return: A tensor with the broadcasted shape of `x` and `y`,
|
|
886
|
+
where each element is the floored result of the division.
|
|
887
|
+
:rtype: Tensor
|
|
888
|
+
|
|
889
|
+
:raises NotImplementedError: If the backend does not provide an
|
|
890
|
+
implementation for `floor_divide`.
|
|
891
|
+
"""
|
|
892
|
+
raise NotImplementedError(
|
|
893
|
+
"Backend '{}' has not implemented `floor_divide`.".format(self.name)
|
|
894
|
+
)
|
|
895
|
+
|
|
896
|
+
def floor(self: Any, a: Tensor) -> Tensor:
|
|
869
897
|
"""
|
|
870
898
|
Compute the element-wise floor of the input tensor.
|
|
871
899
|
|
|
@@ -873,10 +901,10 @@ class ExtendedBackend:
|
|
|
873
901
|
less than or equal to each element of the input tensor,
|
|
874
902
|
i.e. it rounds each value down towards negative infinity.
|
|
875
903
|
|
|
876
|
-
:param
|
|
877
|
-
:type
|
|
878
|
-
:return: A tensor with the same shape as `
|
|
879
|
-
is the floored value of the corresponding element in `
|
|
904
|
+
:param a: Input tensor containing numeric values.
|
|
905
|
+
:type a: Tensor
|
|
906
|
+
:return: A tensor with the same shape as `a`, where each element
|
|
907
|
+
is the floored value of the corresponding element in `a`.
|
|
880
908
|
:rtype: Tensor
|
|
881
909
|
|
|
882
910
|
:raises NotImplementedError: If the backend does not provide an
|
|
@@ -352,6 +352,9 @@ class JaxBackend(jax_backend.JaxBackend, ExtendedBackend): # type: ignore
|
|
|
352
352
|
def floor(self, a: Tensor) -> Tensor:
|
|
353
353
|
return jnp.floor(a)
|
|
354
354
|
|
|
355
|
+
def floor_divide(self, x: Tensor, y: Tensor) -> Tensor:
|
|
356
|
+
return jnp.floor_divide(x, y)
|
|
357
|
+
|
|
355
358
|
def clip(self, a: Tensor, a_min: Tensor, a_max: Tensor) -> Tensor:
|
|
356
359
|
return jnp.clip(a, a_min, a_max)
|
|
357
360
|
|
|
@@ -250,6 +250,9 @@ class NumpyBackend(numpy_backend.NumPyBackend, ExtendedBackend): # type: ignore
|
|
|
250
250
|
def mod(self, x: Tensor, y: Tensor) -> Tensor:
|
|
251
251
|
return np.mod(x, y)
|
|
252
252
|
|
|
253
|
+
def floor_divide(self, x: Tensor, y: Tensor) -> Tensor:
|
|
254
|
+
return np.floor_divide(x, y)
|
|
255
|
+
|
|
253
256
|
def floor(self, a: Tensor) -> Tensor:
|
|
254
257
|
return np.floor(a)
|
|
255
258
|
|
|
@@ -429,6 +429,9 @@ class PyTorchBackend(pytorch_backend.PyTorchBackend, ExtendedBackend): # type:
|
|
|
429
429
|
def mod(self, x: Tensor, y: Tensor) -> Tensor:
|
|
430
430
|
return torchlib.fmod(x, y)
|
|
431
431
|
|
|
432
|
+
def floor_divide(self, x: Tensor, y: Tensor) -> Tensor:
|
|
433
|
+
return torchlib.floor_divide(x, y)
|
|
434
|
+
|
|
432
435
|
def floor(self, a: Tensor) -> Tensor:
|
|
433
436
|
return torchlib.floor(a)
|
|
434
437
|
|
|
@@ -581,6 +581,9 @@ class TensorFlowBackend(tensorflow_backend.TensorFlowBackend, ExtendedBackend):
|
|
|
581
581
|
return a
|
|
582
582
|
return tf.math.floor(a)
|
|
583
583
|
|
|
584
|
+
def floor_divide(self, x: Tensor, y: Tensor) -> Tensor:
|
|
585
|
+
return tf.math.floordiv(x, y)
|
|
586
|
+
|
|
584
587
|
def concat(self, a: Sequence[Tensor], axis: int = 0) -> Tensor:
|
|
585
588
|
return tf.concat(a, axis=axis)
|
|
586
589
|
|
tensorcircuit/basecircuit.py
CHANGED
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
"""
|
|
2
2
|
Quantum circuit: common methods for all circuit classes as MixIn
|
|
3
|
+
|
|
4
|
+
Note:
|
|
5
|
+
- Supports qubit (d = 2) and qudit (d >= 2) systems.
|
|
6
|
+
- For string-encoded samples/counts when d <= 36, digits use base-d characters 0–9A–Z (A = 10, …, Z = 35).
|
|
3
7
|
"""
|
|
4
8
|
|
|
5
9
|
# pylint: disable=invalid-name
|
|
@@ -19,8 +23,10 @@ from .quantum import (
|
|
|
19
23
|
correlation_from_counts,
|
|
20
24
|
measurement_counts,
|
|
21
25
|
sample_int2bin,
|
|
22
|
-
sample_bin2int,
|
|
23
26
|
sample2all,
|
|
27
|
+
_infer_num_sites,
|
|
28
|
+
_decode_basis_label,
|
|
29
|
+
onehot_d_tensor,
|
|
24
30
|
)
|
|
25
31
|
from .abstractcircuit import AbstractCircuit
|
|
26
32
|
from .cons import npdtype, backend, dtypestr, contractor, rdtypestr
|
|
@@ -41,8 +47,9 @@ class BaseCircuit(AbstractCircuit):
|
|
|
41
47
|
is_mps = False
|
|
42
48
|
|
|
43
49
|
@staticmethod
|
|
44
|
-
def all_zero_nodes(n: int,
|
|
45
|
-
|
|
50
|
+
def all_zero_nodes(n: int, prefix: str = "qb-", dim: int = 2) -> List[tn.Node]:
|
|
51
|
+
prefix = "qd-" if dim > 2 else prefix
|
|
52
|
+
l = [0.0 for _ in range(dim)]
|
|
46
53
|
l[0] = 1.0
|
|
47
54
|
nodes = [
|
|
48
55
|
tn.Node(
|
|
@@ -289,7 +296,7 @@ class BaseCircuit(AbstractCircuit):
|
|
|
289
296
|
for op, index in ops:
|
|
290
297
|
if not isinstance(op, tn.Node):
|
|
291
298
|
# op is only a matrix
|
|
292
|
-
op = backend.
|
|
299
|
+
op = backend.reshaped(op, d=self._d)
|
|
293
300
|
op = backend.cast(op, dtype=dtypestr)
|
|
294
301
|
op = gates.Gate(op)
|
|
295
302
|
else:
|
|
@@ -355,12 +362,12 @@ class BaseCircuit(AbstractCircuit):
|
|
|
355
362
|
|
|
356
363
|
def perfect_sampling(self, status: Optional[Tensor] = None) -> Tuple[str, float]:
|
|
357
364
|
"""
|
|
358
|
-
Sampling
|
|
365
|
+
Sampling base-d strings (0–9A–Z when d <= 36) from the circuit output based on quantum amplitudes.
|
|
359
366
|
Reference: arXiv:1201.3974.
|
|
360
367
|
|
|
361
368
|
:param status: external randomness, with shape [nqubits], defaults to None
|
|
362
369
|
:type status: Optional[Tensor]
|
|
363
|
-
:return: Sampled
|
|
370
|
+
:return: Sampled base-d string and the corresponding theoretical probability.
|
|
364
371
|
:rtype: Tuple[str, float]
|
|
365
372
|
"""
|
|
366
373
|
return self.measure_jit(*range(self._nqubits), with_prob=True, status=status)
|
|
@@ -369,10 +376,10 @@ class BaseCircuit(AbstractCircuit):
|
|
|
369
376
|
self, *index: int, with_prob: bool = False, status: Optional[Tensor] = None
|
|
370
377
|
) -> Tuple[Tensor, Tensor]:
|
|
371
378
|
"""
|
|
372
|
-
Take measurement
|
|
379
|
+
Take measurement on the given site indices (computational basis).
|
|
373
380
|
This method is jittable is and about 100 times faster than unjit version!
|
|
374
381
|
|
|
375
|
-
:param index: Measure on which
|
|
382
|
+
:param index: Measure on which site (wire) index.
|
|
376
383
|
:type index: int
|
|
377
384
|
:param with_prob: If true, theoretical probability is also returned.
|
|
378
385
|
:type with_prob: bool, optional
|
|
@@ -383,9 +390,8 @@ class BaseCircuit(AbstractCircuit):
|
|
|
383
390
|
"""
|
|
384
391
|
# finally jit compatible ! and much faster than unjit version ! (100x)
|
|
385
392
|
sample: List[Tensor] = []
|
|
386
|
-
|
|
387
|
-
p =
|
|
388
|
-
p = backend.cast(p, dtype=rdtypestr)
|
|
393
|
+
one_r = backend.cast(backend.convert_to_tensor(1.0), rdtypestr)
|
|
394
|
+
p = one_r
|
|
389
395
|
for k, j in enumerate(index):
|
|
390
396
|
if self.is_dm is False:
|
|
391
397
|
nodes1, edge1 = self._copy()
|
|
@@ -400,40 +406,71 @@ class BaseCircuit(AbstractCircuit):
|
|
|
400
406
|
if i != j:
|
|
401
407
|
e ^ edge2[i]
|
|
402
408
|
for i in range(k):
|
|
403
|
-
|
|
404
|
-
i
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
newnodes
|
|
414
|
-
|
|
415
|
-
|
|
409
|
+
if self._d == 2:
|
|
410
|
+
m = (1 - sample[i]) * gates.array_to_tensor(
|
|
411
|
+
np.array([1, 0])
|
|
412
|
+
) + sample[i] * gates.array_to_tensor(np.array([0, 1]))
|
|
413
|
+
else:
|
|
414
|
+
m = onehot_d_tensor(sample[i], d=self._d)
|
|
415
|
+
g1 = Gate(m)
|
|
416
|
+
g1.id = id(g1)
|
|
417
|
+
g1.is_dagger = False
|
|
418
|
+
g1.flag = "measurement"
|
|
419
|
+
newnodes.append(g1)
|
|
420
|
+
g1.get_edge(0) ^ edge1[index[i]]
|
|
421
|
+
g2 = Gate(m)
|
|
422
|
+
g2.id = id(g2)
|
|
423
|
+
g2.is_dagger = True
|
|
424
|
+
g2.flag = "measurement"
|
|
425
|
+
newnodes.append(g2)
|
|
426
|
+
g2.get_edge(0) ^ edge2[index[i]]
|
|
427
|
+
|
|
416
428
|
rho = (
|
|
417
429
|
1
|
|
418
430
|
/ backend.cast(p, dtypestr)
|
|
419
431
|
* contractor(newnodes, output_edge_order=[edge1[j], edge2[j]]).tensor
|
|
420
432
|
)
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
433
|
+
if self._d == 2:
|
|
434
|
+
pu = backend.real(rho[0, 0])
|
|
435
|
+
if status is None:
|
|
436
|
+
r = backend.implicit_randu()[0]
|
|
437
|
+
else:
|
|
438
|
+
r = status[k]
|
|
439
|
+
r = backend.real(backend.cast(r, dtypestr))
|
|
440
|
+
eps = 0.31415926 * 1e-12
|
|
441
|
+
sign = (
|
|
442
|
+
backend.sign(r - pu + eps) / 2 + 0.5
|
|
443
|
+
) # in case status is exactly 0.5
|
|
444
|
+
sign = backend.convert_to_tensor(sign)
|
|
445
|
+
sign = backend.cast(sign, dtype=rdtypestr)
|
|
446
|
+
sign_complex = backend.cast(sign, dtypestr)
|
|
447
|
+
sample.append(sign_complex)
|
|
448
|
+
p = p * (pu * (-1) ** sign + sign)
|
|
424
449
|
else:
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
450
|
+
pu = backend.clip(
|
|
451
|
+
backend.real(backend.diagonal(rho)),
|
|
452
|
+
backend.convert_to_tensor(0.0),
|
|
453
|
+
backend.convert_to_tensor(1.0),
|
|
454
|
+
)
|
|
455
|
+
pu = pu / backend.sum(pu)
|
|
456
|
+
if status is None:
|
|
457
|
+
ind = backend.implicit_randc(
|
|
458
|
+
a=backend.arange(self._d),
|
|
459
|
+
shape=1,
|
|
460
|
+
p=backend.cast(pu, rdtypestr),
|
|
461
|
+
)
|
|
462
|
+
else:
|
|
463
|
+
one_r = backend.cast(backend.convert_to_tensor(1.0), rdtypestr)
|
|
464
|
+
st = backend.cast(status[k : k + 1], rdtypestr)
|
|
465
|
+
ind = backend.probability_sample(
|
|
466
|
+
shots=1,
|
|
467
|
+
p=backend.cast(pu, rdtypestr),
|
|
468
|
+
status=one_r - st,
|
|
469
|
+
)
|
|
470
|
+
k_out = backend.cast(ind[0], "int32")
|
|
471
|
+
sample.append(backend.cast(k_out, rdtypestr))
|
|
472
|
+
p = p * backend.cast(pu[k_out], rdtypestr)
|
|
473
|
+
sample = backend.real(backend.stack(sample))
|
|
437
474
|
if with_prob:
|
|
438
475
|
return sample, p
|
|
439
476
|
else:
|
|
@@ -443,35 +480,48 @@ class BaseCircuit(AbstractCircuit):
|
|
|
443
480
|
|
|
444
481
|
def amplitude_before(self, l: Union[str, Tensor]) -> List[Gate]:
|
|
445
482
|
r"""
|
|
446
|
-
Returns the tensornetwor nodes for the amplitude of the circuit given
|
|
447
|
-
For state simulator, it computes :math:`\langle l\vert \psi\rangle
|
|
448
|
-
for density
|
|
483
|
+
Returns the tensornetwor nodes for the amplitude of the circuit given a computational-basis label ``l``.
|
|
484
|
+
For a state simulator, it computes :math:`\langle l \vert \psi\rangle`;
|
|
485
|
+
for a density-matrix simulator, it computes :math:`\mathrm{Tr}(\rho \vert l\rangle\langle l\vert)`.
|
|
449
486
|
Note how these two are different up to a square operation.
|
|
450
487
|
|
|
451
|
-
:
|
|
488
|
+
:Example:
|
|
489
|
+
|
|
490
|
+
>>> c = tc.Circuit(2)
|
|
491
|
+
>>> c.X(0)
|
|
492
|
+
>>> c.amplitude("10") # d=2, per-qubit digits
|
|
493
|
+
array(1.+0.j, dtype=complex64)
|
|
494
|
+
>>> c.CNOT(0, 1)
|
|
495
|
+
>>> c.amplitude("11")
|
|
496
|
+
array(1.+0.j, dtype=complex64)
|
|
497
|
+
|
|
498
|
+
For qudits (d>2, d<=36):
|
|
499
|
+
>>> c = tc.Circuit(3, dim=12)
|
|
500
|
+
>>> c.amplitude("0A2") # base-12 string, A stands for 10
|
|
501
|
+
|
|
502
|
+
:param l: Basis label.
|
|
503
|
+
- If a string: it must be a base-d string of length ``nqubits``, using 0–9A–Z (A=10,…,Z=35) when ``d<=36``.
|
|
504
|
+
- If a tensor/array/list: it should contain per-site integers in ``[0, d-1]`` with length ``nqubits``.
|
|
452
505
|
:type l: Union[str, Tensor]
|
|
453
506
|
:return: The tensornetwork nodes for the amplitude of the circuit.
|
|
454
507
|
:rtype: List[Gate]
|
|
455
508
|
"""
|
|
509
|
+
|
|
456
510
|
no, d_edges = self._copy()
|
|
457
511
|
ms = []
|
|
458
512
|
if self.is_dm:
|
|
459
513
|
msconj = []
|
|
460
514
|
if isinstance(l, str):
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
endn = np.array([1, 0], dtype=npdtype)
|
|
466
|
-
ms.append(tn.Node(endn))
|
|
515
|
+
symbols = _decode_basis_label(l, n=self._nqubits, dim=self._d)
|
|
516
|
+
for k in symbols:
|
|
517
|
+
n = onehot_d_tensor(k, d=self._d)
|
|
518
|
+
ms.append(tn.Node(n))
|
|
467
519
|
if self.is_dm:
|
|
468
|
-
msconj.append(tn.Node(
|
|
469
|
-
else:
|
|
520
|
+
msconj.append(tn.Node(n))
|
|
521
|
+
else:
|
|
470
522
|
l = backend.cast(l, dtype=dtypestr)
|
|
471
523
|
for i in range(self._nqubits):
|
|
472
|
-
endn = l[i]
|
|
473
|
-
1 - l[i]
|
|
474
|
-
) * gates.array_to_tensor(np.array([1, 0]))
|
|
524
|
+
endn = onehot_d_tensor(l[i], d=self._d)
|
|
475
525
|
ms.append(tn.Node(endn))
|
|
476
526
|
if self.is_dm:
|
|
477
527
|
msconj.append(tn.Node(endn))
|
|
@@ -522,17 +572,18 @@ class BaseCircuit(AbstractCircuit):
|
|
|
522
572
|
|
|
523
573
|
def probability(self) -> Tensor:
|
|
524
574
|
"""
|
|
525
|
-
get the
|
|
575
|
+
get the d^n length probability vector over computational basis
|
|
526
576
|
|
|
527
|
-
:return: probability vector
|
|
577
|
+
:return: probability vector of shape [dim**n]
|
|
528
578
|
:rtype: Tensor
|
|
529
579
|
"""
|
|
530
580
|
s = self.state() # type: ignore
|
|
531
581
|
if self.is_dm is False:
|
|
532
|
-
|
|
533
|
-
|
|
582
|
+
amp = backend.reshape(s, [-1])
|
|
583
|
+
p = backend.real(backend.abs(amp) ** 2)
|
|
534
584
|
else:
|
|
535
|
-
|
|
585
|
+
diag = backend.diagonal(s)
|
|
586
|
+
p = backend.real(backend.reshape(diag, [-1]))
|
|
536
587
|
return p
|
|
537
588
|
|
|
538
589
|
@partial(arg_alias, alias_dict={"format": ["format_"]})
|
|
@@ -546,7 +597,7 @@ class BaseCircuit(AbstractCircuit):
|
|
|
546
597
|
status: Optional[Tensor] = None,
|
|
547
598
|
jittable: bool = True,
|
|
548
599
|
) -> Any:
|
|
549
|
-
"""
|
|
600
|
+
r"""
|
|
550
601
|
batched sampling from state or circuit tensor network directly
|
|
551
602
|
|
|
552
603
|
:param batch: number of samples, defaults to None
|
|
@@ -569,6 +620,7 @@ class BaseCircuit(AbstractCircuit):
|
|
|
569
620
|
"count_tuple": # (np.array([0]), np.array([2]))
|
|
570
621
|
|
|
571
622
|
"count_dict_bin": # {"00": 2, "01": 0, "10": 0, "11": 0}
|
|
623
|
+
for cases d\in [11, 36], use 0–9A–Z digits (e.g., 'A' -> 10, …, 'Z' -> 35);
|
|
572
624
|
|
|
573
625
|
"count_dict_int": # {0: 2, 1: 0, 2: 0, 3: 0}
|
|
574
626
|
|
|
@@ -619,8 +671,8 @@ class BaseCircuit(AbstractCircuit):
|
|
|
619
671
|
if format is None:
|
|
620
672
|
return r
|
|
621
673
|
r = backend.stack([ri[0] for ri in r]) # type: ignore
|
|
622
|
-
|
|
623
|
-
ch = sample_bin2int(r, self._nqubits)
|
|
674
|
+
ch = backend.cast(r, "int32")
|
|
675
|
+
# ch = sample_bin2int(r, self._nqubits, dim=self._d)
|
|
624
676
|
else: # allow_state
|
|
625
677
|
if batch is None:
|
|
626
678
|
nbatch = 1
|
|
@@ -645,7 +697,7 @@ class BaseCircuit(AbstractCircuit):
|
|
|
645
697
|
# 2,
|
|
646
698
|
# )
|
|
647
699
|
if format is None: # for backward compatibility
|
|
648
|
-
confg = sample_int2bin(ch, self._nqubits)
|
|
700
|
+
confg = sample_int2bin(ch, self._nqubits, dim=self._d)
|
|
649
701
|
prob = backend.gather1d(p, ch)
|
|
650
702
|
r = list(zip(confg, prob)) # type: ignore
|
|
651
703
|
if batch is None:
|
|
@@ -653,7 +705,9 @@ class BaseCircuit(AbstractCircuit):
|
|
|
653
705
|
return r
|
|
654
706
|
if self._nqubits > 35:
|
|
655
707
|
jittable = False
|
|
656
|
-
return sample2all(
|
|
708
|
+
return sample2all(
|
|
709
|
+
sample=ch, n=self._nqubits, format=format, jittable=jittable, dim=self._d
|
|
710
|
+
)
|
|
657
711
|
|
|
658
712
|
def sample_expectation_ps(
|
|
659
713
|
self,
|
|
@@ -853,9 +907,9 @@ class BaseCircuit(AbstractCircuit):
|
|
|
853
907
|
"""
|
|
854
908
|
inputs = backend.reshape(inputs, [-1])
|
|
855
909
|
N = inputs.shape[0]
|
|
856
|
-
n =
|
|
910
|
+
n = _infer_num_sites(N, self._d)
|
|
857
911
|
assert n == self._nqubits
|
|
858
|
-
inputs = backend.reshape(inputs, [
|
|
912
|
+
inputs = backend.reshape(inputs, [self._d for _ in range(n)])
|
|
859
913
|
if self.inputs is not None:
|
|
860
914
|
self._nodes[0].tensor = inputs
|
|
861
915
|
if self.is_dm:
|
|
@@ -886,9 +940,9 @@ class BaseCircuit(AbstractCircuit):
|
|
|
886
940
|
|
|
887
941
|
|
|
888
942
|
|
|
889
|
-
:param index: the
|
|
943
|
+
:param index: the site index for the Z-basis measurement
|
|
890
944
|
:type index: int
|
|
891
|
-
:return: 0 or 1 for
|
|
945
|
+
:return: 0 or 1 for Z-basis measurement outcome
|
|
892
946
|
:rtype: Tensor
|
|
893
947
|
"""
|
|
894
948
|
return self.general_kraus( # type: ignore
|
|
@@ -967,8 +1021,8 @@ class BaseCircuit(AbstractCircuit):
|
|
|
967
1021
|
|
|
968
1022
|
def projected_subsystem(self, traceout: Tensor, left: Tuple[int, ...]) -> Tensor:
|
|
969
1023
|
"""
|
|
970
|
-
remaining wavefunction or density matrix on
|
|
971
|
-
fixed
|
|
1024
|
+
remaining wavefunction or density matrix on sites in ``left``, with other sites
|
|
1025
|
+
fixed to given digits (0..d-1) as indicated by ``traceout``
|
|
972
1026
|
|
|
973
1027
|
:param traceout: can be jitted
|
|
974
1028
|
:type traceout: Tensor
|
|
@@ -977,15 +1031,14 @@ class BaseCircuit(AbstractCircuit):
|
|
|
977
1031
|
:return: _description_
|
|
978
1032
|
:rtype: Tensor
|
|
979
1033
|
"""
|
|
980
|
-
|
|
1034
|
+
|
|
981
1035
|
traceout = backend.cast(traceout, dtypestr)
|
|
982
1036
|
nodes, front = self._copy()
|
|
983
1037
|
L = self._nqubits
|
|
984
1038
|
edges = []
|
|
985
1039
|
for i in range(len(traceout)):
|
|
986
1040
|
if i not in left:
|
|
987
|
-
|
|
988
|
-
n = gates.Gate((1 - b) * end0 + b * end1)
|
|
1041
|
+
n = Gate(onehot_d_tensor(traceout[i], d=self._d))
|
|
989
1042
|
nodes.append(n)
|
|
990
1043
|
front[i] ^ n[0]
|
|
991
1044
|
else:
|
|
@@ -994,8 +1047,7 @@ class BaseCircuit(AbstractCircuit):
|
|
|
994
1047
|
if self.is_dm:
|
|
995
1048
|
for i in range(len(traceout)):
|
|
996
1049
|
if i not in left:
|
|
997
|
-
|
|
998
|
-
n = gates.Gate((1 - b) * end0 + b * end1)
|
|
1050
|
+
n = Gate(onehot_d_tensor(traceout[i], d=self._d))
|
|
999
1051
|
nodes.append(n)
|
|
1000
1052
|
front[i + L] ^ n[0]
|
|
1001
1053
|
else:
|