pyqrackising 9.5.11__py3-none-manylinux_2_39_x86_64.whl → 9.7.1__py3-none-manylinux_2_39_x86_64.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.
@@ -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, init_thresholds, 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, heuristic_threshold, 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:
@@ -22,6 +22,9 @@ def update_repulsion_choice(G_m, weights, n, used, node, repulsion_base):
22
22
  # Select node
23
23
  used[node] = True
24
24
 
25
+ if abs(1.0 - repulsion_base) <= epsilon:
26
+ return
27
+
25
28
  # Repulsion: penalize neighbors
26
29
  for nbr in range(n):
27
30
  if used[nbr]:
@@ -239,6 +242,60 @@ def run_cut_opencl(best_energy, samples, G_m_buf, is_segmented, local_size, glob
239
242
  return samples[max_index_host[best_x]], energy
240
243
 
241
244
 
245
+ @njit
246
+ def exact_maxcut(G):
247
+ """Brute-force exact MAXCUT solver using Numba JIT."""
248
+ n = G.shape[0]
249
+ max_cut = -1.0
250
+ best_mask = 0
251
+
252
+ # Enumerate all 2^n possible bitstrings
253
+ for mask in range(1 << n):
254
+ cut = 0.0
255
+ for i in range(n):
256
+ bi = (mask >> i) & 1
257
+ for j in range(i + 1, n):
258
+ if bi != ((mask >> j) & 1):
259
+ cut += G[i, j]
260
+ if cut > max_cut:
261
+ max_cut = cut
262
+ best_mask = mask
263
+
264
+ # Reconstruct best bitstring
265
+ best_bits = np.zeros(n, dtype=np.bool_)
266
+ for i in range(n):
267
+ best_bits[i] = (best_mask >> i) & 1
268
+
269
+ return best_bits, max_cut
270
+
271
+
272
+ @njit
273
+ def exact_spin_glass(G):
274
+ """Brute-force exact spin-glass solver using Numba JIT."""
275
+ n = G.shape[0]
276
+ max_cut = -1.0
277
+ best_mask = 0
278
+
279
+ # Enumerate all 2^n possible bitstrings
280
+ for mask in range(1 << n):
281
+ cut = 0.0
282
+ for i in range(n):
283
+ bi = (mask >> i) & 1
284
+ for j in range(i + 1, n):
285
+ val = G[i, j]
286
+ cut += val if bi == ((mask >> j) & 1) else -val
287
+ if cut > max_cut:
288
+ max_cut = cut
289
+ best_mask = mask
290
+
291
+ # Reconstruct best bitstring
292
+ best_bits = np.zeros(n, dtype=np.bool_)
293
+ for i in range(n):
294
+ best_bits[i] = (best_mask >> i) & 1
295
+
296
+ return best_bits, max_cut
297
+
298
+
242
299
  def maxcut_tfim(
243
300
  G,
244
301
  quality=None,
@@ -261,22 +318,15 @@ def maxcut_tfim(
261
318
 
262
319
  n_qubits = len(G_m)
263
320
 
264
- if n_qubits < 3:
265
- empty = [nodes[0]]
266
- empty.clear()
267
-
268
- if n_qubits == 0:
269
- return "", 0, (empty, empty.copy())
270
-
271
- if n_qubits == 1:
272
- return "0", 0, (nodes, empty)
321
+ if n_qubits < heuristic_threshold:
322
+ best_solution, best_value = exact_spin_glass(G_m) if is_spin_glass else exact_maxcut(G_m)
323
+ bit_string, l, r = get_cut(best_solution, nodes, n_qubits)
273
324
 
274
- if n_qubits == 2:
275
- weight = G_m[0, 1]
276
- if weight < 0.0:
277
- return "00", 0, (nodes, empty)
325
+ if best_value < 0.0:
326
+ # Best cut is trivial partition, all/empty
327
+ return '0' * n_qubits, 0.0, (nodes, [])
278
328
 
279
- return "01", weight, ([nodes[0]], [nodes[1]])
329
+ return bit_string, best_value, (l, r)
280
330
 
281
331
  if quality is None:
282
332
  quality = 6
@@ -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, 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
6
+ from .maxcut_tfim_util import binary_search, compute_cut_sparse, compute_energy_sparse, convert_bool_to_uint, get_cut, get_cut_base, heuristic_threshold_sparse, 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:
@@ -22,6 +22,9 @@ def update_repulsion_choice(G_data, G_rows, G_cols, weights, n, used, node, repu
22
22
  # Select node
23
23
  used[node] = True
24
24
 
25
+ if abs(1.0 - repulsion_base) <= epsilon:
26
+ return
27
+
25
28
  # Repulsion: penalize neighbors
26
29
  for j in range(G_rows[node], G_rows[node + 1]):
27
30
  nbr = G_cols[j]
@@ -253,6 +256,69 @@ def run_cut_opencl(best_energy, samples, G_data_buf, G_rows_buf, G_cols_buf, is_
253
256
  return samples[max_index_host[best_x]], energy
254
257
 
255
258
 
259
+ @njit
260
+ def exact_maxcut(G_data, G_rows, G_cols):
261
+ """Brute-force exact MAXCUT solver using Numba JIT."""
262
+ n = G_rows.shape[0] - 1
263
+ max_cut = -1.0
264
+ best_mask = 0
265
+
266
+ # Enumerate all 2^n possible bitstrings
267
+ for mask in range(1 << n):
268
+ cut = 0.0
269
+ for i in range(n):
270
+ bi = (mask >> i) & 1
271
+ for j in range(i + 1, n):
272
+ if bi != ((mask >> j) & 1):
273
+ u, v = (i, j) if i < j else (j, i)
274
+ start = G_rows[u]
275
+ end = G_rows[u + 1]
276
+ k = binary_search(G_cols[start:end], v) + start
277
+ if k < end:
278
+ cut += G_data[k]
279
+ if cut > max_cut:
280
+ max_cut = cut
281
+ best_mask = mask
282
+
283
+ # Reconstruct best bitstring
284
+ best_bits = np.zeros(n, dtype=np.bool_)
285
+ for i in range(n):
286
+ best_bits[i] = (best_mask >> i) & 1
287
+
288
+ return best_bits, max_cut
289
+
290
+
291
+ @njit
292
+ def exact_spin_glass(G_data, G_rows, G_cols):
293
+ """Brute-force exact spin-glass solver using Numba JIT."""
294
+ n = G_rows.shape[0] - 1
295
+ max_cut = -1.0
296
+ best_mask = 0
297
+
298
+ # Enumerate all 2^n possible bitstrings
299
+ for mask in range(1 << n):
300
+ cut = 0.0
301
+ for i in range(n):
302
+ bi = (mask >> i) & 1
303
+ for j in range(i + 1, n):
304
+ u, v = (i, j) if i < j else (j, i)
305
+ start = G_rows[u]
306
+ end = G_rows[u + 1]
307
+ k = binary_search(G_cols[start:end], v) + start
308
+ if k < end:
309
+ val = G_data[k]
310
+ cut += val if bi == ((mask >> j) & 1) else -val
311
+ if cut > max_cut:
312
+ max_cut = cut
313
+ best_mask = mask
314
+
315
+ # Reconstruct best bitstring
316
+ best_bits = np.zeros(n, dtype=np.bool_)
317
+ for i in range(n):
318
+ best_bits[i] = (best_mask >> i) & 1
319
+
320
+ return best_bits, max_cut
321
+
256
322
 
257
323
  def maxcut_tfim_sparse(
258
324
  G,
@@ -278,19 +344,15 @@ def maxcut_tfim_sparse(
278
344
  nodes = list(range(n_qubits))
279
345
  G_m = G
280
346
 
281
- if n_qubits < 3:
282
- if n_qubits == 0:
283
- return "", 0, ([], [])
284
-
285
- if n_qubits == 1:
286
- return "0", 0, (nodes, [])
347
+ if n_qubits < heuristic_threshold_sparse:
348
+ best_solution, best_value = exact_spin_glass(G_m.data, G_m.indptr, G_m.indices) if is_spin_glass else exact_maxcut(G_m.data, G_m.indptr, G_m.indices)
349
+ bit_string, l, r = get_cut(best_solution, nodes, n_qubits)
287
350
 
288
- if n_qubits == 2:
289
- weight = G_m[0, 1]
290
- if weight < 0.0:
291
- return "00", 0, (nodes, [])
351
+ if best_value < 0.0:
352
+ # Best cut is trivial partition, all/empty
353
+ return '0' * n_qubits, 0.0, (nodes, [])
292
354
 
293
- return "01", weight, ([nodes[0]], [nodes[1]])
355
+ return bit_string, best_value, (l, r)
294
356
 
295
357
  if quality is None:
296
358
  quality = 6
@@ -324,7 +386,7 @@ def maxcut_tfim_sparse(
324
386
  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
387
  else:
326
388
  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)
389
+ 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)
328
390
 
329
391
  bit_string, l, r = get_cut(best_solution, nodes, n_qubits)
330
392
 
@@ -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, init_thresholds, 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, heuristic_threshold, init_thresholds, maxcut_hamming_cdf, opencl_context, sample_mag, bit_pick
7
7
 
8
8
 
9
9
  epsilon = opencl_context.epsilon
@@ -15,6 +15,9 @@ def update_repulsion_choice(G_func, nodes, weights, n, used, node, repulsion_bas
15
15
  # Select node
16
16
  used[node] = True
17
17
 
18
+ if abs(1.0 - repulsion_base) <= epsilon:
19
+ return
20
+
18
21
  # Repulsion: penalize neighbors
19
22
  for nbr in range(n):
20
23
  if used[nbr]:
@@ -145,6 +148,58 @@ def find_G_min(G_func, nodes, n_nodes):
145
148
  return G_min
146
149
 
147
150
 
151
+ @njit
152
+ def exact_maxcut(G_func, n):
153
+ """Brute-force exact MAXCUT solver using Numba JIT."""
154
+ max_cut = -1.0
155
+ best_mask = 0
156
+
157
+ # Enumerate all 2^n possible bitstrings
158
+ for mask in range(1 << n):
159
+ cut = 0.0
160
+ for i in range(n):
161
+ bi = (mask >> i) & 1
162
+ for j in range(i + 1, n):
163
+ if bi != ((mask >> j) & 1):
164
+ cut += G_func(i, j)
165
+ if cut > max_cut:
166
+ max_cut = cut
167
+ best_mask = mask
168
+
169
+ # Reconstruct best bitstring
170
+ best_bits = np.zeros(n, dtype=np.bool_)
171
+ for i in range(n):
172
+ best_bits[i] = (best_mask >> i) & 1
173
+
174
+ return best_bits, max_cut
175
+
176
+
177
+ @njit
178
+ def exact_spin_glass(G_func, n):
179
+ """Brute-force exact spin-glass solver using Numba JIT."""
180
+ max_cut = -1.0
181
+ best_mask = 0
182
+
183
+ # Enumerate all 2^n possible bitstrings
184
+ for mask in range(1 << n):
185
+ cut = 0.0
186
+ for i in range(n):
187
+ bi = (mask >> i) & 1
188
+ for j in range(i + 1, n):
189
+ val = G_func(i, j)
190
+ cut += val if bi == ((mask >> j) & 1) else -val
191
+ if cut > max_cut:
192
+ max_cut = cut
193
+ best_mask = mask
194
+
195
+ # Reconstruct best bitstring
196
+ best_bits = np.zeros(n, dtype=np.bool_)
197
+ for i in range(n):
198
+ best_bits[i] = (best_mask >> i) & 1
199
+
200
+ return best_bits, max_cut
201
+
202
+
148
203
  def maxcut_tfim_streaming(
149
204
  G_func,
150
205
  nodes,
@@ -158,19 +213,15 @@ def maxcut_tfim_streaming(
158
213
  wgs = opencl_context.work_group_size
159
214
  n_qubits = len(nodes)
160
215
 
161
- if n_qubits < 3:
162
- if n_qubits == 0:
163
- return "", 0, ([], [])
164
-
165
- if n_qubits == 1:
166
- return "0", 0, (nodes, [])
216
+ if n_qubits < heuristic_threshold:
217
+ best_solution, best_value = exact_spin_glass(G_func, n_qubits) if is_spin_glass else exact_maxcut(G_func, n_qubits)
218
+ bit_string, l, r = get_cut(best_solution, nodes, n_qubits)
167
219
 
168
- if n_qubits == 2:
169
- weight = G_func(nodes[0], nodes[1])
170
- if weight < 0.0:
171
- return "00", 0, (nodes, [])
220
+ if best_value < 0.0:
221
+ # Best cut is trivial partition, all/empty
222
+ return '0' * n_qubits, 0.0, (nodes, [])
172
223
 
173
- return "01", weight, ([nodes[0]], [nodes[1]])
224
+ return bit_string, best_value, (l, r)
174
225
 
175
226
  if quality is None:
176
227
  quality = 6
@@ -121,6 +121,8 @@ except ImportError:
121
121
  print("PyOpenCL not installed. (If you have any OpenCL accelerator devices with available ICDs, you might want to optionally install pyopencl.)")
122
122
 
123
123
  opencl_context = OpenCLContext(compute_units, IS_OPENCL_AVAILABLE, work_group_size, dtype, epsilon, max_alloc, ctx, queue, calculate_cut_kernel, calculate_cut_sparse_kernel, calculate_cut_segmented_kernel, calculate_cut_sparse_segmented_kernel, single_bit_flips_kernel, single_bit_flips_sparse_kernel, single_bit_flips_segmented_kernel, single_bit_flips_sparse_segmented_kernel, double_bit_flips_kernel, double_bit_flips_sparse_kernel, double_bit_flips_segmented_kernel, double_bit_flips_sparse_segmented_kernel)
124
+ heuristic_threshold = 24
125
+ heuristic_threshold_sparse = 23
124
126
 
125
127
 
126
128
  def setup_opencl(l, g, args_np):
@@ -390,19 +392,21 @@ def init_theta(h_mult, n_qubits, J_eff, degrees):
390
392
 
391
393
 
392
394
  def init_thresholds(n_qubits):
393
- n_bias = n_qubits - 1
395
+ n_bias = n_qubits + 1
394
396
  thresholds = np.empty(n_bias, dtype=np.float64)
395
- tot_prob = 0
396
- p = n_qubits
397
- for q in range(1, n_qubits >> 1):
398
- thresholds[q - 1] = p
399
- thresholds[n_bias - q] = p
400
- tot_prob += 2 * p
397
+ normalizer = 0
398
+ for q in range(n_qubits >> 1):
399
+ normalizer += math.comb(n_qubits, q) << 1
400
+ if n_qubits & 1:
401
+ normalizer += math.comb(n_qubits, n_qubits >> 1)
402
+ p = 1
403
+ for q in range(n_qubits >> 1):
404
+ val = p / normalizer
405
+ thresholds[q] = val
406
+ thresholds[n_bias - (q + 1)] = val
401
407
  p = math.comb(n_qubits, q + 1)
402
408
  if n_qubits & 1:
403
- thresholds[n_qubits >> 1] = p
404
- tot_prob += p
405
- thresholds /= tot_prob
409
+ thresholds[n_qubits >> 1] = p / normalizer
406
410
 
407
411
  return thresholds
408
412
 
@@ -438,7 +442,7 @@ def probability_by_hamming_weight(J, h, z, theta, t, n_bias, normalized=True):
438
442
  return bias
439
443
 
440
444
 
441
- @njit(parallel=True)
445
+ @njit
442
446
  def maxcut_hamming_cdf(hamming_prob, n_qubits, J_func, degrees, quality, tot_t, h_mult):
443
447
  n_steps = 1 << quality
444
448
  delta_t = tot_t / n_steps
@@ -446,7 +450,7 @@ def maxcut_hamming_cdf(hamming_prob, n_qubits, J_func, degrees, quality, tot_t,
446
450
 
447
451
  theta = init_theta(h_mult, n_qubits, J_func, degrees)
448
452
 
449
- for qc in prange(n_qubits, n_steps * n_qubits):
453
+ for qc in range(n_qubits, n_steps * n_qubits):
450
454
  step = qc // n_qubits
451
455
  q = qc % n_qubits
452
456
  J_eff = J_func[q]
pyqrackising/otoc.py CHANGED
@@ -51,8 +51,6 @@ def get_otoc_hamming_distribution(J=-1.0, h=2.0, z=4, theta=0.0, t=5, n_qubits=6
51
51
  rev = probability_by_hamming_weight(h, J, z, phi - np.pi, t, n_qubits + 1)
52
52
  diff_phi = rev - fwd
53
53
 
54
- diff_lam = (diff_theta + diff_phi) / 2
55
-
56
54
  for b in pauli_string:
57
55
  match b:
58
56
  case 'X':
@@ -1,5 +1,5 @@
1
1
  from .maxcut_tfim import maxcut_tfim
2
- from .maxcut_tfim_util import compute_cut, compute_energy, get_cut, gray_code_next, gray_mutation, int_to_bitstring, make_G_m_buf, make_best_theta_buf, opencl_context, setup_opencl
2
+ from .maxcut_tfim_util import compute_cut, compute_energy, get_cut, gray_code_next, gray_mutation, heuristic_threshold, int_to_bitstring, make_G_m_buf, make_best_theta_buf, opencl_context, setup_opencl
3
3
  import networkx as nx
4
4
  import numpy as np
5
5
  from numba import njit, prange
@@ -296,6 +296,9 @@ def spin_glass_solver(
296
296
 
297
297
  return "01", weight, ([nodes[0]], [nodes[1]]), -weight
298
298
 
299
+ if n_qubits < heuristic_threshold:
300
+ best_guess = None
301
+
299
302
  bitstring = ""
300
303
  if isinstance(best_guess, str):
301
304
  bitstring = best_guess
@@ -305,16 +308,27 @@ def spin_glass_solver(
305
308
  bitstring = "".join(["1" if b else "0" for b in best_guess])
306
309
  else:
307
310
  bitstring, cut_value, _ = maxcut_tfim(G_m, quality=quality, shots=shots, is_spin_glass=is_spin_glass, anneal_t=anneal_t, anneal_h=anneal_h, repulsion_base=repulsion_base, is_maxcut_gpu=is_maxcut_gpu, is_nested=True)
311
+
308
312
  best_theta = np.array([b == "1" for b in list(bitstring)], dtype=np.bool_)
313
+ max_energy = compute_energy(best_theta, G_m, n_qubits) if is_spin_glass else cut_value
314
+
315
+ if n_qubits < heuristic_threshold:
316
+ bitstring, l, r = get_cut(best_theta, nodes, n_qubits)
317
+ if is_spin_glass:
318
+ cut_value = compute_cut(best_theta, G_m, n_qubits)
319
+ min_energy = -max_energy
320
+ else:
321
+ cut_value = max_energy
322
+ min_energy = compute_energy(best_theta, G_m, n_qubits)
323
+
324
+ return bitstring, float(cut_value), (l, r), float(min_energy)
309
325
 
310
326
  if gray_iterations is None:
311
- gray_iterations = n_qubits * os.cpu_count()
327
+ gray_iterations = n_qubits * n_qubits
312
328
 
313
329
  if gray_seed_multiple is None:
314
330
  gray_seed_multiple = os.cpu_count()
315
331
 
316
- max_energy = compute_energy(best_theta, G_m, n_qubits) if is_spin_glass else cut_value
317
-
318
332
  is_opencl = is_maxcut_gpu and IS_OPENCL_AVAILABLE
319
333
 
320
334
  if is_opencl:
@@ -1,5 +1,5 @@
1
1
  from .maxcut_tfim_sparse import maxcut_tfim_sparse
2
- from .maxcut_tfim_util import compute_cut_sparse, compute_energy_sparse, get_cut, gray_code_next, gray_mutation, int_to_bitstring, make_G_m_csr_buf, make_best_theta_buf, opencl_context, setup_opencl, to_scipy_sparse_upper_triangular
2
+ from .maxcut_tfim_util import compute_cut_sparse, compute_energy_sparse, get_cut, gray_code_next, gray_mutation, heuristic_threshold_sparse, int_to_bitstring, make_G_m_csr_buf, make_best_theta_buf, opencl_context, setup_opencl, to_scipy_sparse_upper_triangular
3
3
  import networkx as nx
4
4
  import numpy as np
5
5
  from numba import njit, prange
@@ -300,6 +300,9 @@ def spin_glass_solver_sparse(
300
300
 
301
301
  return "01", weight, ([nodes[0]], [nodes[1]]), -weight
302
302
 
303
+ if n_qubits < heuristic_threshold_sparse:
304
+ best_guess = None
305
+
303
306
  bitstring = ""
304
307
  if isinstance(best_guess, str):
305
308
  bitstring = best_guess
@@ -309,16 +312,27 @@ def spin_glass_solver_sparse(
309
312
  bitstring = "".join(["1" if b else "0" for b in best_guess])
310
313
  else:
311
314
  bitstring, cut_value, _ = maxcut_tfim_sparse(G_m, quality=quality, shots=shots, is_spin_glass=is_spin_glass, anneal_t=anneal_t, anneal_h=anneal_h, repulsion_base=repulsion_base, is_maxcut_gpu=is_maxcut_gpu, is_nested=True)
315
+
312
316
  best_theta = np.array([b == "1" for b in list(bitstring)], dtype=np.bool_)
317
+ max_energy = compute_energy(best_theta, G_m, n_qubits) if is_spin_glass else cut_value
318
+
319
+ if n_qubits < heuristic_threshold_sparse:
320
+ bitstring, l, r = get_cut(best_theta, nodes, n_qubits)
321
+ if is_spin_glass:
322
+ cut_value = compute_cut_sparse(best_theta, G_m.data, G_m.indptr, G_m.indices, n_qubits)
323
+ min_energy = -max_energy
324
+ else:
325
+ cut_value = max_energy
326
+ min_energy = compute_energy_sparse(best_theta, G_m.data, G_m.indptr, G_m.indices, n_qubits)
327
+
328
+ return bitstring, float(cut_value), (l, r), float(min_energy)
313
329
 
314
330
  if gray_iterations is None:
315
- gray_iterations = n_qubits * os.cpu_count()
331
+ gray_iterations = n_qubits * n_qubits
316
332
 
317
333
  if gray_seed_multiple is None:
318
334
  gray_seed_multiple = os.cpu_count()
319
335
 
320
- max_energy = compute_energy_sparse(best_theta, G_m.data, G_m.indptr, G_m.indices, n_qubits) if is_spin_glass else cut_value
321
-
322
336
  is_opencl = is_maxcut_gpu and IS_OPENCL_AVAILABLE
323
337
 
324
338
  if is_opencl:
@@ -1,5 +1,5 @@
1
1
  from .maxcut_tfim_streaming import maxcut_tfim_streaming
2
- from .maxcut_tfim_util import compute_cut_streaming, compute_energy_streaming, get_cut, get_cut_base, gray_code_next, gray_mutation, int_to_bitstring, opencl_context
2
+ from .maxcut_tfim_util import compute_cut_streaming, compute_energy_streaming, get_cut, get_cut_base, gray_code_next, gray_mutation, heuristic_threshold, int_to_bitstring, opencl_context
3
3
  import networkx as nx
4
4
  import numpy as np
5
5
  from numba import njit, prange
@@ -207,6 +207,9 @@ def spin_glass_solver_streaming(
207
207
 
208
208
  return "01", weight, ([nodes[0]], [nodes[1]]), -weight
209
209
 
210
+ if n_qubits < heuristic_threshold:
211
+ best_guess = None
212
+
210
213
  bitstring = ""
211
214
  if isinstance(best_guess, str):
212
215
  bitstring = best_guess
@@ -216,16 +219,27 @@ def spin_glass_solver_streaming(
216
219
  bitstring = "".join(["1" if b else "0" for b in best_guess])
217
220
  else:
218
221
  bitstring, cut_value, _ = maxcut_tfim_streaming(G_func, nodes, quality=quality, shots=shots, is_spin_glass=is_spin_glass, anneal_t=anneal_t, anneal_h=anneal_h, repulsion_base=repulsion_base)
222
+
219
223
  best_theta = np.array([b == "1" for b in list(bitstring)], dtype=np.bool_)
224
+ max_energy = compute_energy(best_theta, G_m, n_qubits) if is_spin_glass else cut_value
225
+
226
+ if n_qubits < heuristic_threshold:
227
+ bitstring, l, r = get_cut(best_theta, nodes, n_qubits)
228
+ if is_spin_glass:
229
+ cut_value = compute_cut_streaming(best_theta, G_func, nodes, n_qubits)
230
+ min_energy = -max_energy
231
+ else:
232
+ cut_value = max_energy
233
+ min_energy = compute_energy_streaming(best_theta, G_func, nodes, n_qubits)
234
+
235
+ return bitstring, float(cut_value), (l, r), float(min_energy)
220
236
 
221
237
  if gray_iterations is None:
222
- gray_iterations = n_qubits * os.cpu_count()
238
+ gray_iterations = n_qubits * n_qubits
223
239
 
224
240
  if gray_seed_multiple is None:
225
241
  gray_seed_multiple = os.cpu_count()
226
242
 
227
- max_energy = compute_energy_streaming(best_theta, G_func, nodes, n_qubits) if is_spin_glass else cut_value
228
-
229
243
  thread_count = os.cpu_count() ** 2
230
244
  improved = True
231
245
  while improved:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pyqrackising
3
- Version: 9.5.11
3
+ Version: 9.7.1
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
@@ -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=a2gbK_WypOQz8JTbMSXAtG5h-poumSTUNjK1jfNAF_c,11586
6
+ pyqrackising/maxcut_tfim_sparse.py,sha256=26Rv5yt_LC9OJRobCtOvEFgNphRfof9rduG7XoPehmQ,13361
7
+ pyqrackising/maxcut_tfim_streaming.py,sha256=ne0NH8_I6S9iYE6315UUCMlOtQyYuSJOjckRTIfkHH0,7893
8
+ pyqrackising/maxcut_tfim_util.py,sha256=I2iRXrrEr_YXKcmVlez8ZMwhmIQH3TegdepyM19J0CU,17062
9
+ pyqrackising/otoc.py,sha256=PKmpjwkGpMmwXGWmeqtvbVj1NfE35i9kkIdjQnDUZKE,7208
10
+ pyqrackising/spin_glass_solver.py,sha256=4CP4dTdxl2itZ9Iogth91LJY3DLVV9aXiVNpIYRgbxA,14289
11
+ pyqrackising/spin_glass_solver_sparse.py,sha256=p8w2it4reeqMRDoHvd7CeLkyV872oW1sUiIayEAM0ek,15295
12
+ pyqrackising/spin_glass_solver_streaming.py,sha256=pjn-XFPM4-rMEHVDzZHXzxK_c6tBmXzAVaVH6ujhFY0,10535
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.7.1.dist-info/licenses/LICENSE.md,sha256=46mU2C5kSwOnkqkw9XQAJlhBL2JAf1_uCD8lVcXyMRg,7652
18
+ pyqrackising-9.7.1.dist-info/METADATA,sha256=0hLsFLy5aO3y7j-S1qwCTn6GxKTl-v95V3oOClgn71I,1143
19
+ pyqrackising-9.7.1.dist-info/WHEEL,sha256=k8EuOMBHdXsN9XSTE5LrpwS4FtdLkoSlyO_7W-lE_zg,109
20
+ pyqrackising-9.7.1.dist-info/top_level.txt,sha256=bxlfGuLwzeVEI8Jm5D9HvC_WedgvvkSrpFwbGDjg-Ag,13
21
+ pyqrackising-9.7.1.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=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=zMgaVmEgfZWL2tp728PuEg5Dc_jbQBUPsgbP3lXiMiA,11194
7
- pyqrackising/maxcut_tfim_streaming.py,sha256=EcRXKurqLiQs6pMNz-rhMp2YQzRXD726RnkXsPt4IJ0,6346
8
- pyqrackising/maxcut_tfim_util.py,sha256=2FSBcba8Ys8HEe_h-ayB68pAqeeJXeveEHGmZKg_tkI,16889
9
- pyqrackising/otoc.py,sha256=Vq5tHy-XdV6O5qQGVN8E7xLkwHcXDhlWo6GNJTAd4dE,7258
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.11.dist-info/licenses/LICENSE.md,sha256=46mU2C5kSwOnkqkw9XQAJlhBL2JAf1_uCD8lVcXyMRg,7652
18
- pyqrackising-9.5.11.dist-info/METADATA,sha256=6Z3r5ubODul2NQjgGyg7M6l_nUBhntcpEI2mU18q81Q,1144
19
- pyqrackising-9.5.11.dist-info/WHEEL,sha256=k8EuOMBHdXsN9XSTE5LrpwS4FtdLkoSlyO_7W-lE_zg,109
20
- pyqrackising-9.5.11.dist-info/top_level.txt,sha256=bxlfGuLwzeVEI8Jm5D9HvC_WedgvvkSrpFwbGDjg-Ag,13
21
- pyqrackising-9.5.11.dist-info/RECORD,,