pyqrack-cpu-complex128 2.21.2__tar.gz → 2.22.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.21.2/pyqrack_cpu_complex128.egg-info → pyqrack_cpu_complex128-2.22.0}/PKG-INFO +1 -1
- {pyqrack_cpu_complex128-2.21.2 → pyqrack_cpu_complex128-2.22.0}/pyqrack/qrack_ace_backend.py +21 -284
- {pyqrack_cpu_complex128-2.21.2 → pyqrack_cpu_complex128-2.22.0/pyqrack_cpu_complex128.egg-info}/PKG-INFO +1 -1
- {pyqrack_cpu_complex128-2.21.2 → pyqrack_cpu_complex128-2.22.0}/setup.py +1 -1
- {pyqrack_cpu_complex128-2.21.2 → pyqrack_cpu_complex128-2.22.0}/LICENSE +0 -0
- {pyqrack_cpu_complex128-2.21.2 → pyqrack_cpu_complex128-2.22.0}/MANIFEST.in +0 -0
- {pyqrack_cpu_complex128-2.21.2 → pyqrack_cpu_complex128-2.22.0}/Makefile +0 -0
- {pyqrack_cpu_complex128-2.21.2 → pyqrack_cpu_complex128-2.22.0}/README.md +0 -0
- {pyqrack_cpu_complex128-2.21.2 → pyqrack_cpu_complex128-2.22.0}/pyproject.toml +0 -0
- {pyqrack_cpu_complex128-2.21.2 → pyqrack_cpu_complex128-2.22.0}/pyqrack/__init__.py +0 -0
- {pyqrack_cpu_complex128-2.21.2 → pyqrack_cpu_complex128-2.22.0}/pyqrack/neuron_activation_fn.py +0 -0
- {pyqrack_cpu_complex128-2.21.2 → pyqrack_cpu_complex128-2.22.0}/pyqrack/pauli.py +0 -0
- {pyqrack_cpu_complex128-2.21.2 → pyqrack_cpu_complex128-2.22.0}/pyqrack/qrack_circuit.py +0 -0
- {pyqrack_cpu_complex128-2.21.2 → pyqrack_cpu_complex128-2.22.0}/pyqrack/qrack_near_clifford_qec_backend.py +0 -0
- {pyqrack_cpu_complex128-2.21.2 → pyqrack_cpu_complex128-2.22.0}/pyqrack/qrack_neuron.py +0 -0
- {pyqrack_cpu_complex128-2.21.2 → pyqrack_cpu_complex128-2.22.0}/pyqrack/qrack_neuron_torch_layer.py +0 -0
- {pyqrack_cpu_complex128-2.21.2 → pyqrack_cpu_complex128-2.22.0}/pyqrack/qrack_simulator.py +0 -0
- {pyqrack_cpu_complex128-2.21.2 → pyqrack_cpu_complex128-2.22.0}/pyqrack/qrack_stabilizer.py +0 -0
- {pyqrack_cpu_complex128-2.21.2 → pyqrack_cpu_complex128-2.22.0}/pyqrack/qrack_system/__init__.py +0 -0
- {pyqrack_cpu_complex128-2.21.2 → pyqrack_cpu_complex128-2.22.0}/pyqrack/qrack_system/qrack_system.py +0 -0
- {pyqrack_cpu_complex128-2.21.2 → pyqrack_cpu_complex128-2.22.0}/pyqrack/quimb_circuit_type.py +0 -0
- {pyqrack_cpu_complex128-2.21.2 → pyqrack_cpu_complex128-2.22.0}/pyqrack/stats/__init__.py +0 -0
- {pyqrack_cpu_complex128-2.21.2 → pyqrack_cpu_complex128-2.22.0}/pyqrack/stats/load_quantized_data.py +0 -0
- {pyqrack_cpu_complex128-2.21.2 → pyqrack_cpu_complex128-2.22.0}/pyqrack/stats/quantize_by_range.py +0 -0
- {pyqrack_cpu_complex128-2.21.2 → pyqrack_cpu_complex128-2.22.0}/pyqrack_cpu_complex128.egg-info/SOURCES.txt +0 -0
- {pyqrack_cpu_complex128-2.21.2 → pyqrack_cpu_complex128-2.22.0}/pyqrack_cpu_complex128.egg-info/dependency_links.txt +0 -0
- {pyqrack_cpu_complex128-2.21.2 → pyqrack_cpu_complex128-2.22.0}/pyqrack_cpu_complex128.egg-info/not-zip-safe +0 -0
- {pyqrack_cpu_complex128-2.21.2 → pyqrack_cpu_complex128-2.22.0}/pyqrack_cpu_complex128.egg-info/requires.txt +0 -0
- {pyqrack_cpu_complex128-2.21.2 → pyqrack_cpu_complex128-2.22.0}/pyqrack_cpu_complex128.egg-info/top_level.txt +0 -0
- {pyqrack_cpu_complex128-2.21.2 → pyqrack_cpu_complex128-2.22.0}/setup.cfg +0 -0
{pyqrack_cpu_complex128-2.21.2 → pyqrack_cpu_complex128-2.22.0}/pyqrack/qrack_ace_backend.py
RENAMED
|
@@ -7,7 +7,6 @@
|
|
|
7
7
|
import math
|
|
8
8
|
import os
|
|
9
9
|
import random
|
|
10
|
-
from collections import deque
|
|
11
10
|
|
|
12
11
|
from .qrack_system import Qrack
|
|
13
12
|
from .qrack_simulator import QrackSimulator
|
|
@@ -238,7 +237,6 @@ class QrackAceBackend:
|
|
|
238
237
|
is_host_pointer=(True if os.environ.get("PYQRACK_HOST_POINTER_DEFAULT_ON") else False),
|
|
239
238
|
is_near_clifford_tableau_writer=False,
|
|
240
239
|
noise=0,
|
|
241
|
-
history_window=0,
|
|
242
240
|
is_torus=True,
|
|
243
241
|
is_1d_chain=False,
|
|
244
242
|
is_error_detection=True,
|
|
@@ -250,7 +248,6 @@ class QrackAceBackend:
|
|
|
250
248
|
long_range_columns = to_clone.long_range_columns
|
|
251
249
|
long_range_rows = to_clone.long_range_rows
|
|
252
250
|
is_transpose = to_clone.is_transpose
|
|
253
|
-
history_window = to_clone.history_window
|
|
254
251
|
is_torus = to_clone.is_torus
|
|
255
252
|
is_1d_chain = to_clone.is_1d_chain
|
|
256
253
|
is_error_detection = to_clone.is_error_detection
|
|
@@ -259,15 +256,12 @@ class QrackAceBackend:
|
|
|
259
256
|
qubit_count = 0
|
|
260
257
|
if long_range_columns < 0:
|
|
261
258
|
long_range_columns = 0
|
|
262
|
-
if history_window < 0:
|
|
263
|
-
history_window = 0
|
|
264
259
|
|
|
265
260
|
self.is_1d_chain = is_1d_chain
|
|
266
261
|
self._factor_width(qubit_count, is_transpose)
|
|
267
262
|
self.long_range_columns = long_range_columns
|
|
268
263
|
self.long_range_rows = long_range_rows
|
|
269
264
|
self.is_transpose = is_transpose
|
|
270
|
-
self.history_window = history_window
|
|
271
265
|
self.is_torus = is_torus
|
|
272
266
|
self.is_error_detection = is_error_detection
|
|
273
267
|
self.is_boundary_repetition_code = is_boundary_repetition_code
|
|
@@ -343,28 +337,6 @@ class QrackAceBackend:
|
|
|
343
337
|
|
|
344
338
|
self._qubits = []
|
|
345
339
|
self._lhv = {}
|
|
346
|
-
if self.history_window > 0:
|
|
347
|
-
if to_clone and to_clone._coupling_history is not None:
|
|
348
|
-
self._coupling_history = {
|
|
349
|
-
k: deque(v, maxlen=self.history_window)
|
|
350
|
-
for k, v in to_clone._coupling_history.items()
|
|
351
|
-
}
|
|
352
|
-
self._coupling_history_rev = dict(to_clone._coupling_history_rev)
|
|
353
|
-
self._pending_skip = {k: set(v) for k, v in to_clone._pending_skip.items()}
|
|
354
|
-
self._stale_replicas = {k: set(v) for k, v in to_clone._stale_replicas.items()}
|
|
355
|
-
self._witness_map = {k: dict(v) for k, v in to_clone._witness_map.items()}
|
|
356
|
-
else:
|
|
357
|
-
self._coupling_history = {}
|
|
358
|
-
self._coupling_history_rev = {}
|
|
359
|
-
self._pending_skip = {}
|
|
360
|
-
self._stale_replicas = {}
|
|
361
|
-
self._witness_map = {}
|
|
362
|
-
else:
|
|
363
|
-
self._coupling_history = None
|
|
364
|
-
self._coupling_history_rev = None
|
|
365
|
-
self._pending_skip = None
|
|
366
|
-
self._stale_replicas = None
|
|
367
|
-
self._witness_map = None
|
|
368
340
|
sim_counts = [0] * sim_count
|
|
369
341
|
sim_id = 0
|
|
370
342
|
tot_qubits = 0
|
|
@@ -891,10 +863,8 @@ class QrackAceBackend:
|
|
|
891
863
|
end_caps = [p0, p1, p3, p4]
|
|
892
864
|
# Classify each end-cap as decisively high / decisively low /
|
|
893
865
|
# undecided (within epsilon of 0.5), rather than a bare >=0.5
|
|
894
|
-
# check -- a replica reading EXACTLY 0.5
|
|
895
|
-
#
|
|
896
|
-
# zero information) was previously always counted as "high"
|
|
897
|
-
# via this boundary convention alone.
|
|
866
|
+
# check -- a replica reading EXACTLY 0.5 was previously always
|
|
867
|
+
# counted as "high" via this boundary convention alone.
|
|
898
868
|
high_count = sum(1 for x in end_caps if x > (0.5 + self._epsilon))
|
|
899
869
|
low_count = sum(1 for x in end_caps if x < (0.5 - self._epsilon))
|
|
900
870
|
undecided_count = len(end_caps) - high_count - low_count
|
|
@@ -1154,17 +1124,14 @@ class QrackAceBackend:
|
|
|
1154
1124
|
hq = self._unpack(lq)
|
|
1155
1125
|
if len(hq) < 2:
|
|
1156
1126
|
b = hq[0]
|
|
1157
|
-
self._invalidate_for_gate(lq)
|
|
1158
1127
|
self.sim[b[0]].u(b[1], th, ph, lm)
|
|
1159
1128
|
return
|
|
1160
1129
|
|
|
1161
|
-
skip = self._invalidate_for_gate(lq)
|
|
1162
1130
|
qb, _ = QrackAceBackend._get_qb_lhv_indices(hq)
|
|
1163
1131
|
|
|
1164
1132
|
for q in qb:
|
|
1165
1133
|
b = hq[q]
|
|
1166
|
-
|
|
1167
|
-
self.sim[b[0]].u(b[1], th, ph, lm)
|
|
1134
|
+
self.sim[b[0]].u(b[1], th, ph, lm)
|
|
1168
1135
|
|
|
1169
1136
|
lhv = self._lhv.get(lq)
|
|
1170
1137
|
if lhv is not None:
|
|
@@ -1172,87 +1139,18 @@ class QrackAceBackend:
|
|
|
1172
1139
|
|
|
1173
1140
|
# Correction deferred to next 2-qubit gate (_cpauli calls _correct)
|
|
1174
1141
|
|
|
1175
|
-
def _revert_shadow_commitment(self, lq1):
|
|
1176
|
-
"""Revert shadow-committed replicas recorded under lq1. H-reverts
|
|
1177
|
-
each committed shadow replica (undoing the stale Z-basis commitment),
|
|
1178
|
-
stores the reverted tuples in _pending_skip[lq2] so the NEXT gate on
|
|
1179
|
-
that boundary qubit skips those replicas entirely (rotating an H-reverted
|
|
1180
|
-
shadow replica from the wrong starting state gives a wrong result; the
|
|
1181
|
-
right behavior is to skip it and let the next coupling gate re-derive
|
|
1182
|
-
from scratch), and returns the reverted set for the immediate caller to
|
|
1183
|
-
skip as well (for case A, where the control's own rotation should also
|
|
1184
|
-
skip its own shadow replicas that were just un-committed)."""
|
|
1185
|
-
if self._coupling_history is None:
|
|
1186
|
-
return set()
|
|
1187
|
-
hist = self._coupling_history.pop(lq1, None)
|
|
1188
|
-
if hist is None:
|
|
1189
|
-
return set()
|
|
1190
|
-
reverted_all = set()
|
|
1191
|
-
for lq2, targets in hist:
|
|
1192
|
-
reverted = set()
|
|
1193
|
-
for t_sim, t_idx in targets:
|
|
1194
|
-
self.sim[t_sim].h(t_idx)
|
|
1195
|
-
reverted.add((t_sim, t_idx))
|
|
1196
|
-
# Store as pending skip for the NEXT gate on lq2 (case B):
|
|
1197
|
-
# when the boundary qubit's own gate runs, it should skip
|
|
1198
|
-
# these replicas rather than applying its gate to the freshly-
|
|
1199
|
-
# H-reverted, uncommitted state.
|
|
1200
|
-
if reverted:
|
|
1201
|
-
existing = self._pending_skip.get(lq2, set())
|
|
1202
|
-
self._pending_skip[lq2] = existing | reverted
|
|
1203
|
-
existing_stale = self._stale_replicas.get(lq2, set())
|
|
1204
|
-
self._stale_replicas[lq2] = existing_stale | reverted
|
|
1205
|
-
self._coupling_history_rev.pop(lq2, None)
|
|
1206
|
-
reverted_all |= reverted
|
|
1207
|
-
return reverted_all
|
|
1208
|
-
|
|
1209
|
-
def _invalidate_for_gate(self, lq):
|
|
1210
|
-
"""Called by every single-qubit gate dispatcher. Returns the set of
|
|
1211
|
-
(sim_id, idx) shadow replicas that should be SKIPPED in the calling
|
|
1212
|
-
gate's own application loop.
|
|
1213
|
-
- Case A: lq is the coherent-partner (lq1) in a live history entry.
|
|
1214
|
-
A gate on the control side invalidates the shadow commitment: reverts
|
|
1215
|
-
the shadow targets via H (returning them to uncommitted 0.5), stores
|
|
1216
|
-
them in pending_skip[lq2] for the NEXT gate on the boundary qubit,
|
|
1217
|
-
and returns them for the immediate caller to skip as well (since the
|
|
1218
|
-
control's own replica at slot0 may also be in the reverted set).
|
|
1219
|
-
- Case B: lq is the boundary recipient (lq2) of a commitment that a
|
|
1220
|
-
prior case-A revert already H-reverted. Consumes the pending_skip
|
|
1221
|
-
set so the boundary gate doesn't apply itself to the freshly-
|
|
1222
|
-
uncommitted replicas (which would give the wrong result from the
|
|
1223
|
-
wrong starting state). Case B NEVER triggers a fresh revert --
|
|
1224
|
-
only case A does, because only a gate on the control side actually
|
|
1225
|
-
invalidates the commitment; a gate on the boundary side just needs
|
|
1226
|
-
to avoid corrupting the already-reverted starting state."""
|
|
1227
|
-
if self._coupling_history is None:
|
|
1228
|
-
return set()
|
|
1229
|
-
skip = set()
|
|
1230
|
-
# Case A: lq is the coherent control side -- fire the revert.
|
|
1231
|
-
if lq in self._coupling_history:
|
|
1232
|
-
skip |= self._revert_shadow_commitment(lq)
|
|
1233
|
-
# Case B: lq is the boundary side -- ONLY consume pending_skip,
|
|
1234
|
-
# never trigger a fresh revert (that would incorrectly revert
|
|
1235
|
-
# a still-valid commitment that no control-side gate has touched).
|
|
1236
|
-
pending = self._pending_skip.pop(lq, None)
|
|
1237
|
-
if pending:
|
|
1238
|
-
skip |= pending
|
|
1239
|
-
return skip
|
|
1240
|
-
|
|
1241
1142
|
def r(self, p, th, lq):
|
|
1242
1143
|
hq = self._unpack(lq)
|
|
1243
1144
|
if len(hq) < 2:
|
|
1244
1145
|
b = hq[0]
|
|
1245
|
-
self._invalidate_for_gate(lq)
|
|
1246
1146
|
self.sim[b[0]].r(p, th, b[1])
|
|
1247
1147
|
return
|
|
1248
1148
|
|
|
1249
1149
|
qb, _ = QrackAceBackend._get_qb_lhv_indices(hq)
|
|
1250
|
-
skip = self._invalidate_for_gate(lq)
|
|
1251
1150
|
|
|
1252
1151
|
for q in qb:
|
|
1253
1152
|
b = hq[q]
|
|
1254
|
-
|
|
1255
|
-
self.sim[b[0]].r(p, th, b[1])
|
|
1153
|
+
self.sim[b[0]].r(p, th, b[1])
|
|
1256
1154
|
|
|
1257
1155
|
lhv = self._lhv.get(lq)
|
|
1258
1156
|
if lhv is not None:
|
|
@@ -1269,17 +1167,14 @@ class QrackAceBackend:
|
|
|
1269
1167
|
hq = self._unpack(lq)
|
|
1270
1168
|
if len(hq) < 2:
|
|
1271
1169
|
b = hq[0]
|
|
1272
|
-
self._invalidate_for_gate(lq)
|
|
1273
1170
|
self.sim[b[0]].h(b[1])
|
|
1274
1171
|
return
|
|
1275
1172
|
|
|
1276
|
-
skip = self._invalidate_for_gate(lq)
|
|
1277
1173
|
qb, _ = QrackAceBackend._get_qb_lhv_indices(hq)
|
|
1278
1174
|
|
|
1279
1175
|
for q in qb:
|
|
1280
1176
|
b = hq[q]
|
|
1281
|
-
|
|
1282
|
-
self.sim[b[0]].h(b[1])
|
|
1177
|
+
self.sim[b[0]].h(b[1])
|
|
1283
1178
|
|
|
1284
1179
|
lhv = self._lhv.get(lq)
|
|
1285
1180
|
if lhv is not None:
|
|
@@ -1291,17 +1186,14 @@ class QrackAceBackend:
|
|
|
1291
1186
|
hq = self._unpack(lq)
|
|
1292
1187
|
if len(hq) < 2:
|
|
1293
1188
|
b = hq[0]
|
|
1294
|
-
self._invalidate_for_gate(lq)
|
|
1295
1189
|
self.sim[b[0]].s(b[1])
|
|
1296
1190
|
return
|
|
1297
1191
|
|
|
1298
|
-
skip = self._invalidate_for_gate(lq)
|
|
1299
1192
|
qb, _ = QrackAceBackend._get_qb_lhv_indices(hq)
|
|
1300
1193
|
|
|
1301
1194
|
for q in qb:
|
|
1302
1195
|
b = hq[q]
|
|
1303
|
-
|
|
1304
|
-
self.sim[b[0]].s(b[1])
|
|
1196
|
+
self.sim[b[0]].s(b[1])
|
|
1305
1197
|
|
|
1306
1198
|
lhv = self._lhv.get(lq)
|
|
1307
1199
|
if lhv is not None:
|
|
@@ -1311,17 +1203,14 @@ class QrackAceBackend:
|
|
|
1311
1203
|
hq = self._unpack(lq)
|
|
1312
1204
|
if len(hq) < 2:
|
|
1313
1205
|
b = hq[0]
|
|
1314
|
-
self._invalidate_for_gate(lq)
|
|
1315
1206
|
self.sim[b[0]].adjs(b[1])
|
|
1316
1207
|
return
|
|
1317
1208
|
|
|
1318
|
-
skip = self._invalidate_for_gate(lq)
|
|
1319
1209
|
qb, _ = QrackAceBackend._get_qb_lhv_indices(hq)
|
|
1320
1210
|
|
|
1321
1211
|
for q in qb:
|
|
1322
1212
|
b = hq[q]
|
|
1323
|
-
|
|
1324
|
-
self.sim[b[0]].adjs(b[1])
|
|
1213
|
+
self.sim[b[0]].adjs(b[1])
|
|
1325
1214
|
|
|
1326
1215
|
lhv = self._lhv.get(lq)
|
|
1327
1216
|
if lhv is not None:
|
|
@@ -1331,17 +1220,14 @@ class QrackAceBackend:
|
|
|
1331
1220
|
hq = self._unpack(lq)
|
|
1332
1221
|
if len(hq) < 2:
|
|
1333
1222
|
b = hq[0]
|
|
1334
|
-
self._invalidate_for_gate(lq)
|
|
1335
1223
|
self.sim[b[0]].sx(b[1])
|
|
1336
1224
|
return
|
|
1337
1225
|
|
|
1338
|
-
skip = self._invalidate_for_gate(lq)
|
|
1339
1226
|
qb, _ = QrackAceBackend._get_qb_lhv_indices(hq)
|
|
1340
1227
|
|
|
1341
1228
|
for q in qb:
|
|
1342
1229
|
b = hq[q]
|
|
1343
|
-
|
|
1344
|
-
self.sim[b[0]].sx(b[1])
|
|
1230
|
+
self.sim[b[0]].sx(b[1])
|
|
1345
1231
|
|
|
1346
1232
|
lhv = self._lhv.get(lq)
|
|
1347
1233
|
if lhv is not None:
|
|
@@ -1351,17 +1237,14 @@ class QrackAceBackend:
|
|
|
1351
1237
|
hq = self._unpack(lq)
|
|
1352
1238
|
if len(hq) < 2:
|
|
1353
1239
|
b = hq[0]
|
|
1354
|
-
self._invalidate_for_gate(lq)
|
|
1355
1240
|
self.sim[b[0]].adjsx(b[1])
|
|
1356
1241
|
return
|
|
1357
1242
|
|
|
1358
|
-
skip = self._invalidate_for_gate(lq)
|
|
1359
1243
|
qb, _ = QrackAceBackend._get_qb_lhv_indices(hq)
|
|
1360
1244
|
|
|
1361
1245
|
for q in qb:
|
|
1362
1246
|
b = hq[q]
|
|
1363
|
-
|
|
1364
|
-
self.sim[b[0]].adjsx(b[1])
|
|
1247
|
+
self.sim[b[0]].adjsx(b[1])
|
|
1365
1248
|
|
|
1366
1249
|
lhv = self._lhv.get(lq)
|
|
1367
1250
|
if lhv is not None:
|
|
@@ -1495,17 +1378,14 @@ class QrackAceBackend:
|
|
|
1495
1378
|
hq = self._unpack(lq)
|
|
1496
1379
|
if len(hq) < 2:
|
|
1497
1380
|
b = hq[0]
|
|
1498
|
-
self._invalidate_for_gate(lq)
|
|
1499
1381
|
self.sim[b[0]].x(b[1])
|
|
1500
1382
|
return
|
|
1501
1383
|
|
|
1502
|
-
skip = self._invalidate_for_gate(lq)
|
|
1503
1384
|
qb, _ = QrackAceBackend._get_qb_lhv_indices(hq)
|
|
1504
1385
|
|
|
1505
1386
|
for q in qb:
|
|
1506
1387
|
b = hq[q]
|
|
1507
|
-
|
|
1508
|
-
self.sim[b[0]].x(b[1])
|
|
1388
|
+
self.sim[b[0]].x(b[1])
|
|
1509
1389
|
|
|
1510
1390
|
lhv = self._lhv.get(lq)
|
|
1511
1391
|
if lhv is not None:
|
|
@@ -1515,17 +1395,14 @@ class QrackAceBackend:
|
|
|
1515
1395
|
hq = self._unpack(lq)
|
|
1516
1396
|
if len(hq) < 2:
|
|
1517
1397
|
b = hq[0]
|
|
1518
|
-
self._invalidate_for_gate(lq)
|
|
1519
1398
|
self.sim[b[0]].y(b[1])
|
|
1520
1399
|
return
|
|
1521
1400
|
|
|
1522
|
-
skip = self._invalidate_for_gate(lq)
|
|
1523
1401
|
qb, _ = QrackAceBackend._get_qb_lhv_indices(hq)
|
|
1524
1402
|
|
|
1525
1403
|
for q in qb:
|
|
1526
1404
|
b = hq[q]
|
|
1527
|
-
|
|
1528
|
-
self.sim[b[0]].y(b[1])
|
|
1405
|
+
self.sim[b[0]].y(b[1])
|
|
1529
1406
|
|
|
1530
1407
|
lhv = self._lhv.get(lq)
|
|
1531
1408
|
if lhv is not None:
|
|
@@ -1535,17 +1412,14 @@ class QrackAceBackend:
|
|
|
1535
1412
|
hq = self._unpack(lq)
|
|
1536
1413
|
if len(hq) < 2:
|
|
1537
1414
|
b = hq[0]
|
|
1538
|
-
self._invalidate_for_gate(lq)
|
|
1539
1415
|
self.sim[b[0]].z(b[1])
|
|
1540
1416
|
return
|
|
1541
1417
|
|
|
1542
|
-
skip = self._invalidate_for_gate(lq)
|
|
1543
1418
|
qb, _ = QrackAceBackend._get_qb_lhv_indices(hq)
|
|
1544
1419
|
|
|
1545
1420
|
for q in qb:
|
|
1546
1421
|
b = hq[q]
|
|
1547
|
-
|
|
1548
|
-
self.sim[b[0]].z(b[1])
|
|
1422
|
+
self.sim[b[0]].z(b[1])
|
|
1549
1423
|
|
|
1550
1424
|
lhv = self._lhv.get(lq)
|
|
1551
1425
|
if lhv is not None:
|
|
@@ -1555,17 +1429,14 @@ class QrackAceBackend:
|
|
|
1555
1429
|
hq = self._unpack(lq)
|
|
1556
1430
|
if len(hq) < 2:
|
|
1557
1431
|
b = hq[0]
|
|
1558
|
-
self._invalidate_for_gate(lq)
|
|
1559
1432
|
self.sim[b[0]].t(b[1])
|
|
1560
1433
|
return
|
|
1561
1434
|
|
|
1562
|
-
skip = self._invalidate_for_gate(lq)
|
|
1563
1435
|
qb, _ = QrackAceBackend._get_qb_lhv_indices(hq)
|
|
1564
1436
|
|
|
1565
1437
|
for q in qb:
|
|
1566
1438
|
b = hq[q]
|
|
1567
|
-
|
|
1568
|
-
self.sim[b[0]].t(b[1])
|
|
1439
|
+
self.sim[b[0]].t(b[1])
|
|
1569
1440
|
|
|
1570
1441
|
lhv = self._lhv.get(lq)
|
|
1571
1442
|
if lhv is not None:
|
|
@@ -1575,17 +1446,14 @@ class QrackAceBackend:
|
|
|
1575
1446
|
hq = self._unpack(lq)
|
|
1576
1447
|
if len(hq) < 2:
|
|
1577
1448
|
b = hq[0]
|
|
1578
|
-
self._invalidate_for_gate(lq)
|
|
1579
1449
|
self.sim[b[0]].adjt(b[1])
|
|
1580
1450
|
return
|
|
1581
1451
|
|
|
1582
|
-
skip = self._invalidate_for_gate(lq)
|
|
1583
1452
|
qb, _ = QrackAceBackend._get_qb_lhv_indices(hq)
|
|
1584
1453
|
|
|
1585
1454
|
for q in qb:
|
|
1586
1455
|
b = hq[q]
|
|
1587
|
-
|
|
1588
|
-
self.sim[b[0]].adjt(b[1])
|
|
1456
|
+
self.sim[b[0]].adjt(b[1])
|
|
1589
1457
|
|
|
1590
1458
|
lhv = self._lhv.get(lq)
|
|
1591
1459
|
if lhv is not None:
|
|
@@ -1650,16 +1518,6 @@ class QrackAceBackend:
|
|
|
1650
1518
|
|
|
1651
1519
|
def _apply_coupling(self, pauli, anti, qb1, hq1, qb2, hq2, lq1_lr, lq1=None, lq2=None):
|
|
1652
1520
|
shadow_targets = []
|
|
1653
|
-
witnessed_targets = [] # (shadow_target, witness_replica) pairs --
|
|
1654
|
-
# "easy case": a replica of the SAME target
|
|
1655
|
-
# logical qubit lives in the SAME simulator
|
|
1656
|
-
# as the control replica used for this
|
|
1657
|
-
# shadow pair, and is therefore always
|
|
1658
|
-
# exactly correct regardless of how many
|
|
1659
|
-
# later gates happen to the control. No
|
|
1660
|
-
# bounded window, no reactive invalidation
|
|
1661
|
-
# needed for these -- see
|
|
1662
|
-
# _resolve_witnessed_shadow.
|
|
1663
1521
|
|
|
1664
1522
|
# Logical-level error-detection gadget: captures lq1's LOGICAL
|
|
1665
1523
|
# value (and lq2's too, for CZ specifically -- see below) into a
|
|
@@ -1766,8 +1624,6 @@ class QrackAceBackend:
|
|
|
1766
1624
|
elif (q2 not in real_gated_q2) and (lq1_lr or (b1[1] == b2[1])):
|
|
1767
1625
|
shadow_fn(b1, b2)
|
|
1768
1626
|
shadow_targets.append(b2)
|
|
1769
|
-
if witness is not None and witness != b2:
|
|
1770
|
-
witnessed_targets.append((b2, witness))
|
|
1771
1627
|
|
|
1772
1628
|
is_flipped = False
|
|
1773
1629
|
if anc1 is not None:
|
|
@@ -1853,30 +1709,6 @@ class QrackAceBackend:
|
|
|
1853
1709
|
self.x(lq2)
|
|
1854
1710
|
self._in_gadget_capture = False
|
|
1855
1711
|
|
|
1856
|
-
if lq2 is not None and witnessed_targets and self._witness_map is not None:
|
|
1857
|
-
wmap = self._witness_map.setdefault(lq2, {})
|
|
1858
|
-
for target_replica, witness_replica in witnessed_targets:
|
|
1859
|
-
wmap[target_replica] = witness_replica
|
|
1860
|
-
|
|
1861
|
-
if (
|
|
1862
|
-
self._coupling_history is not None
|
|
1863
|
-
and lq1 is not None
|
|
1864
|
-
and lq2 is not None
|
|
1865
|
-
and shadow_targets
|
|
1866
|
-
):
|
|
1867
|
-
# Only the NON-witnessed shadow targets need the bounded,
|
|
1868
|
-
# reactive history/invalidation machinery -- witnessed ones are
|
|
1869
|
-
# always resolvable directly and don't need tracking here at all.
|
|
1870
|
-
witnessed_set = {t for t, _ in witnessed_targets}
|
|
1871
|
-
unwitnessed = tuple(t for t in shadow_targets if t not in witnessed_set)
|
|
1872
|
-
if unwitnessed:
|
|
1873
|
-
entry = (lq2, tuple(unwitnessed))
|
|
1874
|
-
hist = self._coupling_history.setdefault(
|
|
1875
|
-
lq1, deque(maxlen=self.history_window)
|
|
1876
|
-
)
|
|
1877
|
-
hist.append(entry)
|
|
1878
|
-
self._coupling_history_rev[lq2] = lq1
|
|
1879
|
-
|
|
1880
1712
|
# A "coupled twirling" scheme was tried here -- after every real
|
|
1881
1713
|
# inter-logical-qubit coupling gate, SWAP which physical qubit is
|
|
1882
1714
|
# registered as hq[side] with one of its level-0 scratch qubits, to
|
|
@@ -2089,35 +1921,6 @@ class QrackAceBackend:
|
|
|
2089
1921
|
sims2 = {r[0] for r in hq2}
|
|
2090
1922
|
|
|
2091
1923
|
if sims1.isdisjoint(sims2):
|
|
2092
|
-
# Zero shared physical substrate: a SWAP is, by definition,
|
|
2093
|
-
# just "exchange which logical index refers to which
|
|
2094
|
-
# subsystem" -- for two qubits with no shared simulator or
|
|
2095
|
-
# replica at all, that IS the swap, exactly, with zero gates
|
|
2096
|
-
# and zero error, regardless of what either is entangled
|
|
2097
|
-
# with elsewhere (SWAP is a relabeling of tensor-factor
|
|
2098
|
-
# indices; nothing about that depends on which name we call
|
|
2099
|
-
# either subsystem). This also sidesteps the separate
|
|
2100
|
-
# _apply_coupling local-index-match limitation entirely for
|
|
2101
|
-
# this case, since no shadow coupling is attempted between
|
|
2102
|
-
# these qubits at all.
|
|
2103
|
-
#
|
|
2104
|
-
# Must fully resolve any pending shadow/consensus state tied
|
|
2105
|
-
# to EACH qubit's CURRENT identity before relabeling --
|
|
2106
|
-
# otherwise a cross-reference recorded under the old identity
|
|
2107
|
-
# (e.g. coupling_history[lq1], witness_map[lq2]) would
|
|
2108
|
-
# silently end up describing the wrong physical qubit
|
|
2109
|
-
# afterward. Reuses the same resolution methods prob() and
|
|
2110
|
-
# every single-qubit gate already depend on for correctness,
|
|
2111
|
-
# rather than hand-rolling new bookkeeping that could miss a
|
|
2112
|
-
# cross-reference.
|
|
2113
|
-
self._invalidate_for_gate(lq1)
|
|
2114
|
-
self._invalidate_for_gate(lq2)
|
|
2115
|
-
if len(hq1) >= 2:
|
|
2116
|
-
self._resolve_witnessed_shadow(lq1)
|
|
2117
|
-
self._resolve_pending_skip(lq1)
|
|
2118
|
-
if len(hq2) >= 2:
|
|
2119
|
-
self._resolve_witnessed_shadow(lq2)
|
|
2120
|
-
self._resolve_pending_skip(lq2)
|
|
2121
1924
|
self._correct(lq1)
|
|
2122
1925
|
self._correct(lq2)
|
|
2123
1926
|
|
|
@@ -2164,6 +1967,13 @@ class QrackAceBackend:
|
|
|
2164
1967
|
self.cx(lq1, lq2)
|
|
2165
1968
|
return
|
|
2166
1969
|
|
|
1970
|
+
# Boundary-to-boundary handling
|
|
1971
|
+
if (len(hq1) > 1) and (len(hq2) > 1):
|
|
1972
|
+
self.cx(lq1, lq2)
|
|
1973
|
+
self.cx(lq2, lq1)
|
|
1974
|
+
self.cx(lq1, lq2)
|
|
1975
|
+
return
|
|
1976
|
+
|
|
2167
1977
|
# Fast/exact path: every replica of lq1 lines up, position-for-
|
|
2168
1978
|
# position, with the corresponding replica of lq2 on the SAME
|
|
2169
1979
|
# underlying simulator. A native swap() there is pure index
|
|
@@ -2308,85 +2118,12 @@ class QrackAceBackend:
|
|
|
2308
2118
|
self.cz(lq1, lq2)
|
|
2309
2119
|
self.swap(lq1, lq2)
|
|
2310
2120
|
|
|
2311
|
-
def _resolve_pending_skip(self, lq):
|
|
2312
|
-
"""If lq has replicas recorded as STALE (H-reverted after an
|
|
2313
|
-
invalidating control-side rotation, then skipped by their own
|
|
2314
|
-
later gate because _invalidate_for_gate's Case B already popped
|
|
2315
|
-
_pending_skip to decide what to skip -- consuming that record
|
|
2316
|
-
before it could ever reach measurement time), force those
|
|
2317
|
-
specific replicas to match hq[0] directly.
|
|
2318
|
-
|
|
2319
|
-
NOTE: this deliberately does NOT read _pending_skip, because
|
|
2320
|
-
_invalidate_for_gate's Case B already pops (consumes) it the
|
|
2321
|
-
moment the boundary qubit's own next gate runs -- by the time
|
|
2322
|
-
prob()/m() is called at actual measurement time, _pending_skip is
|
|
2323
|
-
already empty even though the replicas never got their intended
|
|
2324
|
-
rotation. _stale_replicas is a SEPARATE record, populated
|
|
2325
|
-
alongside _pending_skip in _revert_shadow_commitment, that is
|
|
2326
|
-
NOT touched by Case B's pop -- only by this method, at the point
|
|
2327
|
-
where staleness actually needs to be resolved.
|
|
2328
|
-
|
|
2329
|
-
Forcing to match hq[0] requires no randomness (unlike an earlier
|
|
2330
|
-
force-correlate-with-control attempt) because hq[0] -- the
|
|
2331
|
-
replica sharing a real simulator with the control, via the exact
|
|
2332
|
-
gate_fn path in _apply_coupling -- is never itself added to
|
|
2333
|
-
shadow_targets/_pending_skip/_stale_replicas, and is verified
|
|
2334
|
-
exact following the _ct_pair_prob/_cz_shadow phase-kickback fix."""
|
|
2335
|
-
if self._stale_replicas is None:
|
|
2336
|
-
return
|
|
2337
|
-
stale = self._stale_replicas.pop(lq, None)
|
|
2338
|
-
if not stale:
|
|
2339
|
-
return
|
|
2340
|
-
hq = self._unpack(lq)
|
|
2341
|
-
b0 = hq[0]
|
|
2342
|
-
ground_truth = self.sim[b0[0]].m(b0[1])
|
|
2343
|
-
for (t_sim, t_idx) in stale:
|
|
2344
|
-
self.sim[t_sim].force_m(t_idx, ground_truth)
|
|
2345
|
-
|
|
2346
|
-
def _resolve_witnessed_shadow(self, lq):
|
|
2347
|
-
"""The 'easy case' generalization of history_window: if lq has any
|
|
2348
|
-
shadow replicas with a recorded witness (a replica of the SAME
|
|
2349
|
-
logical qubit living in the SAME simulator as the control used for
|
|
2350
|
-
that shadow coupling), force each one to match its witness's
|
|
2351
|
-
CURRENT value now, unconditionally.
|
|
2352
|
-
|
|
2353
|
-
This is deliberately unbounded -- no history_window, no deque, no
|
|
2354
|
-
reactive invalidation on the control's later gates at all. It
|
|
2355
|
-
doesn't need any of that, because the witness is a real quantum
|
|
2356
|
-
register: it automatically, continuously reflects the correct
|
|
2357
|
-
joint state through ANY NUMBER of intervening gates on the
|
|
2358
|
-
control (or on itself), for free, simply by being the same real
|
|
2359
|
-
simulator. No matter how long resolution is deferred -- one gate
|
|
2360
|
-
later or a thousand -- matching the witness at the moment it's
|
|
2361
|
-
actually needed is exactly as correct as matching it immediately
|
|
2362
|
-
would have been. This is why the fix for the 'easy case' doesn't
|
|
2363
|
-
need a window at all, bounded or otherwise: unlike the harder,
|
|
2364
|
-
no-witness case (still handled by the existing bounded
|
|
2365
|
-
_coupling_history / _stale_replicas machinery, left for a
|
|
2366
|
-
belief-propagation-style treatment another day), there's no
|
|
2367
|
-
approximation being deferred here, so there's nothing for a
|
|
2368
|
-
window size to trade off against."""
|
|
2369
|
-
if self._witness_map is None:
|
|
2370
|
-
return
|
|
2371
|
-
wmap = self._witness_map.pop(lq, None)
|
|
2372
|
-
if not wmap:
|
|
2373
|
-
return
|
|
2374
|
-
for (t_sim, t_idx), (w_sim, w_idx) in wmap.items():
|
|
2375
|
-
ground_truth = self.sim[w_sim].m(w_idx)
|
|
2376
|
-
self.sim[t_sim].force_m(t_idx, ground_truth)
|
|
2377
|
-
|
|
2378
2121
|
def prob(self, lq):
|
|
2379
2122
|
hq = self._unpack(lq)
|
|
2380
2123
|
if len(hq) < 2:
|
|
2381
2124
|
b = hq[0]
|
|
2382
2125
|
return self.sim[b[0]].prob(b[1])
|
|
2383
2126
|
|
|
2384
|
-
if self._witness_map is not None:
|
|
2385
|
-
self._resolve_witnessed_shadow(lq)
|
|
2386
|
-
|
|
2387
|
-
if self._stale_replicas is not None:
|
|
2388
|
-
self._resolve_pending_skip(lq)
|
|
2389
|
-
|
|
2390
2127
|
self._correct(lq)
|
|
2391
2128
|
if len(hq) == 5:
|
|
2392
2129
|
# RMS
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{pyqrack_cpu_complex128-2.21.2 → pyqrack_cpu_complex128-2.22.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.21.2 → pyqrack_cpu_complex128-2.22.0}/pyqrack/qrack_neuron_torch_layer.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{pyqrack_cpu_complex128-2.21.2 → pyqrack_cpu_complex128-2.22.0}/pyqrack/qrack_system/__init__.py
RENAMED
|
File without changes
|
{pyqrack_cpu_complex128-2.21.2 → pyqrack_cpu_complex128-2.22.0}/pyqrack/qrack_system/qrack_system.py
RENAMED
|
File without changes
|
{pyqrack_cpu_complex128-2.21.2 → pyqrack_cpu_complex128-2.22.0}/pyqrack/quimb_circuit_type.py
RENAMED
|
File without changes
|
|
File without changes
|
{pyqrack_cpu_complex128-2.21.2 → pyqrack_cpu_complex128-2.22.0}/pyqrack/stats/load_quantized_data.py
RENAMED
|
File without changes
|
{pyqrack_cpu_complex128-2.21.2 → pyqrack_cpu_complex128-2.22.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
|