pyqrackising 9.3.0__py3-none-macosx_15_0_arm64.whl → 9.5.12__py3-none-macosx_15_0_arm64.whl
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.
- pyqrackising/generate_tfim_samples.py +13 -2
- pyqrackising/maxcut_tfim.py +12 -36
- pyqrackising/maxcut_tfim_sparse.py +12 -35
- pyqrackising/maxcut_tfim_streaming.py +11 -18
- pyqrackising/maxcut_tfim_util.py +14 -19
- pyqrackising/otoc.py +179 -131
- {pyqrackising-9.3.0.dist-info → pyqrackising-9.5.12.dist-info}/METADATA +1 -1
- pyqrackising-9.5.12.dist-info/RECORD +21 -0
- pyqrackising-9.3.0.dist-info/RECORD +0 -21
- {pyqrackising-9.3.0.dist-info → pyqrackising-9.5.12.dist-info}/WHEEL +0 -0
- {pyqrackising-9.3.0.dist-info → pyqrackising-9.5.12.dist-info}/licenses/LICENSE.md +0 -0
- {pyqrackising-9.3.0.dist-info → pyqrackising-9.5.12.dist-info}/top_level.txt +0 -0
|
@@ -1,10 +1,14 @@
|
|
|
1
|
-
from .maxcut_tfim_util import probability_by_hamming_weight, sample_mag
|
|
1
|
+
from .maxcut_tfim_util import probability_by_hamming_weight, sample_mag, opencl_context
|
|
2
2
|
import itertools
|
|
3
3
|
import math
|
|
4
|
+
import sys
|
|
4
5
|
import numpy as np
|
|
5
6
|
from numba import njit
|
|
6
7
|
|
|
7
8
|
|
|
9
|
+
epsilon = opencl_context.epsilon
|
|
10
|
+
|
|
11
|
+
|
|
8
12
|
@njit
|
|
9
13
|
def factor_width(width, is_transpose=False):
|
|
10
14
|
col_len = math.floor(math.sqrt(width))
|
|
@@ -85,7 +89,7 @@ def expected_closeness_weight(n_rows, n_cols, hamming_weight):
|
|
|
85
89
|
def sample_hamming_weight(thresholds, shots):
|
|
86
90
|
hamming_samples = np.zeros(shots, dtype=np.int32)
|
|
87
91
|
for s in range(shots):
|
|
88
|
-
hamming_samples[s] = sample_mag(thresholds)
|
|
92
|
+
hamming_samples[s] = sample_mag(thresholds) + 1
|
|
89
93
|
|
|
90
94
|
return hamming_samples
|
|
91
95
|
|
|
@@ -104,6 +108,13 @@ def fix_cdf(hamming_prob):
|
|
|
104
108
|
|
|
105
109
|
@njit
|
|
106
110
|
def get_tfim_hamming_distribution(J=-1.0, h=2.0, z=4, theta=0.174532925199432957, t=5, n_qubits=56):
|
|
111
|
+
if h <= epsilon:
|
|
112
|
+
bias = np.empty(n_qubits + 1, dtype=np.float64)
|
|
113
|
+
if J > 0:
|
|
114
|
+
bias[-1] = 1.0
|
|
115
|
+
else:
|
|
116
|
+
bias[0] = 1.0
|
|
117
|
+
return bias
|
|
107
118
|
bias = probability_by_hamming_weight(J, h, z, theta, t, n_qubits + 1)
|
|
108
119
|
return bias / bias.sum()
|
|
109
120
|
|
pyqrackising/maxcut_tfim.py
CHANGED
|
@@ -3,7 +3,7 @@ import numpy as np
|
|
|
3
3
|
from numba import njit, prange
|
|
4
4
|
import os
|
|
5
5
|
|
|
6
|
-
from .maxcut_tfim_util import compute_cut, compute_energy, convert_bool_to_uint, get_cut, get_cut_base, make_G_m_buf, make_theta_buf, maxcut_hamming_cdf, opencl_context, sample_mag, setup_opencl, bit_pick
|
|
6
|
+
from .maxcut_tfim_util import compute_cut, compute_energy, convert_bool_to_uint, get_cut, get_cut_base, init_thresholds, make_G_m_buf, make_theta_buf, maxcut_hamming_cdf, opencl_context, sample_mag, setup_opencl, bit_pick
|
|
7
7
|
|
|
8
8
|
IS_OPENCL_AVAILABLE = True
|
|
9
9
|
try:
|
|
@@ -177,21 +177,6 @@ def init_J_and_z(G_m, repulsion_base):
|
|
|
177
177
|
return J_eff, degrees
|
|
178
178
|
|
|
179
179
|
|
|
180
|
-
@njit
|
|
181
|
-
def cpu_footer(shots, thread_count, quality, n_qubits, G_m, nodes, is_spin_glass, anneal_t, anneal_h, repulsion_base):
|
|
182
|
-
J_eff, degrees = init_J_and_z(G_m, repulsion_base)
|
|
183
|
-
hamming_prob = maxcut_hamming_cdf(n_qubits, J_eff, degrees, quality, anneal_t, anneal_h)
|
|
184
|
-
|
|
185
|
-
degrees = None
|
|
186
|
-
J_eff = None
|
|
187
|
-
|
|
188
|
-
best_solution, best_value = sample_measurement(G_m, shots, thread_count, hamming_prob, repulsion_base, is_spin_glass)
|
|
189
|
-
|
|
190
|
-
bit_string, l, r = get_cut(best_solution, nodes, n_qubits)
|
|
191
|
-
|
|
192
|
-
return bit_string, best_value, (l, r)
|
|
193
|
-
|
|
194
|
-
|
|
195
180
|
def run_cut_opencl(best_energy, samples, G_m_buf, is_segmented, local_size, global_size, args_buf, local_energy_buf, local_index_buf, max_energy_host, max_index_host, max_energy_buf, max_index_buf):
|
|
196
181
|
queue = opencl_context.queue
|
|
197
182
|
calculate_cut_kernel = opencl_context.calculate_cut_segmented_kernel if is_segmented else opencl_context.calculate_cut_kernel
|
|
@@ -253,6 +238,7 @@ def run_cut_opencl(best_energy, samples, G_m_buf, is_segmented, local_size, glob
|
|
|
253
238
|
|
|
254
239
|
return samples[max_index_host[best_x]], energy
|
|
255
240
|
|
|
241
|
+
|
|
256
242
|
def maxcut_tfim(
|
|
257
243
|
G,
|
|
258
244
|
quality=None,
|
|
@@ -308,31 +294,21 @@ def maxcut_tfim(
|
|
|
308
294
|
if repulsion_base is None:
|
|
309
295
|
repulsion_base = 5.0
|
|
310
296
|
|
|
311
|
-
is_opencl = is_maxcut_gpu and IS_OPENCL_AVAILABLE
|
|
312
|
-
|
|
313
|
-
if not is_opencl:
|
|
314
|
-
thread_count = os.cpu_count() ** 2
|
|
315
|
-
|
|
316
|
-
bit_string, best_value, partition = cpu_footer(shots, thread_count, quality, n_qubits, G_m, nodes, is_spin_glass, anneal_t, anneal_h, repulsion_base)
|
|
317
|
-
|
|
318
|
-
if best_value < 0.0:
|
|
319
|
-
# Best cut is trivial partition, all/empty
|
|
320
|
-
return '0' * n_qubits, 0.0, (nodes, [])
|
|
321
|
-
|
|
322
|
-
return bit_string, best_value, partition
|
|
323
|
-
|
|
324
|
-
segment_size = (G_m.shape[0] * G_m.shape[1] + 3) >> 2
|
|
325
|
-
theta_segment_size = (((n_qubits + 31) >> 5) * (((shots + wgs - 1) // wgs) * wgs) + 3) >> 2
|
|
326
|
-
is_segmented = ((G_m.nbytes << 1) > opencl_context.max_alloc) or ((theta_segment_size << 3) > opencl_context.max_alloc)
|
|
327
|
-
G_m_buf = make_G_m_buf(G_m, is_segmented, segment_size)
|
|
328
|
-
|
|
329
297
|
J_eff, degrees = init_J_and_z(G_m, repulsion_base)
|
|
330
|
-
|
|
298
|
+
cum_prob = maxcut_hamming_cdf(init_thresholds(n_qubits), n_qubits, J_eff, degrees, quality, anneal_t, anneal_h)
|
|
331
299
|
|
|
332
300
|
degrees = None
|
|
333
301
|
J_eff = None
|
|
334
302
|
|
|
335
|
-
|
|
303
|
+
if is_maxcut_gpu and IS_OPENCL_AVAILABLE:
|
|
304
|
+
segment_size = (G_m.shape[0] * G_m.shape[1] + 3) >> 2
|
|
305
|
+
theta_segment_size = (((n_qubits + 31) >> 5) * (((shots + wgs - 1) // wgs) * wgs) + 3) >> 2
|
|
306
|
+
is_segmented = ((G_m.nbytes << 1) > opencl_context.max_alloc) or ((theta_segment_size << 3) > opencl_context.max_alloc)
|
|
307
|
+
G_m_buf = make_G_m_buf(G_m, is_segmented, segment_size)
|
|
308
|
+
best_solution, best_value = sample_for_opencl(G_m, G_m_buf, shots, cum_prob, repulsion_base, is_spin_glass, is_segmented, segment_size, theta_segment_size)
|
|
309
|
+
else:
|
|
310
|
+
thread_count = os.cpu_count() ** 2
|
|
311
|
+
best_solution, best_value = sample_measurement(G_m, shots, thread_count, cum_prob, repulsion_base, is_spin_glass)
|
|
336
312
|
|
|
337
313
|
bit_string, l, r = get_cut(best_solution, nodes, n_qubits)
|
|
338
314
|
|
|
@@ -3,7 +3,7 @@ import numpy as np
|
|
|
3
3
|
from numba import njit, prange
|
|
4
4
|
import os
|
|
5
5
|
|
|
6
|
-
from .maxcut_tfim_util import binary_search, compute_cut_sparse, compute_energy_sparse, convert_bool_to_uint, get_cut, get_cut_base, make_G_m_csr_buf, make_theta_buf, maxcut_hamming_cdf, opencl_context, sample_mag, setup_opencl, bit_pick, to_scipy_sparse_upper_triangular
|
|
6
|
+
from .maxcut_tfim_util import binary_search, compute_cut_sparse, compute_energy_sparse, convert_bool_to_uint, get_cut, get_cut_base, init_thresholds, make_G_m_csr_buf, make_theta_buf, maxcut_hamming_cdf, opencl_context, sample_mag, setup_opencl, bit_pick, to_scipy_sparse_upper_triangular
|
|
7
7
|
|
|
8
8
|
IS_OPENCL_AVAILABLE = True
|
|
9
9
|
try:
|
|
@@ -187,17 +187,6 @@ def init_J_and_z(G_m, repulsion_base):
|
|
|
187
187
|
return J_eff, degrees
|
|
188
188
|
|
|
189
189
|
|
|
190
|
-
@njit
|
|
191
|
-
def cpu_footer(J_eff, degrees, shots, thread_count, quality, n_qubits, G_data, G_rows, G_cols, nodes, is_spin_glass, anneal_t, anneal_h, repulsion_base):
|
|
192
|
-
hamming_prob = maxcut_hamming_cdf(n_qubits, J_eff, degrees, quality, anneal_t, anneal_h)
|
|
193
|
-
|
|
194
|
-
best_solution, best_value = sample_measurement(G_data, G_rows, G_cols, shots, thread_count, hamming_prob, repulsion_base, is_spin_glass)
|
|
195
|
-
|
|
196
|
-
bit_string, l, r = get_cut(best_solution, nodes, n_qubits)
|
|
197
|
-
|
|
198
|
-
return bit_string, best_value, (l, r)
|
|
199
|
-
|
|
200
|
-
|
|
201
190
|
def run_cut_opencl(best_energy, samples, G_data_buf, G_rows_buf, G_cols_buf, is_segmented, local_size, global_size, args_buf, local_energy_buf, local_index_buf, max_energy_host, max_index_host, max_energy_buf, max_index_buf):
|
|
202
191
|
queue = opencl_context.queue
|
|
203
192
|
calculate_cut_kernel = opencl_context.calculate_cut_sparse_segmented_kernel if is_segmented else opencl_context.calculate_cut_sparse_kernel
|
|
@@ -319,35 +308,23 @@ def maxcut_tfim_sparse(
|
|
|
319
308
|
if repulsion_base is None:
|
|
320
309
|
repulsion_base = 5.0
|
|
321
310
|
|
|
322
|
-
J_eff, degrees = init_J_and_z(G_m, repulsion_base)
|
|
323
|
-
|
|
324
311
|
n_qubits = G_m.shape[0]
|
|
325
312
|
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
if not is_opencl:
|
|
329
|
-
thread_count = os.cpu_count() ** 2
|
|
330
|
-
|
|
331
|
-
bit_string, best_value, partition = cpu_footer(J_eff, degrees, shots, thread_count, quality, n_qubits, G_m.data, G_m.indptr, G_m.indices, nodes, is_spin_glass, anneal_t, anneal_h, repulsion_base)
|
|
332
|
-
|
|
333
|
-
if best_value < 0.0:
|
|
334
|
-
# Best cut is trivial partition, all/empty
|
|
335
|
-
return '0' * n_qubits, 0.0, (nodes, [])
|
|
336
|
-
|
|
337
|
-
return bit_string, best_value, partition
|
|
338
|
-
|
|
339
|
-
segment_size = (G_m.data.shape[0] + 3) >> 2
|
|
340
|
-
theta_segment_size = (((n_qubits + 31) >> 5) * (((shots + wgs - 1) // wgs) * wgs) + 3) >> 2
|
|
341
|
-
is_segmented = (G_m.data.nbytes << 1) > opencl_context.max_alloc or ((theta_segment_size << 3) > opencl_context.max_alloc)
|
|
342
|
-
|
|
343
|
-
G_data_buf, G_rows_buf, G_cols_buf = make_G_m_csr_buf(G_m, is_segmented, segment_size)
|
|
344
|
-
|
|
345
|
-
hamming_prob = maxcut_hamming_cdf(n_qubits, J_eff, degrees, quality, anneal_t, anneal_h)
|
|
313
|
+
J_eff, degrees = init_J_and_z(G_m, repulsion_base)
|
|
314
|
+
cum_prob = maxcut_hamming_cdf(init_thresholds(n_qubits), n_qubits, J_eff, degrees, quality, anneal_t, anneal_h)
|
|
346
315
|
|
|
347
316
|
degrees = None
|
|
348
317
|
J_eff = None
|
|
349
318
|
|
|
350
|
-
|
|
319
|
+
if is_maxcut_gpu and IS_OPENCL_AVAILABLE:
|
|
320
|
+
segment_size = (G_m.data.shape[0] + 3) >> 2
|
|
321
|
+
theta_segment_size = (((n_qubits + 31) >> 5) * (((shots + wgs - 1) // wgs) * wgs) + 3) >> 2
|
|
322
|
+
is_segmented = (G_m.data.nbytes << 1) > opencl_context.max_alloc or ((theta_segment_size << 3) > opencl_context.max_alloc)
|
|
323
|
+
G_data_buf, G_rows_buf, G_cols_buf = make_G_m_csr_buf(G_m, is_segmented, segment_size)
|
|
324
|
+
best_solution, best_value = sample_for_opencl(G_m.data, G_m.indptr, G_m.indices, G_data_buf, G_rows_buf, G_cols_buf, shots, cum_prob, repulsion_base, is_spin_glass, is_segmented, segment_size, theta_segment_size)
|
|
325
|
+
else:
|
|
326
|
+
thread_count = os.cpu_count() ** 2
|
|
327
|
+
best_solution, best_value = sample_measurement(G_m.data, G_m.indptr, G_m.indices, shots, thread_count, cum_prob, repulsion_base, is_spin_glass)
|
|
351
328
|
|
|
352
329
|
bit_string, l, r = get_cut(best_solution, nodes, n_qubits)
|
|
353
330
|
|
|
@@ -3,7 +3,7 @@ import numpy as np
|
|
|
3
3
|
from numba import njit, prange
|
|
4
4
|
import os
|
|
5
5
|
|
|
6
|
-
from .maxcut_tfim_util import compute_cut_streaming, compute_energy_streaming, get_cut, get_cut_base, maxcut_hamming_cdf, opencl_context, sample_mag, bit_pick
|
|
6
|
+
from .maxcut_tfim_util import compute_cut_streaming, compute_energy_streaming, get_cut, get_cut_base, init_thresholds, maxcut_hamming_cdf, opencl_context, sample_mag, bit_pick
|
|
7
7
|
|
|
8
8
|
|
|
9
9
|
epsilon = opencl_context.epsilon
|
|
@@ -145,21 +145,6 @@ def find_G_min(G_func, nodes, n_nodes):
|
|
|
145
145
|
return G_min
|
|
146
146
|
|
|
147
147
|
|
|
148
|
-
@njit
|
|
149
|
-
def cpu_footer(shots, thread_count, quality, n_qubits, G_min, G_func, nodes, is_spin_glass, anneal_t, anneal_h, repulsion_base):
|
|
150
|
-
J_eff, degrees = init_J_and_z(G_func, nodes, G_min, repulsion_base)
|
|
151
|
-
hamming_prob = maxcut_hamming_cdf(n_qubits, J_eff, degrees, quality, anneal_t, anneal_h)
|
|
152
|
-
|
|
153
|
-
degrees = None
|
|
154
|
-
J_eff = None
|
|
155
|
-
|
|
156
|
-
best_solution, best_value = sample_measurement(G_func, nodes, shots, thread_count, hamming_prob, n_qubits, repulsion_base, is_spin_glass)
|
|
157
|
-
|
|
158
|
-
bit_string, l, r = get_cut(best_solution, nodes, n_qubits)
|
|
159
|
-
|
|
160
|
-
return bit_string, best_value, (l, r)
|
|
161
|
-
|
|
162
|
-
|
|
163
148
|
def maxcut_tfim_streaming(
|
|
164
149
|
G_func,
|
|
165
150
|
nodes,
|
|
@@ -207,10 +192,18 @@ def maxcut_tfim_streaming(
|
|
|
207
192
|
|
|
208
193
|
thread_count = os.cpu_count() ** 2
|
|
209
194
|
|
|
210
|
-
|
|
195
|
+
J_eff, degrees = init_J_and_z(G_func, nodes, G_min, repulsion_base)
|
|
196
|
+
cum_prob = maxcut_hamming_cdf(init_thresholds(n_qubits), n_qubits, J_eff, degrees, quality, anneal_t, anneal_h)
|
|
197
|
+
|
|
198
|
+
degrees = None
|
|
199
|
+
J_eff = None
|
|
200
|
+
|
|
201
|
+
best_solution, best_value = sample_measurement(G_func, nodes, shots, thread_count, cum_prob, n_qubits, repulsion_base, is_spin_glass)
|
|
202
|
+
|
|
203
|
+
bit_string, l, r = get_cut(best_solution, nodes, n_qubits)
|
|
211
204
|
|
|
212
205
|
if best_value < 0.0:
|
|
213
206
|
# Best cut is trivial partition, all/empty
|
|
214
207
|
return '0' * n_qubits, 0.0, (nodes, [])
|
|
215
208
|
|
|
216
|
-
return bit_string, best_value,
|
|
209
|
+
return bit_string, best_value, (l, r)
|
pyqrackising/maxcut_tfim_util.py
CHANGED
|
@@ -389,22 +389,19 @@ def init_theta(h_mult, n_qubits, J_eff, degrees):
|
|
|
389
389
|
return theta
|
|
390
390
|
|
|
391
391
|
|
|
392
|
-
@njit
|
|
393
392
|
def init_thresholds(n_qubits):
|
|
394
|
-
n_bias = n_qubits
|
|
393
|
+
n_bias = n_qubits + 1
|
|
395
394
|
thresholds = np.empty(n_bias, dtype=np.float64)
|
|
396
395
|
tot_prob = 0
|
|
397
|
-
p = 1
|
|
398
|
-
|
|
399
|
-
q =
|
|
400
|
-
thresholds[
|
|
401
|
-
tot_prob = p
|
|
402
|
-
p /= 2
|
|
403
|
-
for q in range(1, n_qubits // 2):
|
|
404
|
-
thresholds[q - 1] = p
|
|
405
|
-
thresholds[n_bias - q] = p
|
|
396
|
+
p = 1
|
|
397
|
+
for q in range(n_qubits >> 1):
|
|
398
|
+
thresholds[q] = p
|
|
399
|
+
thresholds[n_bias - (q + 1)] = p
|
|
406
400
|
tot_prob += 2 * p
|
|
407
|
-
p
|
|
401
|
+
p = math.comb(n_qubits, q + 1)
|
|
402
|
+
if n_qubits & 1:
|
|
403
|
+
thresholds[n_qubits >> 1] = p
|
|
404
|
+
tot_prob += p
|
|
408
405
|
thresholds /= tot_prob
|
|
409
406
|
|
|
410
407
|
return thresholds
|
|
@@ -441,17 +438,15 @@ def probability_by_hamming_weight(J, h, z, theta, t, n_bias, normalized=True):
|
|
|
441
438
|
return bias
|
|
442
439
|
|
|
443
440
|
|
|
444
|
-
@njit
|
|
445
|
-
def maxcut_hamming_cdf(n_qubits, J_func, degrees, quality, tot_t, h_mult):
|
|
446
|
-
hamming_prob = init_thresholds(n_qubits)
|
|
447
|
-
|
|
441
|
+
@njit
|
|
442
|
+
def maxcut_hamming_cdf(hamming_prob, n_qubits, J_func, degrees, quality, tot_t, h_mult):
|
|
448
443
|
n_steps = 1 << quality
|
|
449
444
|
delta_t = tot_t / n_steps
|
|
450
445
|
n_bias = n_qubits + 1
|
|
451
446
|
|
|
452
447
|
theta = init_theta(h_mult, n_qubits, J_func, degrees)
|
|
453
448
|
|
|
454
|
-
for qc in
|
|
449
|
+
for qc in range(n_qubits, n_steps * n_qubits):
|
|
455
450
|
step = qc // n_qubits
|
|
456
451
|
q = qc % n_qubits
|
|
457
452
|
J_eff = J_func[q]
|
|
@@ -488,7 +483,7 @@ def sample_mag(cum_prob):
|
|
|
488
483
|
while True:
|
|
489
484
|
m = (left + right) >> 1
|
|
490
485
|
|
|
491
|
-
if (cum_prob[m] >= p) and ((m == 0) or cum_prob[m - 1] < p):
|
|
486
|
+
if (cum_prob[m] >= p) and ((m == 0) or (cum_prob[m - 1] < p)):
|
|
492
487
|
break
|
|
493
488
|
|
|
494
489
|
if cum_prob[m] < p:
|
|
@@ -496,7 +491,7 @@ def sample_mag(cum_prob):
|
|
|
496
491
|
else:
|
|
497
492
|
right = m - 1
|
|
498
493
|
|
|
499
|
-
return m
|
|
494
|
+
return m
|
|
500
495
|
|
|
501
496
|
|
|
502
497
|
@njit
|
pyqrackising/otoc.py
CHANGED
|
@@ -1,59 +1,79 @@
|
|
|
1
|
-
from .maxcut_tfim_util import probability_by_hamming_weight, sample_mag
|
|
1
|
+
from .maxcut_tfim_util import probability_by_hamming_weight, sample_mag, opencl_context
|
|
2
|
+
import math
|
|
2
3
|
from numba import njit
|
|
3
4
|
import numpy as np
|
|
4
|
-
import
|
|
5
|
+
import sys
|
|
5
6
|
|
|
6
7
|
|
|
7
|
-
|
|
8
|
-
pauli_string = list(pauli_string)
|
|
9
|
-
if len(pauli_string) != n_qubits:
|
|
10
|
-
raise ValueError("OTOCS pauli_string must be same length as n_qubits! (Use 'I' for qubits that aren't changed.)")
|
|
8
|
+
epsilon = opencl_context.epsilon
|
|
11
9
|
|
|
12
|
-
fwd = probability_by_hamming_weight(J, h, z, theta, t, n_qubits + 1, False)
|
|
13
|
-
rev = probability_by_hamming_weight(-J, -h, z, -theta, t, n_qubits + 1, False)
|
|
14
|
-
diff_theta = rev - fwd
|
|
15
|
-
|
|
16
|
-
phi = theta - np.pi / 2
|
|
17
|
-
fwd = probability_by_hamming_weight(J, h, z, phi, t, n_qubits + 1, False)
|
|
18
|
-
rev = probability_by_hamming_weight(-J, -h, z, -phi, t, n_qubits + 1, False)
|
|
19
|
-
diff_phi = rev - fwd
|
|
20
|
-
|
|
21
|
-
diff_theta *= cycles
|
|
22
|
-
diff_phi *= cycles
|
|
23
|
-
diff_lam = 0.5 * (diff_theta + diff_phi)
|
|
24
10
|
|
|
11
|
+
def get_otoc_hamming_distribution(J=-1.0, h=2.0, z=4, theta=0.0, t=5, n_qubits=65, pauli_strings = ['X' + 'I' * 64]):
|
|
25
12
|
n_bias = n_qubits + 1
|
|
13
|
+
if h <= epsilon:
|
|
14
|
+
bias = np.empty(n_bias, dtype=np.float64)
|
|
15
|
+
bias[0] = 1.0
|
|
16
|
+
return bias
|
|
17
|
+
|
|
18
|
+
diff_x = np.empty(n_bias, dtype=np.float64)
|
|
19
|
+
tot_prob = 0
|
|
20
|
+
p = 1.0
|
|
21
|
+
for q in range(n_qubits >> 1):
|
|
22
|
+
diff_x[q] = p
|
|
23
|
+
diff_x[n_bias - (q + 1)] = p
|
|
24
|
+
tot_prob += 2 * p
|
|
25
|
+
p = math.comb(n_qubits, q + 1)
|
|
26
|
+
if n_qubits & 1:
|
|
27
|
+
diff_x[n_qubits >> 1] = p
|
|
28
|
+
tot_prob += p
|
|
29
|
+
diff_x *= n_qubits / tot_prob
|
|
30
|
+
|
|
31
|
+
signal_frac = 0.0
|
|
26
32
|
diff_z = np.zeros(n_bias, dtype=np.float64)
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
33
|
+
diff_z[0] = n_qubits
|
|
34
|
+
for pauli_string in pauli_strings:
|
|
35
|
+
pauli_string = list(pauli_string)
|
|
36
|
+
if len(pauli_string) != n_qubits:
|
|
37
|
+
raise ValueError("OTOCS pauli_string must be same length as n_qubits! (Use 'I' for qubits that aren't changed.)")
|
|
38
|
+
|
|
39
|
+
term_signal = 0.5 * pauli_string.count('X') + pauli_string.count('Z') + 1.5 * pauli_string.count('Y')
|
|
40
|
+
if term_signal == 0:
|
|
41
|
+
continue
|
|
42
|
+
|
|
43
|
+
signal_frac -= term_signal
|
|
44
|
+
|
|
45
|
+
fwd = probability_by_hamming_weight(J, h, z, theta, t, n_qubits + 1)
|
|
46
|
+
rev = probability_by_hamming_weight(-J, -h, z, theta + np.pi, t, n_qubits + 1)
|
|
47
|
+
diff_theta = rev - fwd
|
|
48
|
+
|
|
49
|
+
phi = theta + np.pi / 2
|
|
50
|
+
fwd = probability_by_hamming_weight(-h, -J, z, phi, t, n_qubits + 1)
|
|
51
|
+
rev = probability_by_hamming_weight(h, J, z, phi - np.pi, t, n_qubits + 1)
|
|
52
|
+
diff_phi = rev - fwd
|
|
53
|
+
|
|
54
|
+
for b in pauli_string:
|
|
55
|
+
match b:
|
|
56
|
+
case 'X':
|
|
57
|
+
diff_z += diff_theta
|
|
58
|
+
case 'Z':
|
|
59
|
+
diff_x += diff_phi
|
|
60
|
+
case 'Y':
|
|
61
|
+
diff_z += diff_theta
|
|
62
|
+
diff_x += diff_phi
|
|
63
|
+
case _:
|
|
64
|
+
pass
|
|
65
|
+
|
|
66
|
+
# Normalize:
|
|
52
67
|
diff_z /= diff_z.sum()
|
|
53
68
|
diff_x /= diff_x.sum()
|
|
54
|
-
diff_y /= diff_y.sum()
|
|
55
69
|
|
|
56
|
-
|
|
70
|
+
signal_frac = 2 ** signal_frac
|
|
71
|
+
diff_z = signal_frac * diff_z + (1 - signal_frac) * diff_x
|
|
72
|
+
|
|
73
|
+
# Normalize:
|
|
74
|
+
diff_z /= diff_z.sum()
|
|
75
|
+
|
|
76
|
+
return diff_z
|
|
57
77
|
|
|
58
78
|
|
|
59
79
|
@njit
|
|
@@ -70,104 +90,132 @@ def fix_cdf(hamming_prob):
|
|
|
70
90
|
|
|
71
91
|
|
|
72
92
|
@njit
|
|
73
|
-
def
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
93
|
+
def factor_width(width):
|
|
94
|
+
col_len = int(np.floor(np.sqrt(width)))
|
|
95
|
+
while ((width // col_len) * col_len) != width:
|
|
96
|
+
col_len -= 1
|
|
97
|
+
row_len = width // col_len
|
|
77
98
|
|
|
78
|
-
return
|
|
99
|
+
return row_len, col_len
|
|
79
100
|
|
|
80
101
|
|
|
81
|
-
|
|
102
|
+
# Provided by Google search AI
|
|
103
|
+
def find_all_str_occurrences(main_string, sub_string):
|
|
82
104
|
indices = []
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
105
|
+
start_index = 0
|
|
106
|
+
while True:
|
|
107
|
+
index = main_string.find(sub_string, start_index)
|
|
108
|
+
if index == -1:
|
|
109
|
+
break
|
|
110
|
+
indices.append(index)
|
|
111
|
+
start_index = index + 1 # Start searching after the found occurrence
|
|
112
|
+
|
|
113
|
+
return indices
|
|
114
|
+
|
|
115
|
+
|
|
116
|
+
def take_sample(n_qubits, sample, m, inv_dist):
|
|
117
|
+
indices = [i for i in range(n_qubits)]
|
|
118
|
+
tot_inv_dist = 0.0
|
|
119
|
+
for i in range(n_qubits):
|
|
120
|
+
tot_inv_dist += inv_dist[i]
|
|
121
|
+
selected = []
|
|
122
|
+
for i in range(m):
|
|
123
|
+
r = tot_inv_dist * np.random.random()
|
|
124
|
+
p = inv_dist[indices[0]]
|
|
125
|
+
idx = 0
|
|
126
|
+
while p < r:
|
|
127
|
+
idx += 1
|
|
128
|
+
if idx >= len(indices):
|
|
129
|
+
idx = len(indices) - 1
|
|
130
|
+
break
|
|
131
|
+
p += inv_dist[indices[idx]]
|
|
132
|
+
i = indices[idx]
|
|
133
|
+
del indices[idx]
|
|
134
|
+
selected.append(i)
|
|
135
|
+
tot_inv_dist -= inv_dist[i]
|
|
136
|
+
for i in selected:
|
|
88
137
|
sample |= 1 << i
|
|
89
138
|
|
|
90
139
|
return sample
|
|
91
140
|
|
|
92
141
|
|
|
93
|
-
def
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
142
|
+
def get_willow_inv_dist(butterfly_idx_x, butterfly_idx_z, n_qubits, row_len, col_len, t):
|
|
143
|
+
inv_dist = np.zeros(n_qubits, dtype=np.float64)
|
|
144
|
+
for idx in butterfly_idx_x:
|
|
145
|
+
b_row, b_col = divmod(idx, row_len)
|
|
146
|
+
for q in range(n_qubits):
|
|
147
|
+
q_row, q_col = divmod(q, row_len)
|
|
148
|
+
inv_dist[q] += abs(q_row - b_row) + abs(q_col - b_col)
|
|
149
|
+
for idx in butterfly_idx_z:
|
|
150
|
+
b_row, b_col = divmod(idx, row_len)
|
|
151
|
+
for q in range(n_qubits):
|
|
152
|
+
q_row, q_col = divmod(q, row_len)
|
|
153
|
+
inv_dist[q] -= abs(q_row - b_row) + abs(q_col - b_col)
|
|
154
|
+
inv_dist = 2 ** (inv_dist / t)
|
|
155
|
+
|
|
156
|
+
return inv_dist
|
|
157
|
+
|
|
158
|
+
|
|
159
|
+
def get_inv_dist(butterfly_idx_x, butterfly_idx_z, n_qubits, row_len, col_len, t):
|
|
160
|
+
inv_dist = np.zeros(n_qubits, dtype=np.float64)
|
|
161
|
+
half_row = row_len >> 1
|
|
162
|
+
half_col = col_len >> 1
|
|
163
|
+
for idx in butterfly_idx_x:
|
|
164
|
+
b_row, b_col = divmod(idx, row_len)
|
|
165
|
+
for q in range(n_qubits):
|
|
166
|
+
q_row, q_col = divmod(q, row_len)
|
|
167
|
+
row_d = abs(q_row - b_row)
|
|
168
|
+
if row_d > half_row:
|
|
169
|
+
row_d = row_len - row_d
|
|
170
|
+
col_d = abs(q_col - b_col)
|
|
171
|
+
if col_d > half_col:
|
|
172
|
+
col_d = col_len - col_d
|
|
173
|
+
inv_dist[q] += row_d + col_d
|
|
174
|
+
for idx in butterfly_idx_z:
|
|
175
|
+
b_row, b_col = divmod(idx, row_len)
|
|
176
|
+
for q in range(n_qubits):
|
|
177
|
+
q_row, q_col = divmod(q, row_len)
|
|
178
|
+
row_d = abs(q_row - b_row)
|
|
179
|
+
if row_d > half_row:
|
|
180
|
+
row_d = row_len - row_d
|
|
181
|
+
col_d = abs(q_col - b_col)
|
|
182
|
+
if col_d > half_col:
|
|
183
|
+
col_d = col_len - col_d
|
|
184
|
+
inv_dist[q] -= row_d + col_d
|
|
185
|
+
inv_dist = 2 ** (inv_dist / t)
|
|
186
|
+
|
|
187
|
+
return inv_dist
|
|
188
|
+
|
|
189
|
+
|
|
190
|
+
def generate_otoc_samples(J=-1.0, h=2.0, z=4, theta=0.0, t=5, n_qubits=65, pauli_strings = ['X' + 'I' * 64], shots=100, is_orbifold=True):
|
|
191
|
+
thresholds = fix_cdf(get_otoc_hamming_distribution(J, h, z, theta, t, n_qubits, pauli_strings))
|
|
192
|
+
|
|
193
|
+
row_len, col_len = factor_width(n_qubits)
|
|
194
|
+
inv_dist = np.zeros(n_qubits, dtype=np.float64)
|
|
195
|
+
for pauli_string in pauli_strings:
|
|
196
|
+
if (pauli_string.count('X') + pauli_string.count('Y') + pauli_string.count('Z')) == 0:
|
|
197
|
+
continue
|
|
198
|
+
butterfly_idx_x = find_all_str_occurrences(pauli_string, 'X')
|
|
199
|
+
butterfly_idx_z = find_all_str_occurrences(pauli_string, 'Z')
|
|
200
|
+
if is_orbifold:
|
|
201
|
+
inv_dist += get_inv_dist(butterfly_idx_x, butterfly_idx_z, n_qubits, row_len, col_len, t)
|
|
116
202
|
else:
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
basis_x.append('Z')
|
|
120
|
-
|
|
121
|
-
bases = { 'X': basis_x, 'Y': basis_y, 'Z': basis_z }
|
|
122
|
-
thresholds = { key: fix_cdf(value) for key, value in get_otoc_hamming_distribution(J, h, z, theta, t, n_qubits, cycles, pauli_string).items() }
|
|
123
|
-
|
|
124
|
-
samples_3_axis = {}
|
|
125
|
-
for key, value in thresholds.items():
|
|
126
|
-
basis = bases[key]
|
|
203
|
+
inv_dist += get_willow_inv_dist(butterfly_idx_x, butterfly_idx_z, n_qubits, row_len, col_len, t)
|
|
204
|
+
inv_dist /= 2.0
|
|
127
205
|
|
|
206
|
+
qubit_pows = [1 << q for q in range(n_qubits)]
|
|
128
207
|
samples = []
|
|
129
208
|
for _ in range(shots):
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
z_count = basis.count('Z')
|
|
142
|
-
if z_count > m:
|
|
143
|
-
sample_3_axis[key] = take_sample('Z', basis, sample_3_axis[key], m)
|
|
144
|
-
continue
|
|
145
|
-
m -= z_count
|
|
146
|
-
sample_3_axis[key] = take_all('Z', basis, sample_3_axis[key])
|
|
147
|
-
if m == 0:
|
|
148
|
-
continue
|
|
149
|
-
|
|
150
|
-
i_count = basis.count('I')
|
|
151
|
-
if i_count > m:
|
|
152
|
-
sample_3_axis[key] = take_sample('I', basis, sample_3_axis[key], m)
|
|
153
|
-
continue
|
|
154
|
-
m -= i_count
|
|
155
|
-
sample_3_axis[key] = take_all('I', basis, sample_3_axis[key])
|
|
156
|
-
if m == 0:
|
|
157
|
-
continue
|
|
158
|
-
|
|
159
|
-
sample_3_axis[key] = take_sample('X', basis, sample_3_axis[key], m)
|
|
160
|
-
|
|
161
|
-
sample = 0
|
|
162
|
-
j = 0
|
|
163
|
-
for i in range(n_qubits):
|
|
164
|
-
base = measurement_basis[i]
|
|
165
|
-
if base not in ['X', 'Y', 'Z']:
|
|
166
|
-
continue
|
|
167
|
-
if (sample_3_axis[base] >> i) & 1:
|
|
168
|
-
sample |= 1 << j
|
|
169
|
-
j += 1
|
|
170
|
-
|
|
171
|
-
samples.append(sample)
|
|
209
|
+
# First dimension: Hamming weight
|
|
210
|
+
m = sample_mag(thresholds)
|
|
211
|
+
if m == 0:
|
|
212
|
+
samples.append(0)
|
|
213
|
+
continue
|
|
214
|
+
if m >= n_qubits:
|
|
215
|
+
samples.append((1 << n_qubits) - 1)
|
|
216
|
+
continue
|
|
217
|
+
|
|
218
|
+
# Second dimension: permutation within Hamming weight
|
|
219
|
+
samples.append(take_sample(n_qubits, 0, m, inv_dist))
|
|
172
220
|
|
|
173
221
|
return samples
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
pyqrackising/__init__.py,sha256=Q-fHQRApRseeFnnO6VfD1LpjPHCVkWoz0Gnaqmv6lp0,884
|
|
2
|
+
pyqrackising/convert_tensor_network_to_tsp.py,sha256=IbZdPfHQ2bzYqDXUdHfwdZJh-pC8lri_cAgESaskQWI,3450
|
|
3
|
+
pyqrackising/generate_tfim_samples.py,sha256=IlAz1l8oLExO6wJBO8LCQKlU_4ZPlyGsNE8xUt_iTrg,4762
|
|
4
|
+
pyqrackising/kernels.cl,sha256=Q9LZ1oBOZ2A_VsQ8uRUGQKNVpzqVXYwhG6c27FO6ljI,27004
|
|
5
|
+
pyqrackising/maxcut_tfim.py,sha256=05nRjk5hhEjNFjtXdKVObL0cYYuJ8URfcjrOGK5tGi4,10106
|
|
6
|
+
pyqrackising/maxcut_tfim_sparse.py,sha256=dddVdu54bvA5NCmknkWthnszPsCsC0OKoJswb3qI-hA,11205
|
|
7
|
+
pyqrackising/maxcut_tfim_streaming.py,sha256=EcRXKurqLiQs6pMNz-rhMp2YQzRXD726RnkXsPt4IJ0,6346
|
|
8
|
+
pyqrackising/maxcut_tfim_util.py,sha256=lbyNrUnjPajUUVDbSh1pRwru0eshFsP2hOrVppUf4Co,16865
|
|
9
|
+
pyqrackising/otoc.py,sha256=PKmpjwkGpMmwXGWmeqtvbVj1NfE35i9kkIdjQnDUZKE,7208
|
|
10
|
+
pyqrackising/spin_glass_solver.py,sha256=YtsIfYfpwhEMQPVd_sbjqpz6nQcrv8p2mUBYZ-wRpnM,13792
|
|
11
|
+
pyqrackising/spin_glass_solver_sparse.py,sha256=E4Ft7H-uKXZyq1cS7Z77AgdkL5fMlKMK6DwnXgrgOhk,14740
|
|
12
|
+
pyqrackising/spin_glass_solver_streaming.py,sha256=xpWq63yODMzBPQQtpDuB1Tro6ta8pPbVwc0ZkDWVASk,10018
|
|
13
|
+
pyqrackising/tfim_magnetization.py,sha256=On1MhCNGGHRxJFRmCOpMcdqQJiy25gWkjz0Ka8i5f-Q,499
|
|
14
|
+
pyqrackising/tfim_square_magnetization.py,sha256=9uJCT8ytyufcGFrZiignjCkWJr9UcP44sAAy0BIBw34,531
|
|
15
|
+
pyqrackising/tsp.py,sha256=kqDxU2RCjad-T4tW_C9WO1I-COSwX7fHB6VhIuQsjfQ,62464
|
|
16
|
+
pyqrackising/tsp_maxcut.py,sha256=ngxfSJgePXVwJXfNXYdk4jv1ISznx8zHOqR-Vbf33B0,9772
|
|
17
|
+
pyqrackising-9.5.12.dist-info/licenses/LICENSE.md,sha256=46mU2C5kSwOnkqkw9XQAJlhBL2JAf1_uCD8lVcXyMRg,7652
|
|
18
|
+
pyqrackising-9.5.12.dist-info/METADATA,sha256=BzfdPzf4NK65jk4YO3KtSlSfkSlLoRrWAU827KVmVRM,1144
|
|
19
|
+
pyqrackising-9.5.12.dist-info/WHEEL,sha256=tt4-VHVHv-wywtMZy9Hvv8M6zRlbacCdJyvDZp-_L0E,105
|
|
20
|
+
pyqrackising-9.5.12.dist-info/top_level.txt,sha256=bxlfGuLwzeVEI8Jm5D9HvC_WedgvvkSrpFwbGDjg-Ag,13
|
|
21
|
+
pyqrackising-9.5.12.dist-info/RECORD,,
|
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
pyqrackising/__init__.py,sha256=Q-fHQRApRseeFnnO6VfD1LpjPHCVkWoz0Gnaqmv6lp0,884
|
|
2
|
-
pyqrackising/convert_tensor_network_to_tsp.py,sha256=IbZdPfHQ2bzYqDXUdHfwdZJh-pC8lri_cAgESaskQWI,3450
|
|
3
|
-
pyqrackising/generate_tfim_samples.py,sha256=NZh9dMW7RurMkfawFLdWI8WFZmXS5CTosTQDrwCBOSk,4503
|
|
4
|
-
pyqrackising/kernels.cl,sha256=Q9LZ1oBOZ2A_VsQ8uRUGQKNVpzqVXYwhG6c27FO6ljI,27004
|
|
5
|
-
pyqrackising/maxcut_tfim.py,sha256=U1nNjyfMS48TtTQk7TRf5_VF3pVPfAcZEa2awc2nR8k,10862
|
|
6
|
-
pyqrackising/maxcut_tfim_sparse.py,sha256=eenJNSEwRvgwACfKoH0tj6rpn7uqH6nNTBuxUPh_lDg,11941
|
|
7
|
-
pyqrackising/maxcut_tfim_streaming.py,sha256=FkBsRoXSRhv4gUeN9O7Ivx54oxq_SqiCDKnYsyxU4bs,6664
|
|
8
|
-
pyqrackising/maxcut_tfim_util.py,sha256=D5tIbfKVLazR6f_INAoFypNJA0iuPin_bkiIM7-_pvg,16937
|
|
9
|
-
pyqrackising/otoc.py,sha256=IzARDeNvuGwL_RHBotQsth5d7iz5oGbsIharCrCLUyg,5620
|
|
10
|
-
pyqrackising/spin_glass_solver.py,sha256=YtsIfYfpwhEMQPVd_sbjqpz6nQcrv8p2mUBYZ-wRpnM,13792
|
|
11
|
-
pyqrackising/spin_glass_solver_sparse.py,sha256=E4Ft7H-uKXZyq1cS7Z77AgdkL5fMlKMK6DwnXgrgOhk,14740
|
|
12
|
-
pyqrackising/spin_glass_solver_streaming.py,sha256=xpWq63yODMzBPQQtpDuB1Tro6ta8pPbVwc0ZkDWVASk,10018
|
|
13
|
-
pyqrackising/tfim_magnetization.py,sha256=On1MhCNGGHRxJFRmCOpMcdqQJiy25gWkjz0Ka8i5f-Q,499
|
|
14
|
-
pyqrackising/tfim_square_magnetization.py,sha256=9uJCT8ytyufcGFrZiignjCkWJr9UcP44sAAy0BIBw34,531
|
|
15
|
-
pyqrackising/tsp.py,sha256=kqDxU2RCjad-T4tW_C9WO1I-COSwX7fHB6VhIuQsjfQ,62464
|
|
16
|
-
pyqrackising/tsp_maxcut.py,sha256=ngxfSJgePXVwJXfNXYdk4jv1ISznx8zHOqR-Vbf33B0,9772
|
|
17
|
-
pyqrackising-9.3.0.dist-info/licenses/LICENSE.md,sha256=46mU2C5kSwOnkqkw9XQAJlhBL2JAf1_uCD8lVcXyMRg,7652
|
|
18
|
-
pyqrackising-9.3.0.dist-info/METADATA,sha256=O5jeEBKDsW3iCI2rFiIFTbS997jR8rNZ4ARO-1TrVs4,1143
|
|
19
|
-
pyqrackising-9.3.0.dist-info/WHEEL,sha256=tt4-VHVHv-wywtMZy9Hvv8M6zRlbacCdJyvDZp-_L0E,105
|
|
20
|
-
pyqrackising-9.3.0.dist-info/top_level.txt,sha256=bxlfGuLwzeVEI8Jm5D9HvC_WedgvvkSrpFwbGDjg-Ag,13
|
|
21
|
-
pyqrackising-9.3.0.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|