pyqrack-complex128 1.63.0__py3-none-macosx_14_0_arm64.whl → 1.78.3__py3-none-macosx_14_0_arm64.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 +48 -43
- pyqrack/qrack_circuit.py +49 -34
- pyqrack/qrack_neuron.py +93 -5
- pyqrack/qrack_neuron_torch_layer.py +294 -104
- pyqrack/qrack_simulator.py +310 -193
- pyqrack/qrack_system/qrack_lib/libqrack_pinvoke.9.34.5.dylib +0 -0
- pyqrack/qrack_system/qrack_lib/libqrack_pinvoke.dylib +0 -0
- pyqrack/qrack_system/qrack_system.py +22 -3
- {pyqrack_complex128-1.63.0.dist-info → pyqrack_complex128-1.78.3.dist-info}/METADATA +3 -5
- pyqrack_complex128-1.78.3.dist-info/RECORD +23 -0
- pyqrack/qrack_system/qrack_lib/libqrack_pinvoke.9.22.0.dylib +0 -0
- pyqrack_complex128-1.63.0.dist-info/RECORD +0 -23
- {pyqrack_complex128-1.63.0.dist-info → pyqrack_complex128-1.78.3.dist-info}/LICENSE +0 -0
- {pyqrack_complex128-1.63.0.dist-info → pyqrack_complex128-1.78.3.dist-info}/WHEEL +0 -0
- {pyqrack_complex128-1.63.0.dist-info → pyqrack_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
|
@@ -139,6 +139,12 @@ class LHVQubit:
|
|
|
139
139
|
new_y = 2 * (rho_prime[0][1].imag - rho_prime[1][0].imag)
|
|
140
140
|
new_z = 2 * rho_prime[0][0].real - 1 # since Tr(ρ') = 1
|
|
141
141
|
|
|
142
|
+
p = math.sqrt(new_x**2 + new_y**2 + new_z**2)
|
|
143
|
+
|
|
144
|
+
new_x /= p
|
|
145
|
+
new_y /= p
|
|
146
|
+
new_z /= p
|
|
147
|
+
|
|
142
148
|
self.bloch = [new_x, new_y, new_z]
|
|
143
149
|
|
|
144
150
|
def prob(self, basis=Pauli.PauliZ):
|
|
@@ -202,7 +208,6 @@ class QrackAceBackend:
|
|
|
202
208
|
sim(QrackSimulator): Array of simulators corresponding to "patches" between boundary rows.
|
|
203
209
|
long_range_columns(int): How many ideal rows between QEC boundary rows?
|
|
204
210
|
is_transpose(bool): Rows are long if False, columns are long if True
|
|
205
|
-
correction_bias(float): Bias magnitude and direction during pseudo-QEC
|
|
206
211
|
"""
|
|
207
212
|
|
|
208
213
|
def __init__(
|
|
@@ -211,7 +216,6 @@ class QrackAceBackend:
|
|
|
211
216
|
long_range_columns=4,
|
|
212
217
|
long_range_rows=4,
|
|
213
218
|
is_transpose=False,
|
|
214
|
-
correction_bias=0,
|
|
215
219
|
isTensorNetwork=False,
|
|
216
220
|
isSchmidtDecomposeMulti=False,
|
|
217
221
|
isSchmidtDecompose=True,
|
|
@@ -240,7 +244,6 @@ class QrackAceBackend:
|
|
|
240
244
|
self.long_range_columns = long_range_columns
|
|
241
245
|
self.long_range_rows = long_range_rows
|
|
242
246
|
self.is_transpose = is_transpose
|
|
243
|
-
self.correction_bias = correction_bias
|
|
244
247
|
|
|
245
248
|
fppow = 5
|
|
246
249
|
if "QRACK_FPPOW" in os.environ:
|
|
@@ -429,7 +432,8 @@ class QrackAceBackend:
|
|
|
429
432
|
def _unpack(self, lq):
|
|
430
433
|
return self._qubits[lq]
|
|
431
434
|
|
|
432
|
-
|
|
435
|
+
@staticmethod
|
|
436
|
+
def _get_qb_lhv_indices(hq):
|
|
433
437
|
qb = []
|
|
434
438
|
if len(hq) < 2:
|
|
435
439
|
qb = [0]
|
|
@@ -443,15 +447,16 @@ class QrackAceBackend:
|
|
|
443
447
|
|
|
444
448
|
return qb, lhv
|
|
445
449
|
|
|
446
|
-
|
|
450
|
+
@staticmethod
|
|
451
|
+
def _get_lhv_bloch_angles(sim):
|
|
447
452
|
# Z axis
|
|
448
|
-
z =
|
|
453
|
+
z = sim.bloch[2]
|
|
449
454
|
|
|
450
455
|
# X axis
|
|
451
|
-
x =
|
|
456
|
+
x = sim.bloch[0]
|
|
452
457
|
|
|
453
458
|
# Y axis
|
|
454
|
-
y =
|
|
459
|
+
y = sim.bloch[1]
|
|
455
460
|
|
|
456
461
|
inclination = math.atan2(math.sqrt(x**2 + y**2), z)
|
|
457
462
|
azimuth = math.atan2(y, x)
|
|
@@ -483,9 +488,7 @@ class QrackAceBackend:
|
|
|
483
488
|
|
|
484
489
|
return azimuth, inclination
|
|
485
490
|
|
|
486
|
-
def _rotate_to_bloch(
|
|
487
|
-
self, hq, delta_azimuth, delta_inclination
|
|
488
|
-
):
|
|
491
|
+
def _rotate_to_bloch(self, hq, delta_azimuth, delta_inclination):
|
|
489
492
|
sim = self.sim[hq[0]]
|
|
490
493
|
q = hq[1]
|
|
491
494
|
|
|
@@ -502,10 +505,8 @@ class QrackAceBackend:
|
|
|
502
505
|
|
|
503
506
|
sim.mtrx([m00, m01, m10, m11], q)
|
|
504
507
|
|
|
505
|
-
|
|
506
|
-
def _rotate_lhv_to_bloch(
|
|
507
|
-
self, sim, delta_azimuth, delta_inclination
|
|
508
|
-
):
|
|
508
|
+
@staticmethod
|
|
509
|
+
def _rotate_lhv_to_bloch(sim, delta_azimuth, delta_inclination):
|
|
509
510
|
# Apply rotation as "Azimuth, Inclination" (AI)
|
|
510
511
|
cosA = math.cos(delta_azimuth)
|
|
511
512
|
sinA = math.sin(delta_azimuth)
|
|
@@ -519,14 +520,13 @@ class QrackAceBackend:
|
|
|
519
520
|
|
|
520
521
|
sim.mtrx([m00, m01, m10, m11])
|
|
521
522
|
|
|
522
|
-
|
|
523
523
|
def _correct(self, lq, phase=False, skip_rotation=False):
|
|
524
524
|
hq = self._unpack(lq)
|
|
525
525
|
|
|
526
526
|
if len(hq) == 1:
|
|
527
527
|
return
|
|
528
528
|
|
|
529
|
-
qb, lhv =
|
|
529
|
+
qb, lhv = QrackAceBackend._get_qb_lhv_indices(hq)
|
|
530
530
|
|
|
531
531
|
if phase:
|
|
532
532
|
for q in qb:
|
|
@@ -575,7 +575,7 @@ class QrackAceBackend:
|
|
|
575
575
|
a, i = [0, 0, 0, 0, 0], [0, 0, 0, 0, 0]
|
|
576
576
|
a[0], i[0] = self._get_bloch_angles(hq[0])
|
|
577
577
|
a[1], i[1] = self._get_bloch_angles(hq[1])
|
|
578
|
-
a[2], i[2] =
|
|
578
|
+
a[2], i[2] = QrackAceBackend._get_lhv_bloch_angles(hq[2])
|
|
579
579
|
a[3], i[3] = self._get_bloch_angles(hq[3])
|
|
580
580
|
a[4], i[4] = self._get_bloch_angles(hq[4])
|
|
581
581
|
|
|
@@ -591,12 +591,12 @@ class QrackAceBackend:
|
|
|
591
591
|
i_target /= 5
|
|
592
592
|
for x in range(5):
|
|
593
593
|
if x == 2:
|
|
594
|
-
|
|
594
|
+
QrackAceBackend._rotate_lhv_to_bloch(
|
|
595
|
+
hq[x], a_target - a[x], i_target - i[x]
|
|
596
|
+
)
|
|
595
597
|
else:
|
|
596
598
|
self._rotate_to_bloch(hq[x], a_target - a[x], i_target - i[x])
|
|
597
599
|
|
|
598
|
-
self.apply_magnetic_bias([lq], self.correction_bias)
|
|
599
|
-
|
|
600
600
|
else:
|
|
601
601
|
# RMS
|
|
602
602
|
p = [
|
|
@@ -620,7 +620,7 @@ class QrackAceBackend:
|
|
|
620
620
|
a, i = [0, 0, 0], [0, 0, 0]
|
|
621
621
|
a[0], i[0] = self._get_bloch_angles(hq[0])
|
|
622
622
|
a[1], i[1] = self._get_bloch_angles(hq[1])
|
|
623
|
-
a[2], i[2] =
|
|
623
|
+
a[2], i[2] = QrackAceBackend._get_lhv_bloch_angles(hq[2])
|
|
624
624
|
|
|
625
625
|
a_target = 0
|
|
626
626
|
i_target = 0
|
|
@@ -634,12 +634,12 @@ class QrackAceBackend:
|
|
|
634
634
|
i_target /= 3
|
|
635
635
|
for x in range(3):
|
|
636
636
|
if x == 2:
|
|
637
|
-
|
|
637
|
+
QrackAceBackend._rotate_lhv_to_bloch(
|
|
638
|
+
hq[x], a_target - a[x], i_target - i[x]
|
|
639
|
+
)
|
|
638
640
|
else:
|
|
639
641
|
self._rotate_to_bloch(hq[x], a_target - a[x], i_target - i[x])
|
|
640
642
|
|
|
641
|
-
self.apply_magnetic_bias([lq], self.correction_bias)
|
|
642
|
-
|
|
643
643
|
if phase:
|
|
644
644
|
for q in qb:
|
|
645
645
|
b = hq[q]
|
|
@@ -656,14 +656,18 @@ class QrackAceBackend:
|
|
|
656
656
|
for c in range(len(hq)):
|
|
657
657
|
h = hq[c]
|
|
658
658
|
if c == 2:
|
|
659
|
-
a, i =
|
|
660
|
-
|
|
661
|
-
h,
|
|
659
|
+
a, i = QrackAceBackend._get_lhv_bloch_angles(h)
|
|
660
|
+
QrackAceBackend._rotate_lhv_to_bloch(
|
|
661
|
+
h,
|
|
662
|
+
math.atan(math.tan(a) * b) - a,
|
|
663
|
+
math.atan(math.tan(i) * b) - i,
|
|
662
664
|
)
|
|
663
665
|
else:
|
|
664
666
|
a, i = self._get_bloch_angles(h)
|
|
665
667
|
self._rotate_to_bloch(
|
|
666
|
-
h,
|
|
668
|
+
h,
|
|
669
|
+
math.atan(math.tan(a) * b) - a,
|
|
670
|
+
math.atan(math.tan(i) * b) - i,
|
|
667
671
|
)
|
|
668
672
|
|
|
669
673
|
def u(self, lq, th, ph, lm):
|
|
@@ -673,7 +677,7 @@ class QrackAceBackend:
|
|
|
673
677
|
self.sim[b[0]].u(b[1], th, ph, lm)
|
|
674
678
|
return
|
|
675
679
|
|
|
676
|
-
qb, lhv =
|
|
680
|
+
qb, lhv = QrackAceBackend._get_qb_lhv_indices(hq)
|
|
677
681
|
|
|
678
682
|
for q in qb:
|
|
679
683
|
b = hq[q]
|
|
@@ -692,7 +696,7 @@ class QrackAceBackend:
|
|
|
692
696
|
self.sim[b[0]].r(p, th, b[1])
|
|
693
697
|
return
|
|
694
698
|
|
|
695
|
-
qb, lhv =
|
|
699
|
+
qb, lhv = QrackAceBackend._get_qb_lhv_indices(hq)
|
|
696
700
|
|
|
697
701
|
for q in qb:
|
|
698
702
|
b = hq[q]
|
|
@@ -720,7 +724,7 @@ class QrackAceBackend:
|
|
|
720
724
|
|
|
721
725
|
self._correct(lq)
|
|
722
726
|
|
|
723
|
-
qb, lhv =
|
|
727
|
+
qb, lhv = QrackAceBackend._get_qb_lhv_indices(hq)
|
|
724
728
|
|
|
725
729
|
for q in qb:
|
|
726
730
|
b = hq[q]
|
|
@@ -738,7 +742,7 @@ class QrackAceBackend:
|
|
|
738
742
|
self.sim[b[0]].s(b[1])
|
|
739
743
|
return
|
|
740
744
|
|
|
741
|
-
qb, lhv =
|
|
745
|
+
qb, lhv = QrackAceBackend._get_qb_lhv_indices(hq)
|
|
742
746
|
|
|
743
747
|
for q in qb:
|
|
744
748
|
b = hq[q]
|
|
@@ -754,7 +758,7 @@ class QrackAceBackend:
|
|
|
754
758
|
self.sim[b[0]].adjs(b[1])
|
|
755
759
|
return
|
|
756
760
|
|
|
757
|
-
qb, lhv =
|
|
761
|
+
qb, lhv = QrackAceBackend._get_qb_lhv_indices(hq)
|
|
758
762
|
|
|
759
763
|
for q in qb:
|
|
760
764
|
b = hq[q]
|
|
@@ -770,7 +774,7 @@ class QrackAceBackend:
|
|
|
770
774
|
self.sim[b[0]].x(b[1])
|
|
771
775
|
return
|
|
772
776
|
|
|
773
|
-
qb, lhv =
|
|
777
|
+
qb, lhv = QrackAceBackend._get_qb_lhv_indices(hq)
|
|
774
778
|
|
|
775
779
|
for q in qb:
|
|
776
780
|
b = hq[q]
|
|
@@ -786,7 +790,7 @@ class QrackAceBackend:
|
|
|
786
790
|
self.sim[b[0]].y(b[1])
|
|
787
791
|
return
|
|
788
792
|
|
|
789
|
-
qb, lhv =
|
|
793
|
+
qb, lhv = QrackAceBackend._get_qb_lhv_indices(hq)
|
|
790
794
|
|
|
791
795
|
for q in qb:
|
|
792
796
|
b = hq[q]
|
|
@@ -802,7 +806,7 @@ class QrackAceBackend:
|
|
|
802
806
|
self.sim[b[0]].z(b[1])
|
|
803
807
|
return
|
|
804
808
|
|
|
805
|
-
qb, lhv =
|
|
809
|
+
qb, lhv = QrackAceBackend._get_qb_lhv_indices(hq)
|
|
806
810
|
|
|
807
811
|
for q in qb:
|
|
808
812
|
b = hq[q]
|
|
@@ -818,7 +822,7 @@ class QrackAceBackend:
|
|
|
818
822
|
self.sim[b[0]].t(b[1])
|
|
819
823
|
return
|
|
820
824
|
|
|
821
|
-
qb, lhv =
|
|
825
|
+
qb, lhv = QrackAceBackend._get_qb_lhv_indices(hq)
|
|
822
826
|
|
|
823
827
|
for q in qb:
|
|
824
828
|
b = hq[q]
|
|
@@ -834,7 +838,7 @@ class QrackAceBackend:
|
|
|
834
838
|
self.sim[b[0]].adjt(b[1])
|
|
835
839
|
return
|
|
836
840
|
|
|
837
|
-
qb, lhv =
|
|
841
|
+
qb, lhv = QrackAceBackend._get_qb_lhv_indices(hq)
|
|
838
842
|
|
|
839
843
|
for q in qb:
|
|
840
844
|
b = hq[q]
|
|
@@ -916,8 +920,8 @@ class QrackAceBackend:
|
|
|
916
920
|
|
|
917
921
|
self._correct(lq1)
|
|
918
922
|
|
|
919
|
-
qb1, lhv1 =
|
|
920
|
-
qb2, lhv2 =
|
|
923
|
+
qb1, lhv1 = QrackAceBackend._get_qb_lhv_indices(hq1)
|
|
924
|
+
qb2, lhv2 = QrackAceBackend._get_qb_lhv_indices(hq2)
|
|
921
925
|
# Apply cross coupling on hardware qubits first
|
|
922
926
|
self._apply_coupling(pauli, anti, qb1, lhv1, hq1, qb2, lhv2, hq2, lq1_lr)
|
|
923
927
|
# Apply coupling to the local-hidden-variable target
|
|
@@ -1064,7 +1068,7 @@ class QrackAceBackend:
|
|
|
1064
1068
|
p = self.prob(lq)
|
|
1065
1069
|
result = ((p + self._epsilon) >= 1) or (random.random() < p)
|
|
1066
1070
|
|
|
1067
|
-
qb, lhv =
|
|
1071
|
+
qb, lhv = QrackAceBackend._get_qb_lhv_indices(hq)
|
|
1068
1072
|
|
|
1069
1073
|
for q in qb:
|
|
1070
1074
|
b = hq[q]
|
|
@@ -1090,7 +1094,7 @@ class QrackAceBackend:
|
|
|
1090
1094
|
|
|
1091
1095
|
self._correct(lq)
|
|
1092
1096
|
|
|
1093
|
-
qb, lhv =
|
|
1097
|
+
qb, lhv = QrackAceBackend._get_qb_lhv_indices(hq)
|
|
1094
1098
|
|
|
1095
1099
|
for q in qb:
|
|
1096
1100
|
b = hq[q]
|
|
@@ -1443,6 +1447,7 @@ class QrackAceBackend:
|
|
|
1443
1447
|
|
|
1444
1448
|
return _data
|
|
1445
1449
|
|
|
1450
|
+
@staticmethod
|
|
1446
1451
|
def get_qiskit_basis_gates():
|
|
1447
1452
|
return [
|
|
1448
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)]
|