pyqrack-cpu-complex128 2.26.6__tar.gz → 2.27.0__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_cpu_complex128-2.26.6/pyqrack_cpu_complex128.egg-info → pyqrack_cpu_complex128-2.27.0}/PKG-INFO +1 -1
- {pyqrack_cpu_complex128-2.26.6 → pyqrack_cpu_complex128-2.27.0}/pyqrack/qrack_ace_backend.py +237 -53
- {pyqrack_cpu_complex128-2.26.6 → pyqrack_cpu_complex128-2.27.0/pyqrack_cpu_complex128.egg-info}/PKG-INFO +1 -1
- {pyqrack_cpu_complex128-2.26.6 → pyqrack_cpu_complex128-2.27.0}/setup.py +1 -1
- {pyqrack_cpu_complex128-2.26.6 → pyqrack_cpu_complex128-2.27.0}/LICENSE +0 -0
- {pyqrack_cpu_complex128-2.26.6 → pyqrack_cpu_complex128-2.27.0}/MANIFEST.in +0 -0
- {pyqrack_cpu_complex128-2.26.6 → pyqrack_cpu_complex128-2.27.0}/Makefile +0 -0
- {pyqrack_cpu_complex128-2.26.6 → pyqrack_cpu_complex128-2.27.0}/README.md +0 -0
- {pyqrack_cpu_complex128-2.26.6 → pyqrack_cpu_complex128-2.27.0}/pyproject.toml +0 -0
- {pyqrack_cpu_complex128-2.26.6 → pyqrack_cpu_complex128-2.27.0}/pyqrack/__init__.py +0 -0
- {pyqrack_cpu_complex128-2.26.6 → pyqrack_cpu_complex128-2.27.0}/pyqrack/neuron_activation_fn.py +0 -0
- {pyqrack_cpu_complex128-2.26.6 → pyqrack_cpu_complex128-2.27.0}/pyqrack/pauli.py +0 -0
- {pyqrack_cpu_complex128-2.26.6 → pyqrack_cpu_complex128-2.27.0}/pyqrack/qrack_circuit.py +0 -0
- {pyqrack_cpu_complex128-2.26.6 → pyqrack_cpu_complex128-2.27.0}/pyqrack/qrack_near_clifford_qec_backend.py +0 -0
- {pyqrack_cpu_complex128-2.26.6 → pyqrack_cpu_complex128-2.27.0}/pyqrack/qrack_neuron.py +0 -0
- {pyqrack_cpu_complex128-2.26.6 → pyqrack_cpu_complex128-2.27.0}/pyqrack/qrack_neuron_torch_layer.py +0 -0
- {pyqrack_cpu_complex128-2.26.6 → pyqrack_cpu_complex128-2.27.0}/pyqrack/qrack_simulator.py +0 -0
- {pyqrack_cpu_complex128-2.26.6 → pyqrack_cpu_complex128-2.27.0}/pyqrack/qrack_stabilizer.py +0 -0
- {pyqrack_cpu_complex128-2.26.6 → pyqrack_cpu_complex128-2.27.0}/pyqrack/qrack_system/__init__.py +0 -0
- {pyqrack_cpu_complex128-2.26.6 → pyqrack_cpu_complex128-2.27.0}/pyqrack/qrack_system/qrack_system.py +0 -0
- {pyqrack_cpu_complex128-2.26.6 → pyqrack_cpu_complex128-2.27.0}/pyqrack/quimb_circuit_type.py +0 -0
- {pyqrack_cpu_complex128-2.26.6 → pyqrack_cpu_complex128-2.27.0}/pyqrack/stats/__init__.py +0 -0
- {pyqrack_cpu_complex128-2.26.6 → pyqrack_cpu_complex128-2.27.0}/pyqrack/stats/load_quantized_data.py +0 -0
- {pyqrack_cpu_complex128-2.26.6 → pyqrack_cpu_complex128-2.27.0}/pyqrack/stats/quantize_by_range.py +0 -0
- {pyqrack_cpu_complex128-2.26.6 → pyqrack_cpu_complex128-2.27.0}/pyqrack_cpu_complex128.egg-info/SOURCES.txt +0 -0
- {pyqrack_cpu_complex128-2.26.6 → pyqrack_cpu_complex128-2.27.0}/pyqrack_cpu_complex128.egg-info/dependency_links.txt +0 -0
- {pyqrack_cpu_complex128-2.26.6 → pyqrack_cpu_complex128-2.27.0}/pyqrack_cpu_complex128.egg-info/not-zip-safe +0 -0
- {pyqrack_cpu_complex128-2.26.6 → pyqrack_cpu_complex128-2.27.0}/pyqrack_cpu_complex128.egg-info/requires.txt +0 -0
- {pyqrack_cpu_complex128-2.26.6 → pyqrack_cpu_complex128-2.27.0}/pyqrack_cpu_complex128.egg-info/top_level.txt +0 -0
- {pyqrack_cpu_complex128-2.26.6 → pyqrack_cpu_complex128-2.27.0}/setup.cfg +0 -0
{pyqrack_cpu_complex128-2.26.6 → pyqrack_cpu_complex128-2.27.0}/pyqrack/qrack_ace_backend.py
RENAMED
|
@@ -252,6 +252,7 @@ class QrackAceBackend:
|
|
|
252
252
|
is_1d_chain=False,
|
|
253
253
|
is_error_detection=True,
|
|
254
254
|
is_boundary_repetition_code=False,
|
|
255
|
+
use_crossbars=True,
|
|
255
256
|
to_clone=None,
|
|
256
257
|
):
|
|
257
258
|
if to_clone:
|
|
@@ -263,6 +264,7 @@ class QrackAceBackend:
|
|
|
263
264
|
is_1d_chain = to_clone.is_1d_chain
|
|
264
265
|
is_error_detection = to_clone.is_error_detection
|
|
265
266
|
is_boundary_repetition_code = to_clone.is_boundary_repetition_code
|
|
267
|
+
use_crossbars = to_clone.use_crossbars
|
|
266
268
|
if qubit_count < 0:
|
|
267
269
|
qubit_count = 0
|
|
268
270
|
if long_range_columns < 0:
|
|
@@ -275,6 +277,19 @@ class QrackAceBackend:
|
|
|
275
277
|
self.is_transpose = is_transpose
|
|
276
278
|
self.is_torus = is_torus
|
|
277
279
|
self.is_error_detection = is_error_detection
|
|
280
|
+
# Opt-in revival of the shared boundary "crossbar" QrackSimulator
|
|
281
|
+
# (see the note just below, at the qubit-allocation loop) that was
|
|
282
|
+
# previously removed outright for not scaling with patch count.
|
|
283
|
+
# Off by default -- same topology/behavior as before this option
|
|
284
|
+
# existed. On, it gives every boundary qubit one extra REAL replica
|
|
285
|
+
# in a single simulator shared by every boundary site in the whole
|
|
286
|
+
# grid, which is itself an un-scalable idea (that one simulator's
|
|
287
|
+
# qubit count grows with total boundary-qubit count, not with
|
|
288
|
+
# patch count) -- but for a small number of patches (e.g. 3-4,
|
|
289
|
+
# fitting on one GPU) it was measured to add real, genuine
|
|
290
|
+
# connectivity value on top of the classical LHV proxy, so it's
|
|
291
|
+
# kept available for exactly that regime rather than discarded.
|
|
292
|
+
self.use_crossbars = use_crossbars
|
|
278
293
|
self.is_boundary_repetition_code = is_boundary_repetition_code
|
|
279
294
|
|
|
280
295
|
if Qrack.fppow < 5:
|
|
@@ -334,19 +349,26 @@ class QrackAceBackend:
|
|
|
334
349
|
self._is_row_long_range[-1] = False
|
|
335
350
|
sim_count = col_patch_count * row_patch_count
|
|
336
351
|
|
|
337
|
-
# The shared boundary "crossbar" QrackSimulator
|
|
338
|
-
#
|
|
339
|
-
# alike) one extra real replica in a single
|
|
340
|
-
# boundary qubits, trusting that
|
|
341
|
-
# (set_sdrp) to automatically
|
|
342
|
-
#
|
|
343
|
-
# intersection" logic.
|
|
344
|
-
#
|
|
345
|
-
#
|
|
346
|
-
#
|
|
347
|
-
#
|
|
348
|
-
#
|
|
349
|
-
#
|
|
352
|
+
# The shared boundary "crossbar" QrackSimulator, self.use_crossbars
|
|
353
|
+
# (see the constructor): every boundary site (row- and/or column-
|
|
354
|
+
# boundary alike) gets one extra real replica in a single
|
|
355
|
+
# simulator shared by ALL boundary qubits, trusting that
|
|
356
|
+
# simulator's own greedy elision (set_sdrp) to automatically
|
|
357
|
+
# factor apart whatever boundary sites turn out to be separable,
|
|
358
|
+
# rather than hand-coding "crossbar intersection" logic. Measured
|
|
359
|
+
# to add real connectivity value, but the single shared simulator
|
|
360
|
+
# grows with total boundary-qubit count rather than patch count,
|
|
361
|
+
# so it doesn't scale -- off by default, and worth turning on only
|
|
362
|
+
# for a handful of patches. Every boundary qubit ALSO still gets
|
|
363
|
+
# its classical LHVQubit proxy (self._lhv, below) regardless, same
|
|
364
|
+
# as when this option is off: with the crossbar on, the proxy
|
|
365
|
+
# drops to being only the last-resort tie-breaker _correct() falls
|
|
366
|
+
# back to when even the crossbar replica is itself ambiguous; with
|
|
367
|
+
# it off, the proxy is promoted to cover the crossbar's old
|
|
368
|
+
# tie-breaking role directly.
|
|
369
|
+
boundary_sim_id = sim_count
|
|
370
|
+
boundary_count = 0
|
|
371
|
+
|
|
350
372
|
self._qubits = []
|
|
351
373
|
self._lhv = {}
|
|
352
374
|
sim_counts = [0] * sim_count
|
|
@@ -362,6 +384,10 @@ class QrackAceBackend:
|
|
|
362
384
|
qubit.append((t_sim_id, sim_counts[t_sim_id]))
|
|
363
385
|
sim_counts[t_sim_id] += 1
|
|
364
386
|
|
|
387
|
+
if self.use_crossbars:
|
|
388
|
+
qubit.append((boundary_sim_id, boundary_count))
|
|
389
|
+
boundary_count += 1
|
|
390
|
+
|
|
365
391
|
if (not to_clone) or (tot_qubits in to_clone._lhv):
|
|
366
392
|
self._lhv[tot_qubits] = LHVQubit(
|
|
367
393
|
to_clone=(to_clone._lhv[tot_qubits] if to_clone else None)
|
|
@@ -384,6 +410,18 @@ class QrackAceBackend:
|
|
|
384
410
|
)
|
|
385
411
|
tot_qubits += 1
|
|
386
412
|
|
|
413
|
+
# The crossbar's size is fixed by how many boundary sites exist.
|
|
414
|
+
# When there are none at all (e.g. a grid small enough, relative
|
|
415
|
+
# to long_range_rows/columns, to be fully connected with no QEC
|
|
416
|
+
# boundary), we must NOT allocate a 0-qubit QrackSimulator for it
|
|
417
|
+
# -- sim_count/sim_counts simply stay exactly as they were,
|
|
418
|
+
# exactly mirroring how every other per-simulator allocation below
|
|
419
|
+
# already guards for "nothing to allocate."
|
|
420
|
+
has_boundary = self.use_crossbars and (boundary_count > 0)
|
|
421
|
+
if has_boundary:
|
|
422
|
+
sim_counts.append(boundary_count)
|
|
423
|
+
sim_count += 1
|
|
424
|
+
|
|
387
425
|
# Error-detection gadget (IBM-style detect-and-post-select, not
|
|
388
426
|
# correction): one shared ancilla per simulator -- one per patch,
|
|
389
427
|
# "a single ancilla per patch, overall" -- reused across every real
|
|
@@ -729,16 +767,19 @@ class QrackAceBackend:
|
|
|
729
767
|
|
|
730
768
|
@staticmethod
|
|
731
769
|
def _get_qb_lhv_indices(hq):
|
|
732
|
-
#
|
|
733
|
-
#
|
|
734
|
-
#
|
|
735
|
-
#
|
|
736
|
-
#
|
|
737
|
-
#
|
|
738
|
-
#
|
|
739
|
-
#
|
|
740
|
-
#
|
|
741
|
-
#
|
|
770
|
+
# Every entry of hq is an ordinary (sim_id, idx) tuple into a real
|
|
771
|
+
# physical replica: 1 for a bulk qubit; with use_crossbars=False
|
|
772
|
+
# (default), 2 for an edge-boundary qubit (home + adjacent-patch)
|
|
773
|
+
# or 4 for a corner-boundary qubit (home + adjacent-patch + 2
|
|
774
|
+
# diagonal-patch); with use_crossbars=True, 3 (home + adjacent-
|
|
775
|
+
# patch + shared crossbar) or 5 (home + adjacent-patch + shared
|
|
776
|
+
# crossbar + 2 diagonal-patch). None of them are virtual/LHV-
|
|
777
|
+
# backed slots -- the classical LHVQubit proxy (self._lhv) is
|
|
778
|
+
# tracked entirely separately from hq, not as one of its indices
|
|
779
|
+
# -- so qb is simply every index, in order, regardless of which
|
|
780
|
+
# of those counts applies. We keep this helper's name and
|
|
781
|
+
# signature for minimal call-site churn; "lhv" is always -1 (no
|
|
782
|
+
# index needs special-casing).
|
|
742
783
|
qb = list(range(len(hq)))
|
|
743
784
|
lhv = -1
|
|
744
785
|
|
|
@@ -945,6 +986,164 @@ class QrackAceBackend:
|
|
|
945
986
|
# all -- skip the rotation rather than rotate toward an
|
|
946
987
|
# arbitrary/undefined target derived from noise.
|
|
947
988
|
|
|
989
|
+
elif len(hq) == 5:
|
|
990
|
+
# Corner-boundary qubit, self.use_crossbars=True: 5 real
|
|
991
|
+
# replicas (home, adjacent-patch, the shared crossbar at
|
|
992
|
+
# slot 2, and the 2 diagonal-patch shadows). Structurally
|
|
993
|
+
# identical to the no-crossbar 4-replica case above -- the 4
|
|
994
|
+
# "end-cap" replicas [p0, p1, p3, p4] vote via their own RMS
|
|
995
|
+
# pool first; a genuine 2-2 split among them defers to the
|
|
996
|
+
# crossbar replica (hq[2], a REAL qubit, not a classical
|
|
997
|
+
# proxy); the classical LHV proxy is consulted only if the
|
|
998
|
+
# crossbar itself also turns out ambiguous.
|
|
999
|
+
p0 = self.sim[hq[0][0]].prob(hq[0][1])
|
|
1000
|
+
p1 = self.sim[hq[1][0]].prob(hq[1][1])
|
|
1001
|
+
p2 = self.sim[hq[2][0]].prob(hq[2][1])
|
|
1002
|
+
p3 = self.sim[hq[3][0]].prob(hq[3][1])
|
|
1003
|
+
p4 = self.sim[hq[4][0]].prob(hq[4][1])
|
|
1004
|
+
lhv = self._lhv.get(lq)
|
|
1005
|
+
|
|
1006
|
+
end_caps = [p0, p1, p3, p4]
|
|
1007
|
+
high_count = sum(1 for x in end_caps if x > (0.5 + self._epsilon))
|
|
1008
|
+
low_count = sum(1 for x in end_caps if x < (0.5 - self._epsilon))
|
|
1009
|
+
undecided_count = len(end_caps) - high_count - low_count
|
|
1010
|
+
end_caps_tied = (high_count == 2 and low_count == 2) or (undecided_count > 0)
|
|
1011
|
+
|
|
1012
|
+
if not end_caps_tied:
|
|
1013
|
+
prms = math.sqrt(sum(x**2 for x in end_caps) / 4)
|
|
1014
|
+
qrms = math.sqrt(sum((1 - x) ** 2 for x in end_caps) / 4)
|
|
1015
|
+
eff_prob = (prms + (1 - qrms)) / 2
|
|
1016
|
+
result = (
|
|
1017
|
+
(random.random() < 0.5)
|
|
1018
|
+
if abs(eff_prob - 0.5) <= self._epsilon
|
|
1019
|
+
else (eff_prob >= 0.5)
|
|
1020
|
+
)
|
|
1021
|
+
elif abs(p2 - 0.5) > self._epsilon:
|
|
1022
|
+
result = p2 >= 0.5
|
|
1023
|
+
elif lhv is not None:
|
|
1024
|
+
p_lhv = lhv.prob()
|
|
1025
|
+
result = (
|
|
1026
|
+
(random.random() < 0.5)
|
|
1027
|
+
if abs(p_lhv - 0.5) <= self._epsilon
|
|
1028
|
+
else (p_lhv >= 0.5)
|
|
1029
|
+
)
|
|
1030
|
+
else:
|
|
1031
|
+
result = random.random() < 0.5
|
|
1032
|
+
|
|
1033
|
+
p = [p0, p1, p2, p3, p4]
|
|
1034
|
+
syndrome = [1 - x for x in p] if result else list(p)
|
|
1035
|
+
for q in range(5):
|
|
1036
|
+
if syndrome[q] > (0.5 + self._epsilon):
|
|
1037
|
+
self.sim[hq[q][0]].x(hq[q][1])
|
|
1038
|
+
|
|
1039
|
+
if not skip_rotation:
|
|
1040
|
+
a, i, rs = [0] * 5, [0] * 5, [0] * 5
|
|
1041
|
+
for idx in range(5):
|
|
1042
|
+
a[idx], i[idx], rs[idx] = self._get_bloch_angles(hq[idx])
|
|
1043
|
+
w = [1 - r for r in rs]
|
|
1044
|
+
|
|
1045
|
+
w_total = sum(w)
|
|
1046
|
+
if w_total > self._epsilon:
|
|
1047
|
+
a_target = sum(wx * ax for wx, ax in zip(w, a)) / w_total
|
|
1048
|
+
i_target = sum(wx * ix for wx, ix in zip(w, i)) / w_total
|
|
1049
|
+
# Same separability gating as the 4-replica case
|
|
1050
|
+
# above (hq[0] excluded outright, hq[1:] only
|
|
1051
|
+
# rotated while still reasonably separable).
|
|
1052
|
+
for x in range(1, 5):
|
|
1053
|
+
if rs[x] <= self._rot_epsilon:
|
|
1054
|
+
self._rotate_to_bloch(hq[x], a_target - a[x], i_target - i[x])
|
|
1055
|
+
|
|
1056
|
+
elif len(hq) == 3:
|
|
1057
|
+
# Edge-boundary qubit, self.use_crossbars=True: 3 real
|
|
1058
|
+
# replicas (home, adjacent-patch, and the shared crossbar at
|
|
1059
|
+
# slot 2). Same conditional tie-breaking cascade as the
|
|
1060
|
+
# no-crossbar 2-replica case below, but with the crossbar
|
|
1061
|
+
# (hq[2], a REAL qubit) taking over the role the classical
|
|
1062
|
+
# LHV proxy plays there: trust slot1 (adjacent-patch) and
|
|
1063
|
+
# slot2 (crossbar) together whenever they agree; fall back
|
|
1064
|
+
# to slot0 (home) when they disagree and it has a decisive
|
|
1065
|
+
# opinion; consult the classical LHV proxy only as an
|
|
1066
|
+
# absolute last resort, if even slot0 is ambiguous.
|
|
1067
|
+
p0 = self.sim[hq[0][0]].prob(hq[0][1])
|
|
1068
|
+
p1 = self.sim[hq[1][0]].prob(hq[1][1])
|
|
1069
|
+
p2 = self.sim[hq[2][0]].prob(hq[2][1])
|
|
1070
|
+
lhv = self._lhv.get(lq)
|
|
1071
|
+
|
|
1072
|
+
p1_high = p1 > (0.5 + self._epsilon)
|
|
1073
|
+
p1_low = p1 < (0.5 - self._epsilon)
|
|
1074
|
+
p2_high = p2 > (0.5 + self._epsilon)
|
|
1075
|
+
p2_low = p2 < (0.5 - self._epsilon)
|
|
1076
|
+
end_caps_agree = (p1_high and p2_high) or (p1_low and p2_low)
|
|
1077
|
+
slot0_disagrees_with_end_caps = (
|
|
1078
|
+
end_caps_agree
|
|
1079
|
+
and (abs(p0 - 0.5) > self._epsilon)
|
|
1080
|
+
and ((p0 >= 0.5) != p1_high)
|
|
1081
|
+
)
|
|
1082
|
+
if slot0_disagrees_with_end_caps:
|
|
1083
|
+
# Same reasoning as the no-crossbar 2-replica case below:
|
|
1084
|
+
# the pair agreeing is not, by itself, reliable
|
|
1085
|
+
# corroboration if slot0 has a real, decisive, opposing
|
|
1086
|
+
# opinion -- that contradiction is the signal the pair is
|
|
1087
|
+
# stale, not corroborating.
|
|
1088
|
+
result = p0 >= 0.5
|
|
1089
|
+
elif end_caps_agree:
|
|
1090
|
+
prms = math.sqrt((p1**2 + p2**2) / 2)
|
|
1091
|
+
qrms = math.sqrt(((1 - p1) ** 2 + (1 - p2) ** 2) / 2)
|
|
1092
|
+
eff_prob = (prms + (1 - qrms)) / 2
|
|
1093
|
+
result = (
|
|
1094
|
+
(random.random() < 0.5)
|
|
1095
|
+
if abs(eff_prob - 0.5) <= self._epsilon
|
|
1096
|
+
else (eff_prob >= 0.5)
|
|
1097
|
+
)
|
|
1098
|
+
elif abs(p0 - 0.5) > self._epsilon:
|
|
1099
|
+
# Genuine deadlock between slot1/slot2; slot0 (a real,
|
|
1100
|
+
# exactly-entangled qubit in this common topology) has a
|
|
1101
|
+
# real opinion, so it breaks the tie.
|
|
1102
|
+
result = p0 >= 0.5
|
|
1103
|
+
elif lhv is not None:
|
|
1104
|
+
# slot0 is itself ambiguous, and so is the crossbar pair
|
|
1105
|
+
# above it; only now does the classical LHV's continuous,
|
|
1106
|
+
# non-collapsing proxy actually decide, as the last
|
|
1107
|
+
# resort.
|
|
1108
|
+
p_lhv = lhv.prob()
|
|
1109
|
+
result = (
|
|
1110
|
+
(random.random() < 0.5)
|
|
1111
|
+
if abs(p_lhv - 0.5) <= self._epsilon
|
|
1112
|
+
else (p_lhv >= 0.5)
|
|
1113
|
+
)
|
|
1114
|
+
else:
|
|
1115
|
+
result = random.random() < 0.5
|
|
1116
|
+
|
|
1117
|
+
p = [p0, p1, p2]
|
|
1118
|
+
syndrome = [1 - x for x in p] if result else list(p)
|
|
1119
|
+
for q in range(3):
|
|
1120
|
+
if syndrome[q] > (0.5 + self._epsilon):
|
|
1121
|
+
self.sim[hq[q][0]].x(hq[q][1])
|
|
1122
|
+
# The LHV proxy is never hard-collapsed via x(); it is only
|
|
1123
|
+
# ever updated by its own transversal gate evolution and
|
|
1124
|
+
# _cpauli_lhv, same as every other branch here.
|
|
1125
|
+
|
|
1126
|
+
if (not skip_rotation) and (not end_caps_agree):
|
|
1127
|
+
a, i, rs = [0, 0, 0], [0, 0, 0], [0, 0, 0]
|
|
1128
|
+
a[0], i[0], rs[0] = self._get_bloch_angles(hq[0])
|
|
1129
|
+
a[1], i[1], rs[1] = self._get_bloch_angles(hq[1])
|
|
1130
|
+
a[2], i[2], rs[2] = self._get_bloch_angles(hq[2])
|
|
1131
|
+
w = [1 - r for r in rs]
|
|
1132
|
+
|
|
1133
|
+
w_total = sum(w)
|
|
1134
|
+
if w_total > self._epsilon:
|
|
1135
|
+
a_target = sum(wx * ax for wx, ax in zip(w, a)) / w_total
|
|
1136
|
+
i_target = sum(wx * ix for wx, ix in zip(w, i)) / w_total
|
|
1137
|
+
# slot0 (hq[0]) is excluded from the rotation itself,
|
|
1138
|
+
# same reasoning as every other branch here; slot1
|
|
1139
|
+
# and slot2 (the crossbar) are both real, lossy
|
|
1140
|
+
# shadow-style replicas with no comparable
|
|
1141
|
+
# entanglement to protect, so both are eligible,
|
|
1142
|
+
# each gated on its own separability.
|
|
1143
|
+
for x in (1, 2):
|
|
1144
|
+
if rs[x] <= self._rot_epsilon:
|
|
1145
|
+
self._rotate_to_bloch(hq[x], a_target - a[x], i_target - i[x])
|
|
1146
|
+
|
|
948
1147
|
else:
|
|
949
1148
|
# Edge-boundary qubit: only 2 real replicas remain (home +
|
|
950
1149
|
# adjacent-patch) now that the crossbar replica that used to
|
|
@@ -2112,36 +2311,21 @@ class QrackAceBackend:
|
|
|
2112
2311
|
return self.sim[b[0]].prob(b[1])
|
|
2113
2312
|
|
|
2114
2313
|
self._correct(lq)
|
|
2115
|
-
|
|
2116
|
-
|
|
2117
|
-
|
|
2118
|
-
|
|
2119
|
-
|
|
2120
|
-
|
|
2121
|
-
|
|
2122
|
-
|
|
2123
|
-
|
|
2124
|
-
|
|
2125
|
-
|
|
2126
|
-
|
|
2127
|
-
|
|
2128
|
-
|
|
2129
|
-
|
|
2130
|
-
qrms = math.sqrt(sum((1 - x) ** 2 for x in p) / 4)
|
|
2131
|
-
else:
|
|
2132
|
-
# The 2 real replicas are already mutually consistent here
|
|
2133
|
-
# (the _correct() call above already ran the conditional
|
|
2134
|
-
# tie-breaking cascade, using the LHV proxy as needed, and
|
|
2135
|
-
# forced agreement via x()). Re-weighting in the LHV here
|
|
2136
|
-
# would reintroduce the same center-dragging distortion the
|
|
2137
|
-
# cascade was built to avoid -- a plain RMS over the
|
|
2138
|
-
# now-settled pair is the correct, already-decided answer.
|
|
2139
|
-
p = [
|
|
2140
|
-
self.sim[hq[0][0]].prob(hq[0][1]),
|
|
2141
|
-
self.sim[hq[1][0]].prob(hq[1][1]),
|
|
2142
|
-
]
|
|
2143
|
-
prms = math.sqrt((p[0] ** 2 + p[1] ** 2) / 2)
|
|
2144
|
-
qrms = math.sqrt(((1 - p[0]) ** 2 + (1 - p[1]) ** 2) / 2)
|
|
2314
|
+
# The real replicas are already mutually consistent here (the
|
|
2315
|
+
# _correct() call above already ran the appropriate tie-breaking
|
|
2316
|
+
# cascade for however many replicas hq has -- 2, 3, 4, or 5,
|
|
2317
|
+
# depending on self.use_crossbars and whether this is an edge or
|
|
2318
|
+
# corner boundary qubit -- using the LHV proxy and/or the
|
|
2319
|
+
# crossbar replica as needed, and forced agreement via x()). A
|
|
2320
|
+
# plain, unweighted RMS over the now-settled replicas is the
|
|
2321
|
+
# correct, already-decided answer, regardless of replica count:
|
|
2322
|
+
# re-weighting any particular replica specially here would
|
|
2323
|
+
# reintroduce the same center-dragging distortion the cascade in
|
|
2324
|
+
# _correct() was built to avoid.
|
|
2325
|
+
p = [self.sim[b[0]].prob(b[1]) for b in hq]
|
|
2326
|
+
n = len(p)
|
|
2327
|
+
prms = math.sqrt(sum(x**2 for x in p) / n)
|
|
2328
|
+
qrms = math.sqrt(sum((1 - x) ** 2 for x in p) / n)
|
|
2145
2329
|
|
|
2146
2330
|
return (prms + (1 - qrms)) / 2
|
|
2147
2331
|
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{pyqrack_cpu_complex128-2.26.6 → pyqrack_cpu_complex128-2.27.0}/pyqrack/neuron_activation_fn.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{pyqrack_cpu_complex128-2.26.6 → pyqrack_cpu_complex128-2.27.0}/pyqrack/qrack_neuron_torch_layer.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{pyqrack_cpu_complex128-2.26.6 → pyqrack_cpu_complex128-2.27.0}/pyqrack/qrack_system/__init__.py
RENAMED
|
File without changes
|
{pyqrack_cpu_complex128-2.26.6 → pyqrack_cpu_complex128-2.27.0}/pyqrack/qrack_system/qrack_system.py
RENAMED
|
File without changes
|
{pyqrack_cpu_complex128-2.26.6 → pyqrack_cpu_complex128-2.27.0}/pyqrack/quimb_circuit_type.py
RENAMED
|
File without changes
|
|
File without changes
|
{pyqrack_cpu_complex128-2.26.6 → pyqrack_cpu_complex128-2.27.0}/pyqrack/stats/load_quantized_data.py
RENAMED
|
File without changes
|
{pyqrack_cpu_complex128-2.26.6 → pyqrack_cpu_complex128-2.27.0}/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
|