pyqrack-cpu 1.76.0__py3-none-macosx_14_0_arm64.whl → 1.80.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 CHANGED
@@ -10,8 +10,8 @@ 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
16
  )
17
17
  from .qrack_simulator import QrackSimulator
@@ -224,9 +224,7 @@ class QrackAceBackend:
224
224
  isPaged=True,
225
225
  isCpuGpuHybrid=True,
226
226
  isOpenCL=True,
227
- isHostPointer=(
228
- True if os.environ.get("PYQRACK_HOST_POINTER_DEFAULT_ON") else False
229
- ),
227
+ isHostPointer=(True if os.environ.get("PYQRACK_HOST_POINTER_DEFAULT_ON") else False),
230
228
  noise=0,
231
229
  toClone=None,
232
230
  ):
@@ -294,11 +292,7 @@ class QrackAceBackend:
294
292
  sim_counts[t_sim_id] += 1
295
293
 
296
294
  qubit.append(
297
- LHVQubit(
298
- toClone=(
299
- toClone._qubits[tot_qubits][2] if toClone else None
300
- )
301
- )
295
+ LHVQubit(toClone=(toClone._qubits[tot_qubits][2] if toClone else None))
302
296
  )
303
297
 
304
298
  if (not c) and (not r):
@@ -432,7 +426,8 @@ class QrackAceBackend:
432
426
  def _unpack(self, lq):
433
427
  return self._qubits[lq]
434
428
 
435
- def _get_qb_lhv_indices(self, hq):
429
+ @staticmethod
430
+ def _get_qb_lhv_indices(hq):
436
431
  qb = []
437
432
  if len(hq) < 2:
438
433
  qb = [0]
@@ -446,7 +441,8 @@ class QrackAceBackend:
446
441
 
447
442
  return qb, lhv
448
443
 
449
- def _get_lhv_bloch_angles(self, sim):
444
+ @staticmethod
445
+ def _get_lhv_bloch_angles(sim):
450
446
  # Z axis
451
447
  z = sim.bloch[2]
452
448
 
@@ -503,7 +499,8 @@ class QrackAceBackend:
503
499
 
504
500
  sim.mtrx([m00, m01, m10, m11], q)
505
501
 
506
- def _rotate_lhv_to_bloch(self, sim, delta_azimuth, delta_inclination):
502
+ @staticmethod
503
+ def _rotate_lhv_to_bloch(sim, delta_azimuth, delta_inclination):
507
504
  # Apply rotation as "Azimuth, Inclination" (AI)
508
505
  cosA = math.cos(delta_azimuth)
509
506
  sinA = math.sin(delta_azimuth)
@@ -523,7 +520,7 @@ class QrackAceBackend:
523
520
  if len(hq) == 1:
524
521
  return
525
522
 
526
- qb, lhv = self._get_qb_lhv_indices(hq)
523
+ qb, lhv = QrackAceBackend._get_qb_lhv_indices(hq)
527
524
 
528
525
  if phase:
529
526
  for q in qb:
@@ -542,9 +539,7 @@ class QrackAceBackend:
542
539
  self.sim[hq[4][0]].prob(hq[4][1]),
543
540
  ]
544
541
  # Balancing suggestion from Elara (the custom OpenAI GPT)
