pyqrack-cuda-complex128 2.2.2__tar.gz → 2.2.4__tar.gz
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.
- {pyqrack_cuda_complex128-2.2.2 → pyqrack_cuda_complex128-2.2.4}/Makefile +1 -1
- {pyqrack_cuda_complex128-2.2.2/pyqrack_cuda_complex128.egg-info → pyqrack_cuda_complex128-2.2.4}/PKG-INFO +1 -1
- {pyqrack_cuda_complex128-2.2.2 → pyqrack_cuda_complex128-2.2.4}/pyqrack/qrack_ace_backend.py +269 -202
- {pyqrack_cuda_complex128-2.2.2 → pyqrack_cuda_complex128-2.2.4/pyqrack_cuda_complex128.egg-info}/PKG-INFO +1 -1
- {pyqrack_cuda_complex128-2.2.2 → pyqrack_cuda_complex128-2.2.4}/setup.py +1 -1
- {pyqrack_cuda_complex128-2.2.2 → pyqrack_cuda_complex128-2.2.4}/LICENSE +0 -0
- {pyqrack_cuda_complex128-2.2.2 → pyqrack_cuda_complex128-2.2.4}/MANIFEST.in +0 -0
- {pyqrack_cuda_complex128-2.2.2 → pyqrack_cuda_complex128-2.2.4}/README.md +0 -0
- {pyqrack_cuda_complex128-2.2.2 → pyqrack_cuda_complex128-2.2.4}/pyproject.toml +0 -0
- {pyqrack_cuda_complex128-2.2.2 → pyqrack_cuda_complex128-2.2.4}/pyqrack/__init__.py +0 -0
- {pyqrack_cuda_complex128-2.2.2 → pyqrack_cuda_complex128-2.2.4}/pyqrack/neuron_activation_fn.py +0 -0
- {pyqrack_cuda_complex128-2.2.2 → pyqrack_cuda_complex128-2.2.4}/pyqrack/pauli.py +0 -0
- {pyqrack_cuda_complex128-2.2.2 → pyqrack_cuda_complex128-2.2.4}/pyqrack/qrack_circuit.py +0 -0
- {pyqrack_cuda_complex128-2.2.2 → pyqrack_cuda_complex128-2.2.4}/pyqrack/qrack_near_clifford_qec_backend.py +0 -0
- {pyqrack_cuda_complex128-2.2.2 → pyqrack_cuda_complex128-2.2.4}/pyqrack/qrack_neuron.py +0 -0
- {pyqrack_cuda_complex128-2.2.2 → pyqrack_cuda_complex128-2.2.4}/pyqrack/qrack_neuron_torch_layer.py +0 -0
- {pyqrack_cuda_complex128-2.2.2 → pyqrack_cuda_complex128-2.2.4}/pyqrack/qrack_simulator.py +0 -0
- {pyqrack_cuda_complex128-2.2.2 → pyqrack_cuda_complex128-2.2.4}/pyqrack/qrack_stabilizer.py +0 -0
- {pyqrack_cuda_complex128-2.2.2 → pyqrack_cuda_complex128-2.2.4}/pyqrack/qrack_system/__init__.py +0 -0
- {pyqrack_cuda_complex128-2.2.2 → pyqrack_cuda_complex128-2.2.4}/pyqrack/qrack_system/qrack_system.py +0 -0
- {pyqrack_cuda_complex128-2.2.2 → pyqrack_cuda_complex128-2.2.4}/pyqrack/quimb_circuit_type.py +0 -0
- {pyqrack_cuda_complex128-2.2.2 → pyqrack_cuda_complex128-2.2.4}/pyqrack/stats/__init__.py +0 -0
- {pyqrack_cuda_complex128-2.2.2 → pyqrack_cuda_complex128-2.2.4}/pyqrack/stats/load_quantized_data.py +0 -0
- {pyqrack_cuda_complex128-2.2.2 → pyqrack_cuda_complex128-2.2.4}/pyqrack/stats/quantize_by_range.py +0 -0
- {pyqrack_cuda_complex128-2.2.2 → pyqrack_cuda_complex128-2.2.4}/pyqrack_cuda_complex128.egg-info/SOURCES.txt +0 -0
- {pyqrack_cuda_complex128-2.2.2 → pyqrack_cuda_complex128-2.2.4}/pyqrack_cuda_complex128.egg-info/dependency_links.txt +0 -0
- {pyqrack_cuda_complex128-2.2.2 → pyqrack_cuda_complex128-2.2.4}/pyqrack_cuda_complex128.egg-info/not-zip-safe +0 -0
- {pyqrack_cuda_complex128-2.2.2 → pyqrack_cuda_complex128-2.2.4}/pyqrack_cuda_complex128.egg-info/requires.txt +0 -0
- {pyqrack_cuda_complex128-2.2.2 → pyqrack_cuda_complex128-2.2.4}/pyqrack_cuda_complex128.egg-info/top_level.txt +0 -0
- {pyqrack_cuda_complex128-2.2.2 → pyqrack_cuda_complex128-2.2.4}/setup.cfg +0 -0
|
@@ -30,7 +30,7 @@ build-deps:
|
|
|
30
30
|
rm -rf pyqrack/qrack_system/qrack_cl_precompile
|
|
31
31
|
ifneq ($(OS),Windows_NT)
|
|
32
32
|
ifeq ($(QRACK_PRESENT),)
|
|
33
|
-
git clone https://github.com/unitaryfund/qrack.git; cd qrack; git checkout
|
|
33
|
+
git clone https://github.com/unitaryfund/qrack.git; cd qrack; git checkout 01dbf96198e4df51cebcf23e506571cee0927244; cd ..
|
|
34
34
|
endif
|
|
35
35
|
mkdir -p qrack/build
|
|
36
36
|
ifeq ($(UNAME_S),Linux)
|
{pyqrack_cuda_complex128-2.2.2 → pyqrack_cuda_complex128-2.2.4}/pyqrack/qrack_ace_backend.py
RENAMED
|
@@ -191,7 +191,6 @@ def _cpauli_lhv(prob, targ, axis, anti, theta=math.pi):
|
|
|
191
191
|
elif axis == Pauli.PauliZ:
|
|
192
192
|
targ.rz(effective_theta)
|
|
193
193
|
|
|
194
|
-
|
|
195
194
|
class QrackAceBackend:
|
|
196
195
|
"""A back end for elided quantum error correction
|
|
197
196
|
|
|
@@ -212,6 +211,12 @@ class QrackAceBackend:
|
|
|
212
211
|
is_transpose(bool): Rows are long if False, columns are long if True
|
|
213
212
|
"""
|
|
214
213
|
|
|
214
|
+
# Sweepable vote weights for the 4-source boundary correction pool:
|
|
215
|
+
# [slot0, slot1, slot2, lhv]. Must sum to an odd number so the
|
|
216
|
+
# underlying hard-vote tally (independent of the continuous RMS
|
|
217
|
+
# formula) is always tie-free.
|
|
218
|
+
_LHV_VOTE_WEIGHTS = [2, 1, 1, 1]
|
|
219
|
+
|
|
215
220
|
def __init__(
|
|
216
221
|
self,
|
|
217
222
|
qubit_count=1,
|
|
@@ -276,7 +281,20 @@ class QrackAceBackend:
|
|
|
276
281
|
self._is_row_long_range[-1] = False
|
|
277
282
|
sim_count = col_patch_count * row_patch_count
|
|
278
283
|
|
|
284
|
+
# Boundary qubits no longer carry a private classical LHV proxy.
|
|
285
|
+
# Instead, every boundary site (row- and/or column-boundary alike)
|
|
286
|
+
# gets a real qubit in one single, shared "crossbar" QrackSimulator.
|
|
287
|
+
# That simulator's own greedy elision (set_sdrp) is trusted to
|
|
288
|
+
# automatically factor apart whatever boundary sites turn out to be
|
|
289
|
+
# separable (e.g. disjoint rails, rail intersections), exactly the
|
|
290
|
+
# same way it already factors apart unentangled subspaces within
|
|
291
|
+
# any other single QrackSimulator instance. We don't need to special
|
|
292
|
+
# -case "crossbar intersections" by hand; the elision does it for us.
|
|
293
|
+
boundary_sim_id = sim_count
|
|
294
|
+
boundary_count = 0
|
|
295
|
+
|
|
279
296
|
self._qubits = []
|
|
297
|
+
self._lhv = {}
|
|
280
298
|
sim_counts = [0] * sim_count
|
|
281
299
|
sim_id = 0
|
|
282
300
|
tot_qubits = 0
|
|
@@ -290,8 +308,11 @@ class QrackAceBackend:
|
|
|
290
308
|
qubit.append((t_sim_id, sim_counts[t_sim_id]))
|
|
291
309
|
sim_counts[t_sim_id] += 1
|
|
292
310
|
|
|
293
|
-
qubit.append(
|
|
294
|
-
|
|
311
|
+
qubit.append((boundary_sim_id, boundary_count))
|
|
312
|
+
boundary_count += 1
|
|
313
|
+
|
|
314
|
+
self._lhv[tot_qubits] = LHVQubit(
|
|
315
|
+
to_clone=(to_clone._lhv[tot_qubits] if to_clone else None)
|
|
295
316
|
)
|
|
296
317
|
|
|
297
318
|
if (not c) and (not r):
|
|
@@ -309,8 +330,23 @@ class QrackAceBackend:
|
|
|
309
330
|
self._qubits.append(qubit)
|
|
310
331
|
tot_qubits += 1
|
|
311
332
|
|
|
333
|
+
# The crossbar's size is fixed by how many boundary sites exist.
|
|
334
|
+
# When there are none (e.g. a grid small enough, relative to
|
|
335
|
+
# long_range_rows/columns, that the whole thing is "fully
|
|
336
|
+
# connected" with no QEC boundary at all), we must NOT allocate a
|
|
337
|
+
# 0-qubit QrackSimulator for the crossbar: a 0-qubit QrackSimulator
|
|
338
|
+
# can be constructed, but calling .clone() on one crashes the
|
|
339
|
+
# native Qrack core (segfault), and clone() is called routinely by
|
|
340
|
+
# measure_shots()/clone(). So the boundary sim is only created when
|
|
341
|
+
# boundary_count > 0, exactly mirroring how the original LHV-based
|
|
342
|
+
# code never instantiated anything for the boundary case when
|
|
343
|
+
# there were no boundary sites.
|
|
344
|
+
has_boundary = boundary_count > 0
|
|
345
|
+
if has_boundary:
|
|
346
|
+
sim_counts.append(boundary_count)
|
|
347
|
+
|
|
312
348
|
self.sim = []
|
|
313
|
-
for i in range(sim_count):
|
|
349
|
+
for i in range(sim_count + (1 if has_boundary else 0)):
|
|
314
350
|
self.sim.append(
|
|
315
351
|
to_clone.sim[i].clone()
|
|
316
352
|
if to_clone
|
|
@@ -331,13 +367,11 @@ class QrackAceBackend:
|
|
|
331
367
|
# # (1 - 1 / sqrt(2)) / 4 (but empirically tuned)
|
|
332
368
|
# self.sim[i].set_sdrp(0.073223304703363119)
|
|
333
369
|
|
|
370
|
+
self._boundary_sim_id = boundary_sim_id if has_boundary else None
|
|
371
|
+
|
|
334
372
|
def clone(self):
|
|
335
373
|
return QrackAceBackend(to_clone=self)
|
|
336
374
|
|
|
337
|
-
def set_sdrp(self, sdrp):
|
|
338
|
-
for sim in self.sim:
|
|
339
|
-
sim.set_sdrp(sdrp)
|
|
340
|
-
|
|
341
375
|
def measure_shots_consensus(self, q, s, n_instances=3, threshold=0.1):
|
|
342
376
|
# Consensus measurement across n_instances independent clones.
|
|
343
377
|
#
|
|
@@ -405,6 +439,24 @@ class QrackAceBackend:
|
|
|
405
439
|
p1 = self.sim[q1[0]].prob(q1[1]) if isinstance(q1, tuple) else q1.prob()
|
|
406
440
|
p2 = self.sim[q2[0]].prob(q2[1]) if isinstance(q2, tuple) else q2.prob()
|
|
407
441
|
|
|
442
|
+
# When p1 and p2 are within floating-point noise of each other
|
|
443
|
+
# (self._epsilon), they carry no real information about which
|
|
444
|
+
# qubit is "more likely 1" -- e.g. a fresh target right after
|
|
445
|
+
# _cx_shadow's H() always reads ~0.5, indistinguishably from a
|
|
446
|
+
# genuinely-mixed control. This shadow mechanism can only return
|
|
447
|
+
# ONE definite classical pick per call, so resolving every such
|
|
448
|
+
# near-tie to a FIXED qubit (as a plain "<" or "<=" comparison
|
|
449
|
+
# would, once p1/p2 are within epsilon of each other) reintroduces
|
|
450
|
+
# a systematic bias -- it just moves the bias from "favors q1" to
|
|
451
|
+
# "always favors q2" instead of removing it. The aggregate
|
|
452
|
+
# statistics this shadow is meant to approximate (e.g. a real CX
|
|
453
|
+
# from a maximally-mixed control onto a fresh target makes BOTH
|
|
454
|
+
# qubits individually read prob=0.5, perfectly correlated) are
|
|
455
|
+
# only reproduced, across many circuit instances, if a genuine
|
|
456
|
+
# tie is broken at random rather than by a fixed rule.
|
|
457
|
+
if abs(p1 - p2) <= self._epsilon:
|
|
458
|
+
return (p1, q2) if random.random() < 0.5 else (p2, q1)
|
|
459
|
+
|
|
408
460
|
if p1 < p2:
|
|
409
461
|
return p2, q1
|
|
410
462
|
|
|
@@ -412,7 +464,16 @@ class QrackAceBackend:
|
|
|
412
464
|
|
|
413
465
|
def _cz_shadow(self, q1, q2):
|
|
414
466
|
prob_max, t = self._ct_pair_prob(q1, q2)
|
|
415
|
-
|
|
467
|
+
# NOTE: this must be ">=", not ">". H() applied to any qubit in a
|
|
468
|
+
# definite computational-basis state (e.g. a fresh boundary/ancilla
|
|
469
|
+
# qubit, as in _cx_shadow's H-sandwich) lands at EXACTLY prob=0.5,
|
|
470
|
+
# deterministically -- this is the ordinary case, not a rare
|
|
471
|
+
# floating-point tie. A strict "> 0.5" therefore silently no-ops
|
|
472
|
+
# the shadow gate every time it targets a fresh qubit, which
|
|
473
|
+
# breaks entanglement transfer for the extremely common case of a
|
|
474
|
+
# CX/CY/CZ from a maximally-mixed-looking control onto a fresh
|
|
475
|
+
# target (e.g. H(0); cx(0,1) for a Bell pair).
|
|
476
|
+
if prob_max >= (0.5 - self._epsilon):
|
|
416
477
|
if isinstance(t, tuple):
|
|
417
478
|
self.sim[t[0]].z(t[1])
|
|
418
479
|
else:
|
|
@@ -472,35 +533,23 @@ class QrackAceBackend:
|
|
|
472
533
|
|
|
473
534
|
@staticmethod
|
|
474
535
|
def _get_qb_lhv_indices(hq):
|
|
475
|
-
|
|
536
|
+
# Historically, index 2 (when present) pointed at a private
|
|
537
|
+
# classical LHVQubit proxy and had to be special-cased everywhere.
|
|
538
|
+
# It is now an ordinary (sim_id, idx) tuple into the shared
|
|
539
|
+
# boundary "crossbar" QrackSimulator, so it is just one more
|
|
540
|
+
# coupling target like every other index. We keep this helper's
|
|
541
|
+
# name and signature for minimal call-site churn; "lhv" is now
|
|
542
|
+
# always -1 (no index needs special-casing any more).
|
|
476
543
|
if len(hq) < 2:
|
|
477
544
|
qb = [0]
|
|
478
|
-
lhv = -1
|
|
479
545
|
elif len(hq) < 4:
|
|
480
|
-
qb = [0, 1]
|
|
481
|
-
lhv = 2
|
|
546
|
+
qb = [0, 1, 2]
|
|
482
547
|
else:
|
|
483
|
-
qb = [0, 1, 3, 4]
|
|
484
|
-
|
|
548
|
+
qb = [0, 1, 2, 3, 4]
|
|
549
|
+
lhv = -1
|
|
485
550
|
|
|
486
551
|
return qb, lhv
|
|
487
552
|
|
|
488
|
-
@staticmethod
|
|
489
|
-
def _get_lhv_bloch_angles(sim):
|
|
490
|
-
# Z axis
|
|
491
|
-
z = sim.bloch[2]
|
|
492
|
-
|
|
493
|
-
# X axis
|
|
494
|
-
x = sim.bloch[0]
|
|
495
|
-
|
|
496
|
-
# Y axis
|
|
497
|
-
y = sim.bloch[1]
|
|
498
|
-
|
|
499
|
-
inclination = math.atan2(math.sqrt(x**2 + y**2), z)
|
|
500
|
-
azimuth = math.atan2(y, x)
|
|
501
|
-
|
|
502
|
-
return azimuth, inclination
|
|
503
|
-
|
|
504
553
|
def _get_bloch_angles(self, hq):
|
|
505
554
|
sim = self.sim[hq[0]].clone()
|
|
506
555
|
q = hq[1]
|
|
@@ -543,9 +592,17 @@ class QrackAceBackend:
|
|
|
543
592
|
|
|
544
593
|
sim.mtrx([m00, m01, m10, m11], q)
|
|
545
594
|
|
|
595
|
+
@staticmethod
|
|
596
|
+
def _get_lhv_bloch_angles(sim):
|
|
597
|
+
z = sim.bloch[2]
|
|
598
|
+
x = sim.bloch[0]
|
|
599
|
+
y = sim.bloch[1]
|
|
600
|
+
inclination = math.atan2(math.sqrt(x**2 + y**2), z)
|
|
601
|
+
azimuth = math.atan2(y, x)
|
|
602
|
+
return azimuth, inclination
|
|
603
|
+
|
|
546
604
|
@staticmethod
|
|
547
605
|
def _rotate_lhv_to_bloch(sim, delta_azimuth, delta_inclination):
|
|
548
|
-
# Apply rotation as "Azimuth, Inclination" (AI)
|
|
549
606
|
cosA = math.cos(delta_azimuth)
|
|
550
607
|
sinA = math.sin(delta_azimuth)
|
|
551
608
|
cosI = math.cos(delta_inclination / 2)
|
|
@@ -564,21 +621,21 @@ class QrackAceBackend:
|
|
|
564
621
|
if len(hq) == 1:
|
|
565
622
|
return
|
|
566
623
|
|
|
567
|
-
qb,
|
|
624
|
+
qb, _ = QrackAceBackend._get_qb_lhv_indices(hq)
|
|
568
625
|
|
|
569
626
|
if phase:
|
|
570
627
|
for q in qb:
|
|
571
628
|
b = hq[q]
|
|
572
629
|
self.sim[b[0]].h(b[1])
|
|
573
|
-
|
|
574
|
-
|
|
630
|
+
if lq in self._lhv:
|
|
631
|
+
self._lhv[lq].h()
|
|
575
632
|
|
|
576
633
|
if len(hq) == 5:
|
|
577
634
|
# RMS
|
|
578
635
|
p = [
|
|
579
636
|
self.sim[hq[0][0]].prob(hq[0][1]),
|
|
580
637
|
self.sim[hq[1][0]].prob(hq[1][1]),
|
|
581
|
-
hq[2].prob(),
|
|
638
|
+
self.sim[hq[2][0]].prob(hq[2][1]),
|
|
582
639
|
self.sim[hq[3][0]].prob(hq[3][1]),
|
|
583
640
|
self.sim[hq[4][0]].prob(hq[4][1]),
|
|
584
641
|
]
|
|
@@ -597,8 +654,8 @@ class QrackAceBackend:
|
|
|
597
654
|
eff_prob = (prms + (1 - qrms)) / 2
|
|
598
655
|
result = (
|
|
599
656
|
(random.random() < 0.5)
|
|
600
|
-
if (eff_prob - 0.5)
|
|
601
|
-
else (eff_prob
|
|
657
|
+
if abs(eff_prob - 0.5) <= self._epsilon
|
|
658
|
+
else (eff_prob >= 0.5)
|
|
602
659
|
)
|
|
603
660
|
syndrome = (
|
|
604
661
|
[1 - p[0], 1 - p[1], 1 - p[2], 1 - p[3], 1 - p[4]]
|
|
@@ -607,91 +664,91 @@ class QrackAceBackend:
|
|
|
607
664
|
)
|
|
608
665
|
for q in range(5):
|
|
609
666
|
if syndrome[q] > (0.5 + self._epsilon):
|
|
610
|
-
|
|
611
|
-
hq[q].x()
|
|
612
|
-
else:
|
|
613
|
-
self.sim[hq[q][0]].x(hq[q][1])
|
|
667
|
+
self.sim[hq[q][0]].x(hq[q][1])
|
|
614
668
|
|
|
615
669
|
if not skip_rotation:
|
|
616
670
|
a, i = [0, 0, 0, 0, 0], [0, 0, 0, 0, 0]
|
|
617
671
|
a[0], i[0] = self._get_bloch_angles(hq[0])
|
|
618
672
|
a[1], i[1] = self._get_bloch_angles(hq[1])
|
|
619
|
-
a[2], i[2] =
|
|
673
|
+
a[2], i[2] = self._get_bloch_angles(hq[2])
|
|
620
674
|
a[3], i[3] = self._get_bloch_angles(hq[3])
|
|
621
675
|
a[4], i[4] = self._get_bloch_angles(hq[4])
|
|
622
676
|
|
|
623
|
-
a_target =
|
|
624
|
-
i_target =
|
|
677
|
+
a_target = sum(a) / 5
|
|
678
|
+
i_target = sum(i) / 5
|
|
625
679
|
for x in range(5):
|
|
626
|
-
|
|
627
|
-
continue
|
|
628
|
-
a_target += a[x]
|
|
629
|
-
i_target += i[x]
|
|
630
|
-
|
|
631
|
-
a_target /= 5
|
|
632
|
-
i_target /= 5
|
|
633
|
-
for x in range(5):
|
|
634
|
-
if x == 2:
|
|
635
|
-
QrackAceBackend._rotate_lhv_to_bloch(
|
|
636
|
-
hq[x], a_target - a[x], i_target - i[x]
|
|
637
|
-
)
|
|
638
|
-
else:
|
|
639
|
-
self._rotate_to_bloch(hq[x], a_target - a[x], i_target - i[x])
|
|
680
|
+
self._rotate_to_bloch(hq[x], a_target - a[x], i_target - i[x])
|
|
640
681
|
|
|
641
682
|
else:
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
(
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
else:
|
|
683
|
+
lhv = self._lhv.get(lq)
|
|
684
|
+
if lhv is None:
|
|
685
|
+
# RMS
|
|
686
|
+
p = [
|
|
687
|
+
self.sim[hq[0][0]].prob(hq[0][1]),
|
|
688
|
+
self.sim[hq[1][0]].prob(hq[1][1]),
|
|
689
|
+
self.sim[hq[2][0]].prob(hq[2][1]),
|
|
690
|
+
]
|
|
691
|
+
# Balancing suggestion from Elara (the custom OpenAI GPT)
|
|
692
|
+
prms = math.sqrt((p[0] ** 2 + p[1] ** 2 + p[2] ** 2) / 3)
|
|
693
|
+
qrms = math.sqrt(((1 - p[0]) ** 2 + (1 - p[1]) ** 2 + (1 - p[2]) ** 2) / 3)
|
|
694
|
+
eff_prob = (prms + (1 - qrms)) / 2
|
|
695
|
+
result = (
|
|
696
|
+
(random.random() < 0.5)
|
|
697
|
+
if abs(eff_prob - 0.5) <= self._epsilon
|
|
698
|
+
else (eff_prob >= 0.5)
|
|
699
|
+
)
|
|
700
|
+
syndrome = [1 - p[0], 1 - p[1], 1 - p[2]] if result else [p[0], p[1], p[2]]
|
|
701
|
+
for q in range(3):
|
|
702
|
+
if syndrome[q] > (0.5 + self._epsilon):
|
|
663
703
|
self.sim[hq[q][0]].x(hq[q][1])
|
|
704
|
+
else:
|
|
705
|
+
# Weighted 4-source vote: slot0, slot1, slot2 (real qubits)
|
|
706
|
+
# plus lhv (continuous, non-collapsing proxy). Weights sum
|
|
707
|
+
# to an odd total (QrackAceBackend._LHV_VOTE_WEIGHTS), so
|
|
708
|
+
# the underlying hard-vote tally is always tie-free, while
|
|
709
|
+
# the RMS formula itself generalizes the existing unweighted
|
|
710
|
+
# one (and reduces to it exactly when all weights are equal).
|
|
711
|
+
p = [
|
|
712
|
+
self.sim[hq[0][0]].prob(hq[0][1]),
|
|
713
|
+
self.sim[hq[1][0]].prob(hq[1][1]),
|
|
714
|
+
self.sim[hq[2][0]].prob(hq[2][1]),
|
|
715
|
+
lhv.prob(),
|
|
716
|
+
]
|
|
717
|
+
w = QrackAceBackend._LHV_VOTE_WEIGHTS
|
|
718
|
+
sw = sum(w)
|
|
719
|
+
prms = math.sqrt(sum(wi * pi**2 for wi, pi in zip(w, p)) / sw)
|
|
720
|
+
qrms = math.sqrt(sum(wi * (1 - pi) ** 2 for wi, pi in zip(w, p)) / sw)
|
|
721
|
+
eff_prob = (prms + (1 - qrms)) / 2
|
|
722
|
+
result = (
|
|
723
|
+
(random.random() < 0.5)
|
|
724
|
+
if abs(eff_prob - 0.5) <= self._epsilon
|
|
725
|
+
else (eff_prob >= 0.5)
|
|
726
|
+
)
|
|
727
|
+
syndrome = [1 - x for x in p] if result else list(p)
|
|
728
|
+
for q in range(3):
|
|
729
|
+
if syndrome[q] > (0.5 + self._epsilon):
|
|
730
|
+
self.sim[hq[q][0]].x(hq[q][1])
|
|
731
|
+
# The LHV proxy is never hard-collapsed via x(); only ever
|
|
732
|
+
# updated by continuous rotation, preserving the property
|
|
733
|
+
# that makes it useful as a non-collapsing stabilizing term.
|
|
664
734
|
|
|
665
735
|
if not skip_rotation:
|
|
666
736
|
a, i = [0, 0, 0], [0, 0, 0]
|
|
667
737
|
a[0], i[0] = self._get_bloch_angles(hq[0])
|
|
668
738
|
a[1], i[1] = self._get_bloch_angles(hq[1])
|
|
669
|
-
a[2], i[2] =
|
|
670
|
-
|
|
671
|
-
a_target = 0
|
|
672
|
-
i_target = 0
|
|
673
|
-
for x in range(3):
|
|
674
|
-
if x == 2:
|
|
675
|
-
continue
|
|
676
|
-
a_target += a[x]
|
|
677
|
-
i_target += i[x]
|
|
739
|
+
a[2], i[2] = self._get_bloch_angles(hq[2])
|
|
678
740
|
|
|
679
|
-
a_target
|
|
680
|
-
i_target
|
|
741
|
+
a_target = sum(a) / 3
|
|
742
|
+
i_target = sum(i) / 3
|
|
681
743
|
for x in range(3):
|
|
682
|
-
|
|
683
|
-
QrackAceBackend._rotate_lhv_to_bloch(
|
|
684
|
-
hq[x], a_target - a[x], i_target - i[x]
|
|
685
|
-
)
|
|
686
|
-
else:
|
|
687
|
-
self._rotate_to_bloch(hq[x], a_target - a[x], i_target - i[x])
|
|
744
|
+
self._rotate_to_bloch(hq[x], a_target - a[x], i_target - i[x])
|
|
688
745
|
|
|
689
746
|
if phase:
|
|
690
747
|
for q in qb:
|
|
691
748
|
b = hq[q]
|
|
692
749
|
self.sim[b[0]].h(b[1])
|
|
693
|
-
|
|
694
|
-
|
|
750
|
+
if lq in self._lhv:
|
|
751
|
+
self._lhv[lq].h()
|
|
695
752
|
|
|
696
753
|
def apply_magnetic_bias(self, q, b):
|
|
697
754
|
if b == 0:
|
|
@@ -699,22 +756,13 @@ class QrackAceBackend:
|
|
|
699
756
|
b = math.exp(b)
|
|
700
757
|
for x in q:
|
|
701
758
|
hq = self._unpack(x)
|
|
702
|
-
for
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
math.atan(math.tan(i) * b) - i,
|
|
710
|
-
)
|
|
711
|
-
else:
|
|
712
|
-
a, i = self._get_bloch_angles(h)
|
|
713
|
-
self._rotate_to_bloch(
|
|
714
|
-
h,
|
|
715
|
-
math.atan(math.tan(a) * b) - a,
|
|
716
|
-
math.atan(math.tan(i) * b) - i,
|
|
717
|
-
)
|
|
759
|
+
for h in hq:
|
|
760
|
+
a, i = self._get_bloch_angles(h)
|
|
761
|
+
self._rotate_to_bloch(
|
|
762
|
+
h,
|
|
763
|
+
math.atan(math.tan(a) * b) - a,
|
|
764
|
+
math.atan(math.tan(i) * b) - i,
|
|
765
|
+
)
|
|
718
766
|
|
|
719
767
|
def u(self, lq, th, ph, lm):
|
|
720
768
|
hq = self._unpack(lq)
|
|
@@ -723,14 +771,15 @@ class QrackAceBackend:
|
|
|
723
771
|
self.sim[b[0]].u(b[1], th, ph, lm)
|
|
724
772
|
return
|
|
725
773
|
|
|
726
|
-
qb,
|
|
774
|
+
qb, _ = QrackAceBackend._get_qb_lhv_indices(hq)
|
|
727
775
|
|
|
728
776
|
for q in qb:
|
|
729
777
|
b = hq[q]
|
|
730
778
|
self.sim[b[0]].u(b[1], th, ph, lm)
|
|
731
779
|
|
|
732
|
-
|
|
733
|
-
|
|
780
|
+
lhv = self._lhv.get(lq)
|
|
781
|
+
if lhv is not None:
|
|
782
|
+
lhv.u(th, ph, lm)
|
|
734
783
|
|
|
735
784
|
# Correction deferred to next 2-qubit gate (_cpauli calls _correct)
|
|
736
785
|
|
|
@@ -741,19 +790,20 @@ class QrackAceBackend:
|
|
|
741
790
|
self.sim[b[0]].r(p, th, b[1])
|
|
742
791
|
return
|
|
743
792
|
|
|
744
|
-
qb,
|
|
793
|
+
qb, _ = QrackAceBackend._get_qb_lhv_indices(hq)
|
|
745
794
|
|
|
746
795
|
for q in qb:
|
|
747
796
|
b = hq[q]
|
|
748
797
|
self.sim[b[0]].r(p, th, b[1])
|
|
749
798
|
|
|
750
|
-
|
|
751
|
-
if
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
799
|
+
lhv = self._lhv.get(lq)
|
|
800
|
+
if lhv is not None:
|
|
801
|
+
if p == Pauli.PauliX:
|
|
802
|
+
lhv.rx(th)
|
|
803
|
+
elif p == Pauli.PauliY:
|
|
804
|
+
lhv.ry(th)
|
|
805
|
+
elif p == Pauli.PauliZ:
|
|
806
|
+
lhv.rz(th)
|
|
757
807
|
|
|
758
808
|
# Correction deferred to next 2-qubit gate (_cpauli calls _correct)
|
|
759
809
|
|
|
@@ -766,14 +816,15 @@ class QrackAceBackend:
|
|
|
766
816
|
|
|
767
817
|
self._correct(lq)
|
|
768
818
|
|
|
769
|
-
qb,
|
|
819
|
+
qb, _ = QrackAceBackend._get_qb_lhv_indices(hq)
|
|
770
820
|
|
|
771
821
|
for q in qb:
|
|
772
822
|
b = hq[q]
|
|
773
823
|
self.sim[b[0]].h(b[1])
|
|
774
824
|
|
|
775
|
-
|
|
776
|
-
|
|
825
|
+
lhv = self._lhv.get(lq)
|
|
826
|
+
if lhv is not None:
|
|
827
|
+
lhv.h()
|
|
777
828
|
|
|
778
829
|
# Correction deferred to next 2-qubit gate (_cpauli calls _correct)
|
|
779
830
|
|
|
@@ -784,14 +835,15 @@ class QrackAceBackend:
|
|
|
784
835
|
self.sim[b[0]].s(b[1])
|
|
785
836
|
return
|
|
786
837
|
|
|
787
|
-
qb,
|
|
838
|
+
qb, _ = QrackAceBackend._get_qb_lhv_indices(hq)
|
|
788
839
|
|
|
789
840
|
for q in qb:
|
|
790
841
|
b = hq[q]
|
|
791
842
|
self.sim[b[0]].s(b[1])
|
|
792
843
|
|
|
793
|
-
|
|
794
|
-
|
|
844
|
+
lhv = self._lhv.get(lq)
|
|
845
|
+
if lhv is not None:
|
|
846
|
+
lhv.s()
|
|
795
847
|
|
|
796
848
|
def adjs(self, lq):
|
|
797
849
|
hq = self._unpack(lq)
|
|
@@ -800,14 +852,15 @@ class QrackAceBackend:
|
|
|
800
852
|
self.sim[b[0]].adjs(b[1])
|
|
801
853
|
return
|
|
802
854
|
|
|
803
|
-
qb,
|
|
855
|
+
qb, _ = QrackAceBackend._get_qb_lhv_indices(hq)
|
|
804
856
|
|
|
805
857
|
for q in qb:
|
|
806
858
|
b = hq[q]
|
|
807
859
|
self.sim[b[0]].adjs(b[1])
|
|
808
860
|
|
|
809
|
-
|
|
810
|
-
|
|
861
|
+
lhv = self._lhv.get(lq)
|
|
862
|
+
if lhv is not None:
|
|
863
|
+
lhv.adjs()
|
|
811
864
|
|
|
812
865
|
def x(self, lq):
|
|
813
866
|
hq = self._unpack(lq)
|
|
@@ -816,14 +869,15 @@ class QrackAceBackend:
|
|
|
816
869
|
self.sim[b[0]].x(b[1])
|
|
817
870
|
return
|
|
818
871
|
|
|
819
|
-
qb,
|
|
872
|
+
qb, _ = QrackAceBackend._get_qb_lhv_indices(hq)
|
|
820
873
|
|
|
821
874
|
for q in qb:
|
|
822
875
|
b = hq[q]
|
|
823
876
|
self.sim[b[0]].x(b[1])
|
|
824
877
|
|
|
825
|
-
|
|
826
|
-
|
|
878
|
+
lhv = self._lhv.get(lq)
|
|
879
|
+
if lhv is not None:
|
|
880
|
+
lhv.x()
|
|
827
881
|
|
|
828
882
|
def y(self, lq):
|
|
829
883
|
hq = self._unpack(lq)
|
|
@@ -832,14 +886,15 @@ class QrackAceBackend:
|
|
|
832
886
|
self.sim[b[0]].y(b[1])
|
|
833
887
|
return
|
|
834
888
|
|
|
835
|
-
qb,
|
|
889
|
+
qb, _ = QrackAceBackend._get_qb_lhv_indices(hq)
|
|
836
890
|
|
|
837
891
|
for q in qb:
|
|
838
892
|
b = hq[q]
|
|
839
893
|
self.sim[b[0]].y(b[1])
|
|
840
894
|
|
|
841
|
-
|
|
842
|
-
|
|
895
|
+
lhv = self._lhv.get(lq)
|
|
896
|
+
if lhv is not None:
|
|
897
|
+
lhv.y()
|
|
843
898
|
|
|
844
899
|
def z(self, lq):
|
|
845
900
|
hq = self._unpack(lq)
|
|
@@ -848,14 +903,15 @@ class QrackAceBackend:
|
|
|
848
903
|
self.sim[b[0]].z(b[1])
|
|
849
904
|
return
|
|
850
905
|
|
|
851
|
-
qb,
|
|
906
|
+
qb, _ = QrackAceBackend._get_qb_lhv_indices(hq)
|
|
852
907
|
|
|
853
908
|
for q in qb:
|
|
854
909
|
b = hq[q]
|
|
855
910
|
self.sim[b[0]].z(b[1])
|
|
856
911
|
|
|
857
|
-
|
|
858
|
-
|
|
912
|
+
lhv = self._lhv.get(lq)
|
|
913
|
+
if lhv is not None:
|
|
914
|
+
lhv.z()
|
|
859
915
|
|
|
860
916
|
def t(self, lq):
|
|
861
917
|
hq = self._unpack(lq)
|
|
@@ -864,14 +920,15 @@ class QrackAceBackend:
|
|
|
864
920
|
self.sim[b[0]].t(b[1])
|
|
865
921
|
return
|
|
866
922
|
|
|
867
|
-
qb,
|
|
923
|
+
qb, _ = QrackAceBackend._get_qb_lhv_indices(hq)
|
|
868
924
|
|
|
869
925
|
for q in qb:
|
|
870
926
|
b = hq[q]
|
|
871
927
|
self.sim[b[0]].t(b[1])
|
|
872
928
|
|
|
873
|
-
|
|
874
|
-
|
|
929
|
+
lhv = self._lhv.get(lq)
|
|
930
|
+
if lhv is not None:
|
|
931
|
+
lhv.t()
|
|
875
932
|
|
|
876
933
|
def adjt(self, lq):
|
|
877
934
|
hq = self._unpack(lq)
|
|
@@ -880,14 +937,15 @@ class QrackAceBackend:
|
|
|
880
937
|
self.sim[b[0]].adjt(b[1])
|
|
881
938
|
return
|
|
882
939
|
|
|
883
|
-
qb,
|
|
940
|
+
qb, _ = QrackAceBackend._get_qb_lhv_indices(hq)
|
|
884
941
|
|
|
885
942
|
for q in qb:
|
|
886
943
|
b = hq[q]
|
|
887
944
|
self.sim[b[0]].adjt(b[1])
|
|
888
945
|
|
|
889
|
-
|
|
890
|
-
|
|
946
|
+
lhv = self._lhv.get(lq)
|
|
947
|
+
if lhv is not None:
|
|
948
|
+
lhv.adjt()
|
|
891
949
|
|
|
892
950
|
def _get_gate(self, pauli, anti, sim_id):
|
|
893
951
|
gate = None
|
|
@@ -927,15 +985,11 @@ class QrackAceBackend:
|
|
|
927
985
|
|
|
928
986
|
return connected, boundary
|
|
929
987
|
|
|
930
|
-
def _apply_coupling(self, pauli, anti, qb1,
|
|
988
|
+
def _apply_coupling(self, pauli, anti, qb1, hq1, qb2, hq2, lq1_lr):
|
|
931
989
|
for q1 in qb1:
|
|
932
|
-
if q1 == lhv1:
|
|
933
|
-
continue
|
|
934
990
|
b1 = hq1[q1]
|
|
935
991
|
gate_fn, shadow_fn = self._get_gate(pauli, anti, b1[0])
|
|
936
992
|
for q2 in qb2:
|
|
937
|
-
if q2 == lhv2:
|
|
938
|
-
continue
|
|
939
993
|
b2 = hq2[q2]
|
|
940
994
|
if b1[0] == b2[0]:
|
|
941
995
|
gate_fn([b1[1]], b2[1])
|
|
@@ -956,18 +1010,15 @@ class QrackAceBackend:
|
|
|
956
1010
|
|
|
957
1011
|
self._correct(lq1)
|
|
958
1012
|
|
|
959
|
-
qb1,
|
|
960
|
-
qb2,
|
|
961
|
-
# Apply cross coupling on
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
pauli,
|
|
969
|
-
anti,
|
|
970
|
-
)
|
|
1013
|
+
qb1, _ = QrackAceBackend._get_qb_lhv_indices(hq1)
|
|
1014
|
+
qb2, _ = QrackAceBackend._get_qb_lhv_indices(hq2)
|
|
1015
|
+
# Apply cross coupling on every qubit, including former-LHV boundary
|
|
1016
|
+
# qubits, which now live as real qubits in the shared boundary sim.
|
|
1017
|
+
self._apply_coupling(pauli, anti, qb1, hq1, qb2, hq2, lq1_lr)
|
|
1018
|
+
|
|
1019
|
+
if lq2 in self._lhv:
|
|
1020
|
+
ctrl_prob = self.sim[hq1[0][0]].prob(hq1[0][1])
|
|
1021
|
+
_cpauli_lhv(ctrl_prob, self._lhv[lq2], pauli, anti)
|
|
971
1022
|
|
|
972
1023
|
self._correct(lq1, True)
|
|
973
1024
|
if pauli != Pauli.PauliZ:
|
|
@@ -1064,7 +1115,7 @@ class QrackAceBackend:
|
|
|
1064
1115
|
p = [
|
|
1065
1116
|
self.sim[hq[0][0]].prob(hq[0][1]),
|
|
1066
1117
|
self.sim[hq[1][0]].prob(hq[1][1]),
|
|
1067
|
-
hq[2].prob(),
|
|
1118
|
+
self.sim[hq[2][0]].prob(hq[2][1]),
|
|
1068
1119
|
self.sim[hq[3][0]].prob(hq[3][1]),
|
|
1069
1120
|
self.sim[hq[4][0]].prob(hq[4][1]),
|
|
1070
1121
|
]
|
|
@@ -1081,15 +1132,28 @@ class QrackAceBackend:
|
|
|
1081
1132
|
/ 7
|
|
1082
1133
|
)
|
|
1083
1134
|
else:
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
|
|
1135
|
+
lhv = self._lhv.get(lq)
|
|
1136
|
+
if lhv is None:
|
|
1137
|
+
# RMS
|
|
1138
|
+
p = [
|
|
1139
|
+
self.sim[hq[0][0]].prob(hq[0][1]),
|
|
1140
|
+
self.sim[hq[1][0]].prob(hq[1][1]),
|
|
1141
|
+
self.sim[hq[2][0]].prob(hq[2][1]),
|
|
1142
|
+
]
|
|
1143
|
+
# Balancing suggestion from Elara (the custom OpenAI GPT)
|
|
1144
|
+
prms = math.sqrt((p[0] ** 2 + p[1] ** 2 + p[2] ** 2) / 3)
|
|
1145
|
+
qrms = math.sqrt(((1 - p[0]) ** 2 + (1 - p[1]) ** 2 + (1 - p[2]) ** 2) / 3)
|
|
1146
|
+
else:
|
|
1147
|
+
p = [
|
|
1148
|
+
self.sim[hq[0][0]].prob(hq[0][1]),
|
|
1149
|
+
self.sim[hq[1][0]].prob(hq[1][1]),
|
|
1150
|
+
self.sim[hq[2][0]].prob(hq[2][1]),
|
|
1151
|
+
lhv.prob(),
|
|
1152
|
+
]
|
|
1153
|
+
w = QrackAceBackend._LHV_VOTE_WEIGHTS
|
|
1154
|
+
sw = sum(w)
|
|
1155
|
+
prms = math.sqrt(sum(wi * pi**2 for wi, pi in zip(w, p)) / sw)
|
|
1156
|
+
qrms = math.sqrt(sum(wi * (1 - pi) ** 2 for wi, pi in zip(w, p)) / sw)
|
|
1093
1157
|
|
|
1094
1158
|
return (prms + (1 - qrms)) / 2
|
|
1095
1159
|
|
|
@@ -1102,7 +1166,7 @@ class QrackAceBackend:
|
|
|
1102
1166
|
p = self.prob(lq)
|
|
1103
1167
|
result = ((p + self._epsilon) >= 1) or (random.random() < p)
|
|
1104
1168
|
|
|
1105
|
-
qb,
|
|
1169
|
+
qb, _ = QrackAceBackend._get_qb_lhv_indices(hq)
|
|
1106
1170
|
|
|
1107
1171
|
for q in qb:
|
|
1108
1172
|
b = hq[q]
|
|
@@ -1113,10 +1177,11 @@ class QrackAceBackend:
|
|
|
1113
1177
|
else:
|
|
1114
1178
|
self.sim[b[0]].force_m(b[1], result)
|
|
1115
1179
|
|
|
1116
|
-
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
-
|
|
1180
|
+
lhv = self._lhv.get(lq)
|
|
1181
|
+
if lhv is not None:
|
|
1182
|
+
lhv.reset()
|
|
1183
|
+
if result:
|
|
1184
|
+
lhv.x()
|
|
1120
1185
|
|
|
1121
1186
|
return result
|
|
1122
1187
|
|
|
@@ -1128,7 +1193,7 @@ class QrackAceBackend:
|
|
|
1128
1193
|
|
|
1129
1194
|
self._correct(lq)
|
|
1130
1195
|
|
|
1131
|
-
qb,
|
|
1196
|
+
qb, _ = QrackAceBackend._get_qb_lhv_indices(hq)
|
|
1132
1197
|
|
|
1133
1198
|
for q in qb:
|
|
1134
1199
|
b = hq[q]
|
|
@@ -1139,10 +1204,11 @@ class QrackAceBackend:
|
|
|
1139
1204
|
else:
|
|
1140
1205
|
self.sim[b[0]].force_m(b[1], result)
|
|
1141
1206
|
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
|
|
1207
|
+
lhv = self._lhv.get(lq)
|
|
1208
|
+
if lhv is not None:
|
|
1209
|
+
lhv.reset()
|
|
1210
|
+
if result:
|
|
1211
|
+
lhv.x()
|
|
1146
1212
|
|
|
1147
1213
|
return result
|
|
1148
1214
|
|
|
@@ -1509,25 +1575,22 @@ class QrackAceBackend:
|
|
|
1509
1575
|
return self._coupling_map
|
|
1510
1576
|
|
|
1511
1577
|
coupling_map = set()
|
|
1512
|
-
|
|
1513
|
-
# i.e. the column count); self._col_length is the number of rows.
|
|
1514
|
-
num_rows, num_cols = self._col_length, self._row_length
|
|
1578
|
+
rows, cols = self._row_length, self._col_length
|
|
1515
1579
|
|
|
1516
|
-
#
|
|
1580
|
+
# Map each column index to its full list of logical qubit indices
|
|
1517
1581
|
def logical_index(row, col):
|
|
1518
|
-
return row *
|
|
1582
|
+
return row * cols + col
|
|
1519
1583
|
|
|
1520
|
-
for
|
|
1521
|
-
|
|
1522
|
-
for
|
|
1523
|
-
|
|
1584
|
+
for col in range(cols):
|
|
1585
|
+
connected_cols, _ = self._get_connected(col, False)
|
|
1586
|
+
for row in range(rows):
|
|
1587
|
+
connected_rows, _ = self._get_connected(row, False)
|
|
1524
1588
|
a = logical_index(row, col)
|
|
1525
|
-
for
|
|
1526
|
-
for
|
|
1589
|
+
for c in connected_cols:
|
|
1590
|
+
for r in connected_rows:
|
|
1527
1591
|
b = logical_index(r, c)
|
|
1528
1592
|
if a != b:
|
|
1529
1593
|
coupling_map.add((a, b))
|
|
1530
|
-
coupling_map.add((b, a))
|
|
1531
1594
|
|
|
1532
1595
|
self._coupling_map = sorted(coupling_map)
|
|
1533
1596
|
|
|
@@ -1541,11 +1604,9 @@ class QrackAceBackend:
|
|
|
1541
1604
|
)
|
|
1542
1605
|
noise_model = NoiseModel()
|
|
1543
1606
|
|
|
1607
|
+
# Single-qubit depolarizing only on boundary qubits
|
|
1544
1608
|
boundary_qubits = set()
|
|
1545
1609
|
for a, b in self.get_logical_coupling_map():
|
|
1546
|
-
if a > b:
|
|
1547
|
-
#Skip duplicates
|
|
1548
|
-
continue
|
|
1549
1610
|
col_a = a % self._row_length
|
|
1550
1611
|
col_b = b % self._row_length
|
|
1551
1612
|
is_long_a = self._is_col_long_range[col_a]
|
|
@@ -1556,6 +1617,12 @@ class QrackAceBackend:
|
|
|
1556
1617
|
if not is_long_b:
|
|
1557
1618
|
boundary_qubits.add(b)
|
|
1558
1619
|
|
|
1620
|
+
for q in boundary_qubits:
|
|
1621
|
+
for gate in ["u", "u1", "u2", "u3", "h", "x", "y", "z",
|
|
1622
|
+
"s", "sdg", "t", "tdg", "rx", "ry", "rz"]:
|
|
1623
|
+
noise_model.add_quantum_error(
|
|
1624
|
+
depolarizing_error(x, 1), gate, [q])
|
|
1625
|
+
|
|
1559
1626
|
# Two-qubit depolarizing on boundary-crossing and boundary-adjacent gates
|
|
1560
1627
|
for a, b in self.get_logical_coupling_map():
|
|
1561
1628
|
col_a = a % self._row_length
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{pyqrack_cuda_complex128-2.2.2 → pyqrack_cuda_complex128-2.2.4}/pyqrack/neuron_activation_fn.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{pyqrack_cuda_complex128-2.2.2 → pyqrack_cuda_complex128-2.2.4}/pyqrack/qrack_neuron_torch_layer.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{pyqrack_cuda_complex128-2.2.2 → pyqrack_cuda_complex128-2.2.4}/pyqrack/qrack_system/__init__.py
RENAMED
|
File without changes
|
{pyqrack_cuda_complex128-2.2.2 → pyqrack_cuda_complex128-2.2.4}/pyqrack/qrack_system/qrack_system.py
RENAMED
|
File without changes
|
{pyqrack_cuda_complex128-2.2.2 → pyqrack_cuda_complex128-2.2.4}/pyqrack/quimb_circuit_type.py
RENAMED
|
File without changes
|
|
File without changes
|
{pyqrack_cuda_complex128-2.2.2 → pyqrack_cuda_complex128-2.2.4}/pyqrack/stats/load_quantized_data.py
RENAMED
|
File without changes
|
{pyqrack_cuda_complex128-2.2.2 → pyqrack_cuda_complex128-2.2.4}/pyqrack/stats/quantize_by_range.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|