pyqrack-cuda 1.55.4__tar.gz → 1.57.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_cuda-1.55.4/pyqrack_cuda.egg-info → pyqrack_cuda-1.57.0}/PKG-INFO +1 -1
- {pyqrack_cuda-1.55.4 → pyqrack_cuda-1.57.0}/pyqrack/qrack_ace_backend.py +334 -241
- {pyqrack_cuda-1.55.4 → pyqrack_cuda-1.57.0}/pyqrack/qrack_simulator.py +1 -1
- {pyqrack_cuda-1.55.4 → pyqrack_cuda-1.57.0/pyqrack_cuda.egg-info}/PKG-INFO +1 -1
- {pyqrack_cuda-1.55.4 → pyqrack_cuda-1.57.0}/setup.py +1 -1
- {pyqrack_cuda-1.55.4 → pyqrack_cuda-1.57.0}/LICENSE +0 -0
- {pyqrack_cuda-1.55.4 → pyqrack_cuda-1.57.0}/MANIFEST.in +0 -0
- {pyqrack_cuda-1.55.4 → pyqrack_cuda-1.57.0}/Makefile +0 -0
- {pyqrack_cuda-1.55.4 → pyqrack_cuda-1.57.0}/README.md +0 -0
- {pyqrack_cuda-1.55.4 → pyqrack_cuda-1.57.0}/pyproject.toml +0 -0
- {pyqrack_cuda-1.55.4 → pyqrack_cuda-1.57.0}/pyqrack/__init__.py +0 -0
- {pyqrack_cuda-1.55.4 → pyqrack_cuda-1.57.0}/pyqrack/neuron_activation_fn.py +0 -0
- {pyqrack_cuda-1.55.4 → pyqrack_cuda-1.57.0}/pyqrack/pauli.py +0 -0
- {pyqrack_cuda-1.55.4 → pyqrack_cuda-1.57.0}/pyqrack/qrack_circuit.py +0 -0
- {pyqrack_cuda-1.55.4 → pyqrack_cuda-1.57.0}/pyqrack/qrack_neuron.py +0 -0
- {pyqrack_cuda-1.55.4 → pyqrack_cuda-1.57.0}/pyqrack/qrack_neuron_torch_layer.py +0 -0
- {pyqrack_cuda-1.55.4 → pyqrack_cuda-1.57.0}/pyqrack/qrack_stabilizer.py +0 -0
- {pyqrack_cuda-1.55.4 → pyqrack_cuda-1.57.0}/pyqrack/qrack_system/__init__.py +0 -0
- {pyqrack_cuda-1.55.4 → pyqrack_cuda-1.57.0}/pyqrack/qrack_system/qrack_system.py +0 -0
- {pyqrack_cuda-1.55.4 → pyqrack_cuda-1.57.0}/pyqrack/quimb_circuit_type.py +0 -0
- {pyqrack_cuda-1.55.4 → pyqrack_cuda-1.57.0}/pyqrack/stats/__init__.py +0 -0
- {pyqrack_cuda-1.55.4 → pyqrack_cuda-1.57.0}/pyqrack/stats/load_quantized_data.py +0 -0
- {pyqrack_cuda-1.55.4 → pyqrack_cuda-1.57.0}/pyqrack/stats/quantize_by_range.py +0 -0
- {pyqrack_cuda-1.55.4 → pyqrack_cuda-1.57.0}/pyqrack_cuda.egg-info/SOURCES.txt +0 -0
- {pyqrack_cuda-1.55.4 → pyqrack_cuda-1.57.0}/pyqrack_cuda.egg-info/dependency_links.txt +0 -0
- {pyqrack_cuda-1.55.4 → pyqrack_cuda-1.57.0}/pyqrack_cuda.egg-info/not-zip-safe +0 -0
- {pyqrack_cuda-1.55.4 → pyqrack_cuda-1.57.0}/pyqrack_cuda.egg-info/requires.txt +0 -0
- {pyqrack_cuda-1.55.4 → pyqrack_cuda-1.57.0}/pyqrack_cuda.egg-info/top_level.txt +0 -0
- {pyqrack_cuda-1.55.4 → pyqrack_cuda-1.57.0}/setup.cfg +0 -0
@@ -168,16 +168,27 @@ class QrackAceBackend:
|
|
168
168
|
def __init__(
|
169
169
|
self,
|
170
170
|
qubit_count=1,
|
171
|
-
long_range_columns=
|
171
|
+
long_range_columns=5,
|
172
|
+
long_range_rows=2,
|
172
173
|
is_transpose=False,
|
173
174
|
isTensorNetwork=False,
|
175
|
+
isSchmidtDecomposeMulti=False,
|
176
|
+
isSchmidtDecompose=True,
|
174
177
|
isStabilizerHybrid=False,
|
175
178
|
isBinaryDecisionTree=False,
|
179
|
+
isPaged=True,
|
180
|
+
isCpuGpuHybrid=True,
|
181
|
+
isOpenCL=True,
|
182
|
+
isHostPointer=(
|
183
|
+
True if os.environ.get("PYQRACK_HOST_POINTER_DEFAULT_ON") else False
|
184
|
+
),
|
185
|
+
noise=0,
|
176
186
|
toClone=None,
|
177
187
|
):
|
178
188
|
if toClone:
|
179
189
|
qubit_count = toClone.num_qubits()
|
180
190
|
long_range_columns = toClone.long_range_columns
|
191
|
+
long_range_rows = toClone.long_range_rows
|
181
192
|
is_transpose = toClone.is_transpose
|
182
193
|
if qubit_count < 0:
|
183
194
|
qubit_count = 0
|
@@ -186,6 +197,7 @@ class QrackAceBackend:
|
|
186
197
|
|
187
198
|
self._factor_width(qubit_count, is_transpose)
|
188
199
|
self.long_range_columns = long_range_columns
|
200
|
+
self.long_range_rows = long_range_rows
|
189
201
|
self.is_transpose = is_transpose
|
190
202
|
|
191
203
|
fppow = 5
|
@@ -200,57 +212,86 @@ class QrackAceBackend:
|
|
200
212
|
|
201
213
|
self._coupling_map = None
|
202
214
|
|
203
|
-
# If there's only one or zero "False" columns,
|
215
|
+
# If there's only one or zero "False" columns or rows,
|
204
216
|
# the entire simulator is connected, anyway.
|
205
217
|
len_col_seq = long_range_columns + 1
|
206
|
-
|
207
|
-
if (long_range_columns + 1) >= self._row_length:
|
218
|
+
col_patch_count = (self._row_length + len_col_seq - 1) // len_col_seq
|
219
|
+
if (self._row_length < 3) or ((long_range_columns + 1) >= self._row_length):
|
208
220
|
self._is_col_long_range = [True] * self._row_length
|
209
221
|
else:
|
210
222
|
col_seq = [True] * long_range_columns + [False]
|
211
|
-
self._is_col_long_range = (col_seq *
|
223
|
+
self._is_col_long_range = (col_seq * col_patch_count)[: self._row_length]
|
212
224
|
if long_range_columns < self._row_length:
|
213
225
|
self._is_col_long_range[-1] = False
|
226
|
+
len_row_seq = long_range_rows + 1
|
227
|
+
row_patch_count = (self._col_length + len_row_seq - 1) // len_row_seq
|
228
|
+
if (self._col_length < 3) or ((long_range_rows + 1) >= self._col_length):
|
229
|
+
self._is_row_long_range = [True] * self._col_length
|
230
|
+
else:
|
231
|
+
row_seq = [True] * long_range_rows + [False]
|
232
|
+
self._is_row_long_range = (row_seq * row_patch_count)[: self._col_length]
|
233
|
+
if long_range_rows < self._col_length:
|
234
|
+
self._is_row_long_range[-1] = False
|
235
|
+
sim_count = col_patch_count * row_patch_count
|
236
|
+
self._row_offset = 0
|
237
|
+
for r in range(self._col_length):
|
238
|
+
for c in self._is_col_long_range:
|
239
|
+
self._row_offset += 1 if c else 3
|
214
240
|
|
215
241
|
self._qubit_dict = {}
|
216
|
-
self._lhv_dict = {}
|
217
|
-
self._hardware_offset = []
|
218
242
|
sim_counts = [0] * sim_count
|
219
243
|
sim_id = 0
|
220
244
|
tot_qubits = 0
|
221
|
-
for r in
|
245
|
+
for r in self._is_row_long_range:
|
222
246
|
for c in self._is_col_long_range:
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
|
247
|
+
qubit = [(sim_id, sim_counts[sim_id])]
|
248
|
+
sim_counts[sim_id] += 1
|
249
|
+
|
250
|
+
if (not c) or (not r):
|
251
|
+
t_sim_id = (sim_id + 1) % sim_count
|
252
|
+
qubit.append((t_sim_id, sim_counts[t_sim_id]))
|
253
|
+
sim_counts[t_sim_id] += 1
|
254
|
+
|
255
|
+
qubit.append(
|
256
|
+
LHVQubit(
|
257
|
+
toClone=(
|
258
|
+
toClone._qubit_dict[tot_qubits][2] if toClone else None
|
259
|
+
)
|
260
|
+
)
|
235
261
|
)
|
236
|
-
tot_qubits += 1
|
237
262
|
|
263
|
+
if (not c) and (not r):
|
264
|
+
t_sim_id = (sim_id + col_patch_count) % sim_count
|
265
|
+
qubit.append((t_sim_id, sim_counts[t_sim_id]))
|
266
|
+
sim_counts[t_sim_id] += 1
|
267
|
+
|
268
|
+
t_sim_id = (t_sim_id + 1) % sim_count
|
269
|
+
qubit.append((t_sim_id, sim_counts[t_sim_id]))
|
270
|
+
sim_counts[t_sim_id] += 1
|
271
|
+
|
272
|
+
if not c:
|
238
273
|
sim_id = (sim_id + 1) % sim_count
|
239
|
-
|
240
|
-
|
241
|
-
|
274
|
+
|
275
|
+
self._qubit_dict[tot_qubits] = qubit
|
276
|
+
tot_qubits += 1
|
242
277
|
|
243
278
|
self.sim = []
|
244
279
|
for i in range(sim_count):
|
245
|
-
sim_counts[i] += 1
|
246
280
|
self.sim.append(
|
247
281
|
toClone.sim[i].clone()
|
248
282
|
if toClone
|
249
283
|
else QrackSimulator(
|
250
284
|
sim_counts[i],
|
251
285
|
isTensorNetwork=isTensorNetwork,
|
286
|
+
isSchmidtDecomposeMulti=isSchmidtDecomposeMulti,
|
287
|
+
isSchmidtDecompose=isSchmidtDecompose,
|
252
288
|
isStabilizerHybrid=isStabilizerHybrid,
|
253
289
|
isBinaryDecisionTree=isBinaryDecisionTree,
|
290
|
+
isPaged=isPaged,
|
291
|
+
isCpuGpuHybrid=isCpuGpuHybrid,
|
292
|
+
isOpenCL=isOpenCL,
|
293
|
+
isHostPointer=isHostPointer,
|
294
|
+
noise=noise,
|
254
295
|
)
|
255
296
|
)
|
256
297
|
|
@@ -347,57 +388,97 @@ class QrackAceBackend:
|
|
347
388
|
self._qec_x(c)
|
348
389
|
|
349
390
|
def _unpack(self, lq):
|
350
|
-
|
391
|
+
return self._qubit_dict[lq]
|
351
392
|
|
352
|
-
|
353
|
-
|
393
|
+
def _get_qb_lhv_indices(self, hq):
|
394
|
+
qb = []
|
395
|
+
if len(hq) < 2:
|
396
|
+
qb = [0]
|
397
|
+
lhv = -1
|
398
|
+
elif len(hq) < 4:
|
399
|
+
qb = [0, 1]
|
400
|
+
lhv = 2
|
401
|
+
else:
|
402
|
+
qb = [0, 1, 3, 4]
|
403
|
+
lhv = 2
|
354
404
|
|
355
|
-
return
|
356
|
-
self._qubit_dict[offset],
|
357
|
-
self._lhv_dict[offset + 1],
|
358
|
-
self._qubit_dict[offset + 2],
|
359
|
-
]
|
405
|
+
return qb, lhv
|
360
406
|
|
361
407
|
def _correct(self, lq, phase=False):
|
362
|
-
|
408
|
+
hq = self._unpack(lq)
|
409
|
+
|
410
|
+
if len(hq) == 1:
|
363
411
|
return
|
364
412
|
|
365
|
-
|
413
|
+
qb, lhv = self._get_qb_lhv_indices(hq)
|
366
414
|
|
367
415
|
if phase:
|
368
|
-
|
369
|
-
|
370
|
-
|
416
|
+
for q in qb:
|
417
|
+
b = hq[q]
|
418
|
+
self.sim[b[0]].h(b[1])
|
419
|
+
b = hq[lhv]
|
371
420
|
b.h()
|
372
|
-
b = hq[2]
|
373
|
-
self.sim[b[0]].h(b[1])
|
374
421
|
|
375
|
-
|
376
|
-
|
377
|
-
|
378
|
-
|
379
|
-
|
380
|
-
|
381
|
-
|
382
|
-
|
383
|
-
|
384
|
-
|
385
|
-
|
386
|
-
|
387
|
-
|
388
|
-
|
389
|
-
|
390
|
-
|
391
|
-
|
392
|
-
|
422
|
+
if len(hq) == 5:
|
423
|
+
# RMS
|
424
|
+
p = [
|
425
|
+
self.sim[hq[0][0]].prob(hq[0][1]),
|
426
|
+
self.sim[hq[1][0]].prob(hq[1][1]),
|
427
|
+
hq[2].prob(),
|
428
|
+
self.sim[hq[3][0]].prob(hq[3][1]),
|
429
|
+
self.sim[hq[4][0]].prob(hq[4][1]),
|
430
|
+
]
|
431
|
+
# Balancing suggestion from Elara (the custom OpenAI GPT)
|
432
|
+
prms = math.sqrt(
|
433
|
+
(p[0] ** 2 + p[1] ** 2 + 3 * (p[2] ** 2) + p[3] ** 2 + p[4] ** 2) / 7
|
434
|
+
)
|
435
|
+
qrms = math.sqrt(
|
436
|
+
(
|
437
|
+
(1 - p[0]) ** 2
|
438
|
+
+ (1 - p[1]) ** 2
|
439
|
+
+ 3 * ((1 - p[2]) ** 2)
|
440
|
+
+ (1 - p[3]) ** 2
|
441
|
+
+ (1 - p[4]) ** 2
|
442
|
+
)
|
443
|
+
/ 7
|
444
|
+
)
|
445
|
+
result = ((prms + (1 - qrms)) / 2) >= 0.5
|
446
|
+
syndrome = (
|
447
|
+
[1 - p[0], 1 - p[1], 1 - p[2], 1 - p[3], 1 - p[4]]
|
448
|
+
if result
|
449
|
+
else [p[0], p[1], p[2], p[3], p[4]]
|
450
|
+
)
|
451
|
+
for q in range(5):
|
452
|
+
if syndrome[q] > (0.5 + self._epsilon):
|
453
|
+
if q == 2:
|
454
|
+
hq[q].x()
|
455
|
+
else:
|
456
|
+
self.sim[hq[q][0]].x(hq[q][1])
|
457
|
+
else:
|
458
|
+
# RMS
|
459
|
+
p = [
|
460
|
+
self.sim[hq[0][0]].prob(hq[0][1]),
|
461
|
+
self.sim[hq[1][0]].prob(hq[1][1]),
|
462
|
+
hq[2].prob(),
|
463
|
+
]
|
464
|
+
# Balancing suggestion from Elara (the custom OpenAI GPT)
|
465
|
+
prms = math.sqrt((p[0] ** 2 + p[1] ** 2 + p[2] ** 2) / 3)
|
466
|
+
qrms = math.sqrt(((1 - p[0]) ** 2 + (1 - p[1]) ** 2 + (1 - p[2]) ** 2) / 3)
|
467
|
+
result = ((prms + (1 - qrms)) / 2) >= 0.5
|
468
|
+
syndrome = [1 - p[0], 1 - p[1], 1 - p[2]] if result else [p[0], p[1], p[2]]
|
469
|
+
for q in range(3):
|
470
|
+
if syndrome[q] > (0.5 + self._epsilon):
|
471
|
+
if q == 2:
|
472
|
+
hq[q].x()
|
473
|
+
else:
|
474
|
+
self.sim[hq[q][0]].x(hq[q][1])
|
393
475
|
|
394
476
|
if phase:
|
395
|
-
|
396
|
-
|
397
|
-
|
477
|
+
for q in qb:
|
478
|
+
b = hq[q]
|
479
|
+
self.sim[b[0]].h(b[1])
|
480
|
+
b = hq[lhv]
|
398
481
|
b.h()
|
399
|
-
b = hq[2]
|
400
|
-
self.sim[b[0]].h(b[1])
|
401
482
|
|
402
483
|
def u(self, lq, th, ph, lm):
|
403
484
|
hq = self._unpack(lq)
|
@@ -406,12 +487,14 @@ class QrackAceBackend:
|
|
406
487
|
self.sim[b[0]].u(b[1], th, ph, lm)
|
407
488
|
return
|
408
489
|
|
409
|
-
|
410
|
-
|
411
|
-
|
490
|
+
qb, lhv = self._get_qb_lhv_indices(hq)
|
491
|
+
|
492
|
+
for q in qb:
|
493
|
+
b = hq[q]
|
494
|
+
self.sim[b[0]].u(b[1], th, ph, lm)
|
495
|
+
|
496
|
+
b = hq[lhv]
|
412
497
|
b.u(th, ph, lm)
|
413
|
-
b = hq[2]
|
414
|
-
self.sim[b[0]].u(b[1], th, ph, lm)
|
415
498
|
|
416
499
|
self._correct(lq, False)
|
417
500
|
self._correct(lq, True)
|
@@ -423,17 +506,19 @@ class QrackAceBackend:
|
|
423
506
|
self.sim[b[0]].r(p, th, b[1])
|
424
507
|
return
|
425
508
|
|
426
|
-
|
427
|
-
|
428
|
-
|
509
|
+
qb, lhv = self._get_qb_lhv_indices(hq)
|
510
|
+
|
511
|
+
for q in qb:
|
512
|
+
b = hq[q]
|
513
|
+
self.sim[b[0]].r(p, th, b[1])
|
514
|
+
|
515
|
+
b = hq[lhv]
|
429
516
|
if p == Pauli.PauliX:
|
430
517
|
b.rx(th)
|
431
518
|
elif p == Pauli.PauliY:
|
432
519
|
b.ry(th)
|
433
520
|
elif p == Pauli.PauliZ:
|
434
521
|
b.rz(th)
|
435
|
-
b = hq[2]
|
436
|
-
self.sim[b[0]].r(p, th, b[1])
|
437
522
|
|
438
523
|
if p != Pauli.PauliZ:
|
439
524
|
self._correct(lq, False)
|
@@ -448,12 +533,16 @@ class QrackAceBackend:
|
|
448
533
|
return
|
449
534
|
|
450
535
|
self._correct(lq)
|
451
|
-
|
452
|
-
self.
|
453
|
-
|
536
|
+
|
537
|
+
qb, lhv = self._get_qb_lhv_indices(hq)
|
538
|
+
|
539
|
+
for q in qb:
|
540
|
+
b = hq[q]
|
541
|
+
self.sim[b[0]].h(b[1])
|
542
|
+
|
543
|
+
b = hq[lhv]
|
454
544
|
b.h()
|
455
|
-
|
456
|
-
self.sim[b[0]].h(b[1])
|
545
|
+
|
457
546
|
self._correct(lq)
|
458
547
|
|
459
548
|
def s(self, lq):
|
@@ -463,12 +552,14 @@ class QrackAceBackend:
|
|
463
552
|
self.sim[b[0]].s(b[1])
|
464
553
|
return
|
465
554
|
|
466
|
-
|
467
|
-
|
468
|
-
|
555
|
+
qb, lhv = self._get_qb_lhv_indices(hq)
|
556
|
+
|
557
|
+
for q in qb:
|
558
|
+
b = hq[q]
|
559
|
+
self.sim[b[0]].s(b[1])
|
560
|
+
|
561
|
+
b = hq[lhv]
|
469
562
|
b.s()
|
470
|
-
b = hq[2]
|
471
|
-
self.sim[b[0]].s(b[1])
|
472
563
|
|
473
564
|
def adjs(self, lq):
|
474
565
|
hq = self._unpack(lq)
|
@@ -477,12 +568,14 @@ class QrackAceBackend:
|
|
477
568
|
self.sim[b[0]].adjs(b[1])
|
478
569
|
return
|
479
570
|
|
480
|
-
|
481
|
-
|
482
|
-
|
571
|
+
qb, lhv = self._get_qb_lhv_indices(hq)
|
572
|
+
|
573
|
+
for q in qb:
|
574
|
+
b = hq[q]
|
575
|
+
self.sim[b[0]].adjs(b[1])
|
576
|
+
|
577
|
+
b = hq[lhv]
|
483
578
|
b.adjs()
|
484
|
-
b = hq[2]
|
485
|
-
self.sim[b[0]].adjs(b[1])
|
486
579
|
|
487
580
|
def x(self, lq):
|
488
581
|
hq = self._unpack(lq)
|
@@ -491,12 +584,14 @@ class QrackAceBackend:
|
|
491
584
|
self.sim[b[0]].x(b[1])
|
492
585
|
return
|
493
586
|
|
494
|
-
|
495
|
-
|
496
|
-
|
587
|
+
qb, lhv = self._get_qb_lhv_indices(hq)
|
588
|
+
|
589
|
+
for q in qb:
|
590
|
+
b = hq[q]
|
591
|
+
self.sim[b[0]].x(b[1])
|
592
|
+
|
593
|
+
b = hq[lhv]
|
497
594
|
b.x()
|
498
|
-
b = hq[2]
|
499
|
-
self.sim[b[0]].x(b[1])
|
500
595
|
|
501
596
|
def y(self, lq):
|
502
597
|
hq = self._unpack(lq)
|
@@ -505,12 +600,14 @@ class QrackAceBackend:
|
|
505
600
|
self.sim[b[0]].y(b[1])
|
506
601
|
return
|
507
602
|
|
508
|
-
|
509
|
-
|
510
|
-
|
603
|
+
qb, lhv = self._get_qb_lhv_indices(hq)
|
604
|
+
|
605
|
+
for q in qb:
|
606
|
+
b = hq[q]
|
607
|
+
self.sim[b[0]].y(b[1])
|
608
|
+
|
609
|
+
b = hq[lhv]
|
511
610
|
b.y()
|
512
|
-
b = hq[2]
|
513
|
-
self.sim[b[0]].y(b[1])
|
514
611
|
|
515
612
|
def z(self, lq):
|
516
613
|
hq = self._unpack(lq)
|
@@ -519,12 +616,14 @@ class QrackAceBackend:
|
|
519
616
|
self.sim[b[0]].z(b[1])
|
520
617
|
return
|
521
618
|
|
522
|
-
|
523
|
-
|
524
|
-
|
619
|
+
qb, lhv = self._get_qb_lhv_indices(hq)
|
620
|
+
|
621
|
+
for q in qb:
|
622
|
+
b = hq[q]
|
623
|
+
self.sim[b[0]].z(b[1])
|
624
|
+
|
625
|
+
b = hq[lhv]
|
525
626
|
b.z()
|
526
|
-
b = hq[2]
|
527
|
-
self.sim[b[0]].z(b[1])
|
528
627
|
|
529
628
|
def t(self, lq):
|
530
629
|
hq = self._unpack(lq)
|
@@ -533,12 +632,14 @@ class QrackAceBackend:
|
|
533
632
|
self.sim[b[0]].t(b[1])
|
534
633
|
return
|
535
634
|
|
536
|
-
|
537
|
-
|
538
|
-
|
635
|
+
qb, lhv = self._get_qb_lhv_indices(hq)
|
636
|
+
|
637
|
+
for q in qb:
|
638
|
+
b = hq[q]
|
639
|
+
self.sim[b[0]].t(b[1])
|
640
|
+
|
641
|
+
b = hq[lhv]
|
539
642
|
b.t()
|
540
|
-
b = hq[2]
|
541
|
-
self.sim[b[0]].t(b[1])
|
542
643
|
|
543
644
|
def adjt(self, lq):
|
544
645
|
hq = self._unpack(lq)
|
@@ -547,12 +648,14 @@ class QrackAceBackend:
|
|
547
648
|
self.sim[b[0]].adjt(b[1])
|
548
649
|
return
|
549
650
|
|
550
|
-
|
551
|
-
|
552
|
-
|
651
|
+
qb, lhv = self._get_qb_lhv_indices(hq)
|
652
|
+
|
653
|
+
for q in qb:
|
654
|
+
b = hq[q]
|
655
|
+
self.sim[b[0]].adjt(b[1])
|
656
|
+
|
657
|
+
b = hq[lhv]
|
553
658
|
b.adjt()
|
554
|
-
b = hq[2]
|
555
|
-
self.sim[b[0]].adjt(b[1])
|
556
659
|
|
557
660
|
def _get_gate(self, pauli, anti, sim_id):
|
558
661
|
gate = None
|
@@ -573,10 +676,47 @@ class QrackAceBackend:
|
|
573
676
|
|
574
677
|
return gate, shadow
|
575
678
|
|
576
|
-
def
|
577
|
-
|
578
|
-
|
679
|
+
def _get_connected(self, i, is_row):
|
680
|
+
long_range = self._is_row_long_range if is_row else self._is_col_long_range
|
681
|
+
length = self._col_length if is_row else self._row_length
|
682
|
+
|
683
|
+
connected = [i]
|
684
|
+
c = (i - 1) % length
|
685
|
+
while long_range[c] and (len(connected) < length):
|
686
|
+
connected.append(c)
|
687
|
+
c = (c - 1) % length
|
688
|
+
if len(connected) < length:
|
689
|
+
connected.append(c)
|
690
|
+
boundary = len(connected)
|
691
|
+
c = (i + 1) % length
|
692
|
+
while long_range[c] and (len(connected) < length):
|
693
|
+
connected.append(c)
|
694
|
+
c = (c + 1) % length
|
695
|
+
if len(connected) < length:
|
696
|
+
connected.append(c)
|
697
|
+
|
698
|
+
return connected, boundary
|
699
|
+
|
700
|
+
def _apply_coupling(self, pauli, anti, qb1, lhv1, hq1, qb2, lhv2, hq2, lq1_lr):
|
701
|
+
for q1 in qb1:
|
702
|
+
if q1 == lhv1:
|
703
|
+
continue
|
704
|
+
b1 = hq1[q1]
|
705
|
+
gate_fn, shadow_fn = self._get_gate(pauli, anti, b1[0])
|
706
|
+
for q2 in qb2:
|
707
|
+
if q2 == lhv2:
|
708
|
+
continue
|
709
|
+
b2 = hq2[q2]
|
710
|
+
if b1[0] == b2[0]:
|
711
|
+
gate_fn([b1[1]], b2[1])
|
712
|
+
elif (
|
713
|
+
lq1_lr
|
714
|
+
or (b1[1] == b2[1])
|
715
|
+
or ((len(qb1) == 2) and (b1[1] == (b2[1] & 1)))
|
716
|
+
):
|
717
|
+
shadow_fn(b1, b2)
|
579
718
|
|
719
|
+
def _cpauli(self, lq1, lq2, anti, pauli):
|
580
720
|
lq1_row = lq1 // self._row_length
|
581
721
|
lq1_col = lq1 % self._row_length
|
582
722
|
lq2_row = lq2 // self._row_length
|
@@ -585,6 +725,9 @@ class QrackAceBackend:
|
|
585
725
|
hq1 = self._unpack(lq1)
|
586
726
|
hq2 = self._unpack(lq2)
|
587
727
|
|
728
|
+
lq1_lr = len(hq1) == 1
|
729
|
+
lq2_lr = len(hq2) == 1
|
730
|
+
|
588
731
|
if lq1_lr and lq2_lr:
|
589
732
|
connected = (lq1_col == lq2_col) or (
|
590
733
|
(self.long_range_columns + 1) >= self._row_length
|
@@ -607,80 +750,20 @@ class QrackAceBackend:
|
|
607
750
|
shadow(b1, b2)
|
608
751
|
return
|
609
752
|
|
610
|
-
if self._row_length == 2:
|
611
|
-
gate, shadow = self._get_gate(pauli, anti, hq1[2][0])
|
612
|
-
gate([hq1[2][1]], hq2[0][1])
|
613
|
-
gate, shadow = self._get_gate(pauli, anti, hq1[0][0])
|
614
|
-
gate([hq1[0][1]], hq2[2][1])
|
615
|
-
_cpauli_lhv(hq1[1].prob(), hq2[1], pauli, anti)
|
616
|
-
return
|
617
|
-
|
618
|
-
connected_cols = []
|
619
|
-
c = (lq1_col - 1) % self._row_length
|
620
|
-
while self._is_col_long_range[c] and (
|
621
|
-
len(connected_cols) < (self._row_length - 1)
|
622
|
-
):
|
623
|
-
connected_cols.append(c)
|
624
|
-
c = (c - 1) % self._row_length
|
625
|
-
if len(connected_cols) < (self._row_length - 1):
|
626
|
-
connected_cols.append(c)
|
627
|
-
boundary = len(connected_cols)
|
628
|
-
c = (lq1_col + 1) % self._row_length
|
629
|
-
while self._is_col_long_range[c] and (
|
630
|
-
len(connected_cols) < (self._row_length - 1)
|
631
|
-
):
|
632
|
-
connected_cols.append(c)
|
633
|
-
c = (c + 1) % self._row_length
|
634
|
-
if len(connected_cols) < (self._row_length - 1):
|
635
|
-
connected_cols.append(c)
|
636
|
-
|
637
753
|
self._correct(lq1)
|
638
754
|
|
639
|
-
|
640
|
-
|
641
|
-
|
642
|
-
|
643
|
-
|
644
|
-
|
645
|
-
|
646
|
-
|
647
|
-
|
648
|
-
|
649
|
-
|
650
|
-
|
651
|
-
_cpauli_lhv(hq1[1].prob(), hq2[1], pauli, anti)
|
652
|
-
elif lq2_col in connected_cols:
|
653
|
-
# lq1_col < lq2_col
|
654
|
-
gate, shadow = self._get_gate(pauli, anti, hq2[0][0])
|
655
|
-
if lq1_lr:
|
656
|
-
gate([hq1[0][1]], hq2[0][1])
|
657
|
-
shadow(hq1[0], hq2[2])
|
658
|
-
_cpauli_lhv(self.sim[hq1[0][0]].prob(hq1[0][1]), hq2[1], pauli, anti)
|
659
|
-
elif lq2_lr:
|
660
|
-
gate([hq1[2][1]], hq2[0][1])
|
661
|
-
else:
|
662
|
-
gate([hq1[2][1]], hq2[0][1])
|
663
|
-
shadow(hq1[0], hq2[2])
|
664
|
-
_cpauli_lhv(hq1[1].prob(), hq2[1], pauli, anti)
|
665
|
-
elif lq1_col == lq2_col:
|
666
|
-
# Both are in the same boundary column.
|
667
|
-
b = hq1[0]
|
668
|
-
gate, shadow = self._get_gate(pauli, anti, b[0])
|
669
|
-
gate([b[1]], hq2[0][1])
|
670
|
-
_cpauli_lhv(hq1[1].prob(), hq2[1], pauli, anti)
|
671
|
-
b = hq1[2]
|
672
|
-
gate, shadow = self._get_gate(pauli, anti, b[0])
|
673
|
-
gate([b[1]], hq2[2][1])
|
674
|
-
else:
|
675
|
-
# The qubits have no quantum connection.
|
676
|
-
gate, shadow = self._get_gate(pauli, anti, hq1[0][0])
|
677
|
-
shadow(hq1[0], hq2[0])
|
678
|
-
if lq1_lr:
|
679
|
-
shadow(hq1[0], hq2[2])
|
680
|
-
shadow(hq1[0], hq2[1])
|
681
|
-
elif not lq2_lr:
|
682
|
-
_cpauli_lhv(hq1[1].prob(), hq2[1], pauli, anti)
|
683
|
-
shadow(hq1[2], hq2[2])
|
755
|
+
qb1, lhv1 = self._get_qb_lhv_indices(hq1)
|
756
|
+
qb2, lhv2 = self._get_qb_lhv_indices(hq2)
|
757
|
+
# Apply cross coupling on hardware qubits first
|
758
|
+
self._apply_coupling(pauli, anti, qb1, lhv1, hq1, qb2, lhv2, hq2, lq1_lr)
|
759
|
+
# Apply coupling to the local-hidden-variable target
|
760
|
+
if lhv2 >= 0:
|
761
|
+
_cpauli_lhv(
|
762
|
+
hq1[lhv1].prob() if lhv1 >= 0 else self.sim[hq1[0][0]].prob(hq1[0][1]),
|
763
|
+
hq2[lhv2],
|
764
|
+
pauli,
|
765
|
+
anti,
|
766
|
+
)
|
684
767
|
|
685
768
|
self._correct(lq1, True)
|
686
769
|
if pauli != Pauli.PauliZ:
|
@@ -772,14 +855,39 @@ class QrackAceBackend:
|
|
772
855
|
return self.sim[b[0]].prob(b[1])
|
773
856
|
|
774
857
|
self._correct(lq)
|
775
|
-
|
776
|
-
|
777
|
-
|
778
|
-
|
779
|
-
|
780
|
-
|
781
|
-
|
782
|
-
|
858
|
+
if len(hq) == 5:
|
859
|
+
# RMS
|
860
|
+
p = [
|
861
|
+
self.sim[hq[0][0]].prob(hq[0][1]),
|
862
|
+
self.sim[hq[1][0]].prob(hq[1][1]),
|
863
|
+
hq[2].prob(),
|
864
|
+
self.sim[hq[3][0]].prob(hq[3][1]),
|
865
|
+
self.sim[hq[4][0]].prob(hq[4][1]),
|
866
|
+
]
|
867
|
+
# Balancing suggestion from Elara (the custom OpenAI GPT)
|
868
|
+
prms = math.sqrt(
|
869
|
+
(p[0] ** 2 + p[1] ** 2 + 3 * (p[2] ** 2) + p[3] ** 2 + p[4] ** 2) / 7
|
870
|
+
)
|
871
|
+
qrms = math.sqrt(
|
872
|
+
(
|
873
|
+
(1 - p[0]) ** 2
|
874
|
+
+ (1 - p[1]) ** 2
|
875
|
+
+ 3 * ((1 - p[2]) ** 2)
|
876
|
+
+ (1 - p[3]) ** 2
|
877
|
+
+ (1 - p[4]) ** 2
|
878
|
+
)
|
879
|
+
/ 7
|
880
|
+
)
|
881
|
+
else:
|
882
|
+
# RMS
|
883
|
+
p = [
|
884
|
+
self.sim[hq[0][0]].prob(hq[0][1]),
|
885
|
+
self.sim[hq[1][0]].prob(hq[1][1]),
|
886
|
+
hq[2].prob(),
|
887
|
+
]
|
888
|
+
# Balancing suggestion from Elara (the custom OpenAI GPT)
|
889
|
+
prms = math.sqrt((p[0] ** 2 + p[1] ** 2 + p[2] ** 2) / 3)
|
890
|
+
qrms = math.sqrt(((1 - p[0]) ** 2 + (1 - p[1]) ** 2 + (1 - p[2]) ** 2) / 3)
|
783
891
|
|
784
892
|
return (prms + (1 - qrms)) / 2
|
785
893
|
|
@@ -792,44 +900,47 @@ class QrackAceBackend:
|
|
792
900
|
p = self.prob(lq)
|
793
901
|
result = ((p + self._epsilon) >= 1) or (random.random() < p)
|
794
902
|
|
795
|
-
|
796
|
-
p = self.sim[b[0]].prob(b[1]) if result else (1 - self.sim[b[0]].prob(b[1]))
|
797
|
-
if p < self._epsilon:
|
798
|
-
if self.sim[b[0]].m(b[1]) != result:
|
799
|
-
self.sim[b[0]].x(b[1])
|
800
|
-
else:
|
801
|
-
self.sim[b[0]].force_m(b[1], result)
|
903
|
+
qb, lhv = self._get_qb_lhv_indices(hq)
|
802
904
|
|
803
|
-
|
905
|
+
for q in qb:
|
906
|
+
b = hq[q]
|
907
|
+
p = self.sim[b[0]].prob(b[1]) if result else (1 - self.sim[b[0]].prob(b[1]))
|
908
|
+
if p < self._epsilon:
|
909
|
+
if self.sim[b[0]].m(b[1]) != result:
|
910
|
+
self.sim[b[0]].x(b[1])
|
911
|
+
else:
|
912
|
+
self.sim[b[0]].force_m(b[1], result)
|
913
|
+
|
914
|
+
b = hq[lhv]
|
804
915
|
b.reset()
|
805
916
|
if result:
|
806
917
|
b.x()
|
807
918
|
|
808
|
-
b = hq[2]
|
809
|
-
p = self.sim[b[0]].prob(b[1]) if result else (1 - self.sim[b[0]].prob(b[1]))
|
810
|
-
if p < self._epsilon:
|
811
|
-
if self.sim[b[0]].m(b[1]) != result:
|
812
|
-
self.sim[b[0]].x(b[1])
|
813
|
-
else:
|
814
|
-
self.sim[b[0]].force_m(b[1], result)
|
815
|
-
|
816
919
|
return result
|
817
920
|
|
818
|
-
def force_m(self, lq,
|
921
|
+
def force_m(self, lq, result):
|
819
922
|
hq = self._unpack(lq)
|
820
923
|
if len(hq) < 2:
|
821
924
|
b = hq[0]
|
822
|
-
return self.sim[b[0]].force_m(b[1])
|
925
|
+
return self.sim[b[0]].force_m(b[1], result)
|
823
926
|
|
824
927
|
self._correct(lq)
|
928
|
+
|
929
|
+
qb, lhv = self._get_qb_lhv_indices(hq)
|
930
|
+
|
931
|
+
for q in qb:
|
932
|
+
b = hq[q]
|
933
|
+
p = self.sim[b[0]].prob(b[1]) if result else (1 - self.sim[b[0]].prob(b[1]))
|
934
|
+
if p < self._epsilon:
|
935
|
+
if self.sim[b[0]].m(b[1]) != result:
|
936
|
+
self.sim[b[0]].x(b[1])
|
937
|
+
else:
|
938
|
+
self.sim[b[0]].force_m(b[1], result)
|
939
|
+
|
825
940
|
b = hq[1]
|
826
941
|
b.reset()
|
827
|
-
if
|
942
|
+
if result:
|
828
943
|
b.x()
|
829
|
-
b = hq[0]
|
830
|
-
self.sim[b[0]].force_m(b[1], c)
|
831
|
-
b = hq[2]
|
832
|
-
self.sim[b[0]].force_m(b[1], c)
|
833
944
|
|
834
945
|
return c
|
835
946
|
|
@@ -1212,28 +1323,12 @@ class QrackAceBackend:
|
|
1212
1323
|
return row * cols + col
|
1213
1324
|
|
1214
1325
|
for col in range(cols):
|
1215
|
-
connected_cols =
|
1216
|
-
c = (col - 1) % cols
|
1217
|
-
while self._is_col_long_range[c] and (
|
1218
|
-
len(connected_cols) < self._row_length
|
1219
|
-
):
|
1220
|
-
connected_cols.append(c)
|
1221
|
-
c = (c - 1) % cols
|
1222
|
-
if len(connected_cols) < self._row_length:
|
1223
|
-
connected_cols.append(c)
|
1224
|
-
c = (col + 1) % cols
|
1225
|
-
while self._is_col_long_range[c] and (
|
1226
|
-
len(connected_cols) < self._row_length
|
1227
|
-
):
|
1228
|
-
connected_cols.append(c)
|
1229
|
-
c = (c + 1) % cols
|
1230
|
-
if len(connected_cols) < self._row_length:
|
1231
|
-
connected_cols.append(c)
|
1232
|
-
|
1326
|
+
connected_cols, _ = self._get_connected(col, False)
|
1233
1327
|
for row in range(rows):
|
1328
|
+
connected_rows, _ = self._get_connected(row, False)
|
1234
1329
|
a = logical_index(row, col)
|
1235
1330
|
for c in connected_cols:
|
1236
|
-
for r in
|
1331
|
+
for r in connected_rows:
|
1237
1332
|
b = logical_index(r, c)
|
1238
1333
|
if a != b:
|
1239
1334
|
coupling_map.add((a, b))
|
@@ -1259,9 +1354,7 @@ class QrackAceBackend:
|
|
1259
1354
|
if is_long_a and is_long_b:
|
1260
1355
|
continue # No noise on long-to-long
|
1261
1356
|
|
1262
|
-
|
1263
|
-
|
1264
|
-
if same_col:
|
1357
|
+
if (col_a == col_b) or (row_a == row_b):
|
1265
1358
|
continue # No noise for same column
|
1266
1359
|
|
1267
1360
|
if is_long_a or is_long_b:
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|