545
- prms = math.sqrt(
546
- (p[0] ** 2 + p[1] ** 2 + 3 * (p[2] ** 2) + p[3] ** 2 + p[4] ** 2) / 7
547
- )
542
+ prms = math.sqrt((p[0] ** 2 + p[1] ** 2 + 3 * (p[2] ** 2) + p[3] ** 2 + p[4] ** 2) / 7)
548
543
  qrms = math.sqrt(
549
544
  (
550
545
  (1 - p[0]) ** 2
@@ -572,7 +567,7 @@ class QrackAceBackend:
572
567
  a, i = [0, 0, 0, 0, 0], [0, 0, 0, 0, 0]
573
568
  a[0], i[0] = self._get_bloch_angles(hq[0])
574
569
  a[1], i[1] = self._get_bloch_angles(hq[1])
575
- a[2], i[2] = self._get_lhv_bloch_angles(hq[2])
570
+ a[2], i[2] = QrackAceBackend._get_lhv_bloch_angles(hq[2])
576
571
  a[3], i[3] = self._get_bloch_angles(hq[3])
577
572
  a[4], i[4] = self._get_bloch_angles(hq[4])
578
573
 
@@ -588,7 +583,7 @@ class QrackAceBackend:
588
583
  i_target /= 5
589
584
  for x in range(5):
590
585
  if x == 2:
591
- self._rotate_lhv_to_bloch(
586
+ QrackAceBackend._rotate_lhv_to_bloch(
592
587
  hq[x], a_target - a[x], i_target - i[x]
593
588
  )
594
589
  else:
@@ -617,7 +612,7 @@ class QrackAceBackend:
617
612
  a, i = [0, 0, 0], [0, 0, 0]
618
613
  a[0], i[0] = self._get_bloch_angles(hq[0])
619
614
  a[1], i[1] = self._get_bloch_angles(hq[1])
620
- a[2], i[2] = self._get_lhv_bloch_angles(hq[2])
615
+ a[2], i[2] = QrackAceBackend._get_lhv_bloch_angles(hq[2])
621
616
 
622
617
  a_target = 0
623
618
  i_target = 0
@@ -631,7 +626,7 @@ class QrackAceBackend:
631
626
  i_target /= 3
632
627
  for x in range(3):
633
628
  if x == 2:
634
- self._rotate_lhv_to_bloch(
629
+ QrackAceBackend._rotate_lhv_to_bloch(
635
630
  hq[x], a_target - a[x], i_target - i[x]
636
631
  )
637
632
  else:
@@ -653,8 +648,8 @@ class QrackAceBackend:
653
648
  for c in range(len(hq)):
654
649
  h = hq[c]
655
650
  if c == 2:
656
- a, i = self._get_lhv_bloch_angles(h)
657
- self._rotate_lhv_to_bloch(
651
+ a, i = QrackAceBackend._get_lhv_bloch_angles(h)
652
+ QrackAceBackend._rotate_lhv_to_bloch(
658
653
  h,
659
654
  math.atan(math.tan(a) * b) - a,
660
655
  math.atan(math.tan(i) * b) - i,
@@ -674,7 +669,7 @@ class QrackAceBackend:
674
669
  self.sim[b[0]].u(b[1], th, ph, lm)
675
670
  return
676
671
 
677
- qb, lhv = self._get_qb_lhv_indices(hq)
672
+ qb, lhv = QrackAceBackend._get_qb_lhv_indices(hq)
678
673
 
679
674
  for q in qb:
680
675
  b = hq[q]
@@ -693,7 +688,7 @@ class QrackAceBackend:
693
688
  self.sim[b[0]].r(p, th, b[1])
694
689
  return
695
690
 
696
- qb, lhv = self._get_qb_lhv_indices(hq)
691
+ qb, lhv = QrackAceBackend._get_qb_lhv_indices(hq)
697
692
 
698
693
  for q in qb:
699
694
  b = hq[q]
@@ -721,7 +716,7 @@ class QrackAceBackend:
721
716
 
722
717
  self._correct(lq)
723
718
 
724
- qb, lhv = self._get_qb_lhv_indices(hq)
719
+ qb, lhv = QrackAceBackend._get_qb_lhv_indices(hq)
725
720
 
726
721
  for q in qb:
727
722
  b = hq[q]
@@ -739,7 +734,7 @@ class QrackAceBackend:
739
734
  self.sim[b[0]].s(b[1])
740
735
  return
741
736
 
742
- qb, lhv = self._get_qb_lhv_indices(hq)
737
+ qb, lhv = QrackAceBackend._get_qb_lhv_indices(hq)
743
738
 
744
739
  for q in qb:
745
740
  b = hq[q]
@@ -755,7 +750,7 @@ class QrackAceBackend:
755
750
  self.sim[b[0]].adjs(b[1])
756
751
  return
757
752
 
758
- qb, lhv = self._get_qb_lhv_indices(hq)
753
+ qb, lhv = QrackAceBackend._get_qb_lhv_indices(hq)
759
754
 
760
755
  for q in qb:
761
756
  b = hq[q]
@@ -771,7 +766,7 @@ class QrackAceBackend:
771
766
  self.sim[b[0]].x(b[1])
772
767
  return
773
768
 
774
- qb, lhv = self._get_qb_lhv_indices(hq)
769
+ qb, lhv = QrackAceBackend._get_qb_lhv_indices(hq)
775
770
 
776
771
  for q in qb:
777
772
  b = hq[q]
@@ -787,7 +782,7 @@ class QrackAceBackend:
787
782
  self.sim[b[0]].y(b[1])
788
783
  return
789
784
 
790
- qb, lhv = self._get_qb_lhv_indices(hq)
785
+ qb, lhv = QrackAceBackend._get_qb_lhv_indices(hq)
791
786
 
792
787
  for q in qb:
793
788
  b = hq[q]
@@ -803,7 +798,7 @@ class QrackAceBackend:
803
798
  self.sim[b[0]].z(b[1])
804
799
  return
805
800
 
806
- qb, lhv = self._get_qb_lhv_indices(hq)
801
+ qb, lhv = QrackAceBackend._get_qb_lhv_indices(hq)
807
802
 
808
803
  for q in qb:
809
804
  b = hq[q]
@@ -819,7 +814,7 @@ class QrackAceBackend:
819
814
  self.sim[b[0]].t(b[1])
820
815
  return
821
816
 
822
- qb, lhv = self._get_qb_lhv_indices(hq)
817
+ qb, lhv = QrackAceBackend._get_qb_lhv_indices(hq)
823
818
 
824
819
  for q in qb:
825
820
  b = hq[q]
@@ -835,7 +830,7 @@ class QrackAceBackend:
835
830
  self.sim[b[0]].adjt(b[1])
836
831
  return
837
832
 
838
- qb, lhv = self._get_qb_lhv_indices(hq)
833
+ qb, lhv = QrackAceBackend._get_qb_lhv_indices(hq)
839
834
 
840
835
  for q in qb:
841
836
  b = hq[q]
@@ -857,9 +852,7 @@ class QrackAceBackend:
857
852
  gate = self.sim[sim_id].macz if anti else self.sim[sim_id].mcz
858
853
  shadow = self._anti_cz_shadow if anti else self._cz_shadow
859
854
  else:
860
- raise RuntimeError(
861
- "QrackAceBackend._get_gate() should never return identity!"
862
- )
855
+ raise RuntimeError("QrackAceBackend._get_gate() should never return identity!")
863
856
 
864
857
  return gate, shadow
865
858
 
@@ -896,11 +889,7 @@ class QrackAceBackend:
896
889
  b2 = hq2[q2]
897
890
  if b1[0] == b2[0]:
898
891
  gate_fn([b1[1]], b2[1])
899
- elif (
900
- lq1_lr
901
- or (b1[1] == b2[1])
902
- or ((len(qb1) == 2) and (b1[1] == (b2[1] & 1)))
903
- ):
892
+ elif lq1_lr or (b1[1] == b2[1]) or ((len(qb1) == 2) and (b1[1] == (b2[1] & 1))):
904
893
  shadow_fn(b1, b2)
905
894
 
906
895
  def _cpauli(self, lq1, lq2, anti, pauli):
@@ -917,8 +906,8 @@ class QrackAceBackend:
917
906
 
918
907
  self._correct(lq1)
919
908
 
920
- qb1, lhv1 = self._get_qb_lhv_indices(hq1)
921
- qb2, lhv2 = self._get_qb_lhv_indices(hq2)
909
+ qb1, lhv1 = QrackAceBackend._get_qb_lhv_indices(hq1)
910
+ qb2, lhv2 = QrackAceBackend._get_qb_lhv_indices(hq2)
922
911
  # Apply cross coupling on hardware qubits first
923
912
  self._apply_coupling(pauli, anti, qb1, lhv1, hq1, qb2, lhv2, hq2, lq1_lr)
924
913
  # Apply coupling to the local-hidden-variable target
@@ -1030,9 +1019,7 @@ class QrackAceBackend:
1030
1019
  self.sim[hq[4][0]].prob(hq[4][1]),
1031
1020
  ]
1032
1021
  # Balancing suggestion from Elara (the custom OpenAI GPT)
1033
- prms = math.sqrt(
1034
- (p[0] ** 2 + p[1] ** 2 + 3 * (p[2] ** 2) + p[3] ** 2 + p[4] ** 2) / 7
1035
- )
1022
+ prms = math.sqrt((p[0] ** 2 + p[1] ** 2 + 3 * (p[2] ** 2) + p[3] ** 2 + p[4] ** 2) / 7)
1036
1023
  qrms = math.sqrt(
1037
1024
  (
1038
1025
  (1 - p[0]) ** 2
@@ -1065,7 +1052,7 @@ class QrackAceBackend:
1065
1052
  p = self.prob(lq)
1066
1053
  result = ((p + self._epsilon) >= 1) or (random.random() < p)
1067
1054
 
1068
- qb, lhv = self._get_qb_lhv_indices(hq)
1055
+ qb, lhv = QrackAceBackend._get_qb_lhv_indices(hq)
1069
1056
 
1070
1057
  for q in qb:
1071
1058
  b = hq[q]
@@ -1091,7 +1078,7 @@ class QrackAceBackend:
1091
1078
 
1092
1079
  self._correct(lq)
1093
1080
 
1094
- qb, lhv = self._get_qb_lhv_indices(hq)
1081
+ qb, lhv = QrackAceBackend._get_qb_lhv_indices(hq)
1095
1082
 
1096
1083
  for q in qb:
1097
1084
  b = hq[q]
@@ -1184,17 +1171,11 @@ class QrackAceBackend:
1184
1171
  (-1 * float(operation.params[1])) + math.pi / 2,
1185
1172
  )
1186
1173
  elif name == "rx":
1187
- self._sim.r(
1188
- Pauli.PauliX, float(operation.params[0]), operation.qubits[0]._index
1189
- )
1174
+ self._sim.r(Pauli.PauliX, float(operation.params[0]), operation.qubits[0]._index)
1190
1175
  elif name == "ry":
1191
- self._sim.r(
1192
- Pauli.PauliY, float(operation.params[0]), operation.qubits[0]._index
1193
- )
1176
+ self._sim.r(Pauli.PauliY, float(operation.params[0]), operation.qubits[0]._index)
1194
1177
  elif name == "rz":
1195
- self._sim.r(
1196
- Pauli.PauliZ, float(operation.params[0]), operation.qubits[0]._index
1197
- )
1178
+ self._sim.r(Pauli.PauliZ, float(operation.params[0]), operation.qubits[0]._index)
1198
1179
  elif name == "h":
1199
1180
  self._sim.h(operation.qubits[0]._index)
1200
1181
  elif name == "x":
@@ -1259,9 +1240,9 @@ class QrackAceBackend:
1259
1240
  cregbit = clbit
1260
1241
 
1261
1242
  regbit = 1 << cregbit
1262
- self._classical_register = (
1263
- self._classical_register & (~regbit)
1264
- ) | (qubit_outcome << cregbit)
1243
+ self._classical_register = (self._classical_register & (~regbit)) | (
1244
+ qubit_outcome << cregbit
1245
+ )
1265
1246
 
1266
1247
  elif name == "bfunc":
1267
1248
  mask = int(operation.mask, 16)
@@ -1376,9 +1357,7 @@ class QrackAceBackend:
1376
1357
  if operation.name == "id" or operation.name == "barrier":
1377
1358
  continue
1378
1359
 
1379
- if is_initializing and (
1380
- (operation.name == "measure") or (operation.name == "reset")
1381
- ):
1360
+ if is_initializing and ((operation.name == "measure") or (operation.name == "reset")):
1382
1361
  continue
1383
1362
 
1384
1363
  is_initializing = False
@@ -1436,14 +1415,13 @@ class QrackAceBackend:
1436
1415
  self._sample_cregbits = []
1437
1416
 
1438
1417
  if self._sample_measure and (len(self._sample_qubits) > 0):
1439
- _data = self._add_sample_measure(
1440
- self._sample_qubits, self._sample_clbits, self._shots
1441
- )
1418
+ _data = self._add_sample_measure(self._sample_qubits, self._sample_clbits, self._shots)
1442
1419
 
1443
1420
  del self._sim
1444
1421
 
1445
1422
  return _data
1446
1423
 
1424
+ @staticmethod
1447
1425
  def get_qiskit_basis_gates():
1448
1426
  return [
1449
1427
  "id",
@@ -1528,17 +1506,13 @@ class QrackAceBackend:
1528
1506
  noise_model.add_quantum_error(depolarizing_error(y, 2), "cx", [a, b])
1529
1507
  noise_model.add_quantum_error(depolarizing_error(y_cy, 2), "cy", [a, b])
1530
1508
  noise_model.add_quantum_error(depolarizing_error(y_cy, 2), "cz", [a, b])
1531
- noise_model.add_quantum_error(
1532
- depolarizing_error(y_swap, 2), "swap", [a, b]
1533
- )
1509
+ noise_model.add_quantum_error(depolarizing_error(y_swap, 2), "swap", [a, b])
1534
1510
  else:
1535
1511
  y_cy = 1 - (1 - y) ** 2
1536
1512
  y_swap = 1 - (1 - y) ** 3
1537
1513
  noise_model.add_quantum_error(depolarizing_error(y_cy, 2), "cx", [a, b])
1538
1514
  noise_model.add_quantum_error(depolarizing_error(y_cy, 2), "cy", [a, b])
1539
1515
  noise_model.add_quantum_error(depolarizing_error(y_cy, 2), "cz", [a, b])
1540
- noise_model.add_quantum_error(
1541
- depolarizing_error(y_swap, 2), "swap", [a, b]
1542
- )
1516
+ noise_model.add_quantum_error(depolarizing_error(y_swap, 2), "swap", [a, b])
1543
1517
 
1544
1518
  return noise_model
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,
@@ -494,9 +507,7 @@ class QrackCircuit:
494
507
  )
495
508
  if circuit_type == QuimbCircuitType.Circuit
496
509
  else (
497
- qtn.CircuitDense(
498
- N=qcirc.num_qubits, psi0=psi0, gate_opts=gate_opts, tags=tags
499
- )
510
+ qtn.CircuitDense(N=qcirc.num_qubits, psi0=psi0, gate_opts=gate_opts, tags=tags)
500
511
  if circuit_type == QuimbCircuitType.CircuitDense
501
512
  else qtn.CircuitMPS(
502
513
  N=qcirc.num_qubits,
@@ -526,9 +537,8 @@ class QrackCircuit:
526
537
 
527
538
  return tcirc
528
539
 
529
- def file_to_tensorcircuit(
530
- filename, inputs=None, circuit_params=None, binding_params=None
531
- ):
540
+ @staticmethod
541
+ def file_to_tensorcircuit(filename, inputs=None, circuit_params=None, binding_params=None):
532
542
  """Convert an output file to a TensorCircuit circuit
533
543
 
534
544
  Reads in an (optimized) circuit from a file named
@@ -558,6 +568,7 @@ class QrackCircuit:
558
568
  qcirc, qcirc.num_qubits, inputs, circuit_params, binding_params
559
569
  )
560
570
 
571
+ @staticmethod
561
572
  def in_from_tensorcircuit(tcirc, enable_instruction=False, enable_inputs=False):
562
573
  """Convert a TensorCircuit circuit to a QrackCircuit
563
574
 
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,15 +99,32 @@ 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)
109
111
  return (ctypes.c_double * len(a))(*a)
110
112
 
113
+ def set_simulator(self, s):
114
+ """Set the neuron simulator
115
+
116
+ Set the simulator used by this neuron
117
+
118
+ Args:
119
+ s(QrackSimulator): The simulator to use
120
+
121
+ Raises:
122
+ RuntimeError: QrackSimulator raised an exception.
123
+ """
124
+ Qrack.qrack_lib.set_qneuron_sim(self.nid, s.sid)
125
+ self._throw_if_error()
126
+ self.simulator = s
127
+
111
128
  def set_angles(self, a):
112
129
  """Directly sets the neuron parameters.
113
130
 
@@ -125,7 +142,7 @@ class QrackNeuron:
125
142
  raise ValueError(
126
143
  "Angles 'a' in QrackNeuron.set_angles() must contain at least (2 ** len(self.controls)) elements."
127
144
  )
128
- Qrack.qrack_lib.set_qneuron_angles(self.nid, self._real1_byref(a))
145
+ Qrack.qrack_lib.set_qneuron_angles(self.nid, QrackNeuron._real1_byref(a))
129
146
  self._throw_if_error()
130
147
 
131
148
  def get_angles(self):
@@ -137,7 +154,7 @@ class QrackNeuron:
137
154
  Raises:
138
155
  RuntimeError: QrackNeuron C++ library raised an exception.
139
156
  """
140
- ket = self._real1_byref([0.0] * (1 << len(self.controls)))
157
+ ket = QrackNeuron._real1_byref([0.0] * (1 << len(self.controls)))
141
158
  Qrack.qrack_lib.get_qneuron_angles(self.nid, ket)
142
159
  self._throw_if_error()
143
160
  return list(ket)
@@ -261,8 +278,9 @@ class QrackNeuron:
261
278
  Qrack.qrack_lib.qneuron_learn_permutation(self.nid, eta, e, r)
262
279
  self._throw_if_error()
263
280
 
281
+ @staticmethod
264
282
  def quantile_bounds(vec, bits):
265
- """ Calculate vector quantile bounds
283
+ """Calculate vector quantile bounds
266
284
 
267
285
  This is a static helper method to calculate the quantile
268
286
  bounds of 2 ** bits worth of quantiles.
@@ -280,10 +298,15 @@ class QrackNeuron:
280
298
  n = len(vec)
281
299
  vec_sorted = sorted(vec)
282
300
 
283
- return [vec_sorted[0]] + [vec_sorted[(k * n) // bins] for k in range(1, bins)] + [vec_sorted[-1]]
301
+ return (
302
+ [vec_sorted[0]]
303
+ + [vec_sorted[(k * n) // bins] for k in range(1, bins)]
304
+ + [vec_sorted[-1]]
305
+ )
284
306
 
307
+ @staticmethod
285
308
  def discretize(vec, bounds):
286
- """ Discretize vector by quantile bounds
309
+ """Discretize vector by quantile bounds
287
310
 
288
311
  This is a static helper method to discretize a numerical
289
312
  vector according to quantile bounds calculated by the
@@ -311,8 +334,9 @@ class QrackNeuron:
311
334
 
312
335
  return vec_discrete
313
336
 
337
+ @staticmethod
314
338
  def flatten_and_transpose(arr):
315
- """ Flatten and transpose feature matrix
339
+ """Flatten and transpose feature matrix
316
340
 
317
341
  This is a static helper method to convert a multi-feature
318
342
  bit-row matrix to an observation-row matrix with flat
@@ -326,8 +350,9 @@ class QrackNeuron:
326
350
  """
327
351
  return list(zip(*[item for sublist in arr for item in sublist]))
328
352
 
353
+ @staticmethod
329
354
  def bin_endpoints_average(bounds):
330
- """ Bin endpoints average
355
+ """Bin endpoints average
331
356
 
332
357
  This is a static helper method that accepts the output
333
358
  bins from quantile_bounds() and returns the average points