pyqrackising 9.3.11__py3-none-win_amd64.whl → 9.5.0__py3-none-win_amd64.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.

Potentially problematic release.


This version of pyqrackising might be problematic. Click here for more details.

pyqrackising/otoc.py CHANGED
@@ -7,57 +7,47 @@ import sys
7
7
  epsilon = opencl_context.epsilon
8
8
 
9
9
 
10
- def get_otoc_hamming_distribution(J=-1.0, h=2.0, z=4, theta=0.174532925199432957, t=5, n_qubits=56, cycles=1, pauli_string = 'X' + 'I' * 55):
11
- pauli_string = list(pauli_string)
12
- if len(pauli_string) != n_qubits:
13
- raise ValueError("OTOCS pauli_string must be same length as n_qubits! (Use 'I' for qubits that aren't changed.)")
14
-
10
+ 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]):
15
11
  n_bias = n_qubits + 1
16
12
  if h <= epsilon:
17
13
  bias = np.empty(n_bias, dtype=np.float64)
18
14
  bias[0] = 1.0
19
- return { 'X': bias, 'Y': bias, 'Z': bias }
20
-
21
- fwd = probability_by_hamming_weight(J, h, z, theta, t, n_qubits + 1)
22
- rev = probability_by_hamming_weight(-J, -h, z, theta + np.pi, t, n_qubits + 1)
23
- diff_theta = rev - fwd
24
-
25
- phi = theta + np.pi / 2
26
- fwd = probability_by_hamming_weight(-h, -J, z, phi, t, n_qubits + 1)
27
- rev = probability_by_hamming_weight(h, J, z, phi + np.pi, t, n_qubits + 1)
28
- diff_phi = rev - fwd
29
-
30
- # Lambda (Y-axis) is at a right angle to both J and h,
31
- # so there is no difference in this dimension.
32
-
33
- diff_theta *= cycles
34
- diff_phi *= cycles
35
- # diff_lam = diff_phi
15
+ return bias
36
16
 
37
17
  diff_z = np.zeros(n_bias, dtype=np.float64)
38
- diff_x = np.zeros(n_bias, dtype=np.float64)
39
- diff_y = np.zeros(n_bias, dtype=np.float64)
40
- for b in pauli_string:
41
- match b:
42
- case 'X':
43
- diff_z += diff_theta
44
- diff_y += diff_phi
45
- case 'Z':
46
- diff_x += diff_phi
47
- diff_y += diff_theta
48
- case 'Y':
49
- diff_z += diff_theta
50
- diff_x += diff_phi
51
-
52
- diff_z[0] += n_qubits
53
- diff_x[0] += n_qubits
54
- diff_y[0] += n_qubits
55
-
18
+ for pauli_string in pauli_strings:
19
+ pauli_string = list(pauli_string)
20
+ if len(pauli_string) != n_qubits:
21
+ raise ValueError("OTOCS pauli_string must be same length as n_qubits! (Use 'I' for qubits that aren't changed.)")
22
+
23
+ fwd = probability_by_hamming_weight(J, h, z, theta, t, n_qubits + 1)
24
+ rev = probability_by_hamming_weight(-J, -h, z, theta + np.pi, t, n_qubits + 1)
25
+ diff_theta = rev - fwd
26
+
27
+ phi = theta + np.pi / 2
28
+ fwd = probability_by_hamming_weight(-h, -J, z, phi, t, n_qubits + 1)
29
+ rev = probability_by_hamming_weight(h, J, z, phi + np.pi, t, n_qubits + 1)
30
+ diff_phi = rev - fwd
31
+
32
+ # Lambda (Y-axis) is at a right angle to both J and h,
33
+ # so there is no difference in this dimension.
34
+
35
+ diff_z[0] += n_qubits
36
+ for b in pauli_string:
37
+ match b:
38
+ case 'X':
39
+ diff_z += diff_theta
40
+ case 'Z':
41
+ diff_z += diff_phi
42
+ case 'Y':
43
+ diff_z += diff_theta + diff_phi
44
+ case _:
45
+ pass
46
+
47
+ # Normalize:
56
48
  diff_z /= diff_z.sum()
57
- diff_x /= diff_x.sum()
58
- diff_y /= diff_y.sum()
59
49
 
60
- return { 'X': diff_x, 'Y': diff_y, 'Z': diff_z }
50
+ return diff_z
61
51
 
62
52
 
63
53
  @njit
