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 +3 -2
- pyqrack/qrack_ace_backend.py +28 -24
- pyqrack/qrack_circuit.py +49 -34
- pyqrack/qrack_neuron.py +93 -5
- pyqrack/qrack_neuron_torch_layer.py +294 -104
- pyqrack/qrack_simulator.py +234 -183
- pyqrack/qrack_system/qrack_lib/qrack_pinvoke.dll +0 -0
- pyqrack/qrack_system/qrack_system.py +9 -2
- {pyqrack_cpu_complex128-1.69.0.dist-info → pyqrack_cpu_complex128-1.78.3.dist-info}/METADATA +2 -4
- pyqrack_cpu_complex128-1.78.3.dist-info/RECORD +21 -0
- pyqrack_cpu_complex128-1.69.0.dist-info/RECORD +0 -21
- {pyqrack_cpu_complex128-1.69.0.dist-info → pyqrack_cpu_complex128-1.78.3.dist-info}/LICENSE +0 -0
- {pyqrack_cpu_complex128-1.69.0.dist-info → pyqrack_cpu_complex128-1.78.3.dist-info}/WHEEL +0 -0
- {pyqrack_cpu_complex128-1.69.0.dist-info → pyqrack_cpu_complex128-1.78.3.dist-info}/top_level.txt +0 -0
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
|
-
|
|
14
|
-
|
|
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
|
pyqrack/qrack_ace_backend.py
CHANGED
|
@@ -432,7 +432,8 @@ class QrackAceBackend:
|
|
|
432
432
|
def _unpack(self, lq):
|
|
433
433
|
return self._qubits[lq]
|
|
434
434
|
|
|
435
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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 =
|
|
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] =
|
|
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
|
-
|
|
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] =
|
|
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
|
-
|
|
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 =
|
|
657
|
-
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
921
|
-
qb2, lhv2 =
|
|
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 =
|
|
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 =
|
|
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),
|
|
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
|
-
|
|
72
|
+
@staticmethod
|
|
73
|
+
def _ulonglong_byref(a):
|
|
73
74
|
return (ctypes.c_ulonglong * len(a))(*a)
|
|
74
75
|
|
|
75
|
-
|
|
76
|
+
@staticmethod
|
|
77
|
+
def _double_byref(a):
|
|
76
78
|
return (ctypes.c_double * len(a))(*a)
|
|
77
79
|
|
|
78
|
-
|
|
80
|
+
@staticmethod
|
|
81
|
+
def _complex_byref(a):
|
|
79
82
|
t = [(c.real, c.imag) for c in a]
|
|
80
|
-
return
|
|
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,
|
|
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,
|
|
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
|
-
|
|
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
|
-
|
|
102
|
+
@staticmethod
|
|
103
|
+
def _ulonglong_byref(a):
|
|
103
104
|
return (ctypes.c_ulonglong * len(a))(*a)
|
|
104
105
|
|
|
105
|
-
|
|
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,
|
|
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 =
|
|
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)]
|