pyqrack-cuda 1.49.9__tar.gz → 1.50.1__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.49.9/pyqrack_cuda.egg-info → pyqrack_cuda-1.50.1}/PKG-INFO +1 -1
- {pyqrack_cuda-1.49.9 → pyqrack_cuda-1.50.1}/pyqrack/qrack_ace_backend.py +295 -289
- {pyqrack_cuda-1.49.9 → pyqrack_cuda-1.50.1/pyqrack_cuda.egg-info}/PKG-INFO +1 -1
- {pyqrack_cuda-1.49.9 → pyqrack_cuda-1.50.1}/setup.py +1 -1
- {pyqrack_cuda-1.49.9 → pyqrack_cuda-1.50.1}/LICENSE +0 -0
- {pyqrack_cuda-1.49.9 → pyqrack_cuda-1.50.1}/MANIFEST.in +0 -0
- {pyqrack_cuda-1.49.9 → pyqrack_cuda-1.50.1}/Makefile +0 -0
- {pyqrack_cuda-1.49.9 → pyqrack_cuda-1.50.1}/README.md +0 -0
- {pyqrack_cuda-1.49.9 → pyqrack_cuda-1.50.1}/pyproject.toml +0 -0
- {pyqrack_cuda-1.49.9 → pyqrack_cuda-1.50.1}/pyqrack/__init__.py +0 -0
- {pyqrack_cuda-1.49.9 → pyqrack_cuda-1.50.1}/pyqrack/neuron_activation_fn.py +0 -0
- {pyqrack_cuda-1.49.9 → pyqrack_cuda-1.50.1}/pyqrack/pauli.py +0 -0
- {pyqrack_cuda-1.49.9 → pyqrack_cuda-1.50.1}/pyqrack/qrack_circuit.py +0 -0
- {pyqrack_cuda-1.49.9 → pyqrack_cuda-1.50.1}/pyqrack/qrack_neuron.py +0 -0
- {pyqrack_cuda-1.49.9 → pyqrack_cuda-1.50.1}/pyqrack/qrack_neuron_torch_layer.py +0 -0
- {pyqrack_cuda-1.49.9 → pyqrack_cuda-1.50.1}/pyqrack/qrack_simulator.py +0 -0
- {pyqrack_cuda-1.49.9 → pyqrack_cuda-1.50.1}/pyqrack/qrack_stabilizer.py +0 -0
- {pyqrack_cuda-1.49.9 → pyqrack_cuda-1.50.1}/pyqrack/qrack_system/__init__.py +0 -0
- {pyqrack_cuda-1.49.9 → pyqrack_cuda-1.50.1}/pyqrack/qrack_system/qrack_system.py +0 -0
- {pyqrack_cuda-1.49.9 → pyqrack_cuda-1.50.1}/pyqrack/quimb_circuit_type.py +0 -0
- {pyqrack_cuda-1.49.9 → pyqrack_cuda-1.50.1}/pyqrack/stats/__init__.py +0 -0
- {pyqrack_cuda-1.49.9 → pyqrack_cuda-1.50.1}/pyqrack/stats/load_quantized_data.py +0 -0
- {pyqrack_cuda-1.49.9 → pyqrack_cuda-1.50.1}/pyqrack/stats/quantize_by_range.py +0 -0
- {pyqrack_cuda-1.49.9 → pyqrack_cuda-1.50.1}/pyqrack_cuda.egg-info/SOURCES.txt +0 -0
- {pyqrack_cuda-1.49.9 → pyqrack_cuda-1.50.1}/pyqrack_cuda.egg-info/dependency_links.txt +0 -0
- {pyqrack_cuda-1.49.9 → pyqrack_cuda-1.50.1}/pyqrack_cuda.egg-info/not-zip-safe +0 -0
- {pyqrack_cuda-1.49.9 → pyqrack_cuda-1.50.1}/pyqrack_cuda.egg-info/requires.txt +0 -0
- {pyqrack_cuda-1.49.9 → pyqrack_cuda-1.50.1}/pyqrack_cuda.egg-info/top_level.txt +0 -0
- {pyqrack_cuda-1.49.9 → pyqrack_cuda-1.50.1}/setup.cfg +0 -0
@@ -3,6 +3,7 @@
|
|
3
3
|
# Use of this source code is governed by an MIT-style license that can be
|
4
4
|
# found in the LICENSE file or at https://opensource.org/licenses/MIT.
|
5
5
|
import math
|
6
|
+
import os
|
6
7
|
import random
|
7
8
|
import sys
|
8
9
|
import time
|
@@ -48,7 +49,7 @@ class QrackAceBackend:
|
|
48
49
|
def __init__(
|
49
50
|
self,
|
50
51
|
qubit_count=1,
|
51
|
-
long_range_columns
|
52
|
+
long_range_columns=-1,
|
52
53
|
alternating_codes=True,
|
53
54
|
reverse_row_and_col=False,
|
54
55
|
isTensorNetwork=False,
|
@@ -56,8 +57,6 @@ class QrackAceBackend:
|
|
56
57
|
isBinaryDecisionTree=False,
|
57
58
|
toClone=None,
|
58
59
|
):
|
59
|
-
if long_range_columns < 0:
|
60
|
-
long_range_columns = 0
|
61
60
|
if qubit_count < 0:
|
62
61
|
qubit_count = 0
|
63
62
|
if toClone:
|
@@ -65,43 +64,75 @@ class QrackAceBackend:
|
|
65
64
|
long_range_columns = toClone.long_range_columns
|
66
65
|
|
67
66
|
self._factor_width(qubit_count, reverse_row_and_col)
|
68
|
-
|
67
|
+
if long_range_columns < 0:
|
68
|
+
long_range_columns = 3 if (self.row_length % 3) == 1 else 2
|
69
69
|
self.long_range_columns = long_range_columns
|
70
|
-
|
70
|
+
|
71
|
+
self.alternating_codes = alternating_codes
|
71
72
|
self._coupling_map = None
|
72
73
|
|
73
74
|
# If there's only one or zero "False" columns,
|
74
75
|
# the entire simulator is connected, anyway.
|
76
|
+
len_col_seq = long_range_columns + 1
|
77
|
+
sim_count = (self.row_length + len_col_seq - 1) // len_col_seq
|
75
78
|
if (long_range_columns + 1) >= self.row_length:
|
76
79
|
self._is_col_long_range = [True] * self.row_length
|
77
80
|
else:
|
78
81
|
col_seq = [True] * long_range_columns + [False]
|
79
|
-
|
80
|
-
self._is_col_long_range = (
|
81
|
-
col_seq * ((self.row_length + len_col_seq - 1) // len_col_seq)
|
82
|
-
)[: self.row_length]
|
82
|
+
self._is_col_long_range = (col_seq * sim_count)[: self.row_length]
|
83
83
|
if long_range_columns < self.row_length:
|
84
84
|
self._is_col_long_range[-1] = False
|
85
85
|
|
86
|
+
self._qubit_dict = {}
|
86
87
|
self._hardware_offset = []
|
88
|
+
self._ancilla = [0] * sim_count
|
89
|
+
sim_counts = [0] * sim_count
|
90
|
+
sim_id = 0
|
87
91
|
tot_qubits = 0
|
88
|
-
for
|
92
|
+
for r in range(self.col_length):
|
89
93
|
for c in self._is_col_long_range:
|
90
94
|
self._hardware_offset.append(tot_qubits)
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
95
|
+
if c:
|
96
|
+
self._qubit_dict[tot_qubits] = (sim_id, sim_counts[sim_id])
|
97
|
+
tot_qubits += 1
|
98
|
+
sim_counts[sim_id] += 1
|
99
|
+
elif not self.alternating_codes or not (r & 1):
|
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
|
104
|
+
for _ in range(2):
|
105
|
+
self._qubit_dict[tot_qubits] = (sim_id, sim_counts[sim_id])
|
106
|
+
tot_qubits += 1
|
107
|
+
sim_counts[sim_id] += 1
|
108
|
+
else:
|
109
|
+
for _ in range(2):
|
110
|
+
self._qubit_dict[tot_qubits] = (sim_id, sim_counts[sim_id])
|
111
|
+
tot_qubits += 1
|
112
|
+
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
|
+
|
118
|
+
self.sim = []
|
119
|
+
for i in range(sim_count):
|
120
|
+
self._ancilla[i] = sim_counts[i]
|
121
|
+
sim_counts[i] += 1
|
122
|
+
self.sim.append(
|
123
|
+
toClone.sim[i].clone()
|
124
|
+
if toClone
|
125
|
+
else QrackSimulator(
|
126
|
+
sim_counts[i],
|
127
|
+
isTensorNetwork=isTensorNetwork,
|
128
|
+
isStabilizerHybrid=isStabilizerHybrid,
|
129
|
+
isBinaryDecisionTree=isBinaryDecisionTree,
|
130
|
+
)
|
103
131
|
)
|
104
|
-
|
132
|
+
|
133
|
+
# You can still "monkey-patch" this, after the constructor.
|
134
|
+
if "QRACK_QUNIT_SEPARABILITY_THRESHOLD" not in os.environ:
|
135
|
+
self.sim[i].set_sdrp(0.03)
|
105
136
|
|
106
137
|
def clone(self):
|
107
138
|
return QrackAceBackend(toClone=self)
|
@@ -119,8 +150,8 @@ class QrackAceBackend:
|
|
119
150
|
self.row_length = col_len if reverse else row_len
|
120
151
|
|
121
152
|
def _ct_pair_prob(self, q1, q2):
|
122
|
-
p1 = self.sim.prob(q1)
|
123
|
-
p2 = self.sim.prob(q2)
|
153
|
+
p1 = self.sim[q1[0]].prob(q1[1])
|
154
|
+
p2 = self.sim[q2[0]].prob(q2[1])
|
124
155
|
|
125
156
|
if p1 < p2:
|
126
157
|
return p2, q1
|
@@ -130,96 +161,77 @@ class QrackAceBackend:
|
|
130
161
|
def _cz_shadow(self, q1, q2):
|
131
162
|
prob_max, t = self._ct_pair_prob(q1, q2)
|
132
163
|
if prob_max > 0.5:
|
133
|
-
self.sim.z(t)
|
164
|
+
self.sim[t[0]].z(t[1])
|
134
165
|
|
135
|
-
def _anti_cz_shadow(self,
|
136
|
-
self.sim.x(
|
137
|
-
self._cz_shadow(
|
138
|
-
self.sim.x(
|
166
|
+
def _anti_cz_shadow(self, c, t):
|
167
|
+
self.sim[c[0]].x(c[1])
|
168
|
+
self._cz_shadow(c, t)
|
169
|
+
self.sim[c[0]].x(c[1])
|
139
170
|
|
140
171
|
def _cx_shadow(self, c, t):
|
141
|
-
self.sim.h(t)
|
172
|
+
self.sim[t[0]].h(t[1])
|
142
173
|
self._cz_shadow(c, t)
|
143
|
-
self.sim.h(t)
|
174
|
+
self.sim[t[0]].h(t[1])
|
144
175
|
|
145
176
|
def _anti_cx_shadow(self, c, t):
|
146
|
-
self.sim.x(
|
177
|
+
self.sim[c[0]].x(c[1])
|
147
178
|
self._cx_shadow(c, t)
|
148
|
-
self.sim.x(
|
179
|
+
self.sim[c[0]].x(c[1])
|
149
180
|
|
150
181
|
def _cy_shadow(self, c, t):
|
151
|
-
self.sim.adjs(t)
|
182
|
+
self.sim[t[0]].adjs(t[1])
|
152
183
|
self._cx_shadow(c, t)
|
153
|
-
self.sim.s(t)
|
184
|
+
self.sim[t[0]].s(t[1])
|
154
185
|
|
155
186
|
def _anti_cy_shadow(self, c, t):
|
156
|
-
self.sim.x(
|
187
|
+
self.sim[c[0]].x(c[1])
|
157
188
|
self._cy_shadow(c, t)
|
158
|
-
self.sim.x(
|
189
|
+
self.sim[c[0]].x(c[1])
|
159
190
|
|
160
191
|
def _ccz_shadow(self, c1, q2, q3):
|
161
|
-
self.sim.mcx([q2], q3)
|
162
|
-
self.sim.adjt(q3)
|
192
|
+
self.sim[q2[0]].mcx([q2[1]], q3[1])
|
193
|
+
self.sim[q3[0]].adjt(q3[1])
|
163
194
|
self._cx_shadow(c1, q3)
|
164
|
-
self.sim.t(q3)
|
165
|
-
self.sim.mcx([q2], q3)
|
166
|
-
self.sim.adjt(q3)
|
195
|
+
self.sim[q3[0]].t(q3[1])
|
196
|
+
self.sim[q2[0]].mcx([q2[1]], q3[1])
|
197
|
+
self.sim[q3[0]].adjt(q3[1])
|
167
198
|
self._cx_shadow(c1, q3)
|
168
|
-
self.sim.t(q3)
|
169
|
-
self.sim.t(q2)
|
199
|
+
self.sim[q3[0]].t(q3[1])
|
200
|
+
self.sim[q2[0]].t(q2[1])
|
170
201
|
self._cx_shadow(c1, q2)
|
171
|
-
self.sim.adjt(q2)
|
172
|
-
self.sim.t(c1)
|
202
|
+
self.sim[q2[0]].adjt(q2[1])
|
203
|
+
self.sim[c1[0]].t(c1[1])
|
173
204
|
self._cx_shadow(c1, q2)
|
174
205
|
|
175
|
-
def _ccx_shadow(self, c1, q2,
|
176
|
-
self.sim.h(
|
177
|
-
self._ccz_shadow(c1, q2,
|
178
|
-
self.sim.h(
|
206
|
+
def _ccx_shadow(self, c1, q2, t):
|
207
|
+
self.sim[t[0]].h(t[1])
|
208
|
+
self._ccz_shadow(c1, q2, t)
|
209
|
+
self.sim[t[0]].h(t[1])
|
179
210
|
|
180
|
-
def _unpack(self, lq
|
211
|
+
def _unpack(self, lq):
|
181
212
|
offset = self._hardware_offset[lq]
|
182
213
|
|
183
214
|
if self._is_col_long_range[lq % self.row_length]:
|
184
|
-
return [offset]
|
185
|
-
|
186
|
-
return (
|
187
|
-
[offset + 2, offset + 1, offset]
|
188
|
-
if reverse
|
189
|
-
else [offset, offset + 1, offset + 2]
|
190
|
-
)
|
215
|
+
return [self._qubit_dict[offset]]
|
191
216
|
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
if ((not self.alternating_codes) and reverse) or (even_row == reverse):
|
198
|
-
self.sim.mcx([hq[2]], hq[1])
|
199
|
-
else:
|
200
|
-
self.sim.mcx([hq[0]], hq[1])
|
201
|
-
self._is_init[lq] = True
|
217
|
+
return [
|
218
|
+
self._qubit_dict[offset],
|
219
|
+
self._qubit_dict[offset + 1],
|
220
|
+
self._qubit_dict[offset + 2],
|
221
|
+
]
|
202
222
|
|
203
|
-
def
|
204
|
-
if
|
223
|
+
def _encode_decode(self, lq, hq):
|
224
|
+
if len(hq) < 2:
|
205
225
|
return
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
self.sim.mcx([hq[2]], hq[1])
|
210
|
-
else:
|
211
|
-
# Decode entangled-first
|
212
|
-
self.sim.mcx([hq[0]], hq[1])
|
213
|
-
self._cx_shadow(hq[0], hq[2])
|
214
|
-
|
215
|
-
def _encode_decode_1qb(self, lq, hq):
|
216
|
-
if not self.alternating_codes or not ((lq // self.row_length) & 1):
|
217
|
-
self.sim.mcx([hq[0]], hq[1])
|
226
|
+
if hq[0][0] == hq[1][0]:
|
227
|
+
b0 = hq[0]
|
228
|
+
self.sim[b0[0]].mcx([b0[1]], hq[1][1])
|
218
229
|
else:
|
219
|
-
|
230
|
+
b2 = hq[2]
|
231
|
+
self.sim[b2[0]].mcx([b2[1]], hq[1][1])
|
220
232
|
|
221
233
|
def _correct(self, lq):
|
222
|
-
if
|
234
|
+
if self._is_col_long_range[lq % self.row_length]:
|
223
235
|
return
|
224
236
|
# We can't use true syndrome-based error correction,
|
225
237
|
# because one of the qubits in the code is separated.
|
@@ -228,25 +240,31 @@ class QrackAceBackend:
|
|
228
240
|
|
229
241
|
single_bit = 0
|
230
242
|
other_bits = []
|
231
|
-
|
243
|
+
hq = self._unpack(lq)
|
244
|
+
if hq[0][0] == hq[1][0]:
|
232
245
|
single_bit = 2
|
233
246
|
other_bits = [0, 1]
|
234
|
-
|
247
|
+
elif hq[1][0] == hq[2][0]:
|
235
248
|
single_bit = 0
|
236
249
|
other_bits = [1, 2]
|
250
|
+
else:
|
251
|
+
raise RuntimeError("Invalid boundary qubit!")
|
237
252
|
|
238
|
-
|
253
|
+
ancilla_sim = hq[other_bits[0]][0]
|
254
|
+
ancilla = self._ancilla[ancilla_sim]
|
239
255
|
|
240
|
-
single_bit_value = self.sim.prob(hq[single_bit])
|
256
|
+
single_bit_value = self.sim[hq[single_bit][0]].prob(hq[single_bit][1])
|
241
257
|
single_bit_polarization = max(single_bit_value, 1 - single_bit_value)
|
242
258
|
|
243
259
|
# Suggestion from Elara (the custom OpenAI GPT):
|
244
260
|
# Create phase parity tie before measurement.
|
245
|
-
self._ccx_shadow(hq[single_bit], hq[other_bits[0]],
|
246
|
-
self.sim.mcx([hq[other_bits[1]]],
|
247
|
-
self.sim.force_m(
|
261
|
+
# self._ccx_shadow(hq[single_bit], hq[other_bits[0]], [ancilla_sim, ancilla])
|
262
|
+
# self.sim[ancilla_sim].mcx([hq[other_bits[1]][1]], ancilla)
|
263
|
+
# self.sim[ancilla_sim].force_m(ancilla, False)
|
248
264
|
|
249
|
-
samples = self.sim.measure_shots(
|
265
|
+
samples = self.sim[ancilla_sim].measure_shots(
|
266
|
+
[hq[other_bits[0]][1], hq[other_bits[1]][1]], shots
|
267
|
+
)
|
250
268
|
|
251
269
|
syndrome_indices = (
|
252
270
|
[other_bits[1], other_bits[0]]
|
@@ -296,31 +314,29 @@ class QrackAceBackend:
|
|
296
314
|
error_bit = syndrome.index(max(syndrome))
|
297
315
|
if error_bit == single_bit:
|
298
316
|
# The stand-alone bit carries the error.
|
299
|
-
self.sim.x(hq[error_bit])
|
317
|
+
self.sim[hq[error_bit][0]].x(hq[error_bit][1])
|
300
318
|
else:
|
301
319
|
# The coherent bits carry the error.
|
302
320
|
force_syndrome = False
|
303
321
|
# Form their syndrome.
|
304
|
-
self.sim.mcx([hq[other_bits[0]]],
|
305
|
-
self.sim.mcx([hq[other_bits[1]]],
|
322
|
+
self.sim[ancilla_sim].mcx([hq[other_bits[0]][1]], ancilla)
|
323
|
+
self.sim[ancilla_sim].mcx([hq[other_bits[1]][1]], ancilla)
|
306
324
|
# Force the syndrome pathological
|
307
|
-
self.sim.force_m(
|
325
|
+
self.sim[ancilla_sim].force_m(ancilla, True)
|
308
326
|
# Reset the ancilla.
|
309
|
-
self.sim.x(
|
327
|
+
self.sim[ancilla_sim].x(ancilla)
|
310
328
|
# Correct the bit flip.
|
311
|
-
self.sim.x(hq[error_bit])
|
329
|
+
self.sim[ancilla_sim].x(hq[error_bit][1])
|
312
330
|
|
313
331
|
# There is no error.
|
314
332
|
if force_syndrome:
|
315
333
|
# Form the syndrome of the coherent bits.
|
316
|
-
self.sim.mcx([hq[other_bits[0]]],
|
317
|
-
self.sim.mcx([hq[other_bits[1]]],
|
334
|
+
self.sim[ancilla_sim].mcx([hq[other_bits[0]][1]], ancilla)
|
335
|
+
self.sim[ancilla_sim].mcx([hq[other_bits[1]][1]], ancilla)
|
318
336
|
# Force the syndrome non-pathological.
|
319
|
-
self.sim.force_m(
|
337
|
+
self.sim[ancilla_sim].force_m(ancilla, False)
|
320
338
|
|
321
339
|
def _correct_if_like_h(self, th, lq):
|
322
|
-
if not self._is_init[lq]:
|
323
|
-
return
|
324
340
|
while th > math.pi:
|
325
341
|
th -= 2 * math.pi
|
326
342
|
while th <= -math.pi:
|
@@ -331,8 +347,9 @@ class QrackAceBackend:
|
|
331
347
|
|
332
348
|
def u(self, lq, th, ph, lm):
|
333
349
|
hq = self._unpack(lq)
|
334
|
-
if
|
335
|
-
|
350
|
+
if len(hq) < 2:
|
351
|
+
b = hq[0]
|
352
|
+
self.sim[b[0]].u(b[1], th, ph, lm)
|
336
353
|
return
|
337
354
|
|
338
355
|
while ph > math.pi:
|
@@ -346,142 +363,150 @@ class QrackAceBackend:
|
|
346
363
|
|
347
364
|
if not math.isclose(ph, -lm) and not math.isclose(abs(ph), math.pi / 2):
|
348
365
|
# Produces/destroys superposition
|
349
|
-
|
350
|
-
|
351
|
-
|
352
|
-
self.sim.u(
|
353
|
-
|
354
|
-
|
355
|
-
|
356
|
-
else:
|
357
|
-
self._encode(lq, hq)
|
366
|
+
self._correct_if_like_h(th, lq)
|
367
|
+
self._encode_decode(lq, hq)
|
368
|
+
b = hq[0]
|
369
|
+
self.sim[b[0]].u(b[1], th, ph, lm)
|
370
|
+
b = hq[2]
|
371
|
+
self.sim[b[0]].u(b[1], th, ph, lm)
|
372
|
+
self._encode_decode(lq, hq)
|
358
373
|
else:
|
359
374
|
# Shouldn't produce/destroy superposition
|
360
375
|
for b in hq:
|
361
|
-
self.sim.u(b, th, ph, lm)
|
376
|
+
self.sim[b[0]].u(b[1], th, ph, lm)
|
362
377
|
|
363
378
|
def r(self, p, th, lq):
|
364
379
|
hq = self._unpack(lq)
|
365
|
-
if
|
366
|
-
|
380
|
+
if len(hq) < 2:
|
381
|
+
b = hq[0]
|
382
|
+
self.sim[b[0]].r(p, th, b[1])
|
367
383
|
return
|
368
384
|
|
369
385
|
while th > math.pi:
|
370
386
|
th -= 2 * math.pi
|
371
387
|
while th <= -math.pi:
|
372
388
|
th += 2 * math.pi
|
373
|
-
if
|
389
|
+
if p == Pauli.PauliY:
|
374
390
|
self._correct_if_like_h(th, lq)
|
375
391
|
|
376
392
|
if (p == Pauli.PauliZ) or math.isclose(abs(th), math.pi):
|
377
393
|
# Doesn't produce/destroy superposition
|
378
394
|
for b in hq:
|
379
|
-
self.sim.r(p, th, b)
|
395
|
+
self.sim[b[0]].r(p, th, b[1])
|
380
396
|
else:
|
381
397
|
# Produces/destroys superposition
|
382
|
-
|
383
|
-
|
384
|
-
self.sim.r(p, th,
|
385
|
-
|
386
|
-
|
387
|
-
|
388
|
-
else:
|
389
|
-
self._encode(lq, hq)
|
398
|
+
self._encode_decode(lq, hq)
|
399
|
+
b = hq[0]
|
400
|
+
self.sim[b[0]].r(p, th, b[1])
|
401
|
+
b = hq[2]
|
402
|
+
self.sim[b[0]].r(p, th, b[1])
|
403
|
+
self._encode_decode(lq, hq)
|
390
404
|
|
391
405
|
def h(self, lq):
|
392
406
|
hq = self._unpack(lq)
|
393
|
-
if
|
394
|
-
|
407
|
+
if len(hq) < 2:
|
408
|
+
b = hq[0]
|
409
|
+
self.sim[b[0]].h(b[1])
|
395
410
|
return
|
396
411
|
|
397
|
-
|
398
|
-
|
399
|
-
|
400
|
-
self.sim.h(
|
401
|
-
|
402
|
-
|
403
|
-
|
404
|
-
else:
|
405
|
-
self._encode(lq, hq)
|
412
|
+
self._correct(lq)
|
413
|
+
self._encode_decode(lq, hq)
|
414
|
+
b = hq[0]
|
415
|
+
self.sim[b[0]].h(b[1])
|
416
|
+
b = hq[2]
|
417
|
+
self.sim[b[0]].h(b[1])
|
418
|
+
self._encode_decode(lq, hq)
|
406
419
|
|
407
420
|
def s(self, lq):
|
408
421
|
hq = self._unpack(lq)
|
409
|
-
if
|
410
|
-
|
422
|
+
if len(hq) < 2:
|
423
|
+
b = hq[0]
|
424
|
+
self.sim[b[0]].s(b[1])
|
411
425
|
return
|
412
426
|
|
413
427
|
for b in hq:
|
414
|
-
self.sim.s(b)
|
428
|
+
self.sim[b[0]].s(b[1])
|
415
429
|
|
416
430
|
def adjs(self, lq):
|
417
431
|
hq = self._unpack(lq)
|
418
|
-
if
|
419
|
-
|
432
|
+
if len(hq) < 2:
|
433
|
+
b = hq[0]
|
434
|
+
self.sim[b[0]].adjs(b[1])
|
420
435
|
return
|
421
436
|
|
422
437
|
for b in hq:
|
423
|
-
self.sim.adjs(b)
|
438
|
+
self.sim[b[0]].adjs(b[1])
|
424
439
|
|
425
440
|
def x(self, lq):
|
426
441
|
hq = self._unpack(lq)
|
427
|
-
if
|
428
|
-
|
442
|
+
if len(hq) < 2:
|
443
|
+
b = hq[0]
|
444
|
+
self.sim[b[0]].x(b[1])
|
429
445
|
return
|
430
446
|
|
431
447
|
for b in hq:
|
432
|
-
self.sim.x(b)
|
448
|
+
self.sim[b[0]].x(b[1])
|
433
449
|
|
434
450
|
def y(self, lq):
|
435
451
|
hq = self._unpack(lq)
|
436
|
-
if
|
437
|
-
|
452
|
+
if len(hq) < 2:
|
453
|
+
b = hq[0]
|
454
|
+
self.sim[b[0]].y(b[1])
|
438
455
|
return
|
439
456
|
|
440
457
|
for b in hq:
|
441
|
-
self.sim.y(b)
|
458
|
+
self.sim[b[0]].y(b[1])
|
442
459
|
|
443
460
|
def z(self, lq):
|
444
461
|
hq = self._unpack(lq)
|
445
|
-
if
|
446
|
-
|
462
|
+
if len(hq) < 2:
|
463
|
+
b = hq[0]
|
464
|
+
self.sim[b[0]].z(b[1])
|
447
465
|
return
|
448
466
|
|
449
467
|
for b in hq:
|
450
|
-
self.sim.z(b)
|
468
|
+
self.sim[b[0]].z(b[1])
|
451
469
|
|
452
470
|
def t(self, lq):
|
453
471
|
hq = self._unpack(lq)
|
454
|
-
if
|
455
|
-
|
472
|
+
if len(hq) < 2:
|
473
|
+
b = hq[0]
|
474
|
+
self.sim[b[0]].t(b[1])
|
456
475
|
return
|
457
476
|
|
458
477
|
for b in hq:
|
459
|
-
self.sim.t(b)
|
478
|
+
self.sim[b[0]].t(b[1])
|
460
479
|
|
461
480
|
def adjt(self, lq):
|
462
481
|
hq = self._unpack(lq)
|
463
|
-
if
|
464
|
-
|
482
|
+
if len(hq) < 2:
|
483
|
+
b = hq[0]
|
484
|
+
self.sim[b[0]].adjt(b[1])
|
465
485
|
return
|
466
486
|
|
467
487
|
for b in hq:
|
468
|
-
self.sim.adjt(b)
|
488
|
+
self.sim[b[0]].adjt(b[1])
|
469
489
|
|
470
|
-
def
|
490
|
+
def _get_gate(self, pauli, anti, sim_id):
|
471
491
|
gate = None
|
472
492
|
shadow = None
|
473
493
|
if pauli == Pauli.PauliX:
|
474
|
-
gate = self.sim.macx if anti else self.sim.mcx
|
494
|
+
gate = self.sim[sim_id].macx if anti else self.sim[sim_id].mcx
|
475
495
|
shadow = self._anti_cx_shadow if anti else self._cx_shadow
|
476
496
|
elif pauli == Pauli.PauliY:
|
477
|
-
gate = self.sim.macy if anti else self.sim.mcy
|
497
|
+
gate = self.sim[sim_id].macy if anti else self.sim[sim_id].mcy
|
478
498
|
shadow = self._anti_cy_shadow if anti else self._cy_shadow
|
479
499
|
elif pauli == Pauli.PauliZ:
|
480
|
-
gate = self.sim.macz if anti else self.sim.mcz
|
500
|
+
gate = self.sim[sim_id].macz if anti else self.sim[sim_id].mcz
|
481
501
|
shadow = self._anti_cz_shadow if anti else self._cz_shadow
|
482
502
|
else:
|
483
|
-
|
503
|
+
raise RuntimeError(
|
504
|
+
"QrackAceBackend._get_gate() should never return identity!"
|
505
|
+
)
|
506
|
+
|
507
|
+
return gate, shadow
|
484
508
|
|
509
|
+
def _cpauli(self, lq1, lq2, anti, pauli):
|
485
510
|
lq1_lr = self._is_col_long_range[lq1 % self.row_length]
|
486
511
|
lq2_lr = self._is_col_long_range[lq2 % self.row_length]
|
487
512
|
|
@@ -492,125 +517,90 @@ class QrackAceBackend:
|
|
492
517
|
|
493
518
|
connected_cols = []
|
494
519
|
c = (lq1_col - 1) % self.row_length
|
495
|
-
while self._is_col_long_range[c] and (
|
520
|
+
while self._is_col_long_range[c] and (
|
521
|
+
len(connected_cols) < (self.row_length - 1)
|
522
|
+
):
|
496
523
|
connected_cols.append(c)
|
497
524
|
c = (c - 1) % self.row_length
|
498
|
-
if len(connected_cols) < self.row_length:
|
525
|
+
if len(connected_cols) < (self.row_length - 1):
|
499
526
|
connected_cols.append(c)
|
500
527
|
boundary = len(connected_cols)
|
501
528
|
c = (lq1_col + 1) % self.row_length
|
502
|
-
while self._is_col_long_range[c] and (
|
529
|
+
while self._is_col_long_range[c] and (
|
530
|
+
len(connected_cols) < (self.row_length - 1)
|
531
|
+
):
|
503
532
|
connected_cols.append(c)
|
504
533
|
c = (c + 1) % self.row_length
|
505
|
-
if len(connected_cols) < self.row_length:
|
534
|
+
if len(connected_cols) < (self.row_length - 1):
|
506
535
|
connected_cols.append(c)
|
507
536
|
|
537
|
+
hq1 = self._unpack(lq1)
|
538
|
+
hq2 = self._unpack(lq2)
|
539
|
+
|
508
540
|
if lq1_lr and lq2_lr:
|
541
|
+
b1 = hq1[0]
|
542
|
+
b2 = hq2[0]
|
543
|
+
gate, shadow = self._get_gate(pauli, anti, b1[0])
|
509
544
|
if lq2_col in connected_cols:
|
510
|
-
gate(
|
545
|
+
gate([b1[1]], b2[1])
|
511
546
|
else:
|
512
|
-
shadow(
|
547
|
+
shadow(b1, b2)
|
513
548
|
return
|
514
549
|
|
515
550
|
self._correct(lq1)
|
551
|
+
self._correct(lq2)
|
516
552
|
|
517
|
-
if not self._is_init[lq1]:
|
518
|
-
hq1 = self._unpack(lq1)
|
519
|
-
hq2 = self._unpack(lq2)
|
520
|
-
if lq1_lr:
|
521
|
-
self._decode(lq2, hq2)
|
522
|
-
gate(hq1, hq2[0])
|
523
|
-
self._encode(lq2, hq2)
|
524
|
-
elif lq2_lr:
|
525
|
-
self._decode(lq1, hq1)
|
526
|
-
gate([hq1[0]], hq2[0])
|
527
|
-
self._encode(lq1, hq1)
|
528
|
-
else:
|
529
|
-
gate([hq1[0]], hq2[0])
|
530
|
-
gate([hq1[1]], hq2[1])
|
531
|
-
gate([hq1[2]], hq2[2])
|
532
|
-
|
533
|
-
return
|
534
|
-
|
535
|
-
hq1 = None
|
536
|
-
hq2 = None
|
537
553
|
if (lq2_col in connected_cols) and (connected_cols.index(lq2_col) < boundary):
|
554
|
+
# lq2_col < lq1_col
|
555
|
+
self._encode_decode(lq1, hq1)
|
556
|
+
self._encode_decode(lq2, hq2)
|
557
|
+
b = hq1[0]
|
538
558
|
if lq1_lr:
|
539
|
-
self.
|
540
|
-
hq1 = self._unpack(lq1)
|
541
|
-
hq2 = self._unpack(lq2, False)
|
542
|
-
self._decode(lq2, hq2, False)
|
543
|
-
gate(hq1, hq2[0])
|
544
|
-
self._encode(lq2, hq2, False)
|
559
|
+
self._get_gate(pauli, anti, hq1[0][0])[0]([b[1]], hq2[2][1])
|
545
560
|
elif lq2_lr:
|
546
|
-
|
547
|
-
hq2 = self._unpack(lq2)
|
548
|
-
self._decode(lq1, hq1, True)
|
549
|
-
gate([hq1[0]], hq2[0])
|
550
|
-
self._encode(lq1, hq1, True)
|
561
|
+
self._get_gate(pauli, anti, hq2[0][0])[0]([b[1]], hq2[0][1])
|
551
562
|
else:
|
552
|
-
self.
|
553
|
-
|
554
|
-
|
555
|
-
self._decode(lq1, hq1, True)
|
556
|
-
self._decode(lq2, hq2, False)
|
557
|
-
gate([hq1[0]], hq2[0])
|
558
|
-
self._encode(lq2, hq2, False)
|
559
|
-
self._encode(lq1, hq1, True)
|
563
|
+
self._get_gate(pauli, anti, b[0])[0]([b[1]], hq2[2][1])
|
564
|
+
self._encode_decode(lq2, hq2)
|
565
|
+
self._encode_decode(lq1, hq1)
|
560
566
|
elif lq2_col in connected_cols:
|
567
|
+
# lq1_col < lq2_col
|
568
|
+
self._encode_decode(lq1, hq1)
|
569
|
+
self._encode_decode(lq2, hq2)
|
570
|
+
b = hq2[0]
|
561
571
|
if lq1_lr:
|
562
|
-
self.
|
563
|
-
hq2 = self._unpack(lq2, True)
|
564
|
-
hq1 = self._unpack(lq1)
|
565
|
-
self._decode(lq2, hq2, True)
|
566
|
-
gate(hq1, hq2[0])
|
567
|
-
self._encode(lq2, hq2, True)
|
572
|
+
self._get_gate(pauli, anti, hq1[0][0])[0]([hq1[0][1]], b[1])
|
568
573
|
elif lq2_lr:
|
569
|
-
|
570
|
-
hq1 = self._unpack(lq1, False)
|
571
|
-
self._decode(lq1, hq1, False)
|
572
|
-
gate([hq1[0]], hq2[0])
|
573
|
-
self._encode(lq1, hq1, False)
|
574
|
+
self._get_gate(pauli, anti, hq2[0][0])[0]([hq1[2][1]], b[1])
|
574
575
|
else:
|
575
|
-
self.
|
576
|
-
|
577
|
-
|
578
|
-
self._decode(lq2, hq2, True)
|
579
|
-
self._decode(lq1, hq1, False)
|
580
|
-
gate([hq1[0]], hq2[0])
|
581
|
-
self._encode(lq1, hq1, False)
|
582
|
-
self._encode(lq2, hq2, True)
|
576
|
+
self._get_gate(pauli, anti, b[0])[0]([hq1[2][1]], b[1])
|
577
|
+
self._encode_decode(lq2, hq2)
|
578
|
+
self._encode_decode(lq1, hq1)
|
583
579
|
elif lq1_col == lq2_col:
|
584
|
-
|
585
|
-
|
586
|
-
|
587
|
-
|
588
|
-
|
589
|
-
|
590
|
-
|
591
|
-
|
592
|
-
|
593
|
-
gate([hq1[0]], hq2[0])
|
594
|
-
self._encode(lq1, hq1)
|
580
|
+
# Both are in the same boundary column.
|
581
|
+
b = hq1[0]
|
582
|
+
gate, shadow = self._get_gate(pauli, anti, b[0])
|
583
|
+
gate([b[1]], hq2[0][1])
|
584
|
+
b = hq1[2]
|
585
|
+
gate, shadow = self._get_gate(pauli, anti, b[0])
|
586
|
+
gate([b[1]], hq2[2][1])
|
587
|
+
if hq1[1][0] != hq2[1][0]:
|
588
|
+
shadow(hq1[1], hq2[1])
|
595
589
|
else:
|
596
|
-
|
597
|
-
|
598
|
-
|
599
|
-
else:
|
600
|
-
gate([hq1[1]], hq2[1])
|
601
|
-
gate([hq1[2]], hq2[2])
|
590
|
+
b = hq1[1]
|
591
|
+
gate, shadow = self._get_gate(pauli, anti, b[0])
|
592
|
+
gate([b[1]], hq2[1][1])
|
602
593
|
else:
|
603
|
-
|
604
|
-
|
594
|
+
# The qubits have no quantum connection.
|
595
|
+
gate, shadow = self._get_gate(pauli, anti, hq1[0][0])
|
605
596
|
if lq1_lr:
|
606
|
-
self.
|
607
|
-
self._decode(lq2, hq2)
|
597
|
+
self._encode_decode(lq2, hq2)
|
608
598
|
shadow(hq1[0], hq2[0])
|
609
|
-
self.
|
599
|
+
self._encode_decode(lq2, hq2)
|
610
600
|
elif lq2_lr:
|
611
|
-
self.
|
601
|
+
self._encode_decode(lq1, hq1)
|
612
602
|
shadow(hq1[0], hq2[0])
|
613
|
-
self.
|
603
|
+
self._encode_decode(lq1, hq1)
|
614
604
|
else:
|
615
605
|
shadow(hq1[0], hq2[0])
|
616
606
|
shadow(hq1[1], hq2[1])
|
@@ -694,12 +684,12 @@ class QrackAceBackend:
|
|
694
684
|
self.swap(lq1, lq2)
|
695
685
|
|
696
686
|
def m(self, lq):
|
697
|
-
self._is_init[lq] = False
|
698
687
|
hq = self._unpack(lq)
|
699
|
-
if
|
700
|
-
|
688
|
+
if len(hq) < 2:
|
689
|
+
b = hq[0]
|
690
|
+
return self.sim[b[0]].m(b[1])
|
701
691
|
|
702
|
-
if
|
692
|
+
if hq[0][0] == hq[0][1]:
|
703
693
|
single_bit = 2
|
704
694
|
other_bits = [0, 1]
|
705
695
|
else:
|
@@ -707,24 +697,27 @@ class QrackAceBackend:
|
|
707
697
|
other_bits = [1, 2]
|
708
698
|
# The syndrome of "other_bits" is guaranteed to be fixed, after this.
|
709
699
|
self._correct(lq)
|
710
|
-
|
711
|
-
syndrome
|
700
|
+
b = hq[other_bits[0]]
|
701
|
+
syndrome = self.sim[b[0]].m(b[1])
|
702
|
+
b = hq[other_bits[1]]
|
703
|
+
syndrome += self.sim[b[0]].force_m(b[1], bool(syndrome))
|
712
704
|
# The two separable parts of the code are correlated,
|
713
705
|
# but not non-locally, via entanglement.
|
714
706
|
# Collapse the other separable part toward agreement.
|
715
|
-
|
707
|
+
b = hq[single_bit]
|
708
|
+
syndrome += self.sim[b[0]].force_m(b[1], bool(syndrome))
|
716
709
|
|
717
710
|
return True if (syndrome > 1) else False
|
718
711
|
|
719
712
|
def force_m(self, lq, c):
|
720
713
|
hq = self._unpack(lq)
|
721
|
-
|
722
|
-
|
723
|
-
return self.sim.force_m(
|
714
|
+
if len(hq) < 2:
|
715
|
+
b = hq[0]
|
716
|
+
return self.sim[b[0]].force_m(b[1])
|
724
717
|
|
725
718
|
self._correct(lq)
|
726
719
|
for q in hq:
|
727
|
-
self.sim.force_m(q, c)
|
720
|
+
self.sim[q[0]].force_m(q[1], c)
|
728
721
|
|
729
722
|
return c
|
730
723
|
|
@@ -763,17 +756,20 @@ class QrackAceBackend:
|
|
763
756
|
|
764
757
|
def prob(self, lq):
|
765
758
|
hq = self._unpack(lq)
|
766
|
-
if
|
767
|
-
|
759
|
+
if len(hq) < 2:
|
760
|
+
b = hq[0]
|
761
|
+
return self.sim[b[0]].prob(b[1])
|
768
762
|
|
769
763
|
self._correct(lq)
|
770
764
|
if not self.alternating_codes or not ((lq // self.row_length) & 1):
|
771
765
|
other_bits = [0, 1]
|
772
766
|
else:
|
773
767
|
other_bits = [1, 2]
|
774
|
-
|
775
|
-
|
776
|
-
self.sim.mcx([
|
768
|
+
b0 = hq[other_bits[0]]
|
769
|
+
b1 = hq[other_bits[1]]
|
770
|
+
self.sim[b0[0]].mcx([b0[1]], b1[1])
|
771
|
+
result = self.sim[b0[0]].prob(b0[1])
|
772
|
+
self.sim[b0[0]].mcx([b0[1]], b1[1])
|
777
773
|
|
778
774
|
return result
|
779
775
|
|
@@ -1129,13 +1125,17 @@ class QrackAceBackend:
|
|
1129
1125
|
for col in range(cols):
|
1130
1126
|
connected_cols = [col]
|
1131
1127
|
c = (col - 1) % cols
|
1132
|
-
while self._is_col_long_range[c] and (
|
1128
|
+
while self._is_col_long_range[c] and (
|
1129
|
+
len(connected_cols) < self.row_length
|
1130
|
+
):
|
1133
1131
|
connected_cols.append(c)
|
1134
1132
|
c = (c - 1) % cols
|
1135
1133
|
if len(connected_cols) < self.row_length:
|
1136
1134
|
connected_cols.append(c)
|
1137
1135
|
c = (col + 1) % cols
|
1138
|
-
while self._is_col_long_range[c] and (
|
1136
|
+
while self._is_col_long_range[c] and (
|
1137
|
+
len(connected_cols) < self.row_length
|
1138
|
+
):
|
1139
1139
|
connected_cols.append(c)
|
1140
1140
|
c = (c + 1) % cols
|
1141
1141
|
if len(connected_cols) < self.row_length:
|
@@ -1177,25 +1177,31 @@ class QrackAceBackend:
|
|
1177
1177
|
continue # No noise for even-even or odd-odd within a boundary column
|
1178
1178
|
|
1179
1179
|
if same_col:
|
1180
|
-
x_cy = 1 - (1 - x)**2
|
1181
|
-
x_swap = 1 - (1 - x)**3
|
1182
|
-
noise_model.add_quantum_error(depolarizing_error(x, 2),
|
1183
|
-
noise_model.add_quantum_error(depolarizing_error(x_cy, 2),
|
1184
|
-
noise_model.add_quantum_error(depolarizing_error(x_cy, 2),
|
1185
|
-
noise_model.add_quantum_error(
|
1180
|
+
x_cy = 1 - (1 - x) ** 2
|
1181
|
+
x_swap = 1 - (1 - x) ** 3
|
1182
|
+
noise_model.add_quantum_error(depolarizing_error(x, 2), "cx", [a, b])
|
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
|
+
)
|
1186
1188
|
elif is_long_a or is_long_b:
|
1187
|
-
y_cy = 1 - (1 - y)**2
|
1188
|
-
y_swap = 1 - (1 - y)**3
|
1189
|
-
noise_model.add_quantum_error(depolarizing_error(y, 2),
|
1190
|
-
noise_model.add_quantum_error(depolarizing_error(y_cy, 2),
|
1191
|
-
noise_model.add_quantum_error(depolarizing_error(y_cy, 2),
|
1192
|
-
noise_model.add_quantum_error(
|
1189
|
+
y_cy = 1 - (1 - y) ** 2
|
1190
|
+
y_swap = 1 - (1 - y) ** 3
|
1191
|
+
noise_model.add_quantum_error(depolarizing_error(y, 2), "cx", [a, b])
|
1192
|
+
noise_model.add_quantum_error(depolarizing_error(y_cy, 2), "cy", [a, b])
|
1193
|
+
noise_model.add_quantum_error(depolarizing_error(y_cy, 2), "cz", [a, b])
|
1194
|
+
noise_model.add_quantum_error(
|
1195
|
+
depolarizing_error(y_swap, 2), "swap", [a, b]
|
1196
|
+
)
|
1193
1197
|
else:
|
1194
|
-
y_cy = 1 - (1 - y)**2
|
1195
|
-
y_swap = 1 - (1 - y)**3
|
1196
|
-
noise_model.add_quantum_error(depolarizing_error(y_cy, 2),
|
1197
|
-
noise_model.add_quantum_error(depolarizing_error(y_cy, 2),
|
1198
|
-
noise_model.add_quantum_error(depolarizing_error(y_cy, 2),
|
1199
|
-
noise_model.add_quantum_error(
|
1198
|
+
y_cy = 1 - (1 - y) ** 2
|
1199
|
+
y_swap = 1 - (1 - y) ** 3
|
1200
|
+
noise_model.add_quantum_error(depolarizing_error(y_cy, 2), "cx", [a, b])
|
1201
|
+
noise_model.add_quantum_error(depolarizing_error(y_cy, 2), "cy", [a, b])
|
1202
|
+
noise_model.add_quantum_error(depolarizing_error(y_cy, 2), "cz", [a, b])
|
1203
|
+
noise_model.add_quantum_error(
|
1204
|
+
depolarizing_error(y_swap, 2), "swap", [a, b]
|
1205
|
+
)
|
1200
1206
|
|
1201
1207
|
return noise_model
|
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
|