pyqrack-cpu-complex128 1.69.0__py3-none-win_amd64.whl → 1.78.3__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.
pyqrack/__init__.py CHANGED
@@ -10,9 +10,10 @@ from .qrack_ace_backend import QrackAceBackend
10
10
  from .qrack_circuit import QrackCircuit
11
11
  from .qrack_neuron import QrackNeuron
12
12
  from .qrack_neuron_torch_layer import (
13
- QrackTorchNeuron,
14
- QrackNeuronFunction,
13
+ QrackNeuronTorch,
14
+ QrackNeuronTorchFunction,
15
15
  QrackNeuronTorchLayer,
16
+ QrackNeuronTorchLayerFunction,
16
17
  )
17
18
  from .qrack_simulator import QrackSimulator
18
19
  from .qrack_stabilizer import QrackStabilizer
@@ -432,7 +432,8 @@ class QrackAceBackend:
432
432
  def _unpack(self, lq):
433
433
  return self._qubits[lq]
434
434
 
435
- def _get_qb_lhv_indices(self, hq):
435
+ @staticmethod
436
+ def _get_qb_lhv_indices(hq):
436
437
  qb = []
437
438
  if len(hq) < 2:
438
439
  qb = [0]
@@ -446,7 +447,8 @@ class QrackAceBackend:
446
447
 
447
448
  return qb, lhv
448
449
 
449
- def _get_lhv_bloch_angles(self, sim):
450
+ @staticmethod
451
+ def _get_lhv_bloch_angles(sim):
450
452
  # Z axis
451
453
  z = sim.bloch[2]
452
454
 
@@ -503,7 +505,8 @@ class QrackAceBackend:
503
505
 
504
506
  sim.mtrx([m00, m01, m10, m11], q)
505
507
 
506
- def _rotate_lhv_to_bloch(self, sim, delta_azimuth, delta_inclination):
508
+ @staticmethod
509
+ def _rotate_lhv_to_bloch(sim, delta_azimuth, delta_inclination):
507
510
  # Apply rotation as "Azimuth, Inclination" (AI)
508
511
  cosA = math.cos(delta_azimuth)
509
512
  sinA = math.sin(delta_azimuth)
@@ -523,7 +526,7 @@ class QrackAceBackend:
523
526
  if len(hq) == 1:
524
527
  return
525
528
 
526
- qb, lhv = self._get_qb_lhv_indices(hq)
529
+ qb, lhv = QrackAceBackend._get_qb_lhv_indices(hq)
527
530
 
528
531
  if phase:
529
532
  for q in qb:
@@ -572,7 +575,7 @@ class QrackAceBackend:
572
575
  a, i = [0, 0, 0, 0, 0], [0, 0, 0, 0, 0]
573
576
  a[0], i[0] = self._get_bloch_angles(hq[0])
574
577
  a[1], i[1] = self._get_bloch_angles(hq[1])
575
- a[2], i[2] = self._get_lhv_bloch_angles(hq[2])
578
+ a[2], i[2] = QrackAceBackend._get_lhv_bloch_angles(hq[2])
576
579
  a[3], i[3] = self._get_bloch_angles(hq[3])
577
580
  a[4], i[4] = self._get_bloch_angles(hq[4])
578
581
 
@@ -588,7 +591,7 @@ class QrackAceBackend:
588
591
  i_target /= 5
589
592
  for x in range(5):
590
593
  if x == 2:
591
- self._rotate_lhv_to_bloch(
594
+ QrackAceBackend._rotate_lhv_to_bloch(
592
595
  hq[x], a_target - a[x], i_target - i[x]
593
596
  )
594
597
  else:
@@ -617,7 +620,7 @@ class QrackAceBackend:
617
620
  a, i = [0, 0, 0], [0, 0, 0]
618
621
  a[0], i[0] = self._get_bloch_angles(hq[0])
619
622
  a[1], i[1] = self._get_bloch_angles(hq[1])
620
- a[2], i[2] = self._get_lhv_bloch_angles(hq[2])
623
+ a[2], i[2] = QrackAceBackend._get_lhv_bloch_angles(hq[2])
621
624
 
622
625
  a_target = 0
623
626
  i_target = 0
@@ -631,7 +634,7 @@ class QrackAceBackend:
631
634
  i_target /= 3
632
635
  for x in range(3):
633
636
  if x == 2:
634
- self._rotate_lhv_to_bloch(
637
+ QrackAceBackend._rotate_lhv_to_bloch(
635
638
  hq[x], a_target - a[x], i_target - i[x]
636
639
  )
637
640
  else:
@@ -653,8 +656,8 @@ class QrackAceBackend:
653
656
  for c in range(len(hq)):
654
657
  h = hq[c]
655
658
  if c == 2:
656
- a, i = self._get_lhv_bloch_angles(h)
657
- self._rotate_lhv_to_bloch(
659
+ a, i = QrackAceBackend._get_lhv_bloch_angles(h)
660
+ QrackAceBackend._rotate_lhv_to_bloch(
658
661
  h,
659
662
  math.atan(math.tan(a) * b) - a,
660
663
  math.atan(math.tan(i) * b) - i,
@@ -674,7 +677,7 @@ class QrackAceBackend:
674
677
  self.sim[b[0]].u(b[1], th, ph, lm)
675
678
  return
676
679
 
677
- qb, lhv = self._get_qb_lhv_indices(hq)
680
+ qb, lhv = QrackAceBackend._get_qb_lhv_indices(hq)
678
681
 
679
682
  for q in qb:
680
683
  b = hq[q]
@@ -693,7 +696,7 @@ class QrackAceBackend:
693
696
  self.sim[b[0]].r(p, th, b[1])
694
697
  return
695
698
 
696
- qb, lhv = self._get_qb_lhv_indices(hq)
699
+ qb, lhv = QrackAceBackend._get_qb_lhv_indices(hq)
697
700
 
698
701
  for q in qb:
699
702
  b = hq[q]
@@ -721,7 +724,7 @@ class QrackAceBackend:
721
724
 
722
725
  self._correct(lq)
723
726
 
724
- qb, lhv = self._get_qb_lhv_indices(hq)
727
+ qb, lhv = QrackAceBackend._get_qb_lhv_indices(hq)
725
728
 
726
729
  for q in qb:
727
730
  b = hq[q]
@@ -739,7 +742,7 @@ class QrackAceBackend:
739
742
  self.sim[b[0]].s(b[1])
740
743
  return
741
744
 
742
- qb, lhv = self._get_qb_lhv_indices(hq)
745
+ qb, lhv = QrackAceBackend._get_qb_lhv_indices(hq)
743
746
 
744
747
  for q in qb:
745
748
  b = hq[q]
@@ -755,7 +758,7 @@ class QrackAceBackend:
755
758
  self.sim[b[0]].adjs(b[1])
756
759
  return
757
760
 
758
- qb, lhv = self._get_qb_lhv_indices(hq)
761
+ qb, lhv = QrackAceBackend._get_qb_lhv_indices(hq)
759
762
 
760
763
  for q in qb:
761
764
  b = hq[q]
@@ -771,7 +774,7 @@ class QrackAceBackend:
771
774
  self.sim[b[0]].x(b[1])
772
775
  return
773
776
 
774
- qb, lhv = self._get_qb_lhv_indices(hq)
777
+ qb, lhv = QrackAceBackend._get_qb_lhv_indices(hq)
775
778
 
776
779
  for q in qb:
777
780
  b = hq[q]
@@ -787,7 +790,7 @@ class QrackAceBackend:
787
790
  self.sim[b[0]].y(b[1])
788
791
  return
789
792
 
790
- qb, lhv = self._get_qb_lhv_indices(hq)
793
+ qb, lhv = QrackAceBackend._get_qb_lhv_indices(hq)
791
794
 
792
795
  for q in qb:
793
796
  b = hq[q]
@@ -803,7 +806,7 @@ class QrackAceBackend:
803
806
  self.sim[b[0]].z(b[1])
804
807
  return
805
808
 
806
- qb, lhv = self._get_qb_lhv_indices(hq)
809
+ qb, lhv = QrackAceBackend._get_qb_lhv_indices(hq)
807
810
 
808
811
  for q in qb:
809
812
  b = hq[q]
@@ -819,7 +822,7 @@ class QrackAceBackend:
819
822
  self.sim[b[0]].t(b[1])
820
823
  return
821
824
 
822
- qb, lhv = self._get_qb_lhv_indices(hq)
825
+ qb, lhv = QrackAceBackend._get_qb_lhv_indices(hq)
823
826
 
824
827
  for q in qb:
825
828
  b = hq[q]
@@ -835,7 +838,7 @@ class QrackAceBackend:
835
838
  self.sim[b[0]].adjt(b[1])
836
839
  return
837
840
 
838
- qb, lhv = self._get_qb_lhv_indices(hq)
841
+ qb, lhv = QrackAceBackend._get_qb_lhv_indices(hq)
839
842
 
840
843
  for q in qb:
841
844
  b = hq[q]
@@ -917,8 +920,8 @@ class QrackAceBackend:
917
920
 
918
921
  self._correct(lq1)
919
922
 
920
- qb1, lhv1 = self._get_qb_lhv_indices(hq1)
921
- qb2, lhv2 = self._get_qb_lhv_indices(hq2)
923
+ qb1, lhv1 = QrackAceBackend._get_qb_lhv_indices(hq1)
924
+ qb2, lhv2 = QrackAceBackend._get_qb_lhv_indices(hq2)
922
925
  # Apply cross coupling on hardware qubits first
923
926
  self._apply_coupling(pauli, anti, qb1, lhv1, hq1, qb2, lhv2, hq2, lq1_lr)
924
927
  # Apply coupling to the local-hidden-variable target
@@ -1065,7 +1068,7 @@ class QrackAceBackend:
1065
1068
  p = self.prob(lq)
1066
1069
  result = ((p + self._epsilon) >= 1) or (random.random() < p)
1067
1070
 
1068
- qb, lhv = self._get_qb_lhv_indices(hq)
1071
+ qb, lhv = QrackAceBackend._get_qb_lhv_indices(hq)
1069
1072
 
1070
1073
  for q in qb:
1071
1074
  b = hq[q]
@@ -1091,7 +1094,7 @@ class QrackAceBackend:
1091
1094
 
1092
1095
  self._correct(lq)
1093
1096
 
1094
- qb, lhv = self._get_qb_lhv_indices(hq)
1097
+ qb, lhv = QrackAceBackend._get_qb_lhv_indices(hq)
1095
1098
 
1096
1099
  for q in qb:
1097
1100
  b = hq[q]
@@ -1444,6 +1447,7 @@ class QrackAceBackend:
1444
1447
 
1445
1448
  return _data
1446
1449
 
1450
+ @staticmethod
1447
1451
  def get_qiskit_basis_gates():
1448
1452
  return [
1449
1453
  "id",
pyqrack/qrack_circuit.py CHANGED
@@ -59,7 +59,7 @@ class QrackCircuit:
59
59
  self.cid = Qrack.qrack_lib.qcircuit_inverse(clone_cid)
60
60
  elif len(past_light_cone) > 0:
61
61
  self.cid = Qrack.qrack_lib.qcircuit_past_light_cone(
62
- clone_cid, len(past_light_cone), self._ulonglong_byref(past_light_cone)
62
+ clone_cid, len(past_light_cone), QrackCircuit._ulonglong_byref(past_light_cone)
63
63
  )
64
64
  else:
65
65
  self.cid = Qrack.qrack_lib.init_qcircuit_clone(clone_cid)
@@ -69,16 +69,20 @@ class QrackCircuit:
69
69
  Qrack.qrack_lib.destroy_qcircuit(self.cid)
70
70
  self.cid = None
71
71
 
72
- def _ulonglong_byref(self, a):
72
+ @staticmethod
73
+ def _ulonglong_byref(a):
73
74
  return (ctypes.c_ulonglong * len(a))(*a)
74
75
 
75
- def _double_byref(self, a):
76
+ @staticmethod
77
+ def _double_byref(a):
76
78
  return (ctypes.c_double * len(a))(*a)
77
79
 
78
- def _complex_byref(self, a):
80
+ @staticmethod
81
+ def _complex_byref(a):
79
82
  t = [(c.real, c.imag) for c in a]
80
- return self._double_byref([float(item) for sublist in t for item in sublist])
83
+ return QrackCircuit._double_byref([float(item) for sublist in t for item in sublist])
81
84
 
85
+ @staticmethod
82
86
  def _mtrx_to_u4(m):
83
87
  nrm = abs(m[0])
84
88
  if (nrm * nrm) < sys.float_info.epsilon:
@@ -103,6 +107,7 @@ class QrackCircuit:
103
107
 
104
108
  return th, ph, lm, np.angle(phase)
105
109
 
110
+ @staticmethod
106
111
  def _u3_to_mtrx(params):
107
112
  th = float(params[0])
108
113
  ph = float(params[1])
@@ -115,6 +120,7 @@ class QrackCircuit:
115
120
 
116
121
  return [c + 0j, -el * s, ep * s, ep * el * c]
117
122
 
123
+ @staticmethod
118
124
  def _u4_to_mtrx(params):
119
125
  m = QrackCircuit._u3_to_mtrx(params)
120
126
  g = np.exp(1j * float(params[3]))
@@ -123,6 +129,7 @@ class QrackCircuit:
123
129
 
124
130
  return m
125
131
 
132
+ @staticmethod
126
133
  def _make_mtrx_unitary(m):
127
134
  return QrackCircuit._u4_to_mtrx(QrackCircuit._mtrx_to_u4(m))
128
135
 
@@ -190,7 +197,7 @@ class QrackCircuit:
190
197
  raise ValueError(
191
198
  "2x2 matrix 'm' in QrackCircuit.mtrx() must contain at least 4 elements."
192
199
  )
193
- Qrack.qrack_lib.qcircuit_append_1qb(self.cid, self._complex_byref(m), q)
200
+ Qrack.qrack_lib.qcircuit_append_1qb(self.cid, QrackCircuit._complex_byref(m), q)
194
201
 
195
202
  def ucmtrx(self, c, m, q, p):
196
203
  """Multi-controlled single-target-qubit gate
@@ -214,7 +221,7 @@ class QrackCircuit:
214
221
  "2x2 matrix 'm' in QrackCircuit.ucmtrx() must contain at least 4 elements."
215
222
  )
216
223
  Qrack.qrack_lib.qcircuit_append_mc(
217
- self.cid, self._complex_byref(m), len(c), self._ulonglong_byref(c), q, p
224
+ self.cid, QrackCircuit._complex_byref(m), len(c), QrackCircuit._ulonglong_byref(c), q, p
218
225
  )
219
226
 
220
227
  def run(self, qsim):
@@ -248,20 +255,6 @@ class QrackCircuit:
248
255
  """
249
256
  Qrack.qrack_lib.qcircuit_out_to_file(self.cid, filename.encode("utf-8"))
250
257
 
251
- def in_from_file(filename):
252
- """Read in optimized circuit from file
253
-
254
- Reads in an (optimized) circuit from a file named
255
- according to the "filename" parameter.
256
-
257
- Args:
258
- filename: Name of file
259
- """
260
- out = QrackCircuit()
261
- Qrack.qrack_lib.qcircuit_in_from_file(out.cid, filename.encode("utf-8"))
262
-
263
- return out
264
-
265
258
  def out_to_string(self):
266
259
  """Output optimized circuit to string
267
260
 
@@ -273,19 +266,6 @@ class QrackCircuit:
273
266
 
274
267
  return out.value.decode("utf-8")
275
268
 
276
- def file_gate_count(filename):
277
- """File gate count
278
-
279
- Return the count of gates in a QrackCircuit file
280
-
281
- Args:
282
- filename: Name of file
283
- """
284
- tokens = []
285
- with open(filename, "r") as file:
286
- tokens = file.read().split()
287
- return int(tokens[1])
288
-
289
269
  def to_qiskit_circuit(self):
290
270
  """Convert to a Qiskit circuit
291
271
 
@@ -302,6 +282,36 @@ class QrackCircuit:
302
282
 
303
283
  return QrackCircuit.string_to_qiskit_circuit(self.out_to_string())
304
284
 
285
+ @staticmethod
286
+ def in_from_file(filename):
287
+ """Read in optimized circuit from file
288
+
289
+ Reads in an (optimized) circuit from a file named
290
+ according to the "filename" parameter.
291
+
292
+ Args:
293
+ filename: Name of file
294
+ """
295
+ out = QrackCircuit()
296
+ Qrack.qrack_lib.qcircuit_in_from_file(out.cid, filename.encode("utf-8"))
297
+
298
+ return out
299
+
300
+ @staticmethod
301
+ def file_gate_count(filename):
302
+ """File gate count
303
+
304
+ Return the count of gates in a QrackCircuit file
305
+
306
+ Args:
307
+ filename: Name of file
308
+ """
309
+ tokens = []
310
+ with open(filename, "r") as file:
311
+ tokens = file.read().split()
312
+ return int(tokens[1])
313
+
314
+ @staticmethod
305
315
  def file_to_qiskit_circuit(filename):
306
316
  """Convert an output file to a Qiskit circuit
307
317
 
@@ -325,6 +335,7 @@ class QrackCircuit:
325
335
  with open(filename, "r") as file:
326
336
  return QrackCircuit.string_to_qiskit_circuit(file.read())
327
337
 
338
+ @staticmethod
328
339
  def string_to_qiskit_circuit(circ_string):
329
340
  """Convert an output string to a Qiskit circuit
330
341
 
@@ -398,6 +409,7 @@ class QrackCircuit:
398
409
 
399
410
  return circ
400
411
 
412
+ @staticmethod
401
413
  def in_from_qiskit_circuit(circ):
402
414
  """Read a Qiskit circuit into a QrackCircuit
403
415
 
@@ -443,6 +455,7 @@ class QrackCircuit:
443
455
 
444
456
  return out
445
457
 
458
+ @staticmethod
446
459
  def file_to_quimb_circuit(
447
460
  filename,
448
461
  circuit_type=QuimbCircuitType.Circuit,
@@ -526,6 +539,7 @@ class QrackCircuit:
526
539
 
527
540
  return tcirc
528
541
 
542
+ @staticmethod
529
543
  def file_to_tensorcircuit(
530
544
  filename, inputs=None, circuit_params=None, binding_params=None
531
545
  ):
@@ -558,6 +572,7 @@ class QrackCircuit:
558
572
  qcirc, qcirc.num_qubits, inputs, circuit_params, binding_params
559
573
  )
560
574
 
575
+ @staticmethod
561
576
  def in_from_tensorcircuit(tcirc, enable_instruction=False, enable_inputs=False):
562
577
  """Convert a TensorCircuit circuit to a QrackCircuit
563
578
 
pyqrack/qrack_neuron.py CHANGED
@@ -64,7 +64,7 @@ class QrackNeuron:
64
64
  self.nid = Qrack.qrack_lib.init_qneuron(
65
65
  simulator.sid,
66
66
  len(controls),
67
- self._ulonglong_byref(controls),
67
+ QrackNeuron._ulonglong_byref(controls),
68
68
  target,
69
69
  activation_fn,
70
70
  alpha,
@@ -99,10 +99,12 @@ class QrackNeuron:
99
99
  self._throw_if_error()
100
100
  return result
101
101
 
102
- def _ulonglong_byref(self, a):
102
+ @staticmethod
103
+ def _ulonglong_byref(a):
103
104
  return (ctypes.c_ulonglong * len(a))(*a)
104
105
 
105
- def _real1_byref(self, a):
106
+ @staticmethod
107
+ def _real1_byref(a):
106
108
  # This needs to be c_double, if PyQrack is built with fp64.
107
109
  if Qrack.fppow < 6:
108
110
  return (ctypes.c_float * len(a))(*a)
@@ -125,7 +127,7 @@ class QrackNeuron:
125
127
  raise ValueError(
126
128
  "Angles 'a' in QrackNeuron.set_angles() must contain at least (2 ** len(self.controls)) elements."
127
129
  )
128
- Qrack.qrack_lib.set_qneuron_angles(self.nid, self._real1_byref(a))
130
+ Qrack.qrack_lib.set_qneuron_angles(self.nid, QrackNeuron._real1_byref(a))
129
131
  self._throw_if_error()
130
132
 
131
133
  def get_angles(self):
@@ -137,7 +139,7 @@ class QrackNeuron:
137
139
  Raises:
138
140
  RuntimeError: QrackNeuron C++ library raised an exception.
139
141
  """
140
- ket = self._real1_byref([0.0] * (1 << len(self.controls)))
142
+ ket = QrackNeuron._real1_byref([0.0] * (1 << len(self.controls)))
141
143
  Qrack.qrack_lib.get_qneuron_angles(self.nid, ket)
142
144
  self._throw_if_error()
143
145
  return list(ket)
@@ -260,3 +262,89 @@ class QrackNeuron:
260
262
  """
261
263
  Qrack.qrack_lib.qneuron_learn_permutation(self.nid, eta, e, r)
262
264
  self._throw_if_error()
265
+
266
+ @staticmethod
267
+ def quantile_bounds(vec, bits):
268
+ """ Calculate vector quantile bounds
269
+
270
+ This is a static helper method to calculate the quantile
271
+ bounds of 2 ** bits worth of quantiles.
272
+
273
+ Args:
274
+ vec: numerical vector
275
+ bits: log2() of quantile count
276
+
277
+ Returns:
278
+ Quantile (n + 1) bounds for n-quantile division, including
279
+ minimum and maximum values
280
+ """
281
+
282
+ bins = 1 << bits
283
+ n = len(vec)
284
+ vec_sorted = sorted(vec)
285
+
286
+ return [vec_sorted[0]] + [vec_sorted[(k * n) // bins] for k in range(1, bins)] + [vec_sorted[-1]]
287
+
288
+ @staticmethod
289
+ def discretize(vec, bounds):
290
+ """ Discretize vector by quantile bounds
291
+
292
+ This is a static helper method to discretize a numerical
293
+ vector according to quantile bounds calculated by the
294
+ quantile_bounds(vec, bits) static method.
295
+
296
+ Args:
297
+ vec: numerical vector
298
+ bounds: (n + 1) n-quantile bounds including extrema
299
+
300
+ Returns:
301
+ Discretized bit-row vector, least-significant first
302
+ """
303
+
304
+ bounds = bounds[1:]
305
+ bounds_len = len(bounds)
306
+ bits = bounds_len.bit_length() - 1
307
+ n = len(vec)
308
+ vec_discrete = [[False] * n for _ in range(bits)]
309
+ for i, v in enumerate(vec):
310
+ p = 0
311
+ while (p < bounds_len) and (v > bounds[p]):
312
+ p += 1
313
+ for b in range(bits):
314
+ vec_discrete[b][i] = bool((p >> b) & 1)
315
+
316
+ return vec_discrete
317
+
318
+ @staticmethod
319
+ def flatten_and_transpose(arr):
320
+ """ Flatten and transpose feature matrix
321
+
322
+ This is a static helper method to convert a multi-feature
323
+ bit-row matrix to an observation-row matrix with flat
324
+ feature columns.
325
+
326
+ Args:
327
+ arr: bit-row matrix
328
+
329
+ Returns:
330
+ Observation-row matrix with flat feature columns
331
+ """
332
+ return list(zip(*[item for sublist in arr for item in sublist]))
333
+
334
+ @staticmethod
335
+ def bin_endpoints_average(bounds):
336
+ """ Bin endpoints average
337
+
338
+ This is a static helper method that accepts the output
339
+ bins from quantile_bounds() and returns the average points
340
+ between the bin endpoints. (This is NOT always necessarily
341
+ the best heuristic for how to convert binned results back
342
+ to numerical results, but it is often a reasonable way.)
343
+
344
+ Args:
345
+ bounds: (n + 1) n-quantile bounds including extrema
346
+
347
+ Returns:
348
+ List of average points between the bin endpoints
349
+ """
350
+ return [((bounds[i] + bounds[i + 1]) / 2) for i in range(len(bounds) - 1)]