@@ -73,32 +63,9 @@ def fix_cdf(hamming_prob):
73
63
  return cum_prob
74
64
 
75
65
 
76
- def take_sample(n_qubits, sample, m, inv_dist):
77
- indices = [i for i in range(n_qubits)]
78
- tot_inv_dist = 0.0
79
- for i in range(n_qubits):
80
- tot_inv_dist += inv_dist[i]
81
- selected = []
82
- for i in range(m):
83
- r = tot_inv_dist * np.random.random()
84
- p = 0.0
85
- idx = 0
86
- while p < r:
87
- p += inv_dist[indices[idx]]
88
- idx += 1
89
- i = indices[idx]
90
- del indices[idx]
91
- selected.append(i)
92
- tot_inv_dist -= inv_dist[i]
93
- for i in selected:
94
- sample |= 1 << i
95
-
96
- return sample
97
-
98
-
99
66
  @njit
100
67
  def factor_width(width):
101
- col_len = np.floor(np.sqrt(width))
68
+ col_len = int(np.floor(np.sqrt(width)))
102
69
  while ((width // col_len) * col_len) != width:
103
70
  col_len -= 1
104
71
  row_len = width // col_len
@@ -120,68 +87,106 @@ def find_all_str_occurrences(main_string, sub_string):
120
87
  return indices
121
88
 
122
89
 
123
- def get_inv_dist(butterfly_idx, n_qubits, row_len):
90
+ def take_sample(n_qubits, sample, m, inv_dist):
91
+ indices = [i for i in range(n_qubits)]
92
+ tot_inv_dist = 0.0
93
+ for i in range(n_qubits):
94
+ tot_inv_dist += inv_dist[i]
95
+ selected = []
96
+ for i in range(m):
97
+ r = tot_inv_dist * np.random.random()
98
+ p = inv_dist[indices[0]]
99
+ idx = 0
100
+ while p < r:
101
+ idx += 1
102
+ if idx >= len(indices):
103
+ idx = len(indices) - 1
104
+ break
105
+ p += inv_dist[indices[idx]]
106
+ i = indices[idx]
107
+ del indices[idx]
108
+ selected.append(i)
109
+ tot_inv_dist -= inv_dist[i]
110
+ for i in selected:
111
+ sample |= 1 << i
112
+
113
+ return sample
114
+
115
+
116
+ def get_willow_inv_dist(butterfly_idx_x, butterfly_idx_z, n_qubits, row_len, col_len):
124
117
  inv_dist = np.zeros(n_qubits, dtype=np.float64)
125
- for idx in butterfly_idx:
118
+ for idx in butterfly_idx_x:
119
+ b_row, b_col = divmod(idx, row_len)
120
+ for q in range(n_qubits):
121
+ q_row, q_col = divmod(q, row_len)
122
+ inv_dist[q] -= abs(q_row - b_row) + abs(q_col - b_col)
123
+ for idx in butterfly_idx_z:
124
+ b_row, b_col = divmod(idx, row_len)
126
125
  for q in range(n_qubits):
127
- b_row = idx // row_len
128
- b_col = idx % row_len
129
- q_row = q // row_len
130
- q_col = q % row_len
131
- dist = (q_row - b_row) ** 2 + (q_col - b_col) ** 2
132
- inv_dist[q] += 1.0 / (1.0 + dist)
126
+ q_row, q_col = divmod(q, row_len)
127
+ inv_dist[q] += abs(q_row - b_row) + abs(q_col - b_col)
128
+ inv_dist += 1.0 - inv_dist.min()
133
129
 
134
130
  return inv_dist
135
131
 
136
132
 
137
- def generate_otoc_samples(J=-1.0, h=2.0, z=4, theta=0.174532925199432957, t=5, n_qubits=56, cycles=1, pauli_string = 'X' + 'I' * 55, shots=100, measurement_basis='Z' * 56):
138
- pauli_string = list(pauli_string)
139
- if len(pauli_string) != n_qubits:
140
- raise ValueError("OTOC pauli_string must be same length as n_qubits! (Use 'I' for qubits that aren't changed.)")
141
-
142
- measurement_basis = list(measurement_basis)
143
- if len(measurement_basis) != n_qubits:
144
- raise ValueError("OTOC measurement_basis must be same length as n_qubits! (Use 'I' for excluded qubits.)")
133
+ def get_inv_dist(butterfly_idx_x, butterfly_idx_z, n_qubits, row_len, col_len):
134
+ inv_dist = np.zeros(n_qubits, dtype=np.float64)
135
+ half_row = row_len >> 1
136
+ half_col = col_len >> 1
137
+ for idx in butterfly_idx_x:
138
+ b_row, b_col = divmod(idx, row_len)
139
+ for q in range(n_qubits):
140
+ q_row, q_col = divmod(q, row_len)
141
+ row_d = abs(q_row - b_row)
142
+ if row_d > half_row:
143
+ row_d = row_len - row_d
144
+ col_d = abs(q_col - b_col)
145
+ if col_d > half_col:
146
+ col_d = col_len - col_d
147
+ inv_dist[q] -= row_d + col_d
148
+ for idx in butterfly_idx_z:
149
+ b_row, b_col = divmod(idx, row_len)
150
+ for q in range(n_qubits):
151
+ q_row, q_col = divmod(q, row_len)
152
+ row_d = abs(q_row - b_row)
153
+ if row_d > half_row:
154
+ row_d = row_len - row_d
155
+ col_d = abs(q_col - b_col)
156
+ if col_d > half_col:
157
+ col_d = col_len - col_d
158
+ inv_dist[q] += row_d + col_d
159
+ inv_dist += 1.0 - inv_dist.min()
145
160
 
146
- thresholds = { key: fix_cdf(value) for key, value in get_otoc_hamming_distribution(J, h, z, theta, t, n_qubits, cycles, pauli_string).items() }
161
+ return inv_dist
147
162
 
148
- row_len, col_len = factor_width(n_qubits)
149
- p_string = "".join(pauli_string)
150
- butterfly_idx_x = find_all_str_occurrences(p_string, 'X')
151
- butterfly_idx_y = find_all_str_occurrences(p_string, 'Y')
152
- butterfly_idx_z = find_all_str_occurrences(p_string, 'Z')
153
163
 
154
- inv_dist_x = get_inv_dist(butterfly_idx_x, n_qubits, row_len)
155
- inv_dist_y = get_inv_dist(butterfly_idx_y, n_qubits, row_len)
156
- inv_dist_z = get_inv_dist(butterfly_idx_z, n_qubits, row_len)
164
+ 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):
165
+ thresholds = fix_cdf(get_otoc_hamming_distribution(J, h, z, theta, t, n_qubits, pauli_strings))
157
166
 
158
- inv_dist = { 'X': inv_dist_x, 'Y': inv_dist_y, 'Z': inv_dist_z }
167
+ row_len, col_len = factor_width(n_qubits)
168
+ inv_dist = np.zeros(n_qubits, dtype=np.float64)
169
+ for pauli_string in pauli_strings:
170
+ butterfly_idx_x = find_all_str_occurrences(pauli_string, 'X')
171
+ butterfly_idx_z = find_all_str_occurrences(pauli_string, 'Z')
172
+ if is_orbifold:
173
+ inv_dist += get_inv_dist(butterfly_idx_x, butterfly_idx_z, n_qubits, row_len, col_len)
174
+ else:
175
+ inv_dist += get_willow_inv_dist(butterfly_idx_x, butterfly_idx_z, n_qubits, row_len, col_len)
176
+ inv_dist /= 2.0
159
177
 
160
178
  samples = []
161
179
  for _ in range(shots):
162
- sample_3_axis = { 'X': 0, 'Y': 0, 'Z': 0 }
163
- for key, value in thresholds.items():
164
- # First dimension: Hamming weight
165
- m = sample_mag(value)
166
- if m == 0:
167
- continue
168
- if m >= n_qubits:
169
- sample_3_axis[key] = (1 << n_qubits) - 1
170
- continue
171
-
172
- # Second dimension: permutation within Hamming weight
173
- sample_3_axis[key] = take_sample(n_qubits, sample_3_axis[key], m, inv_dist[key])
174
-
175
- sample = 0
176
- j = 0
177
- for i in range(n_qubits):
178
- base = measurement_basis[i]
179
- if base not in ['X', 'Y', 'Z']:
180
- continue
181
- if (sample_3_axis[base] >> i) & 1:
182
- sample |= 1 << j
183
- j += 1
184
-
185
- samples.append(sample)
180
+ # First dimension: Hamming weight
181
+ m = sample_mag(thresholds)
182
+ if m == 0:
183
+ samples.append(0)
184
+ continue
185
+ if m >= n_qubits:
186
+ samples.append((1 << n_qubits) - 1)
187
+ continue
188
+
189
+ # Second dimension: permutation within Hamming weight
190
+ samples.append(take_sample(n_qubits, 0, m, inv_dist))
186
191
 
187
192
  return samples
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pyqrackising
3
- Version: 9.3.11
3
+ Version: 9.5.0
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
@@ -6,7 +6,7 @@ pyqrackising/maxcut_tfim.py,sha256=U1nNjyfMS48TtTQk7TRf5_VF3pVPfAcZEa2awc2nR8k,1
6
6
  pyqrackising/maxcut_tfim_sparse.py,sha256=eenJNSEwRvgwACfKoH0tj6rpn7uqH6nNTBuxUPh_lDg,11941
7
7
  pyqrackising/maxcut_tfim_streaming.py,sha256=FkBsRoXSRhv4gUeN9O7Ivx54oxq_SqiCDKnYsyxU4bs,6664
8
8
  pyqrackising/maxcut_tfim_util.py,sha256=nMLrbvDMsCtVgbS4vbRNSZYpdne5YzdifjlQbbWmKjU,16935
9
- pyqrackising/otoc.py,sha256=CciS348HDws8spCgkWxeKaaHNIqGMsml52T337e-db8,6119
9
+ pyqrackising/otoc.py,sha256=B70mFX7GDBR0VPAjIUFCJfqJig6QjvrPfkSyJ5w6vo0,6350
10
10
  pyqrackising/spin_glass_solver.py,sha256=tgmdJ6b1TetnFM--QEzOZFsNkquQYRVYiHVSzIGYvMI,14207
11
11
  pyqrackising/spin_glass_solver_sparse.py,sha256=cmXfAR43n1beRk4LaQbwfrQWkkhMPzPXpdK2T1HhQrk,15159
12
12
  pyqrackising/spin_glass_solver_streaming.py,sha256=joQLMKotgjQMwbG0msv_AookiWva_AiVBIR0Xr1Unho,10310
@@ -14,8 +14,8 @@ pyqrackising/tfim_magnetization.py,sha256=On1MhCNGGHRxJFRmCOpMcdqQJiy25gWkjz0Ka8
14
14
  pyqrackising/tfim_square_magnetization.py,sha256=9uJCT8ytyufcGFrZiignjCkWJr9UcP44sAAy0BIBw34,531
15
15
  pyqrackising/tsp.py,sha256=k8VK6fKw_niR-dVz8MyOT7LedABIwTzcSkhTOircYBg,64290
16
16
  pyqrackising/tsp_maxcut.py,sha256=lEDruz5lhjVu0ufvH5VaMJW3_nohO-rEijJJabEtuSU,10084
17
- pyqrackising-9.3.11.dist-info/licenses/LICENSE.md,sha256=fTqV5eBpeAZO0_jit8j4Ref9ikBSlHJ8xwj5TLg7gFk,7817
18
- pyqrackising-9.3.11.dist-info/METADATA,sha256=pgPnreeoMDwgn_6xb7RmBCYfKhNuzWYiup1hC1WOlXs,1171
19
- pyqrackising-9.3.11.dist-info/WHEEL,sha256=ZjXRCNaQ9YSypEK2TE0LRB0sy2OVXSszb4Sx1XjM99k,97
20
- pyqrackising-9.3.11.dist-info/top_level.txt,sha256=bxlfGuLwzeVEI8Jm5D9HvC_WedgvvkSrpFwbGDjg-Ag,13
21
- pyqrackising-9.3.11.dist-info/RECORD,,
17
+ pyqrackising-9.5.0.dist-info/licenses/LICENSE.md,sha256=fTqV5eBpeAZO0_jit8j4Ref9ikBSlHJ8xwj5TLg7gFk,7817
18
+ pyqrackising-9.5.0.dist-info/METADATA,sha256=bx799MMc3V0fTNSj_Yi-xs3mwJOGkZ0yat1SxxheDlE,1170
19
+ pyqrackising-9.5.0.dist-info/WHEEL,sha256=ZjXRCNaQ9YSypEK2TE0LRB0sy2OVXSszb4Sx1XjM99k,97
20
+ pyqrackising-9.5.0.dist-info/top_level.txt,sha256=bxlfGuLwzeVEI8Jm5D9HvC_WedgvvkSrpFwbGDjg-Ag,13
21
+ pyqrackising-9.5.0.dist-info/RECORD,,