pyqrackising 9.5.2__tar.gz → 9.5.4__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.
Files changed (28) hide show
  1. {pyqrackising-9.5.2/pyqrackising.egg-info → pyqrackising-9.5.4}/PKG-INFO +1 -1
  2. {pyqrackising-9.5.2 → pyqrackising-9.5.4}/pyproject.toml +1 -1
  3. {pyqrackising-9.5.2 → pyqrackising-9.5.4}/pyqrackising/maxcut_tfim.py +12 -36
  4. {pyqrackising-9.5.2 → pyqrackising-9.5.4}/pyqrackising/maxcut_tfim_sparse.py +12 -35
  5. {pyqrackising-9.5.2 → pyqrackising-9.5.4}/pyqrackising/maxcut_tfim_streaming.py +11 -18
  6. {pyqrackising-9.5.2 → pyqrackising-9.5.4}/pyqrackising/maxcut_tfim_util.py +2 -42
  7. {pyqrackising-9.5.2 → pyqrackising-9.5.4}/pyqrackising/otoc.py +15 -1
  8. {pyqrackising-9.5.2 → pyqrackising-9.5.4/pyqrackising.egg-info}/PKG-INFO +1 -1
  9. {pyqrackising-9.5.2 → pyqrackising-9.5.4}/setup.py +1 -1
  10. {pyqrackising-9.5.2 → pyqrackising-9.5.4}/LICENSE.md +0 -0
  11. {pyqrackising-9.5.2 → pyqrackising-9.5.4}/MANIFEST.in +0 -0
  12. {pyqrackising-9.5.2 → pyqrackising-9.5.4}/README.md +0 -0
  13. {pyqrackising-9.5.2 → pyqrackising-9.5.4}/pyqrackising/__init__.py +0 -0
  14. {pyqrackising-9.5.2 → pyqrackising-9.5.4}/pyqrackising/convert_tensor_network_to_tsp.py +0 -0
  15. {pyqrackising-9.5.2 → pyqrackising-9.5.4}/pyqrackising/generate_tfim_samples.py +0 -0
  16. {pyqrackising-9.5.2 → pyqrackising-9.5.4}/pyqrackising/kernels.cl +0 -0
  17. {pyqrackising-9.5.2 → pyqrackising-9.5.4}/pyqrackising/spin_glass_solver.py +0 -0
  18. {pyqrackising-9.5.2 → pyqrackising-9.5.4}/pyqrackising/spin_glass_solver_sparse.py +0 -0
  19. {pyqrackising-9.5.2 → pyqrackising-9.5.4}/pyqrackising/spin_glass_solver_streaming.py +0 -0
  20. {pyqrackising-9.5.2 → pyqrackising-9.5.4}/pyqrackising/tfim_magnetization.py +0 -0
  21. {pyqrackising-9.5.2 → pyqrackising-9.5.4}/pyqrackising/tfim_square_magnetization.py +0 -0
  22. {pyqrackising-9.5.2 → pyqrackising-9.5.4}/pyqrackising/tsp.py +0 -0
  23. {pyqrackising-9.5.2 → pyqrackising-9.5.4}/pyqrackising/tsp_maxcut.py +0 -0
  24. {pyqrackising-9.5.2 → pyqrackising-9.5.4}/pyqrackising.egg-info/SOURCES.txt +0 -0
  25. {pyqrackising-9.5.2 → pyqrackising-9.5.4}/pyqrackising.egg-info/dependency_links.txt +0 -0
  26. {pyqrackising-9.5.2 → pyqrackising-9.5.4}/pyqrackising.egg-info/not-zip-safe +0 -0
  27. {pyqrackising-9.5.2 → pyqrackising-9.5.4}/pyqrackising.egg-info/top_level.txt +0 -0
  28. {pyqrackising-9.5.2 → pyqrackising-9.5.4}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pyqrackising
3
- Version: 9.5.2
3
+ Version: 9.5.4
4
4
  Summary: Fast MAXCUT, TSP, and sampling heuristics from near-ideal transverse field Ising model (TFIM)
5
5
  Home-page: https://github.com/vm6502q/PyQrackIsing
6
6
  Author: Dan Strano
@@ -10,7 +10,7 @@ build-backend = "setuptools.build_meta"
10
10
 
11
11
  [project]
12
12
  name = "pyqrackising"
13
- version = "9.5.2"
13
+ version = "9.5.4"
14
14
  requires-python = ">=3.8"
15
15
  description = "Fast MAXCUT, TSP, and sampling heuristics from near-ideal transverse field Ising model (TFIM)"
16
16
  readme = {file = "README.txt", content-type = "text/markdown"}
@@ -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
- hamming_prob = maxcut_hamming_cdf(n_qubits, J_eff, degrees, quality, anneal_t, anneal_h)
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
- best_solution, best_value = sample_for_opencl(G_m, G_m_buf, shots, hamming_prob, repulsion_base, is_spin_glass, is_segmented, segment_size, theta_segment_size)
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
- is_opencl = is_maxcut_gpu and IS_OPENCL_AVAILABLE
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
- 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, hamming_prob, repulsion_base, is_spin_glass, is_segmented, segment_size, theta_segment_size)
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_data, G_rows, G_cols, 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
- bit_string, best_value, partition = cpu_footer(shots, thread_count, quality, n_qubits, G_min, G_func, nodes, is_spin_glass, anneal_t, anneal_h, repulsion_base)
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, partition
209
+ return bit_string, best_value, (l, r)
@@ -389,44 +389,6 @@ def init_theta(h_mult, n_qubits, J_eff, degrees):
389
389
  return theta
