pyqrack-cuda 1.56.0__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.56.0/pyqrack_cuda.egg-info → pyqrack_cuda-1.57.0}/PKG-INFO +1 -1
- {pyqrack_cuda-1.56.0 → pyqrack_cuda-1.57.0}/pyqrack/qrack_ace_backend.py +318 -240
- {pyqrack_cuda-1.56.0 → pyqrack_cuda-1.57.0/pyqrack_cuda.egg-info}/PKG-INFO +1 -1
- {pyqrack_cuda-1.56.0 → pyqrack_cuda-1.57.0}/setup.py +1 -1
- {pyqrack_cuda-1.56.0 → pyqrack_cuda-1.57.0}/LICENSE +0 -0
- {pyqrack_cuda-1.56.0 → pyqrack_cuda-1.57.0}/MANIFEST.in +0 -0
- {pyqrack_cuda-1.56.0 → pyqrack_cuda-1.57.0}/Makefile +0 -0
- {pyqrack_cuda-1.56.0 → pyqrack_cuda-1.57.0}/README.md +0 -0
- {pyqrack_cuda-1.56.0 → pyqrack_cuda-1.57.0}/pyproject.toml +0 -0
- {pyqrack_cuda-1.56.0 → pyqrack_cuda-1.57.0}/pyqrack/__init__.py +0 -0
- {pyqrack_cuda-1.56.0 → pyqrack_cuda-1.57.0}/pyqrack/neuron_activation_fn.py +0 -0
- {pyqrack_cuda-1.56.0 → pyqrack_cuda-1.57.0}/pyqrack/pauli.py +0 -0
- {pyqrack_cuda-1.56.0 → pyqrack_cuda-1.57.0}/pyqrack/qrack_circuit.py +0 -0
- {pyqrack_cuda-1.56.0 → pyqrack_cuda-1.57.0}/pyqrack/qrack_neuron.py +0 -0
- {pyqrack_cuda-1.56.0 → pyqrack_cuda-1.57.0}/pyqrack/qrack_neuron_torch_layer.py +0 -0
- {pyqrack_cuda-1.56.0 → pyqrack_cuda-1.57.0}/pyqrack/qrack_simulator.py +0 -0
- {pyqrack_cuda-1.56.0 → pyqrack_cuda-1.57.0}/pyqrack/qrack_stabilizer.py +0 -0
- {pyqrack_cuda-1.56.0 → pyqrack_cuda-1.57.0}/pyqrack/qrack_system/__init__.py +0 -0
- {pyqrack_cuda-1.56.0 → pyqrack_cuda-1.57.0}/pyqrack/qrack_system/qrack_system.py +0 -0
- {pyqrack_cuda-1.56.0 → pyqrack_cuda-1.57.0}/pyqrack/quimb_circuit_type.py +0 -0
- {pyqrack_cuda-1.56.0 → pyqrack_cuda-1.57.0}/pyqrack/stats/__init__.py +0 -0
- {pyqrack_cuda-1.56.0 → pyqrack_cuda-1.57.0}/pyqrack/stats/load_quantized_data.py +0 -0
- {pyqrack_cuda-1.56.0 → pyqrack_cuda-1.57.0}/pyqrack/stats/quantize_by_range.py +0 -0
- {pyqrack_cuda-1.56.0 → pyqrack_cuda-1.57.0}/pyqrack_cuda.egg-info/SOURCES.txt +0 -0
- {pyqrack_cuda-1.56.0 → pyqrack_cuda-1.57.0}/pyqrack_cuda.egg-info/dependency_links.txt +0 -0
- {pyqrack_cuda-1.56.0 → pyqrack_cuda-1.57.0}/pyqrack_cuda.egg-info/not-zip-safe +0 -0
- {pyqrack_cuda-1.56.0 → pyqrack_cuda-1.57.0}/pyqrack_cuda.egg-info/requires.txt +0 -0
- {pyqrack_cuda-1.56.0 → pyqrack_cuda-1.57.0}/pyqrack_cuda.egg-info/top_level.txt +0 -0
- {pyqrack_cuda-1.56.0 → pyqrack_cuda-1.57.0}/setup.cfg +0 -0
@@ -168,7 +168,8 @@ 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,
|
174
175
|
isSchmidtDecomposeMulti=False,
|
@@ -187,6 +188,7 @@ class QrackAceBackend:
|
|
187
188
|
if toClone:
|
188
189
|
qubit_count = toClone.num_qubits()
|
189
190
|
long_range_columns = toClone.long_range_columns
|
191
|
+
long_range_rows = toClone.long_range_rows
|
190
192
|
is_transpose = toClone.is_transpose
|
191
193
|
if qubit_count < 0:
|
192
194
|
qubit_count = 0
|
@@ -195,6 +197,7 @@ class QrackAceBackend:
|
|
195
197
|
|
196
198
|
self._factor_width(qubit_count, is_transpose)
|
197
199
|
self.long_range_columns = long_range_columns
|
200
|
+
self.long_range_rows = long_range_rows
|
198
201
|
self.is_transpose = is_transpose
|
199
202
|
|
200
203
|
fppow = 5
|
@@ -209,45 +212,68 @@ class QrackAceBackend:
|
|
209
212
|
|
210
213
|
self._coupling_map = None
|
211
214
|
|
212
|
-
# If there's only one or zero "False" columns,
|
215
|
+
# If there's only one or zero "False" columns or rows,
|
213
216
|
# the entire simulator is connected, anyway.
|
214
217
|
len_col_seq = long_range_columns + 1
|
215
|
-
|
216
|
-
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):
|
217
220
|
self._is_col_long_range = [True] * self._row_length
|
218
221
|
else:
|
219
222
|
col_seq = [True] * long_range_columns + [False]
|
220
|
-
self._is_col_long_range = (col_seq *
|
223
|
+
self._is_col_long_range = (col_seq * col_patch_count)[: self._row_length]
|
221
224
|
if long_range_columns < self._row_length:
|
222
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
|
223
240
|
|
224
241
|
self._qubit_dict = {}
|
225
|
-
self._lhv_dict = {}
|
226
|
-
self._hardware_offset = []
|
227
242
|
sim_counts = [0] * sim_count
|
228
243
|
sim_id = 0
|
229
244
|
tot_qubits = 0
|
230
|
-
for r in
|
245
|
+
for r in self._is_row_long_range:
|
231
246
|
for c in self._is_col_long_range:
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
|
236
|
-
|
237
|
-
|
238
|
-
|
239
|
-
|
240
|
-
|
241
|
-
|
242
|
-
|
243
|
-
|
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
|
+
)
|
244
261
|
)
|
245
|
-
tot_qubits += 1
|
246
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:
|
247
273
|
sim_id = (sim_id + 1) % sim_count
|
248
|
-
|
249
|
-
|
250
|
-
|
274
|
+
|
275
|
+
self._qubit_dict[tot_qubits] = qubit
|
276
|
+
tot_qubits += 1
|
251
277
|
|
252
278
|
self.sim = []
|
253
279
|
for i in range(sim_count):
|
@@ -362,57 +388,97 @@ class QrackAceBackend:
|
|
362
388
|
self._qec_x(c)
|
363
389
|
|
364
390
|
def _unpack(self, lq):
|
365
|
-
|
391
|
+
return self._qubit_dict[lq]
|
366
392
|
|
367
|
-
|
368
|
-
|
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
|
369
404
|
|
370
|
-
return
|
371
|
-
self._qubit_dict[offset],
|
372
|
-
self._lhv_dict[offset + 1],
|
373
|
-
self._qubit_dict[offset + 2],
|
374
|
-
]
|
405
|
+
return qb, lhv
|
375
406
|
|
376
407
|
def _correct(self, lq, phase=False):
|
377
|
-
|
408
|
+
hq = self._unpack(lq)
|
409
|
+
|
410
|
+
if len(hq) == 1:
|
378
411
|
return
|
379
412
|
|
380
|
-
|
413
|
+
qb, lhv = self._get_qb_lhv_indices(hq)
|
381
414
|
|
382
415
|
if phase:
|
383
|
-
|
384
|
-
|
385
|
-
|
416
|
+
for q in qb:
|
417
|
+
b = hq[q]
|
418
|
+
self.sim[b[0]].h(b[1])
|
419
|
+
b = hq[lhv]
|
386
420
|
b.h()
|
387
|
-
b = hq[2]
|
388
|
-
self.sim[b[0]].h(b[1])
|
389
421
|
|
390
|
-
|
391
|
-
|
392
|
-
|
393
|
-
|
394
|
-
|
395
|
-
|
396
|
-
|
397
|
-
|
398
|
-
|
399
|
-
|
400
|
-
|
401
|
-
|
402
|
-
|
403
|
-
|
404
|
-
|
405
|
-
|
406
|
-
|
407
|
-
|
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])
|
408
475
|
|
409
476
|
if phase:
|
410
|
-
|
411
|
-
|
412
|
-
|
477
|
+
for q in qb:
|
478
|
+
b = hq[q]
|
479
|
+
self.sim[b[0]].h(b[1])
|
480
|
+
b = hq[lhv]
|
413
481
|
b.h()
|
414
|
-
b = hq[2]
|
415
|
-
self.sim[b[0]].h(b[1])
|
416
482
|
|
417
483
|
def u(self, lq, th, ph, lm):
|
418
484
|
hq = self._unpack(lq)
|
@@ -421,12 +487,14 @@ class QrackAceBackend:
|
|
421
487
|
self.sim[b[0]].u(b[1], th, ph, lm)
|
422
488
|
return
|
423
489
|
|
424
|
-
|
425
|
-
|
426
|
-
|
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]
|
427
497
|
b.u(th, ph, lm)
|
428
|
-
b = hq[2]
|
429
|
-
self.sim[b[0]].u(b[1], th, ph, lm)
|
430
498
|
|
431
499
|
self._correct(lq, False)
|
432
500
|
self._correct(lq, True)
|
@@ -438,17 +506,19 @@ class QrackAceBackend:
|
|
438
506
|
self.sim[b[0]].r(p, th, b[1])
|
439
507
|
return
|
440
508
|
|
441
|
-
|
442
|
-
|
443
|
-
|
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]
|
444
516
|
if p == Pauli.PauliX:
|
445
517
|
b.rx(th)
|
446
518
|
elif p == Pauli.PauliY:
|
447
519
|
b.ry(th)
|
448
520
|
elif p == Pauli.PauliZ:
|
449
521
|
b.rz(th)
|
450
|
-
b = hq[2]
|
451
|
-
self.sim[b[0]].r(p, th, b[1])
|
452
522
|
|
453
523
|
if p != Pauli.PauliZ:
|
454
524
|
self._correct(lq, False)
|
@@ -463,12 +533,16 @@ class QrackAceBackend:
|
|
463
533
|
return
|
464
534
|
|
465
535
|
self._correct(lq)
|
466
|
-
|
467
|
-
self.
|
468
|
-
|
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]
|
469
544
|
b.h()
|
470
|
-
|
471
|
-
self.sim[b[0]].h(b[1])
|
545
|
+
|
472
546
|
self._correct(lq)
|
473
547
|
|
474
548
|
def s(self, lq):
|
@@ -478,12 +552,14 @@ class QrackAceBackend:
|
|
478
552
|
self.sim[b[0]].s(b[1])
|
479
553
|
return
|
480
554
|
|
481
|
-
|
482
|
-
|
483
|
-
|
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]
|
484
562
|
b.s()
|
485
|
-
b = hq[2]
|
486
|
-
self.sim[b[0]].s(b[1])
|
487
563
|
|
488
564
|
def adjs(self, lq):
|
489
565
|
hq = self._unpack(lq)
|
@@ -492,12 +568,14 @@ class QrackAceBackend:
|
|
492
568
|
self.sim[b[0]].adjs(b[1])
|
493
569
|
return
|
494
570
|
|
495
|
-
|
496
|
-
|
497
|
-
|
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]
|
498
578
|
b.adjs()
|
499
|
-
b = hq[2]
|
500
|
-
self.sim[b[0]].adjs(b[1])
|
501
579
|
|
502
580
|
def x(self, lq):
|
503
581
|
hq = self._unpack(lq)
|
@@ -506,12 +584,14 @@ class QrackAceBackend:
|
|
506
584
|
self.sim[b[0]].x(b[1])
|
507
585
|
return
|
508
586
|
|
509
|
-
|
510
|
-
|
511
|
-
|
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]
|
512
594
|
b.x()
|
513
|
-
b = hq[2]
|
514
|
-
self.sim[b[0]].x(b[1])
|
515
595
|
|
516
596
|
def y(self, lq):
|
517
597
|
hq = self._unpack(lq)
|
@@ -520,12 +600,14 @@ class QrackAceBackend:
|
|
520
600
|
self.sim[b[0]].y(b[1])
|
521
601
|
return
|
522
602
|
|
523
|
-
|
524
|
-
|
525
|
-
|
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]
|
526
610
|
b.y()
|
527
|
-
b = hq[2]
|
528
|
-
self.sim[b[0]].y(b[1])
|
529
611
|
|
530
612
|
def z(self, lq):
|
531
613
|
hq = self._unpack(lq)
|
@@ -534,12 +616,14 @@ class QrackAceBackend:
|
|
534
616
|
self.sim[b[0]].z(b[1])
|
535
617
|
return
|
536
618
|
|
537
|
-
|
538
|
-
|
539
|
-
|
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]
|
540
626
|
b.z()
|
541
|
-
b = hq[2]
|
542
|
-
self.sim[b[0]].z(b[1])
|
543
627
|
|
544
628
|
def t(self, lq):
|
545
629
|
hq = self._unpack(lq)
|
@@ -548,12 +632,14 @@ class QrackAceBackend:
|
|
548
632
|
self.sim[b[0]].t(b[1])
|
549
633
|
return
|
550
634
|
|
551
|
-
|
552
|
-
|
553
|
-
|
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]
|
554
642
|
b.t()
|
555
|
-
b = hq[2]
|
556
|
-
self.sim[b[0]].t(b[1])
|
557
643
|
|
558
644
|
def adjt(self, lq):
|
559
645
|
hq = self._unpack(lq)
|
@@ -562,12 +648,14 @@ class QrackAceBackend:
|
|
562
648
|
self.sim[b[0]].adjt(b[1])
|
563
649
|
return
|
564
650
|
|
565
|
-
|
566
|
-
|
567
|
-
|
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]
|
568
658
|
b.adjt()
|
569
|
-
b = hq[2]
|
570
|
-
self.sim[b[0]].adjt(b[1])
|
571
659
|
|
572
660
|
def _get_gate(self, pauli, anti, sim_id):
|
573
661
|
gate = None
|
@@ -588,10 +676,47 @@ class QrackAceBackend:
|
|
588
676
|
|
589
677
|
return gate, shadow
|
590
678
|
|
591
|
-
def
|
592
|
-
|
593
|
-
|
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)
|
594
718
|
|
719
|
+
def _cpauli(self, lq1, lq2, anti, pauli):
|
595
720
|
lq1_row = lq1 // self._row_length
|
596
721
|
lq1_col = lq1 % self._row_length
|
597
722
|
lq2_row = lq2 // self._row_length
|
@@ -600,6 +725,9 @@ class QrackAceBackend:
|
|
600
725
|
hq1 = self._unpack(lq1)
|
601
726
|
hq2 = self._unpack(lq2)
|
602
727
|
|
728
|
+
lq1_lr = len(hq1) == 1
|
729
|
+
lq2_lr = len(hq2) == 1
|
730
|
+
|
603
731
|
if lq1_lr and lq2_lr:
|
604
732
|
connected = (lq1_col == lq2_col) or (
|
605
733
|
(self.long_range_columns + 1) >= self._row_length
|
@@ -622,80 +750,20 @@ class QrackAceBackend:
|
|
622
750
|
shadow(b1, b2)
|
623
751
|
return
|
624
752
|
|
625
|
-
if self._row_length == 2:
|
626
|
-
gate, shadow = self._get_gate(pauli, anti, hq1[2][0])
|
627
|
-
gate([hq1[2][1]], hq2[0][1])
|
628
|
-
gate, shadow = self._get_gate(pauli, anti, hq1[0][0])
|
629
|
-
gate([hq1[0][1]], hq2[2][1])
|
630
|
-
_cpauli_lhv(hq1[1].prob(), hq2[1], pauli, anti)
|
631
|
-
return
|
632
|
-
|
633
|
-
connected_cols = []
|
634
|
-
c = (lq1_col - 1) % self._row_length
|
635
|
-
while self._is_col_long_range[c] and (
|
636
|
-
len(connected_cols) < (self._row_length - 1)
|
637
|
-
):
|
638
|
-
connected_cols.append(c)
|
639
|
-
c = (c - 1) % self._row_length
|
640
|
-
if len(connected_cols) < (self._row_length - 1):
|
641
|
-
connected_cols.append(c)
|
642
|
-
boundary = len(connected_cols)
|
643
|
-
c = (lq1_col + 1) % self._row_length
|
644
|
-
while self._is_col_long_range[c] and (
|
645
|
-
len(connected_cols) < (self._row_length - 1)
|
646
|
-
):
|
647
|
-
connected_cols.append(c)
|
648
|
-
c = (c + 1) % self._row_length
|
649
|
-
if len(connected_cols) < (self._row_length - 1):
|
650
|
-
connected_cols.append(c)
|
651
|
-
|
652
753
|
self._correct(lq1)
|
653
754
|
|
654
|
-
|
655
|
-
|
656
|
-
|
657
|
-
|
658
|
-
|
659
|
-
|
660
|
-
|
661
|
-
|
662
|
-
|
663
|
-
|
664
|
-
|
665
|
-
|
666
|
-
_cpauli_lhv(hq1[1].prob(), hq2[1], pauli, anti)
|
667
|
-
elif lq2_col in connected_cols:
|
668
|
-
# lq1_col < lq2_col
|
669
|
-
gate, shadow = self._get_gate(pauli, anti, hq2[0][0])
|
670
|
-
if lq1_lr:
|
671
|
-
gate([hq1[0][1]], hq2[0][1])
|
672
|
-
shadow(hq1[0], hq2[2])
|
673
|
-
_cpauli_lhv(self.sim[hq1[0][0]].prob(hq1[0][1]), hq2[1], pauli, anti)
|
674
|
-
elif lq2_lr:
|
675
|
-
gate([hq1[2][1]], hq2[0][1])
|
676
|
-
else:
|
677
|
-
gate([hq1[2][1]], hq2[0][1])
|
678
|
-
shadow(hq1[0], hq2[2])
|
679
|
-
_cpauli_lhv(hq1[1].prob(), hq2[1], pauli, anti)
|
680
|
-
elif lq1_col == lq2_col:
|
681
|
-
# Both are in the same boundary column.
|
682
|
-
b = hq1[0]
|
683
|
-
gate, shadow = self._get_gate(pauli, anti, b[0])
|
684
|
-
gate([b[1]], hq2[0][1])
|
685
|
-
_cpauli_lhv(hq1[1].prob(), hq2[1], pauli, anti)
|
686
|
-
b = hq1[2]
|
687
|
-
gate, shadow = self._get_gate(pauli, anti, b[0])
|
688
|
-
gate([b[1]], hq2[2][1])
|
689
|
-
else:
|
690
|
-
# The qubits have no quantum connection.
|
691
|
-
gate, shadow = self._get_gate(pauli, anti, hq1[0][0])
|
692
|
-
shadow(hq1[0], hq2[0])
|
693
|
-
if lq1_lr:
|
694
|
-
shadow(hq1[0], hq2[2])
|
695
|
-
shadow(hq1[0], hq2[1])
|
696
|
-
elif not lq2_lr:
|
697
|
-
_cpauli_lhv(hq1[1].prob(), hq2[1], pauli, anti)
|
698
|
-
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
|
+
)
|
699
767
|
|
700
768
|
self._correct(lq1, True)
|
701
769
|
if pauli != Pauli.PauliZ:
|
@@ -787,14 +855,39 @@ class QrackAceBackend:
|
|
787
855
|
return self.sim[b[0]].prob(b[1])
|
788
856
|
|
789
857
|
self._correct(lq)
|
790
|
-
|
791
|
-
|
792
|
-
|
793
|
-
|
794
|
-
|
795
|
-
|
796
|
-
|
797
|
-
|
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)
|
798
891
|
|
799
892
|
return (prms + (1 - qrms)) / 2
|
800
893
|
|
@@ -807,44 +900,47 @@ class QrackAceBackend:
|
|
807
900
|
p = self.prob(lq)
|
808
901
|
result = ((p + self._epsilon) >= 1) or (random.random() < p)
|
809
902
|
|
810
|
-
|
811
|
-
p = self.sim[b[0]].prob(b[1]) if result else (1 - self.sim[b[0]].prob(b[1]))
|
812
|
-
if p < self._epsilon:
|
813
|
-
if self.sim[b[0]].m(b[1]) != result:
|
814
|
-
self.sim[b[0]].x(b[1])
|
815
|
-
else:
|
816
|
-
self.sim[b[0]].force_m(b[1], result)
|
903
|
+
qb, lhv = self._get_qb_lhv_indices(hq)
|
817
904
|
|
818
|
-
|
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]
|
819
915
|
b.reset()
|
820
916
|
if result:
|
821
917
|
b.x()
|
822
918
|
|
823
|
-
b = hq[2]
|
824
|
-
p = self.sim[b[0]].prob(b[1]) if result else (1 - self.sim[b[0]].prob(b[1]))
|
825
|
-
if p < self._epsilon:
|
826
|
-
if self.sim[b[0]].m(b[1]) != result:
|
827
|
-
self.sim[b[0]].x(b[1])
|
828
|
-
else:
|
829
|
-
self.sim[b[0]].force_m(b[1], result)
|
830
|
-
|
831
919
|
return result
|
832
920
|
|
833
|
-
def force_m(self, lq,
|
921
|
+
def force_m(self, lq, result):
|
834
922
|
hq = self._unpack(lq)
|
835
923
|
if len(hq) < 2:
|
836
924
|
b = hq[0]
|
837
|
-
return self.sim[b[0]].force_m(b[1])
|
925
|
+
return self.sim[b[0]].force_m(b[1], result)
|
838
926
|
|
839
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
|
+
|
840
940
|
b = hq[1]
|
841
941
|
b.reset()
|
842
|
-
if
|
942
|
+
if result:
|
843
943
|
b.x()
|
844
|
-
b = hq[0]
|
845
|
-
self.sim[b[0]].force_m(b[1], c)
|
846
|
-
b = hq[2]
|
847
|
-
self.sim[b[0]].force_m(b[1], c)
|
848
944
|
|
849
945
|
return c
|
850
946
|
|
@@ -1227,28 +1323,12 @@ class QrackAceBackend:
|
|
1227
1323
|
return row * cols + col
|
1228
1324
|
|
1229
1325
|
for col in range(cols):
|
1230
|
-
connected_cols =
|
1231
|
-
c = (col - 1) % cols
|
1232
|
-
while self._is_col_long_range[c] and (
|
1233
|
-
len(connected_cols) < self._row_length
|
1234
|
-
):
|
1235
|
-
connected_cols.append(c)
|
1236
|
-
c = (c - 1) % cols
|
1237
|
-
if len(connected_cols) < self._row_length:
|
1238
|
-
connected_cols.append(c)
|
1239
|
-
c = (col + 1) % cols
|
1240
|
-
while self._is_col_long_range[c] and (
|
1241
|
-
len(connected_cols) < self._row_length
|
1242
|
-
):
|
1243
|
-
connected_cols.append(c)
|
1244
|
-
c = (c + 1) % cols
|
1245
|
-
if len(connected_cols) < self._row_length:
|
1246
|
-
connected_cols.append(c)
|
1247
|
-
|
1326
|
+
connected_cols, _ = self._get_connected(col, False)
|
1248
1327
|
for row in range(rows):
|
1328
|
+
connected_rows, _ = self._get_connected(row, False)
|
1249
1329
|
a = logical_index(row, col)
|
1250
1330
|
for c in connected_cols:
|
1251
|
-
for r in
|
1331
|
+
for r in connected_rows:
|
1252
1332
|
b = logical_index(r, c)
|
1253
1333
|
if a != b:
|
1254
1334
|
coupling_map.add((a, b))
|
@@ -1274,9 +1354,7 @@ class QrackAceBackend:
|
|
1274
1354
|
if is_long_a and is_long_b:
|
1275
1355
|
continue # No noise on long-to-long
|
1276
1356
|
|
1277
|
-
|
1278
|
-
|
1279
|
-
if same_col:
|
1357
|
+
if (col_a == col_b) or (row_a == row_b):
|
1280
1358
|
continue # No noise for same column
|
1281
1359
|
|
1282
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
|
File without changes
|