pyqrack-cuda 1.50.1__tar.gz → 1.52.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.50.1 → pyqrack_cuda-1.52.0}/Makefile +1 -1
- {pyqrack_cuda-1.50.1/pyqrack_cuda.egg-info → pyqrack_cuda-1.52.0}/PKG-INFO +1 -1
- {pyqrack_cuda-1.50.1 → pyqrack_cuda-1.52.0}/pyqrack/qrack_ace_backend.py +71 -65
- {pyqrack_cuda-1.50.1 → pyqrack_cuda-1.52.0}/pyqrack/qrack_simulator.py +6 -0
- {pyqrack_cuda-1.50.1 → pyqrack_cuda-1.52.0}/pyqrack/qrack_system/qrack_system.py +3 -0
- {pyqrack_cuda-1.50.1 → pyqrack_cuda-1.52.0/pyqrack_cuda.egg-info}/PKG-INFO +1 -1
- {pyqrack_cuda-1.50.1 → pyqrack_cuda-1.52.0}/setup.py +1 -1
- {pyqrack_cuda-1.50.1 → pyqrack_cuda-1.52.0}/LICENSE +0 -0
- {pyqrack_cuda-1.50.1 → pyqrack_cuda-1.52.0}/MANIFEST.in +0 -0
- {pyqrack_cuda-1.50.1 → pyqrack_cuda-1.52.0}/README.md +0 -0
- {pyqrack_cuda-1.50.1 → pyqrack_cuda-1.52.0}/pyproject.toml +0 -0
- {pyqrack_cuda-1.50.1 → pyqrack_cuda-1.52.0}/pyqrack/__init__.py +0 -0
- {pyqrack_cuda-1.50.1 → pyqrack_cuda-1.52.0}/pyqrack/neuron_activation_fn.py +0 -0
- {pyqrack_cuda-1.50.1 → pyqrack_cuda-1.52.0}/pyqrack/pauli.py +0 -0
- {pyqrack_cuda-1.50.1 → pyqrack_cuda-1.52.0}/pyqrack/qrack_circuit.py +0 -0
- {pyqrack_cuda-1.50.1 → pyqrack_cuda-1.52.0}/pyqrack/qrack_neuron.py +0 -0
- {pyqrack_cuda-1.50.1 → pyqrack_cuda-1.52.0}/pyqrack/qrack_neuron_torch_layer.py +0 -0
- {pyqrack_cuda-1.50.1 → pyqrack_cuda-1.52.0}/pyqrack/qrack_stabilizer.py +0 -0
- {pyqrack_cuda-1.50.1 → pyqrack_cuda-1.52.0}/pyqrack/qrack_system/__init__.py +0 -0
- {pyqrack_cuda-1.50.1 → pyqrack_cuda-1.52.0}/pyqrack/quimb_circuit_type.py +0 -0
- {pyqrack_cuda-1.50.1 → pyqrack_cuda-1.52.0}/pyqrack/stats/__init__.py +0 -0
- {pyqrack_cuda-1.50.1 → pyqrack_cuda-1.52.0}/pyqrack/stats/load_quantized_data.py +0 -0
- {pyqrack_cuda-1.50.1 → pyqrack_cuda-1.52.0}/pyqrack/stats/quantize_by_range.py +0 -0
- {pyqrack_cuda-1.50.1 → pyqrack_cuda-1.52.0}/pyqrack_cuda.egg-info/SOURCES.txt +0 -0
- {pyqrack_cuda-1.50.1 → pyqrack_cuda-1.52.0}/pyqrack_cuda.egg-info/dependency_links.txt +0 -0
- {pyqrack_cuda-1.50.1 → pyqrack_cuda-1.52.0}/pyqrack_cuda.egg-info/not-zip-safe +0 -0
- {pyqrack_cuda-1.50.1 → pyqrack_cuda-1.52.0}/pyqrack_cuda.egg-info/requires.txt +0 -0
- {pyqrack_cuda-1.50.1 → pyqrack_cuda-1.52.0}/pyqrack_cuda.egg-info/top_level.txt +0 -0
- {pyqrack_cuda-1.50.1 → pyqrack_cuda-1.52.0}/setup.cfg +0 -0
@@ -18,7 +18,7 @@ help:
|
|
18
18
|
build-deps:
|
19
19
|
ifneq ($(OS),Windows_NT)
|
20
20
|
ifeq ($(QRACK_PRESENT),)
|
21
|
-
git clone https://github.com/unitaryfund/qrack.git; cd qrack; git checkout
|
21
|
+
git clone https://github.com/unitaryfund/qrack.git; cd qrack; git checkout f0738286f49fb0ffaeb46d6e5d2294dbfc7f6138; cd ..
|
22
22
|
endif
|
23
23
|
mkdir -p qrack/build
|
24
24
|
ifeq ($(UNAME_S),Linux)
|
@@ -35,12 +35,14 @@ class QrackAceBackend:
|
|
35
35
|
|
36
36
|
The backend was originally designed assuming an (orbifolded) 2D qubit grid like 2019 Sycamore.
|
37
37
|
However, it quickly became apparent that users can basically design their own connectivity topologies,
|
38
|
-
without breaking the concept. (Not all will work equally well.)
|
39
|
-
|
38
|
+
without breaking the concept. (Not all will work equally well.)
|
39
|
+
|
40
|
+
Consider distributing the different "patches" to different GPUs with self.sim[sim_id].set_device(gpu_id)!
|
41
|
+
(If you have 3+ patches, maybe your discrete GPU can do multiple patches in the time it takes an Intel HD
|
42
|
+
to do one patch worth of work!)
|
40
43
|
|
41
44
|
Attributes:
|
42
|
-
sim(QrackSimulator):
|
43
|
-
alternating_codes(bool): Alternate repetition code elision by index?
|
45
|
+
sim(QrackSimulator): Array of simulators corresponding to "patches" between boundary rows.
|
44
46
|
row_length(int): Qubits per row.
|
45
47
|
col_length(int): Qubits per column.
|
46
48
|
long_range_columns(int): How many ideal rows between QEC boundary rows?
|
@@ -50,7 +52,6 @@ class QrackAceBackend:
|
|
50
52
|
self,
|
51
53
|
qubit_count=1,
|
52
54
|
long_range_columns=-1,
|
53
|
-
alternating_codes=True,
|
54
55
|
reverse_row_and_col=False,
|
55
56
|
isTensorNetwork=False,
|
56
57
|
isStabilizerHybrid=False,
|
@@ -68,7 +69,6 @@ class QrackAceBackend:
|
|
68
69
|
long_range_columns = 3 if (self.row_length % 3) == 1 else 2
|
69
70
|
self.long_range_columns = long_range_columns
|
70
71
|
|
71
|
-
self.alternating_codes = alternating_codes
|
72
72
|
self._coupling_map = None
|
73
73
|
|
74
74
|
# If there's only one or zero "False" columns,
|
@@ -96,24 +96,24 @@ class QrackAceBackend:
|
|
96
96
|
self._qubit_dict[tot_qubits] = (sim_id, sim_counts[sim_id])
|
97
97
|
tot_qubits += 1
|
98
98
|
sim_counts[sim_id] += 1
|
99
|
-
elif
|
100
|
-
self._qubit_dict[tot_qubits] = (sim_id, sim_counts[sim_id])
|
101
|
-
tot_qubits += 1
|
102
|
-
sim_counts[sim_id] += 1
|
103
|
-
sim_id = (sim_id + 1) % sim_count
|
99
|
+
elif (r & 1):
|
104
100
|
for _ in range(2):
|
105
101
|
self._qubit_dict[tot_qubits] = (sim_id, sim_counts[sim_id])
|
106
102
|
tot_qubits += 1
|
107
103
|
sim_counts[sim_id] += 1
|
104
|
+
sim_id = (sim_id + 1) % sim_count
|
105
|
+
self._qubit_dict[tot_qubits] = (sim_id, sim_counts[sim_id])
|
106
|
+
tot_qubits += 1
|
107
|
+
sim_counts[sim_id] += 1
|
108
108
|
else:
|
109
|
+
self._qubit_dict[tot_qubits] = (sim_id, sim_counts[sim_id])
|
110
|
+
tot_qubits += 1
|
111
|
+
sim_counts[sim_id] += 1
|
112
|
+
sim_id = (sim_id + 1) % sim_count
|
109
113
|
for _ in range(2):
|
110
114
|
self._qubit_dict[tot_qubits] = (sim_id, sim_counts[sim_id])
|
111
115
|
tot_qubits += 1
|
112
116
|
sim_counts[sim_id] += 1
|
113
|
-
sim_id = (sim_id + 1) % sim_count
|
114
|
-
self._qubit_dict[tot_qubits] = (sim_id, sim_counts[sim_id])
|
115
|
-
tot_qubits += 1
|
116
|
-
sim_counts[sim_id] += 1
|
117
117
|
|
118
118
|
self.sim = []
|
119
119
|
for i in range(sim_count):
|
@@ -230,6 +230,16 @@ class QrackAceBackend:
|
|
230
230
|
b2 = hq[2]
|
231
231
|
self.sim[b2[0]].mcx([b2[1]], hq[1][1])
|
232
232
|
|
233
|
+
def _encode_decode_half(self, lq, hq, toward_0):
|
234
|
+
if len(hq) < 2:
|
235
|
+
return
|
236
|
+
if toward_0 and (hq[0][0] == hq[1][0]):
|
237
|
+
b0 = hq[0]
|
238
|
+
self.sim[b0[0]].mcx([b0[1]], hq[1][1])
|
239
|
+
elif not toward_0 and (hq[2][0] == hq[1][0]):
|
240
|
+
b2 = hq[2]
|
241
|
+
self.sim[b2[0]].mcx([b2[1]], hq[1][1])
|
242
|
+
|
233
243
|
def _correct(self, lq):
|
234
244
|
if self._is_col_long_range[lq % self.row_length]:
|
235
245
|
return
|
@@ -258,9 +268,9 @@ class QrackAceBackend:
|
|
258
268
|
|
259
269
|
# Suggestion from Elara (the custom OpenAI GPT):
|
260
270
|
# Create phase parity tie before measurement.
|
261
|
-
|
262
|
-
|
263
|
-
|
271
|
+
self._ccx_shadow(hq[single_bit], hq[other_bits[0]], [ancilla_sim, ancilla])
|
272
|
+
self.sim[ancilla_sim].mcx([hq[other_bits[1]][1]], ancilla)
|
273
|
+
self.sim[ancilla_sim].force_m(ancilla, False)
|
264
274
|
|
265
275
|
samples = self.sim[ancilla_sim].measure_shots(
|
266
276
|
[hq[other_bits[0]][1], hq[other_bits[1]][1]], shots
|
@@ -363,13 +373,13 @@ class QrackAceBackend:
|
|
363
373
|
|
364
374
|
if not math.isclose(ph, -lm) and not math.isclose(abs(ph), math.pi / 2):
|
365
375
|
# Produces/destroys superposition
|
366
|
-
self._correct_if_like_h(th, lq)
|
367
376
|
self._encode_decode(lq, hq)
|
368
377
|
b = hq[0]
|
369
378
|
self.sim[b[0]].u(b[1], th, ph, lm)
|
370
379
|
b = hq[2]
|
371
380
|
self.sim[b[0]].u(b[1], th, ph, lm)
|
372
381
|
self._encode_decode(lq, hq)
|
382
|
+
self._correct_if_like_h(th, lq)
|
373
383
|
else:
|
374
384
|
# Shouldn't produce/destroy superposition
|
375
385
|
for b in hq:
|
@@ -386,9 +396,6 @@ class QrackAceBackend:
|
|
386
396
|
th -= 2 * math.pi
|
387
397
|
while th <= -math.pi:
|
388
398
|
th += 2 * math.pi
|
389
|
-
if p == Pauli.PauliY:
|
390
|
-
self._correct_if_like_h(th, lq)
|
391
|
-
|
392
399
|
if (p == Pauli.PauliZ) or math.isclose(abs(th), math.pi):
|
393
400
|
# Doesn't produce/destroy superposition
|
394
401
|
for b in hq:
|
@@ -401,6 +408,7 @@ class QrackAceBackend:
|
|
401
408
|
b = hq[2]
|
402
409
|
self.sim[b[0]].r(p, th, b[1])
|
403
410
|
self._encode_decode(lq, hq)
|
411
|
+
self._correct_if_like_h(th, lq)
|
404
412
|
|
405
413
|
def h(self, lq):
|
406
414
|
hq = self._unpack(lq)
|
@@ -409,13 +417,13 @@ class QrackAceBackend:
|
|
409
417
|
self.sim[b[0]].h(b[1])
|
410
418
|
return
|
411
419
|
|
412
|
-
self._correct(lq)
|
413
420
|
self._encode_decode(lq, hq)
|
414
421
|
b = hq[0]
|
415
422
|
self.sim[b[0]].h(b[1])
|
416
423
|
b = hq[2]
|
417
424
|
self.sim[b[0]].h(b[1])
|
418
425
|
self._encode_decode(lq, hq)
|
426
|
+
self._correct(lq)
|
419
427
|
|
420
428
|
def s(self, lq):
|
421
429
|
hq = self._unpack(lq)
|
@@ -547,13 +555,10 @@ class QrackAceBackend:
|
|
547
555
|
shadow(b1, b2)
|
548
556
|
return
|
549
557
|
|
550
|
-
self._correct(lq1)
|
551
|
-
self._correct(lq2)
|
552
|
-
|
553
558
|
if (lq2_col in connected_cols) and (connected_cols.index(lq2_col) < boundary):
|
554
559
|
# lq2_col < lq1_col
|
555
|
-
self.
|
556
|
-
self.
|
560
|
+
self._encode_decode_half(lq1, hq1, True)
|
561
|
+
self._encode_decode_half(lq2, hq2, False)
|
557
562
|
b = hq1[0]
|
558
563
|
if lq1_lr:
|
559
564
|
self._get_gate(pauli, anti, hq1[0][0])[0]([b[1]], hq2[2][1])
|
@@ -561,12 +566,12 @@ class QrackAceBackend:
|
|
561
566
|
self._get_gate(pauli, anti, hq2[0][0])[0]([b[1]], hq2[0][1])
|
562
567
|
else:
|
563
568
|
self._get_gate(pauli, anti, b[0])[0]([b[1]], hq2[2][1])
|
564
|
-
self.
|
565
|
-
self.
|
569
|
+
self._encode_decode_half(lq2, hq2, False)
|
570
|
+
self._encode_decode_half(lq1, hq1, True)
|
566
571
|
elif lq2_col in connected_cols:
|
567
572
|
# lq1_col < lq2_col
|
568
|
-
self.
|
569
|
-
self.
|
573
|
+
self._encode_decode_half(lq1, hq1, False)
|
574
|
+
self._encode_decode_half(lq2, hq2, True)
|
570
575
|
b = hq2[0]
|
571
576
|
if lq1_lr:
|
572
577
|
self._get_gate(pauli, anti, hq1[0][0])[0]([hq1[0][1]], b[1])
|
@@ -574,37 +579,41 @@ class QrackAceBackend:
|
|
574
579
|
self._get_gate(pauli, anti, hq2[0][0])[0]([hq1[2][1]], b[1])
|
575
580
|
else:
|
576
581
|
self._get_gate(pauli, anti, b[0])[0]([hq1[2][1]], b[1])
|
577
|
-
self.
|
578
|
-
self.
|
582
|
+
self._encode_decode_half(lq2, hq2, True)
|
583
|
+
self._encode_decode_half(lq1, hq1, False)
|
579
584
|
elif lq1_col == lq2_col:
|
580
585
|
# Both are in the same boundary column.
|
586
|
+
self._encode_decode(lq1, hq1)
|
587
|
+
self._encode_decode(lq2, hq2)
|
581
588
|
b = hq1[0]
|
582
589
|
gate, shadow = self._get_gate(pauli, anti, b[0])
|
583
590
|
gate([b[1]], hq2[0][1])
|
584
591
|
b = hq1[2]
|
585
592
|
gate, shadow = self._get_gate(pauli, anti, b[0])
|
586
593
|
gate([b[1]], hq2[2][1])
|
587
|
-
if hq1[1][0] != hq2[1][0]:
|
588
|
-
shadow(hq1[1], hq2[1])
|
589
|
-
else:
|
590
|
-
b = hq1[1]
|
591
|
-
gate, shadow = self._get_gate(pauli, anti, b[0])
|
592
|
-
gate([b[1]], hq2[1][1])
|
593
594
|
else:
|
594
595
|
# The qubits have no quantum connection.
|
595
596
|
gate, shadow = self._get_gate(pauli, anti, hq1[0][0])
|
596
597
|
if lq1_lr:
|
598
|
+
connected01 = (hq2[0][0] == hq2[1][0])
|
597
599
|
self._encode_decode(lq2, hq2)
|
598
|
-
shadow(hq1[0], hq2[0])
|
600
|
+
shadow(hq1[0], hq2[0] if connected01 else hq2[2])
|
599
601
|
self._encode_decode(lq2, hq2)
|
600
602
|
elif lq2_lr:
|
603
|
+
connected01 = (hq1[0][0] == hq1[1][0])
|
601
604
|
self._encode_decode(lq1, hq1)
|
602
|
-
shadow(hq1[0], hq2[0])
|
605
|
+
shadow(hq1[0] if connected01 else hq1[2], hq2[0])
|
603
606
|
self._encode_decode(lq1, hq1)
|
604
607
|
else:
|
608
|
+
self._encode_decode(lq1, hq1)
|
609
|
+
self._encode_decode(lq2, hq2)
|
605
610
|
shadow(hq1[0], hq2[0])
|
606
|
-
shadow(hq1[1], hq2[1])
|
607
611
|
shadow(hq1[2], hq2[2])
|
612
|
+
self._encode_decode(lq2, hq2)
|
613
|
+
self._encode_decode(lq1, hq1)
|
614
|
+
|
615
|
+
self._correct(lq1)
|
616
|
+
self._correct(lq2)
|
608
617
|
|
609
618
|
def cx(self, lq1, lq2):
|
610
619
|
self._cpauli(lq1, lq2, False, Pauli.PauliX)
|
@@ -725,16 +734,23 @@ class QrackAceBackend:
|
|
725
734
|
result = 0
|
726
735
|
# Randomize the order of measurement to amortize error.
|
727
736
|
# However, locality of collapse matters:
|
728
|
-
#
|
729
|
-
|
730
|
-
|
731
|
-
|
737
|
+
# measure in row pairs, and always across rows,
|
738
|
+
# and by row directionality.
|
739
|
+
row_pairs = list(range((self.col_length + 1) // 2))
|
740
|
+
random.shuffle(row_pairs)
|
741
|
+
for row_pair in row_pairs:
|
732
742
|
col_offset = random.randint(0, self.row_length - 1)
|
733
|
-
|
743
|
+
lq_row = row_pair << 1
|
744
|
+
for c in range(self.row_length):
|
745
|
+
lq_col = (c + col_offset) % self.row_length
|
746
|
+
lq = lq_row * self.row_length + lq_col
|
747
|
+
if self.m(lq):
|
748
|
+
result |= 1 << lq
|
749
|
+
lq_row += 1
|
750
|
+
if lq_row == self.col_length:
|
751
|
+
continue
|
734
752
|
for c in range(self.row_length):
|
735
|
-
lq_col = (
|
736
|
-
((self.row_length - (c + 1)) if col_reverse else c) + col_offset
|
737
|
-
) % self.row_length
|
753
|
+
lq_col = ((self.row_length - (c + 1)) + col_offset) % self.row_length
|
738
754
|
lq = lq_row * self.row_length + lq_col
|
739
755
|
if self.m(lq):
|
740
756
|
result |= 1 << lq
|
@@ -761,7 +777,7 @@ class QrackAceBackend:
|
|
761
777
|
return self.sim[b[0]].prob(b[1])
|
762
778
|
|
763
779
|
self._correct(lq)
|
764
|
-
if
|
780
|
+
if hq[0][0] == hq[1][0]:
|
765
781
|
other_bits = [0, 1]
|
766
782
|
else:
|
767
783
|
other_bits = [1, 2]
|
@@ -1171,21 +1187,11 @@ class QrackAceBackend:
|
|
1171
1187
|
continue # No noise on long-to-long
|
1172
1188
|
|
1173
1189
|
same_col = col_a == col_b
|
1174
|
-
even_odd = (row_a % 2) != (row_b % 2)
|
1175
|
-
|
1176
|
-
if same_col and not even_odd:
|
1177
|
-
continue # No noise for even-even or odd-odd within a boundary column
|
1178
1190
|
|
1179
1191
|
if same_col:
|
1180
|
-
|
1181
|
-
|
1182
|
-
|
1183
|
-
noise_model.add_quantum_error(depolarizing_error(x_cy, 2), "cy", [a, b])
|
1184
|
-
noise_model.add_quantum_error(depolarizing_error(x_cy, 2), "cz", [a, b])
|
1185
|
-
noise_model.add_quantum_error(
|
1186
|
-
depolarizing_error(x_swap, 2), "swap", [a, b]
|
1187
|
-
)
|
1188
|
-
elif is_long_a or is_long_b:
|
1192
|
+
continue # No noise for same column
|
1193
|
+
|
1194
|
+
if is_long_a or is_long_b:
|
1189
1195
|
y_cy = 1 - (1 - y) ** 2
|
1190
1196
|
y_swap = 1 - (1 - y) ** 3
|
1191
1197
|
noise_model.add_quantum_error(depolarizing_error(y, 2), "cx", [a, b])
|
@@ -181,9 +181,15 @@ class QrackSimulator:
|
|
181
181
|
self._throw_if_error()
|
182
182
|
|
183
183
|
def set_concurrency(self, p):
|
184
|
+
""" Set the CPU parallel thread count"""
|
184
185
|
Qrack.qrack_lib.set_concurrency(self.sid, p)
|
185
186
|
self._throw_if_error()
|
186
187
|
|
188
|
+
def set_device(self, d):
|
189
|
+
""" Set the GPU device ID"""
|
190
|
+
Qrack.qrack_lib.set_device(self.sid, d)
|
191
|
+
self._throw_if_error()
|
192
|
+
|
187
193
|
def clone(self):
|
188
194
|
return QrackSimulator(cloneSid=self.sid)
|
189
195
|
|
@@ -143,6 +143,9 @@ class QrackSystem:
|
|
143
143
|
self.qrack_lib.set_concurrency.restype = None
|
144
144
|
self.qrack_lib.set_concurrency.argtypes = [c_ulonglong, c_ulonglong]
|
145
145
|
|
146
|
+
self.qrack_lib.set_device.restype = None
|
147
|
+
self.qrack_lib.set_device.argtypes = [c_ulonglong, c_ulonglong]
|
148
|
+
|
146
149
|
# pseudo-quantum
|
147
150
|
|
148
151
|
self.qrack_lib.ProbAll.restype = None
|
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
|