390
390
 
391
391
 
392
- # From Google Search AI
393
- @njit
394
- def factorial(num):
395
- """Calculates the factorial of a non-negative integer."""
396
- if num == 0:
397
- return 1
398
-
399
- result = 1
400
- for i in range(1, num + 1):
401
- result *= i
402
-
403
- return result
404
-
405
-
406
- # From Google Search AI
407
- @njit
408
- def comb(n, k):
409
- """
410
- Calculates the number of combinations (n choose k) from scratch.
411
- n: The total number of items.
412
- k: The number of items to choose.
413
- """
414
- # Optimize by choosing the smaller of k and (n-k)
415
- # This reduces the number of multiplications in the factorial calculation
416
- k = min(k, n - k)
417
-
418
- # Calculate the numerator: n * (n-1) * ... * (n-k+1)
419
- numerator = 1
420
- for i in range(k):
421
- numerator *= (n - i)
422
-
423
- # Calculate the denominator: k!
424
- denominator = factorial(k)
425
-
426
- return numerator // denominator
427
-
428
-
429
- @njit
430
392
  def init_thresholds(n_qubits):
431
393
  n_bias = n_qubits - 1
432
394
  thresholds = np.empty(n_bias, dtype=np.float64)
@@ -436,7 +398,7 @@ def init_thresholds(n_qubits):
436
398
  thresholds[q - 1] = p
437
399
  thresholds[n_bias - q] = p
438
400
  tot_prob += 2 * p
439
- p = comb(n_qubits, q + 1)
401
+ p = math.comb(n_qubits, q + 1)
440
402
  if n_qubits & 1:
441
403
  thresholds[q - 1] = p
442
404
  tot_prob += p
@@ -477,9 +439,7 @@ def probability_by_hamming_weight(J, h, z, theta, t, n_bias, normalized=True):
477
439
 
478
440
 
479
441
  @njit(parallel=True)
480
- def maxcut_hamming_cdf(n_qubits, J_func, degrees, quality, tot_t, h_mult):
481
- hamming_prob = init_thresholds(n_qubits)
482
-
442
+ def maxcut_hamming_cdf(hamming_prob, n_qubits, J_func, degrees, quality, tot_t, h_mult):
483
443
  n_steps = 1 << quality
484
444
  delta_t = tot_t / n_steps
485
445
  n_bias = n_qubits + 1
@@ -184,6 +184,12 @@ def get_inv_dist(butterfly_idx_x, butterfly_idx_z, n_qubits, row_len, col_len):
184
184
  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):
185
185
  thresholds = fix_cdf(get_otoc_hamming_distribution(J, h, z, theta, t, n_qubits, pauli_strings))
186
186
 
187
+ entropy_frac = 0.0
188
+ for pauli_string in pauli_strings:
189
+ pauli_string = list(pauli_string)
190
+ entropy_frac += pauli_string.count('X') + pauli_string.count('Y') + pauli_string.count('Z')
191
+ entropy_frac /= n_qubits * len(pauli_strings)
192
+
187
193
  row_len, col_len = factor_width(n_qubits)
188
194
  inv_dist = np.zeros(n_qubits, dtype=np.float64)
189
195
  for pauli_string in pauli_strings:
@@ -195,6 +201,7 @@ def generate_otoc_samples(J=-1.0, h=2.0, z=4, theta=0.0, t=5, n_qubits=65, pauli
195
201
  inv_dist += get_willow_inv_dist(butterfly_idx_x, butterfly_idx_z, n_qubits, row_len, col_len)
196
202
  inv_dist /= 2.0
197
203
 
204
+ qubit_pows = [1 << q for q in range(n_qubits)]
198
205
  samples = []
199
206
  for _ in range(shots):
200
207
  # First dimension: Hamming weight
@@ -207,6 +214,13 @@ def generate_otoc_samples(J=-1.0, h=2.0, z=4, theta=0.0, t=5, n_qubits=65, pauli
207
214
  continue
208
215
 
209
216
  # Second dimension: permutation within Hamming weight
210
- samples.append(take_sample(n_qubits, 0, m, inv_dist))
217
+ if np.random.random() < entropy_frac:
218
+ bit_pows = np.random.choice(qubit_pows, size=m, replace=False)
219
+ sample = 0
220
+ for bit_pow in bit_pows:
221
+ sample |= bit_pow
222
+ samples.append(sample)
223
+ else:
224
+ samples.append(take_sample(n_qubits, 0, m, inv_dist))
211
225
 
212
226
  return samples
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pyqrackising
3
- Version: 9.5.2
3
+ Version: 9.5.4
4
4
  Summary: Fast MAXCUT, TSP, and sampling heuristics from near-ideal transverse field Ising model (TFIM)
5
5
  Home-page: https://github.com/vm6502q/PyQrackIsing
6
6
  Author: Dan Strano
@@ -7,7 +7,7 @@ with open(README_PATH) as readme_file:
7
7
 
8
8
  setup(
9
9
  name='pyqrackising',
10
- version='9.5.2',
10
+ version='9.5.4',
11
11
  author='Dan Strano',
12
12
  author_email='stranoj@gmail.com',
13
13
  description='Fast MAXCUT, TSP, and sampling heuristics from near-ideal transverse field Ising model (TFIM)',
File without changes
File without changes
File without changes
File without changes