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/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:
|
|
@@ -441,47 +478,34 @@ class BaseCircuit(AbstractCircuit):
|
|
|
441
478
|
|
|
442
479
|
measure = measure_jit
|
|
443
480
|
|
|
444
|
-
def
|
|
481
|
+
def amplitude_before(self, l: Union[str, Tensor]) -> List[Gate]:
|
|
445
482
|
r"""
|
|
446
|
-
Returns the amplitude of the circuit given the bitstring l.
|
|
483
|
+
Returns the tensornetwor nodes for the amplitude of the circuit given the bitstring l.
|
|
447
484
|
For state simulator, it computes :math:`\langle l\vert \psi\rangle`,
|
|
448
485
|
for density matrix simulator, it computes :math:`Tr(\rho \vert l\rangle \langle 1\vert)`
|
|
449
486
|
Note how these two are different up to a square operation.
|
|
450
487
|
|
|
451
|
-
:Example:
|
|
452
|
-
|
|
453
|
-
>>> c = tc.Circuit(2)
|
|
454
|
-
>>> c.X(0)
|
|
455
|
-
>>> c.amplitude("10")
|
|
456
|
-
array(1.+0.j, dtype=complex64)
|
|
457
|
-
>>> c.CNOT(0, 1)
|
|
458
|
-
>>> c.amplitude("11")
|
|
459
|
-
array(1.+0.j, dtype=complex64)
|
|
460
|
-
|
|
461
488
|
:param l: The bitstring of 0 and 1s.
|
|
462
489
|
:type l: Union[str, Tensor]
|
|
463
|
-
:return: The amplitude of the circuit.
|
|
464
|
-
:rtype:
|
|
490
|
+
:return: The tensornetwork nodes for the amplitude of the circuit.
|
|
491
|
+
:rtype: List[Gate]
|
|
465
492
|
"""
|
|
493
|
+
|
|
466
494
|
no, d_edges = self._copy()
|
|
467
495
|
ms = []
|
|
468
496
|
if self.is_dm:
|
|
469
497
|
msconj = []
|
|
470
498
|
if isinstance(l, str):
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
endn = np.array([1, 0], dtype=npdtype)
|
|
476
|
-
ms.append(tn.Node(endn))
|
|
499
|
+
symbols = _decode_basis_label(l, n=self._nqubits, dim=self._d)
|
|
500
|
+
for k in symbols:
|
|
501
|
+
n = onehot_d_tensor(k, d=self._d)
|
|
502
|
+
ms.append(tn.Node(n))
|
|
477
503
|
if self.is_dm:
|
|
478
|
-
msconj.append(tn.Node(
|
|
479
|
-
else:
|
|
504
|
+
msconj.append(tn.Node(n))
|
|
505
|
+
else:
|
|
480
506
|
l = backend.cast(l, dtype=dtypestr)
|
|
481
507
|
for i in range(self._nqubits):
|
|
482
|
-
endn = l[i]
|
|
483
|
-
1 - l[i]
|
|
484
|
-
) * gates.array_to_tensor(np.array([1, 0]))
|
|
508
|
+
endn = onehot_d_tensor(l[i], d=self._d)
|
|
485
509
|
ms.append(tn.Node(endn))
|
|
486
510
|
if self.is_dm:
|
|
487
511
|
msconj.append(tn.Node(endn))
|
|
@@ -502,21 +526,48 @@ class BaseCircuit(AbstractCircuit):
|
|
|
502
526
|
no.extend(ms)
|
|
503
527
|
if self.is_dm:
|
|
504
528
|
no.extend(msconj)
|
|
529
|
+
return no
|
|
530
|
+
|
|
531
|
+
def amplitude(self, l: Union[str, Tensor]) -> Tensor:
|
|
532
|
+
r"""
|
|
533
|
+
Returns the amplitude of the circuit given the bitstring l.
|
|
534
|
+
For state simulator, it computes :math:`\langle l\vert \psi\rangle`,
|
|
535
|
+
for density matrix simulator, it computes :math:`Tr(\rho \vert l\rangle \langle 1\vert)`
|
|
536
|
+
Note how these two are different up to a square operation.
|
|
537
|
+
|
|
538
|
+
:Example:
|
|
539
|
+
|
|
540
|
+
>>> c = tc.Circuit(2)
|
|
541
|
+
>>> c.X(0)
|
|
542
|
+
>>> c.amplitude("10")
|
|
543
|
+
array(1.+0.j, dtype=complex64)
|
|
544
|
+
>>> c.CNOT(0, 1)
|
|
545
|
+
>>> c.amplitude("11")
|
|
546
|
+
array(1.+0.j, dtype=complex64)
|
|
547
|
+
|
|
548
|
+
:param l: The bitstring of 0 and 1s.
|
|
549
|
+
:type l: Union[str, Tensor]
|
|
550
|
+
:return: The amplitude of the circuit.
|
|
551
|
+
:rtype: tn.Node.tensor
|
|
552
|
+
"""
|
|
553
|
+
no = self.amplitude_before(l)
|
|
554
|
+
|
|
505
555
|
return contractor(no).tensor
|
|
506
556
|
|
|
507
557
|
def probability(self) -> Tensor:
|
|
508
558
|
"""
|
|
509
|
-
get the
|
|
559
|
+
get the d^n length probability vector over computational basis
|
|
510
560
|
|
|
511
|
-
:return: probability vector
|
|
561
|
+
:return: probability vector of shape [dim**n]
|
|
512
562
|
:rtype: Tensor
|
|
513
563
|
"""
|
|
514
564
|
s = self.state() # type: ignore
|
|
515
565
|
if self.is_dm is False:
|
|
516
|
-
|
|
517
|
-
|
|
566
|
+
amp = backend.reshape(s, [-1])
|
|
567
|
+
p = backend.real(backend.abs(amp) ** 2)
|
|
518
568
|
else:
|
|
519
|
-
|
|
569
|
+
diag = backend.diagonal(s)
|
|
570
|
+
p = backend.real(backend.reshape(diag, [-1]))
|
|
520
571
|
return p
|
|
521
572
|
|
|
522
573
|
@partial(arg_alias, alias_dict={"format": ["format_"]})
|
|
@@ -530,7 +581,7 @@ class BaseCircuit(AbstractCircuit):
|
|
|
530
581
|
status: Optional[Tensor] = None,
|
|
531
582
|
jittable: bool = True,
|
|
532
583
|
) -> Any:
|
|
533
|
-
"""
|
|
584
|
+
r"""
|
|
534
585
|
batched sampling from state or circuit tensor network directly
|
|
535
586
|
|
|
536
587
|
:param batch: number of samples, defaults to None
|
|
@@ -553,6 +604,7 @@ class BaseCircuit(AbstractCircuit):
|
|
|
553
604
|
"count_tuple": # (np.array([0]), np.array([2]))
|
|
554
605
|
|
|
555
606
|
"count_dict_bin": # {"00": 2, "01": 0, "10": 0, "11": 0}
|
|
607
|
+
for cases d\in [11, 36], use 0-9A-Z digits (e.g., 'A' -> 10, ..., 'Z' -> 35);
|
|
556
608
|
|
|
557
609
|
"count_dict_int": # {0: 2, 1: 0, 2: 0, 3: 0}
|
|
558
610
|
|
|
@@ -560,7 +612,8 @@ class BaseCircuit(AbstractCircuit):
|
|
|
560
612
|
:param random_generator: random generator, defaults to None
|
|
561
613
|
:type random_generator: Optional[Any], optional
|
|
562
614
|
:param status: external randomness given by tensor uniformly from [0, 1],
|
|
563
|
-
if set, can overwrite random_generator
|
|
615
|
+
if set, can overwrite random_generator, shape [batch] for `allow_state=True`
|
|
616
|
+
and shape [batch, nqubits] for `allow_state=False` using perfect sampling implementation
|
|
564
617
|
:type status: Optional[Tensor]
|
|
565
618
|
:param jittable: when converting to count, whether keep the full size. if false, may be conflict
|
|
566
619
|
external jit, if true, may fail for large scale system with actual limited count results
|
|
@@ -581,25 +634,29 @@ class BaseCircuit(AbstractCircuit):
|
|
|
581
634
|
return r
|
|
582
635
|
r = [r] # type: ignore
|
|
583
636
|
else:
|
|
637
|
+
r = [] # type: ignore
|
|
638
|
+
if status is not None:
|
|
639
|
+
assert backend.shape_tuple(status)[0] == batch
|
|
640
|
+
for seed in status:
|
|
641
|
+
r.append(self.perfect_sampling(seed)) # type: ignore
|
|
584
642
|
|
|
585
|
-
|
|
586
|
-
def perfect_sampling(key: Any) -> Any:
|
|
587
|
-
backend.set_random_state(key)
|
|
588
|
-
return self.perfect_sampling()
|
|
643
|
+
else:
|
|
589
644
|
|
|
590
|
-
|
|
645
|
+
@backend.jit
|
|
646
|
+
def perfect_sampling(key: Any) -> Any:
|
|
647
|
+
backend.set_random_state(key)
|
|
648
|
+
return self.perfect_sampling()
|
|
591
649
|
|
|
592
|
-
|
|
650
|
+
subkey = random_generator
|
|
651
|
+
for _ in range(batch):
|
|
652
|
+
key, subkey = backend.random_split(subkey)
|
|
653
|
+
r.append(perfect_sampling(key)) # type: ignore
|
|
593
654
|
|
|
594
|
-
subkey = random_generator
|
|
595
|
-
for _ in range(batch):
|
|
596
|
-
key, subkey = backend.random_split(subkey)
|
|
597
|
-
r.append(perfect_sampling(key)) # type: ignore
|
|
598
655
|
if format is None:
|
|
599
656
|
return r
|
|
600
657
|
r = backend.stack([ri[0] for ri in r]) # type: ignore
|
|
601
|
-
|
|
602
|
-
ch = sample_bin2int(r, self._nqubits)
|
|
658
|
+
ch = backend.cast(r, "int32")
|
|
659
|
+
# ch = sample_bin2int(r, self._nqubits, dim=self._d)
|
|
603
660
|
else: # allow_state
|
|
604
661
|
if batch is None:
|
|
605
662
|
nbatch = 1
|
|
@@ -624,7 +681,7 @@ class BaseCircuit(AbstractCircuit):
|
|
|
624
681
|
# 2,
|
|
625
682
|
# )
|
|
626
683
|
if format is None: # for backward compatibility
|
|
627
|
-
confg = sample_int2bin(ch, self._nqubits)
|
|
684
|
+
confg = sample_int2bin(ch, self._nqubits, dim=self._d)
|
|
628
685
|
prob = backend.gather1d(p, ch)
|
|
629
686
|
r = list(zip(confg, prob)) # type: ignore
|
|
630
687
|
if batch is None:
|
|
@@ -632,7 +689,9 @@ class BaseCircuit(AbstractCircuit):
|
|
|
632
689
|
return r
|
|
633
690
|
if self._nqubits > 35:
|
|
634
691
|
jittable = False
|
|
635
|
-
return sample2all(
|
|
692
|
+
return sample2all(
|
|
693
|
+
sample=ch, n=self._nqubits, format=format, jittable=jittable, dim=self._d
|
|
694
|
+
)
|
|
636
695
|
|
|
637
696
|
def sample_expectation_ps(
|
|
638
697
|
self,
|
|
@@ -796,8 +855,10 @@ class BaseCircuit(AbstractCircuit):
|
|
|
796
855
|
"""
|
|
797
856
|
# if isinstance(readout_error, tuple):
|
|
798
857
|
# readout_error = list[readout_error] # type: ignore
|
|
799
|
-
|
|
800
|
-
|
|
858
|
+
try:
|
|
859
|
+
nqubit = int(readout_error.shape[0]) # type: ignore
|
|
860
|
+
except AttributeError:
|
|
861
|
+
nqubit = len(readout_error) # type: ignore
|
|
801
862
|
readoutlist = []
|
|
802
863
|
for i in range(nqubit):
|
|
803
864
|
readoutlist.append(
|
|
@@ -830,9 +891,9 @@ class BaseCircuit(AbstractCircuit):
|
|
|
830
891
|
"""
|
|
831
892
|
inputs = backend.reshape(inputs, [-1])
|
|
832
893
|
N = inputs.shape[0]
|
|
833
|
-
n =
|
|
894
|
+
n = _infer_num_sites(N, self._d)
|
|
834
895
|
assert n == self._nqubits
|
|
835
|
-
inputs = backend.reshape(inputs, [
|
|
896
|
+
inputs = backend.reshape(inputs, [self._d for _ in range(n)])
|
|
836
897
|
if self.inputs is not None:
|
|
837
898
|
self._nodes[0].tensor = inputs
|
|
838
899
|
if self.is_dm:
|
|
@@ -863,9 +924,9 @@ class BaseCircuit(AbstractCircuit):
|
|
|
863
924
|
|
|
864
925
|
|
|
865
926
|
|
|
866
|
-
:param index: the
|
|
927
|
+
:param index: the site index for the Z-basis measurement
|
|
867
928
|
:type index: int
|
|
868
|
-
:return: 0 or 1 for
|
|
929
|
+
:return: 0 or 1 for Z-basis measurement outcome
|
|
869
930
|
:rtype: Tensor
|
|
870
931
|
"""
|
|
871
932
|
return self.general_kraus( # type: ignore
|
|
@@ -944,8 +1005,8 @@ class BaseCircuit(AbstractCircuit):
|
|
|
944
1005
|
|
|
945
1006
|
def projected_subsystem(self, traceout: Tensor, left: Tuple[int, ...]) -> Tensor:
|
|
946
1007
|
"""
|
|
947
|
-
remaining wavefunction or density matrix on
|
|
948
|
-
fixed
|
|
1008
|
+
remaining wavefunction or density matrix on sites in ``left``, with other sites
|
|
1009
|
+
fixed to given digits (0..d-1) as indicated by ``traceout``
|
|
949
1010
|
|
|
950
1011
|
:param traceout: can be jitted
|
|
951
1012
|
:type traceout: Tensor
|
|
@@ -954,15 +1015,14 @@ class BaseCircuit(AbstractCircuit):
|
|
|
954
1015
|
:return: _description_
|
|
955
1016
|
:rtype: Tensor
|
|
956
1017
|
"""
|
|
957
|
-
|
|
1018
|
+
|
|
958
1019
|
traceout = backend.cast(traceout, dtypestr)
|
|
959
1020
|
nodes, front = self._copy()
|
|
960
1021
|
L = self._nqubits
|
|
961
1022
|
edges = []
|
|
962
1023
|
for i in range(len(traceout)):
|
|
963
1024
|
if i not in left:
|
|
964
|
-
|
|
965
|
-
n = gates.Gate((1 - b) * end0 + b * end1)
|
|
1025
|
+
n = Gate(onehot_d_tensor(traceout[i], d=self._d))
|
|
966
1026
|
nodes.append(n)
|
|
967
1027
|
front[i] ^ n[0]
|
|
968
1028
|
else:
|
|
@@ -971,8 +1031,7 @@ class BaseCircuit(AbstractCircuit):
|
|
|
971
1031
|
if self.is_dm:
|
|
972
1032
|
for i in range(len(traceout)):
|
|
973
1033
|
if i not in left:
|
|
974
|
-
|
|
975
|
-
n = gates.Gate((1 - b) * end0 + b * end1)
|
|
1034
|
+
n = Gate(onehot_d_tensor(traceout[i], d=self._d))
|
|
976
1035
|
nodes.append(n)
|
|
977
1036
|
front[i + L] ^ n[0]
|
|
978
1037
|
else:
|