pyqrack-cuda 1.50.0__tar.gz → 1.51.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.0 → pyqrack_cuda-1.51.0}/Makefile +1 -1
- {pyqrack_cuda-1.50.0/pyqrack_cuda.egg-info → pyqrack_cuda-1.51.0}/PKG-INFO +1 -1
- {pyqrack_cuda-1.50.0 → pyqrack_cuda-1.51.0}/pyqrack/qrack_ace_backend.py +303 -300
- {pyqrack_cuda-1.50.0 → pyqrack_cuda-1.51.0}/pyqrack/qrack_simulator.py +6 -0
- {pyqrack_cuda-1.50.0 → pyqrack_cuda-1.51.0}/pyqrack/qrack_system/qrack_system.py +3 -0
- {pyqrack_cuda-1.50.0 → pyqrack_cuda-1.51.0/pyqrack_cuda.egg-info}/PKG-INFO +1 -1
- {pyqrack_cuda-1.50.0 → pyqrack_cuda-1.51.0}/setup.py +1 -1
- {pyqrack_cuda-1.50.0 → pyqrack_cuda-1.51.0}/LICENSE +0 -0
- {pyqrack_cuda-1.50.0 → pyqrack_cuda-1.51.0}/MANIFEST.in +0 -0
- {pyqrack_cuda-1.50.0 → pyqrack_cuda-1.51.0}/README.md +0 -0
- {pyqrack_cuda-1.50.0 → pyqrack_cuda-1.51.0}/pyproject.toml +0 -0
- {pyqrack_cuda-1.50.0 → pyqrack_cuda-1.51.0}/pyqrack/__init__.py +0 -0
- {pyqrack_cuda-1.50.0 → pyqrack_cuda-1.51.0}/pyqrack/neuron_activation_fn.py +0 -0
- {pyqrack_cuda-1.50.0 → pyqrack_cuda-1.51.0}/pyqrack/pauli.py +0 -0
- {pyqrack_cuda-1.50.0 → pyqrack_cuda-1.51.0}/pyqrack/qrack_circuit.py +0 -0
- {pyqrack_cuda-1.50.0 → pyqrack_cuda-1.51.0}/pyqrack/qrack_neuron.py +0 -0
- {pyqrack_cuda-1.50.0 → pyqrack_cuda-1.51.0}/pyqrack/qrack_neuron_torch_layer.py +0 -0
- {pyqrack_cuda-1.50.0 → pyqrack_cuda-1.51.0}/pyqrack/qrack_stabilizer.py +0 -0
- {pyqrack_cuda-1.50.0 → pyqrack_cuda-1.51.0}/pyqrack/qrack_system/__init__.py +0 -0
- {pyqrack_cuda-1.50.0 → pyqrack_cuda-1.51.0}/pyqrack/quimb_circuit_type.py +0 -0
- {pyqrack_cuda-1.50.0 → pyqrack_cuda-1.51.0}/pyqrack/stats/__init__.py +0 -0
- {pyqrack_cuda-1.50.0 → pyqrack_cuda-1.51.0}/pyqrack/stats/load_quantized_data.py +0 -0
- {pyqrack_cuda-1.50.0 → pyqrack_cuda-1.51.0}/pyqrack/stats/quantize_by_range.py +0 -0
- {pyqrack_cuda-1.50.0 → pyqrack_cuda-1.51.0}/pyqrack_cuda.egg-info/SOURCES.txt +0 -0
- {pyqrack_cuda-1.50.0 → pyqrack_cuda-1.51.0}/pyqrack_cuda.egg-info/dependency_links.txt +0 -0
- {pyqrack_cuda-1.50.0 → pyqrack_cuda-1.51.0}/pyqrack_cuda.egg-info/not-zip-safe +0 -0
- {pyqrack_cuda-1.50.0 → pyqrack_cuda-1.51.0}/pyqrack_cuda.egg-info/requires.txt +0 -0
- {pyqrack_cuda-1.50.0 → pyqrack_cuda-1.51.0}/pyqrack_cuda.egg-info/top_level.txt +0 -0
- {pyqrack_cuda-1.50.0 → pyqrack_cuda-1.51.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)
|
@@ -38,8 +38,12 @@ class QrackAceBackend:
|
|
38
38
|
without breaking the concept. (Not all will work equally well.) For maximum flexibility, set
|
39
39
|
"alternating_codes=False". (For best performance on Sycamore-like topologies,leave it "True.")
|
40
40
|
|
41
|
+
Consider distributing the different "patches" to different GPUs with self.sim[sim_id].set_device(gpu_id)!
|
42
|
+
(If you have 3+ patches, maybe your discrete GPU can do multiple patches in the time it takes an Intel HD
|
43
|
+
to do one patch worth of work!)
|
44
|
+
|
41
45
|
Attributes:
|
42
|
-
sim(QrackSimulator):
|
46
|
+
sim(QrackSimulator): Array of simulators corresponding to "patches" between boundary rows.
|
43
47
|
alternating_codes(bool): Alternate repetition code elision by index?
|
44
48
|
row_length(int): Qubits per row.
|
45
49
|
col_length(int): Qubits per column.
|
@@ -69,45 +73,70 @@ class QrackAceBackend:
|
|
69
73
|
self.long_range_columns = long_range_columns
|
70
74
|
|
71
75
|
self.alternating_codes = alternating_codes
|
72
|
-
self._is_init = [False] * qubit_count
|
73
76
|
self._coupling_map = None
|
74
77
|
|
75
78
|
# If there's only one or zero "False" columns,
|
76
79
|
# the entire simulator is connected, anyway.
|
80
|
+
len_col_seq = long_range_columns + 1
|
81
|
+
sim_count = (self.row_length + len_col_seq - 1) // len_col_seq
|
77
82
|
if (long_range_columns + 1) >= self.row_length:
|
78
83
|
self._is_col_long_range = [True] * self.row_length
|
79
84
|
else:
|
80
85
|
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]
|
86
|
+
self._is_col_long_range = (col_seq * sim_count)[: self.row_length]
|
85
87
|
if long_range_columns < self.row_length:
|
86
88
|
self._is_col_long_range[-1] = False
|
87
89
|
|
90
|
+
self._qubit_dict = {}
|
88
91
|
self._hardware_offset = []
|
92
|
+
self._ancilla = [0] * sim_count
|
93
|
+
sim_counts = [0] * sim_count
|
94
|
+
sim_id = 0
|
89
95
|
tot_qubits = 0
|
90
|
-
for
|
96
|
+
for r in range(self.col_length):
|
91
97
|
for c in self._is_col_long_range:
|
92
98
|
self._hardware_offset.append(tot_qubits)
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
99
|
+
if c:
|
100
|
+
self._qubit_dict[tot_qubits] = (sim_id, sim_counts[sim_id])
|
101
|
+
tot_qubits += 1
|
102
|
+
sim_counts[sim_id] += 1
|
103
|
+
elif not self.alternating_codes or not (r & 1):
|
104
|
+
self._qubit_dict[tot_qubits] = (sim_id, sim_counts[sim_id])
|
105
|
+
tot_qubits += 1
|
106
|
+
sim_counts[sim_id] += 1
|
107
|
+
sim_id = (sim_id + 1) % sim_count
|
108
|
+
for _ in range(2):
|
109
|
+
self._qubit_dict[tot_qubits] = (sim_id, sim_counts[sim_id])
|
110
|
+
tot_qubits += 1
|
111
|
+
sim_counts[sim_id] += 1
|
112
|
+
else:
|
113
|
+
for _ in range(2):
|
114
|
+
self._qubit_dict[tot_qubits] = (sim_id, sim_counts[sim_id])
|
115
|
+
tot_qubits += 1
|
116
|
+
sim_counts[sim_id] += 1
|
117
|
+
sim_id = (sim_id + 1) % sim_count
|
118
|
+
self._qubit_dict[tot_qubits] = (sim_id, sim_counts[sim_id])
|
119
|
+
tot_qubits += 1
|
120
|
+
sim_counts[sim_id] += 1
|
121
|
+
|
122
|
+
self.sim = []
|
123
|
+
for i in range(sim_count):
|
124
|
+
self._ancilla[i] = sim_counts[i]
|
125
|
+
sim_counts[i] += 1
|
126
|
+
self.sim.append(
|
127
|
+
toClone.sim[i].clone()
|
128
|
+
if toClone
|
129
|
+
else QrackSimulator(
|
130
|
+
sim_counts[i],
|
131
|
+
isTensorNetwork=isTensorNetwork,
|
132
|
+
isStabilizerHybrid=isStabilizerHybrid,
|
133
|
+
isBinaryDecisionTree=isBinaryDecisionTree,
|
134
|
+
)
|
105
135
|
)
|
106
|
-
)
|
107
136
|
|
108
|
-
|
109
|
-
|
110
|
-
|
137
|
+
# You can still "monkey-patch" this, after the constructor.
|
138
|
+
if "QRACK_QUNIT_SEPARABILITY_THRESHOLD" not in os.environ:
|
139
|
+
self.sim[i].set_sdrp(0.03)
|
111
140
|
|
112
141
|
def clone(self):
|
113
142
|
return QrackAceBackend(toClone=self)
|
@@ -125,8 +154,8 @@ class QrackAceBackend:
|
|
125
154
|
self.row_length = col_len if reverse else row_len
|
126
155
|
|
127
156
|
def _ct_pair_prob(self, q1, q2):
|
128
|
-
p1 = self.sim.prob(q1)
|
129
|
-
p2 = self.sim.prob(q2)
|
157
|
+
p1 = self.sim[q1[0]].prob(q1[1])
|
158
|
+
p2 = self.sim[q2[0]].prob(q2[1])
|
130
159
|
|
131
160
|
if p1 < p2:
|
132
161
|
return p2, q1
|
@@ -136,96 +165,87 @@ class QrackAceBackend:
|
|
136
165
|
def _cz_shadow(self, q1, q2):
|
137
166
|
prob_max, t = self._ct_pair_prob(q1, q2)
|
138
167
|
if prob_max > 0.5:
|
139
|
-
self.sim.z(t)
|
168
|
+
self.sim[t[0]].z(t[1])
|
140
169
|
|
141
|
-
def _anti_cz_shadow(self,
|
142
|
-
self.sim.x(
|
143
|
-
self._cz_shadow(
|
144
|
-
self.sim.x(
|
170
|
+
def _anti_cz_shadow(self, c, t):
|
171
|
+
self.sim[c[0]].x(c[1])
|
172
|
+
self._cz_shadow(c, t)
|
173
|
+
self.sim[c[0]].x(c[1])
|
145
174
|
|
146
175
|
def _cx_shadow(self, c, t):
|
147
|
-
self.sim.h(t)
|
176
|
+
self.sim[t[0]].h(t[1])
|
148
177
|
self._cz_shadow(c, t)
|
149
|
-
self.sim.h(t)
|
178
|
+
self.sim[t[0]].h(t[1])
|
150
179
|
|
151
180
|
def _anti_cx_shadow(self, c, t):
|
152
|
-
self.sim.x(
|
181
|
+
self.sim[c[0]].x(c[1])
|
153
182
|
self._cx_shadow(c, t)
|
154
|
-
self.sim.x(
|
183
|
+
self.sim[c[0]].x(c[1])
|
155
184
|
|
156
185
|
def _cy_shadow(self, c, t):
|
157
|
-
self.sim.adjs(t)
|
186
|
+
self.sim[t[0]].adjs(t[1])
|
158
187
|
self._cx_shadow(c, t)
|
159
|
-
self.sim.s(t)
|
188
|
+
self.sim[t[0]].s(t[1])
|
160
189
|
|
161
190
|
def _anti_cy_shadow(self, c, t):
|
162
|
-
self.sim.x(
|
191
|
+
self.sim[c[0]].x(c[1])
|
163
192
|
self._cy_shadow(c, t)
|
164
|
-
self.sim.x(
|
193
|
+
self.sim[c[0]].x(c[1])
|
165
194
|
|
166
195
|
def _ccz_shadow(self, c1, q2, q3):
|
167
|
-
self.sim.mcx([q2], q3)
|
168
|
-
self.sim.adjt(q3)
|
196
|
+
self.sim[q2[0]].mcx([q2[1]], q3[1])
|
197
|
+
self.sim[q3[0]].adjt(q3[1])
|
169
198
|
self._cx_shadow(c1, q3)
|
170
|
-
self.sim.t(q3)
|
171
|
-
self.sim.mcx([q2], q3)
|
172
|
-
self.sim.adjt(q3)
|
199
|
+
self.sim[q3[0]].t(q3[1])
|
200
|
+
self.sim[q2[0]].mcx([q2[1]], q3[1])
|
201
|
+
self.sim[q3[0]].adjt(q3[1])
|
173
202
|
self._cx_shadow(c1, q3)
|
174
|
-
self.sim.t(q3)
|
175
|
-
self.sim.t(q2)
|
203
|
+
self.sim[q3[0]].t(q3[1])
|
204
|
+
self.sim[q2[0]].t(q2[1])
|
176
205
|
self._cx_shadow(c1, q2)
|
177
|
-
self.sim.adjt(q2)
|
178
|
-
self.sim.t(c1)
|
206
|
+
self.sim[q2[0]].adjt(q2[1])
|
207
|
+
self.sim[c1[0]].t(c1[1])
|
179
208
|
self._cx_shadow(c1, q2)
|
180
209
|
|
181
|
-
def _ccx_shadow(self, c1, q2,
|
182
|
-
self.sim.h(
|
183
|
-
self._ccz_shadow(c1, q2,
|
184
|
-
self.sim.h(
|
210
|
+
def _ccx_shadow(self, c1, q2, t):
|
211
|
+
self.sim[t[0]].h(t[1])
|
212
|
+
self._ccz_shadow(c1, q2, t)
|
213
|
+
self.sim[t[0]].h(t[1])
|
185
214
|
|
186
|
-
def _unpack(self, lq
|
215
|
+
def _unpack(self, lq):
|
187
216
|
offset = self._hardware_offset[lq]
|
188
217
|
|
189
218
|
if self._is_col_long_range[lq % self.row_length]:
|
190
|
-
return [offset]
|
219
|
+
return [self._qubit_dict[offset]]
|
191
220
|
|
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
|
221
|
+
return [
|
222
|
+
self._qubit_dict[offset],
|
223
|
+
self._qubit_dict[offset + 1],
|
224
|
+
self._qubit_dict[offset + 2],
|
225
|
+
]
|
208
226
|
|
209
|
-
def
|
210
|
-
if
|
227
|
+
def _encode_decode(self, lq, hq):
|
228
|
+
if len(hq) < 2:
|
211
229
|
return
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
self.sim.mcx([hq[2]], hq[1])
|
230
|
+
if hq[0][0] == hq[1][0]:
|
231
|
+
b0 = hq[0]
|
232
|
+
self.sim[b0[0]].mcx([b0[1]], hq[1][1])
|
216
233
|
else:
|
217
|
-
|
218
|
-
self.sim.mcx([
|
219
|
-
self._cx_shadow(hq[0], hq[2])
|
234
|
+
b2 = hq[2]
|
235
|
+
self.sim[b2[0]].mcx([b2[1]], hq[1][1])
|
220
236
|
|
221
|
-
def
|
222
|
-
if
|
223
|
-
|
224
|
-
|
225
|
-
|
237
|
+
def _encode_decode_half(self, lq, hq, toward_0):
|
238
|
+
if len(hq) < 2:
|
239
|
+
return
|
240
|
+
if toward_0 and (hq[0][0] == hq[1][0]):
|
241
|
+
b0 = hq[0]
|
242
|
+
self.sim[b0[0]].mcx([b0[1]], hq[1][1])
|
243
|
+
elif not toward_0 and (hq[2][0] == hq[1][0]):
|
244
|
+
b2 = hq[2]
|
245
|
+
self.sim[b2[0]].mcx([b2[1]], hq[1][1])
|
226
246
|
|
227
247
|
def _correct(self, lq):
|
228
|
-
if
|
248
|
+
if self._is_col_long_range[lq % self.row_length]:
|
229
249
|
return
|
230
250
|
# We can't use true syndrome-based error correction,
|
231
251
|
# because one of the qubits in the code is separated.
|
@@ -234,25 +254,31 @@ class QrackAceBackend:
|
|
234
254
|
|
235
255
|
single_bit = 0
|
236
256
|
other_bits = []
|
237
|
-
|
257
|
+
hq = self._unpack(lq)
|
258
|
+
if hq[0][0] == hq[1][0]:
|
238
259
|
single_bit = 2
|
239
260
|
other_bits = [0, 1]
|
240
|
-
|
261
|
+
elif hq[1][0] == hq[2][0]:
|
241
262
|
single_bit = 0
|
242
263
|
other_bits = [1, 2]
|
264
|
+
else:
|
265
|
+
raise RuntimeError("Invalid boundary qubit!")
|
243
266
|
|
244
|
-
|
267
|
+
ancilla_sim = hq[other_bits[0]][0]
|
268
|
+
ancilla = self._ancilla[ancilla_sim]
|
245
269
|
|
246
|
-
single_bit_value = self.sim.prob(hq[single_bit])
|
270
|
+
single_bit_value = self.sim[hq[single_bit][0]].prob(hq[single_bit][1])
|
247
271
|
single_bit_polarization = max(single_bit_value, 1 - single_bit_value)
|
248
272
|
|
249
273
|
# Suggestion from Elara (the custom OpenAI GPT):
|
250
274
|
# 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(
|
275
|
+
self._ccx_shadow(hq[single_bit], hq[other_bits[0]], [ancilla_sim, ancilla])
|
276
|
+
self.sim[ancilla_sim].mcx([hq[other_bits[1]][1]], ancilla)
|
277
|
+
self.sim[ancilla_sim].force_m(ancilla, False)
|
254
278
|
|
255
|
-
samples = self.sim.measure_shots(
|
279
|
+
samples = self.sim[ancilla_sim].measure_shots(
|
280
|
+
[hq[other_bits[0]][1], hq[other_bits[1]][1]], shots
|
281
|
+
)
|
256
282
|
|
257
283
|
syndrome_indices = (
|
258
284
|
[other_bits[1], other_bits[0]]
|
@@ -302,31 +328,29 @@ class QrackAceBackend:
|
|
302
328
|
error_bit = syndrome.index(max(syndrome))
|
303
329
|
if error_bit == single_bit:
|
304
330
|
# The stand-alone bit carries the error.
|
305
|
-
self.sim.x(hq[error_bit])
|
331
|
+
self.sim[hq[error_bit][0]].x(hq[error_bit][1])
|
306
332
|
else:
|
307
333
|
# The coherent bits carry the error.
|
308
334
|
force_syndrome = False
|
309
335
|
# Form their syndrome.
|
310
|
-
self.sim.mcx([hq[other_bits[0]]],
|
311
|
-
self.sim.mcx([hq[other_bits[1]]],
|
336
|
+
self.sim[ancilla_sim].mcx([hq[other_bits[0]][1]], ancilla)
|
337
|
+
self.sim[ancilla_sim].mcx([hq[other_bits[1]][1]], ancilla)
|
312
338
|
# Force the syndrome pathological
|
313
|
-
self.sim.force_m(
|
339
|
+
self.sim[ancilla_sim].force_m(ancilla, True)
|
314
340
|
# Reset the ancilla.
|
315
|
-
self.sim.x(
|
341
|
+
self.sim[ancilla_sim].x(ancilla)
|
316
342
|
# Correct the bit flip.
|
317
|
-
self.sim.x(hq[error_bit])
|
343
|
+
self.sim[ancilla_sim].x(hq[error_bit][1])
|
318
344
|
|
319
345
|
# There is no error.
|
320
346
|
if force_syndrome:
|
321
347
|
# Form the syndrome of the coherent bits.
|
322
|
-
self.sim.mcx([hq[other_bits[0]]],
|
323
|
-
self.sim.mcx([hq[other_bits[1]]],
|
348
|
+
self.sim[ancilla_sim].mcx([hq[other_bits[0]][1]], ancilla)
|
349
|
+
self.sim[ancilla_sim].mcx([hq[other_bits[1]][1]], ancilla)
|
324
350
|
# Force the syndrome non-pathological.
|
325
|
-
self.sim.force_m(
|
351
|
+
self.sim[ancilla_sim].force_m(ancilla, False)
|
326
352
|
|
327
353
|
def _correct_if_like_h(self, th, lq):
|
328
|
-
if not self._is_init[lq]:
|
329
|
-
return
|
330
354
|
while th > math.pi:
|
331
355
|
th -= 2 * math.pi
|
332
356
|
while th <= -math.pi:
|
@@ -337,8 +361,9 @@ class QrackAceBackend:
|
|
337
361
|
|
338
362
|
def u(self, lq, th, ph, lm):
|
339
363
|
hq = self._unpack(lq)
|
340
|
-
if
|
341
|
-
|
364
|
+
if len(hq) < 2:
|
365
|
+
b = hq[0]
|
366
|
+
self.sim[b[0]].u(b[1], th, ph, lm)
|
342
367
|
return
|
343
368
|
|
344
369
|
while ph > math.pi:
|
@@ -352,142 +377,148 @@ class QrackAceBackend:
|
|
352
377
|
|
353
378
|
if not math.isclose(ph, -lm) and not math.isclose(abs(ph), math.pi / 2):
|
354
379
|
# Produces/destroys superposition
|
355
|
-
|
356
|
-
|
357
|
-
|
358
|
-
|
359
|
-
self.sim.u(
|
360
|
-
|
361
|
-
|
362
|
-
else:
|
363
|
-
self._encode(lq, hq)
|
380
|
+
self._encode_decode(lq, hq)
|
381
|
+
b = hq[0]
|
382
|
+
self.sim[b[0]].u(b[1], th, ph, lm)
|
383
|
+
b = hq[2]
|
384
|
+
self.sim[b[0]].u(b[1], th, ph, lm)
|
385
|
+
self._encode_decode(lq, hq)
|
386
|
+
self._correct_if_like_h(th, lq)
|
364
387
|
else:
|
365
388
|
# Shouldn't produce/destroy superposition
|
366
389
|
for b in hq:
|
367
|
-
self.sim.u(b, th, ph, lm)
|
390
|
+
self.sim[b[0]].u(b[1], th, ph, lm)
|
368
391
|
|
369
392
|
def r(self, p, th, lq):
|
370
393
|
hq = self._unpack(lq)
|
371
|
-
if
|
372
|
-
|
394
|
+
if len(hq) < 2:
|
395
|
+
b = hq[0]
|
396
|
+
self.sim[b[0]].r(p, th, b[1])
|
373
397
|
return
|
374
398
|
|
375
399
|
while th > math.pi:
|
376
400
|
th -= 2 * math.pi
|
377
401
|
while th <= -math.pi:
|
378
402
|
th += 2 * math.pi
|
379
|
-
if self._is_init[lq] and (p == Pauli.PauliY):
|
380
|
-
self._correct_if_like_h(th, lq)
|
381
|
-
|
382
403
|
if (p == Pauli.PauliZ) or math.isclose(abs(th), math.pi):
|
383
404
|
# Doesn't produce/destroy superposition
|
384
405
|
for b in hq:
|
385
|
-
self.sim.r(p, th, b)
|
406
|
+
self.sim[b[0]].r(p, th, b[1])
|
386
407
|
else:
|
387
408
|
# Produces/destroys superposition
|
388
|
-
|
389
|
-
|
390
|
-
self.sim.r(p, th,
|
391
|
-
|
392
|
-
|
393
|
-
|
394
|
-
|
395
|
-
self._encode(lq, hq)
|
409
|
+
self._encode_decode(lq, hq)
|
410
|
+
b = hq[0]
|
411
|
+
self.sim[b[0]].r(p, th, b[1])
|
412
|
+
b = hq[2]
|
413
|
+
self.sim[b[0]].r(p, th, b[1])
|
414
|
+
self._encode_decode(lq, hq)
|
415
|
+
self._correct_if_like_h(th, lq)
|
396
416
|
|
397
417
|
def h(self, lq):
|
398
418
|
hq = self._unpack(lq)
|
399
|
-
if
|
400
|
-
|
419
|
+
if len(hq) < 2:
|
420
|
+
b = hq[0]
|
421
|
+
self.sim[b[0]].h(b[1])
|
401
422
|
return
|
402
423
|
|
403
|
-
|
404
|
-
|
405
|
-
|
406
|
-
|
407
|
-
self.sim.h(
|
408
|
-
|
409
|
-
|
410
|
-
else:
|
411
|
-
self._encode(lq, hq)
|
424
|
+
self._encode_decode(lq, hq)
|
425
|
+
b = hq[0]
|
426
|
+
self.sim[b[0]].h(b[1])
|
427
|
+
b = hq[2]
|
428
|
+
self.sim[b[0]].h(b[1])
|
429
|
+
self._encode_decode(lq, hq)
|
430
|
+
self._correct(lq)
|
412
431
|
|
413
432
|
def s(self, lq):
|
414
433
|
hq = self._unpack(lq)
|
415
|
-
if
|
416
|
-
|
434
|
+
if len(hq) < 2:
|
435
|
+
b = hq[0]
|
436
|
+
self.sim[b[0]].s(b[1])
|
417
437
|
return
|
418
438
|
|
419
439
|
for b in hq:
|
420
|
-
self.sim.s(b)
|
440
|
+
self.sim[b[0]].s(b[1])
|
421
441
|
|
422
442
|
def adjs(self, lq):
|
423
443
|
hq = self._unpack(lq)
|
424
|
-
if
|
425
|
-
|
444
|
+
if len(hq) < 2:
|
445
|
+
b = hq[0]
|
446
|
+
self.sim[b[0]].adjs(b[1])
|
426
447
|
return
|
427
448
|
|
428
449
|
for b in hq:
|
429
|
-
self.sim.adjs(b)
|
450
|
+
self.sim[b[0]].adjs(b[1])
|
430
451
|
|
431
452
|
def x(self, lq):
|
432
453
|
hq = self._unpack(lq)
|
433
|
-
if
|
434
|
-
|
454
|
+
if len(hq) < 2:
|
455
|
+
b = hq[0]
|
456
|
+
self.sim[b[0]].x(b[1])
|
435
457
|
return
|
436
458
|
|
437
459
|
for b in hq:
|
438
|
-
self.sim.x(b)
|
460
|
+
self.sim[b[0]].x(b[1])
|
439
461
|
|
440
462
|
def y(self, lq):
|
441
463
|
hq = self._unpack(lq)
|
442
|
-
if
|
443
|
-
|
464
|
+
if len(hq) < 2:
|
465
|
+
b = hq[0]
|
466
|
+
self.sim[b[0]].y(b[1])
|
444
467
|
return
|
445
468
|
|
446
469
|
for b in hq:
|
447
|
-
self.sim.y(b)
|
470
|
+
self.sim[b[0]].y(b[1])
|
448
471
|
|
449
472
|
def z(self, lq):
|
450
473
|
hq = self._unpack(lq)
|
451
|
-
if
|
452
|
-
|
474
|
+
if len(hq) < 2:
|
475
|
+
b = hq[0]
|
476
|
+
self.sim[b[0]].z(b[1])
|
453
477
|
return
|
454
478
|
|
455
479
|
for b in hq:
|
456
|
-
self.sim.z(b)
|
480
|
+
self.sim[b[0]].z(b[1])
|
457
481
|
|
458
482
|
def t(self, lq):
|
459
483
|
hq = self._unpack(lq)
|
460
|
-
if
|
461
|
-
|
484
|
+
if len(hq) < 2:
|
485
|
+
b = hq[0]
|
486
|
+
self.sim[b[0]].t(b[1])
|
462
487
|
return
|
463
488
|
|
464
489
|
for b in hq:
|
465
|
-
self.sim.t(b)
|
490
|
+
self.sim[b[0]].t(b[1])
|
466
491
|
|
467
492
|
def adjt(self, lq):
|
468
493
|
hq = self._unpack(lq)
|
469
|
-
if
|
470
|
-
|
494
|
+
if len(hq) < 2:
|
495
|
+
b = hq[0]
|
496
|
+
self.sim[b[0]].adjt(b[1])
|
471
497
|
return
|
472
498
|
|
473
499
|
for b in hq:
|
474
|
-
self.sim.adjt(b)
|
500
|
+
self.sim[b[0]].adjt(b[1])
|
475
501
|
|
476
|
-
def
|
502
|
+
def _get_gate(self, pauli, anti, sim_id):
|
477
503
|
gate = None
|
478
504
|
shadow = None
|
479
505
|
if pauli == Pauli.PauliX:
|
480
|
-
gate = self.sim.macx if anti else self.sim.mcx
|
506
|
+
gate = self.sim[sim_id].macx if anti else self.sim[sim_id].mcx
|
481
507
|
shadow = self._anti_cx_shadow if anti else self._cx_shadow
|
482
508
|
elif pauli == Pauli.PauliY:
|
483
|
-
gate = self.sim.macy if anti else self.sim.mcy
|
509
|
+
gate = self.sim[sim_id].macy if anti else self.sim[sim_id].mcy
|
484
510
|
shadow = self._anti_cy_shadow if anti else self._cy_shadow
|
485
511
|
elif pauli == Pauli.PauliZ:
|
486
|
-
gate = self.sim.macz if anti else self.sim.mcz
|
512
|
+
gate = self.sim[sim_id].macz if anti else self.sim[sim_id].mcz
|
487
513
|
shadow = self._anti_cz_shadow if anti else self._cz_shadow
|
488
514
|
else:
|
489
|
-
|
515
|
+
raise RuntimeError(
|
516
|
+
"QrackAceBackend._get_gate() should never return identity!"
|
517
|
+
)
|
490
518
|
|
519
|
+
return gate, shadow
|
520
|
+
|
521
|
+
def _cpauli(self, lq1, lq2, anti, pauli):
|
491
522
|
lq1_lr = self._is_col_long_range[lq1 % self.row_length]
|
492
523
|
lq2_lr = self._is_col_long_range[lq2 % self.row_length]
|
493
524
|
|
@@ -498,129 +529,95 @@ class QrackAceBackend:
|
|
498
529
|
|
499
530
|
connected_cols = []
|
500
531
|
c = (lq1_col - 1) % self.row_length
|
501
|
-
while self._is_col_long_range[c] and (
|
532
|
+
while self._is_col_long_range[c] and (
|
533
|
+
len(connected_cols) < (self.row_length - 1)
|
534
|
+
):
|
502
535
|
connected_cols.append(c)
|
503
536
|
c = (c - 1) % self.row_length
|
504
537
|
if len(connected_cols) < (self.row_length - 1):
|
505
538
|
connected_cols.append(c)
|
506
539
|
boundary = len(connected_cols)
|
507
540
|
c = (lq1_col + 1) % self.row_length
|
508
|
-
while self._is_col_long_range[c] and (
|
541
|
+
while self._is_col_long_range[c] and (
|
542
|
+
len(connected_cols) < (self.row_length - 1)
|
543
|
+
):
|
509
544
|
connected_cols.append(c)
|
510
545
|
c = (c + 1) % self.row_length
|
511
546
|
if len(connected_cols) < (self.row_length - 1):
|
512
547
|
connected_cols.append(c)
|
513
548
|
|
549
|
+
hq1 = self._unpack(lq1)
|
550
|
+
hq2 = self._unpack(lq2)
|
551
|
+
|
514
552
|
if lq1_lr and lq2_lr:
|
553
|
+
b1 = hq1[0]
|
554
|
+
b2 = hq2[0]
|
555
|
+
gate, shadow = self._get_gate(pauli, anti, b1[0])
|
515
556
|
if lq2_col in connected_cols:
|
516
|
-
gate(
|
517
|
-
else:
|
518
|
-
shadow(self._unpack(lq1)[0], self._unpack(lq2)[0])
|
519
|
-
return
|
520
|
-
|
521
|
-
self._correct(lq1)
|
522
|
-
|
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)
|
557
|
+
gate([b1[1]], b2[1])
|
534
558
|
else:
|
535
|
-
|
536
|
-
gate([hq1[1]], hq2[1])
|
537
|
-
gate([hq1[2]], hq2[2])
|
538
|
-
|
559
|
+
shadow(b1, b2)
|
539
560
|
return
|
540
561
|
|
541
|
-
hq1 = None
|
542
|
-
hq2 = None
|
543
562
|
if (lq2_col in connected_cols) and (connected_cols.index(lq2_col) < boundary):
|
563
|
+
# lq2_col < lq1_col
|
564
|
+
self._encode_decode_half(lq1, hq1, True)
|
565
|
+
self._encode_decode_half(lq2, hq2, False)
|
566
|
+
b = hq1[0]
|
544
567
|
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)
|
568
|
+
self._get_gate(pauli, anti, hq1[0][0])[0]([b[1]], hq2[2][1])
|
551
569
|
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)
|
570
|
+
self._get_gate(pauli, anti, hq2[0][0])[0]([b[1]], hq2[0][1])
|
557
571
|
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)
|
572
|
+
self._get_gate(pauli, anti, b[0])[0]([b[1]], hq2[2][1])
|
573
|
+
self._encode_decode_half(lq2, hq2, False)
|
574
|
+
self._encode_decode_half(lq1, hq1, True)
|
566
575
|
elif lq2_col in connected_cols:
|
576
|
+
# lq1_col < lq2_col
|
577
|
+
self._encode_decode_half(lq1, hq1, False)
|
578
|
+
self._encode_decode_half(lq2, hq2, True)
|
579
|
+
b = hq2[0]
|
567
580
|
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)
|
581
|
+
self._get_gate(pauli, anti, hq1[0][0])[0]([hq1[0][1]], b[1])
|
574
582
|
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)
|
583
|
+
self._get_gate(pauli, anti, hq2[0][0])[0]([hq1[2][1]], b[1])
|
580
584
|
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)
|
585
|
+
self._get_gate(pauli, anti, b[0])[0]([hq1[2][1]], b[1])
|
586
|
+
self._encode_decode_half(lq2, hq2, True)
|
587
|
+
self._encode_decode_half(lq1, hq1, False)
|
589
588
|
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)
|
601
|
-
else:
|
602
|
-
gate([hq1[0]], hq2[0])
|
603
|
-
if self.alternating_codes and ((lq2_row & 1) != (lq1_row & 1)):
|
604
|
-
shadow(hq1[1], hq2[1])
|
605
|
-
else:
|
606
|
-
gate([hq1[1]], hq2[1])
|
607
|
-
gate([hq1[2]], hq2[2])
|
589
|
+
# Both are in the same boundary column.
|
590
|
+
self._encode_decode(lq1, hq1)
|
591
|
+
self._encode_decode(lq2, hq2)
|
592
|
+
b = hq1[0]
|
593
|
+
gate, shadow = self._get_gate(pauli, anti, b[0])
|
594
|
+
gate([b[1]], hq2[0][1])
|
595
|
+
b = hq1[2]
|
596
|
+
gate, shadow = self._get_gate(pauli, anti, b[0])
|
597
|
+
gate([b[1]], hq2[2][1])
|
608
598
|
else:
|
609
|
-
|
610
|
-
|
599
|
+
# The qubits have no quantum connection.
|
600
|
+
gate, shadow = self._get_gate(pauli, anti, hq1[0][0])
|
611
601
|
if lq1_lr:
|
612
|
-
|
613
|
-
self.
|
614
|
-
shadow(hq1[0], hq2[0])
|
615
|
-
self.
|
602
|
+
connected01 = (hq2[0][0] == hq2[1][0])
|
603
|
+
self._encode_decode(lq2, hq2)
|
604
|
+
shadow(hq1[0], hq2[0] if connected01 else hq2[2])
|
605
|
+
self._encode_decode(lq2, hq2)
|
616
606
|
elif lq2_lr:
|
617
|
-
|
618
|
-
|
619
|
-
|
607
|
+
connected01 = (hq1[0][0] == hq1[1][0])
|
608
|
+
self._encode_decode(lq1, hq1)
|
609
|
+
shadow(hq1[0] if connected01 else hq1[2], hq2[0])
|
610
|
+
self._encode_decode(lq1, hq1)
|
620
611
|
else:
|
612
|
+
self._encode_decode(lq1, hq1)
|
613
|
+
self._encode_decode(lq2, hq2)
|
621
614
|
shadow(hq1[0], hq2[0])
|
622
|
-
shadow(hq1[1], hq2[1])
|
623
615
|
shadow(hq1[2], hq2[2])
|
616
|
+
self._encode_decode(lq2, hq2)
|
617
|
+
self._encode_decode(lq1, hq1)
|
618
|
+
|
619
|
+
self._correct(lq1)
|
620
|
+
self._correct(lq2)
|
624
621
|
|
625
622
|
def cx(self, lq1, lq2):
|
626
623
|
self._cpauli(lq1, lq2, False, Pauli.PauliX)
|
@@ -700,12 +697,12 @@ class QrackAceBackend:
|
|
700
697
|
self.swap(lq1, lq2)
|
701
698
|
|
702
699
|
def m(self, lq):
|
703
|
-
self._is_init[lq] = False
|
704
700
|
hq = self._unpack(lq)
|
705
|
-
if
|
706
|
-
|
701
|
+
if len(hq) < 2:
|
702
|
+
b = hq[0]
|
703
|
+
return self.sim[b[0]].m(b[1])
|
707
704
|
|
708
|
-
if
|
705
|
+
if hq[0][0] == hq[0][1]:
|
709
706
|
single_bit = 2
|
710
707
|
other_bits = [0, 1]
|
711
708
|
else:
|
@@ -713,24 +710,27 @@ class QrackAceBackend:
|
|
713
710
|
other_bits = [1, 2]
|
714
711
|
# The syndrome of "other_bits" is guaranteed to be fixed, after this.
|
715
712
|
self._correct(lq)
|
716
|
-
|
717
|
-
syndrome
|
713
|
+
b = hq[other_bits[0]]
|
714
|
+
syndrome = self.sim[b[0]].m(b[1])
|
715
|
+
b = hq[other_bits[1]]
|
716
|
+
syndrome += self.sim[b[0]].force_m(b[1], bool(syndrome))
|
718
717
|
# The two separable parts of the code are correlated,
|
719
718
|
# but not non-locally, via entanglement.
|
720
719
|
# Collapse the other separable part toward agreement.
|
721
|
-
|
720
|
+
b = hq[single_bit]
|
721
|
+
syndrome += self.sim[b[0]].force_m(b[1], bool(syndrome))
|
722
722
|
|
723
723
|
return True if (syndrome > 1) else False
|
724
724
|
|
725
725
|
def force_m(self, lq, c):
|
726
726
|
hq = self._unpack(lq)
|
727
|
-
|
728
|
-
|
729
|
-
return self.sim.force_m(
|
727
|
+
if len(hq) < 2:
|
728
|
+
b = hq[0]
|
729
|
+
return self.sim[b[0]].force_m(b[1])
|
730
730
|
|
731
731
|
self._correct(lq)
|
732
732
|
for q in hq:
|
733
|
-
self.sim.force_m(q, c)
|
733
|
+
self.sim[q[0]].force_m(q[1], c)
|
734
734
|
|
735
735
|
return c
|
736
736
|
|
@@ -769,17 +769,20 @@ class QrackAceBackend:
|
|
769
769
|
|
770
770
|
def prob(self, lq):
|
771
771
|
hq = self._unpack(lq)
|
772
|
-
if
|
773
|
-
|
772
|
+
if len(hq) < 2:
|
773
|
+
b = hq[0]
|
774
|
+
return self.sim[b[0]].prob(b[1])
|
774
775
|
|
775
776
|
self._correct(lq)
|
776
|
-
if
|
777
|
+
if hq[0][0] == hq[1][0]:
|
777
778
|
other_bits = [0, 1]
|
778
779
|
else:
|
779
780
|
other_bits = [1, 2]
|
780
|
-
|
781
|
-
|
782
|
-
self.sim.mcx([
|
781
|
+
b0 = hq[other_bits[0]]
|
782
|
+
b1 = hq[other_bits[1]]
|
783
|
+
self.sim[b0[0]].mcx([b0[1]], b1[1])
|
784
|
+
result = self.sim[b0[0]].prob(b0[1])
|
785
|
+
self.sim[b0[0]].mcx([b0[1]], b1[1])
|
783
786
|
|
784
787
|
return result
|
785
788
|
|
@@ -1135,13 +1138,17 @@ class QrackAceBackend:
|
|
1135
1138
|
for col in range(cols):
|
1136
1139
|
connected_cols = [col]
|
1137
1140
|
c = (col - 1) % cols
|
1138
|
-
while self._is_col_long_range[c] and (
|
1141
|
+
while self._is_col_long_range[c] and (
|
1142
|
+
len(connected_cols) < self.row_length
|
1143
|
+
):
|
1139
1144
|
connected_cols.append(c)
|
1140
1145
|
c = (c - 1) % cols
|
1141
1146
|
if len(connected_cols) < self.row_length:
|
1142
1147
|
connected_cols.append(c)
|
1143
1148
|
c = (col + 1) % cols
|
1144
|
-
while self._is_col_long_range[c] and (
|
1149
|
+
while self._is_col_long_range[c] and (
|
1150
|
+
len(connected_cols) < self.row_length
|
1151
|
+
):
|
1145
1152
|
connected_cols.append(c)
|
1146
1153
|
c = (c + 1) % cols
|
1147
1154
|
if len(connected_cols) < self.row_length:
|
@@ -1177,31 +1184,27 @@ class QrackAceBackend:
|
|
1177
1184
|
continue # No noise on long-to-long
|
1178
1185
|
|
1179
1186
|
same_col = col_a == col_b
|
1180
|
-
even_odd = (row_a % 2) != (row_b % 2)
|
1181
|
-
|
1182
|
-
if same_col and not even_odd:
|
1183
|
-
continue # No noise for even-even or odd-odd within a boundary column
|
1184
1187
|
|
1185
1188
|
if same_col:
|
1186
|
-
|
1187
|
-
|
1188
|
-
|
1189
|
-
|
1190
|
-
|
1191
|
-
noise_model.add_quantum_error(depolarizing_error(
|
1192
|
-
|
1193
|
-
y_cy
|
1194
|
-
|
1195
|
-
|
1196
|
-
|
1197
|
-
noise_model.add_quantum_error(depolarizing_error(y_cy, 2), 'cz', [a, b])
|
1198
|
-
noise_model.add_quantum_error(depolarizing_error(y_swap, 2), 'swap', [a, b])
|
1189
|
+
continue # No noise for same column
|
1190
|
+
|
1191
|
+
if is_long_a or is_long_b:
|
1192
|
+
y_cy = 1 - (1 - y) ** 2
|
1193
|
+
y_swap = 1 - (1 - y) ** 3
|
1194
|
+
noise_model.add_quantum_error(depolarizing_error(y, 2), "cx", [a, b])
|
1195
|
+
noise_model.add_quantum_error(depolarizing_error(y_cy, 2), "cy", [a, b])
|
1196
|
+
noise_model.add_quantum_error(depolarizing_error(y_cy, 2), "cz", [a, b])
|
1197
|
+
noise_model.add_quantum_error(
|
1198
|
+
depolarizing_error(y_swap, 2), "swap", [a, b]
|
1199
|
+
)
|
1199
1200
|
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(
|
1201
|
+
y_cy = 1 - (1 - y) ** 2
|
1202
|
+
y_swap = 1 - (1 - y) ** 3
|
1203
|
+
noise_model.add_quantum_error(depolarizing_error(y_cy, 2), "cx", [a, b])
|
1204
|
+
noise_model.add_quantum_error(depolarizing_error(y_cy, 2), "cy", [a, b])
|
1205
|
+
noise_model.add_quantum_error(depolarizing_error(y_cy, 2), "cz", [a, b])
|
1206
|
+
noise_model.add_quantum_error(
|
1207
|
+
depolarizing_error(y_swap, 2), "swap", [a, b]
|
1208
|
+
)
|
1206
1209
|
|
1207
1210
|
return noise_model
|
@@ -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
|