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