pyqrack 1.29.0__py3-none-win_amd64.whl → 1.72.5__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/qrack_circuit.py CHANGED
@@ -1,4 +1,4 @@
1
- # (C) Daniel Strano and the Qrack contributors 2017-2023. All rights reserved.
1
+ # (C) Daniel Strano and the Qrack contributors 2017-2025. All rights reserved.
2
2
  #
3
3
  # Use of this source code is governed by an MIT-style license that can be
4
4
  # found in the LICENSE file or at https://opensource.org/licenses/MIT.
@@ -12,8 +12,10 @@ _IS_QISKIT_AVAILABLE = True
12
12
  try:
13
13
  from qiskit.circuit.quantumcircuit import QuantumCircuit
14
14
  from qiskit.compiler.transpiler import transpile
15
+ from qiskit.circuit.library import UCGate
15
16
  import numpy as np
16
17
  import math
18
+ import sys
17
19
  except ImportError:
18
20
  _IS_QISKIT_AVAILABLE = False
19
21
 
@@ -30,6 +32,7 @@ try:
30
32
  except ImportError:
31
33
  _IS_TENSORCIRCUIT_AVAILABLE = False
32
34
 
35
+
33
36
  class QrackCircuit:
34
37
  """Class that exposes the QCircuit class of Qrack
35
38
 
@@ -42,13 +45,22 @@ class QrackCircuit:
42
45
  cid(int): Qrack ID of this circuit
43
46
  """
44
47
 
45
- def __init__(self, is_collapse = True, is_near_clifford = False, clone_cid = -1, is_inverse=False, past_light_cone = []):
48
+ def __init__(
49
+ self,
50
+ is_collapse=True,
51
+ is_near_clifford=False,
52
+ clone_cid=-1,
53
+ is_inverse=False,
54
+ past_light_cone=[],
55
+ ):
46
56
  if clone_cid < 0:
47
57
  self.cid = Qrack.qrack_lib.init_qcircuit(is_collapse, is_near_clifford)
48
58
  elif is_inverse:
49
59
  self.cid = Qrack.qrack_lib.qcircuit_inverse(clone_cid)
50
60
  elif len(past_light_cone) > 0:
51
- self.cid = Qrack.qrack_lib.qcircuit_past_light_cone(clone_cid, len(past_light_cone), self._ulonglong_byref(past_light_cone))
61
+ self.cid = Qrack.qrack_lib.qcircuit_past_light_cone(
62
+ clone_cid, len(past_light_cone), self._ulonglong_byref(past_light_cone)
63
+ )
52
64
  else:
53
65
  self.cid = Qrack.qrack_lib.init_qcircuit_clone(clone_cid)
54
66
 
@@ -67,13 +79,60 @@ class QrackCircuit:
67
79
  t = [(c.real, c.imag) for c in a]
68
80
  return self._double_byref([float(item) for sublist in t for item in sublist])
69
81
 
82
+ def _mtrx_to_u4(m):
83
+ nrm = abs(m[0])
84
+ if (nrm * nrm) < sys.float_info.epsilon:
85
+ phase = 1.0 + 0.0j
86
+ th = math.pi
87
+ else:
88
+ phase = m[0] / nrm
89
+ if nrm > 1.0:
90
+ nrm = 1.0
91
+ th = 2 * math.acos(nrm)
92
+
93
+ nrm1 = abs(m[1])
94
+ nrm2 = abs(m[2])
95
+ nrm1 *= nrm1
96
+ nrm2 *= nrm2
97
+ if (nrm1 < sys.float_info.epsilon) or (nrm2 < sys.float_info.epsilon):
98
+ ph = np.angle(m[3] / phase)
99
+ lm = 0.0
100
+ else:
101
+ ph = np.angle(m[2] / phase)
102
+ lm = np.angle(-m[1] / phase)
103
+
104
+ return th, ph, lm, np.angle(phase)
105
+
106
+ def _u3_to_mtrx(params):
107
+ th = float(params[0])
108
+ ph = float(params[1])
109
+ lm = float(params[2])
110
+
111
+ c = math.cos(th / 2)
112
+ s = math.sin(th / 2)
113
+ el = np.exp(1j * lm)
114
+ ep = np.exp(1j * ph)
115
+
116
+ return [c + 0j, -el * s, ep * s, ep * el * c]
117
+
118
+ def _u4_to_mtrx(params):
119
+ m = QrackCircuit._u3_to_mtrx(params)
120
+ g = np.exp(1j * float(params[3]))
121
+ for i in range(4):
122
+ m[i] *= g
123
+
124
+ return m
125
+
126
+ def _make_mtrx_unitary(m):
127
+ return QrackCircuit._u4_to_mtrx(QrackCircuit._mtrx_to_u4(m))
128
+
70
129
  def clone(self):
71
130
  """Make a new circuit that is an exact clone of this circuit
72
131
 
73
132
  Raises:
74
133
  RuntimeError: QrackCircuit C++ library raised an exception.
75
134
  """
76
- return QrackCircuit(clone_cid = self.cid, is_inverse = False)
135
+ return QrackCircuit(clone_cid=self.cid, is_inverse=False)
77
136
 
78
137
  def inverse(self):
79
138
  """Make a new circuit that is the exact inverse of this circuit
@@ -81,7 +140,7 @@ class QrackCircuit:
81
140
  Raises:
82
141
  RuntimeError: QrackCircuit C++ library raised an exception.
83
142
  """
84
- return QrackCircuit(clone_cid = self.cid, is_inverse = True)
143
+ return QrackCircuit(clone_cid=self.cid, is_inverse=True)
85
144
 
86
145
  def past_light_cone(self, q):
87
146
  """Make a new circuit with just this circuits' past light cone for certain qubits.
@@ -92,7 +151,7 @@ class QrackCircuit:
92
151
  Raises:
93
152
  RuntimeError: QrackCircuit C++ library raised an exception.
94
153
  """
95
- return QrackCircuit(clone_cid = self.cid, is_inverse = False, past_light_cone = q)
154
+ return QrackCircuit(clone_cid=self.cid, is_inverse=False, past_light_cone=q)
96
155
 
97
156
  def get_qubit_count(self):
98
157
  """Get count of qubits in circuit
@@ -128,7 +187,9 @@ class QrackCircuit:
128
187
  RuntimeError: QrackSimulator raised an exception.
129
188
  """
130
189
  if len(m) < 4:
131
- raise ValueError("2x2 matrix 'm' in QrackCircuit.mtrx() must contain at least 4 elements.")
190
+ raise ValueError(
191
+ "2x2 matrix 'm' in QrackCircuit.mtrx() must contain at least 4 elements."
192
+ )
132
193
  Qrack.qrack_lib.qcircuit_append_1qb(self.cid, self._complex_byref(m), q)
133
194
 
134
195
  def ucmtrx(self, c, m, q, p):
@@ -149,7 +210,9 @@ class QrackCircuit:
149
210
  RuntimeError: QrackSimulator raised an exception.
150
211
  """
151
212
  if len(m) < 4:
152
- raise ValueError("2x2 matrix 'm' in QrackCircuit.ucmtrx() must contain at least 4 elements.")
213
+ raise ValueError(
214
+ "2x2 matrix 'm' in QrackCircuit.ucmtrx() must contain at least 4 elements."
215
+ )
153
216
  Qrack.qrack_lib.qcircuit_append_mc(
154
217
  self.cid, self._complex_byref(m), len(c), self._ulonglong_byref(c), q, p
155
218
  )
@@ -183,7 +246,7 @@ class QrackCircuit:
183
246
  Args:
184
247
  filename: Name of file
185
248
  """
186
- Qrack.qrack_lib.qcircuit_out_to_file(self.cid, filename.encode('utf-8'))
249
+ Qrack.qrack_lib.qcircuit_out_to_file(self.cid, filename.encode("utf-8"))
187
250
 
188
251
  def in_from_file(filename):
189
252
  """Read in optimized circuit from file
@@ -195,10 +258,50 @@ class QrackCircuit:
195
258
  filename: Name of file
196
259
  """
197
260
  out = QrackCircuit()
198
- Qrack.qrack_lib.qcircuit_in_from_file(out.cid, filename.encode('utf-8'))
261
+ Qrack.qrack_lib.qcircuit_in_from_file(out.cid, filename.encode("utf-8"))
199
262
 
200
263
  return out
201
264
 
265
+ def out_to_string(self):
266
+ """Output optimized circuit to string
267
+
268
+ Outputs the (optimized) circuit to a string.
269
+ """
270
+ string_length = Qrack.qrack_lib.qcircuit_out_to_string_length(self.cid)
271
+ out = ctypes.create_string_buffer(string_length)
272
+ Qrack.qrack_lib.qcircuit_out_to_string(self.cid, out)
273
+
274
+ return out.value.decode("utf-8")
275
+
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
+ def to_qiskit_circuit(self):
290
+ """Convert to a Qiskit circuit
291
+
292
+ Outputs a Qiskit circuit from a QrackCircuit.
293
+
294
+ Raises:
295
+ RuntimeErorr: Before trying to string_to_qiskit_circuit() with
296
+ QrackCircuit, you must install Qiskit, numpy, and math!
297
+ """
298
+ if not _IS_QISKIT_AVAILABLE:
299
+ raise RuntimeError(
300
+ "Before trying to_qiskit_circuit() with QrackCircuit, you must install Qiskit, numpy, and math!"
301
+ )
302
+
303
+ return QrackCircuit.string_to_qiskit_circuit(self.out_to_string())
304
+
202
305
  def file_to_qiskit_circuit(filename):
203
306
  """Convert an output file to a Qiskit circuit
204
307
 
@@ -219,79 +322,79 @@ class QrackCircuit:
219
322
  )
220
323
 
221
324
  tokens = []
222
- with open(filename, 'r') as file:
223
- tokens = file.read().split()
325
+ with open(filename, "r") as file:
326
+ return QrackCircuit.string_to_qiskit_circuit(file.read())
327
+
328
+ def string_to_qiskit_circuit(circ_string):
329
+ """Convert an output string to a Qiskit circuit
330
+
331
+ Reads in an (optimized) circuit from a string
332
+ parameter and outputs a Qiskit circuit.
333
+
334
+ Args:
335
+ circ_string: String representation of circuit
336
+
337
+ Raises:
338
+ RuntimeErorr: Before trying to string_to_qiskit_circuit() with
339
+ QrackCircuit, you must install Qiskit, numpy, and math!
340
+ """
341
+ if not _IS_QISKIT_AVAILABLE:
342
+ raise RuntimeError(
343
+ "Before trying to string_to_qiskit_circuit() with QrackCircuit, you must install Qiskit, numpy, and math!"
344
+ )
345
+
346
+ tokens = circ_string.split()
224
347
 
225
348
  i = 0
226
349
  num_qubits = int(tokens[i])
227
- i = i + 1
350
+ i += 1
228
351
  circ = QuantumCircuit(num_qubits)
229
352
 
230
353
  num_gates = int(tokens[i])
231
- i = i + 1
354
+ i += 1
232
355
 
356
+ identity = np.eye(2, dtype=complex)
233
357
  for g in range(num_gates):
234
358
  target = int(tokens[i])
235
- i = i + 1
359
+ i += 1
236
360
 
237
361
  control_count = int(tokens[i])
238
- i = i + 1
362
+ i += 1
239
363
  controls = []
240
364
  for j in range(control_count):
241
365
  controls.append(int(tokens[i]))
242
- i = i + 1
366
+ i += 1
243
367
 
244
368
  payload_count = int(tokens[i])
245
- i = i + 1
369
+ i += 1
246
370
  payloads = {}
247
371
  for j in range(payload_count):
248
372
  key = int(tokens[i])
249
- i = i + 1
250
- op = np.zeros((2,2), dtype=complex)
251
- row = []
252
- for _ in range(2):
253
- amp = tokens[i].replace("(","").replace(")","").split(',')
254
- row.append(float(amp[0]) + float(amp[1])*1j)
255
- i = i + 1
256
- l = math.sqrt(np.real(row[0] * np.conj(row[0]) + row[1] * np.conj(row[1])))
257
- op[0][0] = row[0] / l
258
- op[0][1] = row[1] / l
259
-
260
- if np.abs(op[0][0] - row[0]) > 1e-5:
261
- print("Warning: gate ", str(g), ", payload ", str(j), " might not be unitary!")
262
- if np.abs(op[0][1] - row[1]) > 1e-5:
263
- print("Warning: gate ", str(g), ", payload ", str(j), " might not be unitary!")
264
-
265
- row = []
266
- for _ in range(2):
267
- amp = tokens[i].replace("(","").replace(")","").split(',')
268
- row.append(float(amp[0]) + float(amp[1])*1j)
269
- i = i + 1
270
- l = math.sqrt(np.real(row[0] * np.conj(row[0]) + row[1] * np.conj(row[1])))
271
- op[1][0] = row[0] / l
272
- op[1][1] = row[1] / l
273
-
274
- ph = np.real(np.log(np.linalg.det(op)) / 1j)
275
-
276
- op[1][0] = -np.exp(1j * ph) * np.conj(op[0][1])
277
- op[1][1] = np.exp(1j * ph) * np.conj(op[0][0])
278
-
279
- if np.abs(op[1][0] - row[0]) > 1e-5:
280
- print("Warning: gate ", str(g), ", payload ", str(j), " might not be unitary!")
281
- if np.abs(op[1][1] - row[1]) > 1e-5:
282
- print("Warning: gate ", str(g), ", payload ", str(j), " might not be unitary!")
283
-
284
- # Qiskit has a lower tolerance for deviation from numerically unitary.
285
- payloads[key] = np.array(op)
373
+ i += 1
374
+
375
+ mtrx = []
376
+ for _ in range(4):
377
+ amp = tokens[i].replace("(", "").replace(")", "").split(",")
378
+ mtrx.append(float(amp[0]) + float(amp[1]) * 1j)
379
+ i += 1
380
+
381
+ mtrx = QrackCircuit._make_mtrx_unitary(mtrx)
382
+
383
+ op = np.eye(2, dtype=complex)
384
+ op[0][0] = mtrx[0]
385
+ op[0][1] = mtrx[1]
386
+ op[1][0] = mtrx[2]
387
+ op[1][1] = mtrx[3]
388
+
389
+ payloads[key] = op
286
390
 
287
391
  gate_list = []
288
392
  for j in range(1 << control_count):
289
393
  if j in payloads:
290
394
  gate_list.append(payloads[j])
291
395
  else:
292
- gate_list.append(np.array([[1, 0],[0, 1]]))
293
-
294
- circ.uc(gate_list, controls, target)
396
+ gate_list.append(identity)
397
+ circ.append(UCGate(gate_list), [target] + controls)
295
398
 
296
399
  return circ
297
400
 
@@ -313,31 +416,30 @@ class QrackCircuit:
313
416
  )
314
417
 
315
418
  out = QrackCircuit()
316
-
317
- basis_gates = ["u", "cx"]
318
- circ = transpile(circ, basis_gates=basis_gates, optimization_level=3)
419
+ basis_gates = ["x", "y", "z", "u", "cx", "cy", "cz", "cu"]
420
+ circ = transpile(circ, basis_gates=basis_gates, optimization_level=0)
319
421
  for gate in circ.data:
320
422
  o = gate.operation
321
- if o.name == "u":
322
- th = float(o.params[0])
323
- ph = float(o.params[1])
324
- lm = float(o.params[2])
325
423
 
326
- c = math.cos(th / 2)
327
- s = math.sin(th / 2)
424
+ op = []
425
+ if o.name in ["x", "cx"]:
426
+ op = [0, 1, 1, 0]
427
+ elif o.name in ["y", "cy"]:
428
+ op = [0, -1j, 1j, 0]
429
+ elif o.name in ["z", "cz"]:
430
+ op = [1, 0, 0, -1]
431
+ else:
432
+ op = QrackCircuit._u3_to_mtrx(o.params)
328
433
 
329
- op = [
330
- c + 0j,
331
- -np.exp(1j * lm) * s,
332
- np.exp(1j * ph) * s,
333
- np.exp(1j * (ph + lm)) * c
334
- ]
434
+ if o.name in ["x", "y", "z", "u"]:
335
435
  out.mtrx(op, circ.find_bit(gate.qubits[0])[0])
336
436
  else:
337
- ctrls = []
338
- for c in gate.qubits[0:1]:
339
- ctrls.append(circ.find_bit(c)[0])
340
- out.ucmtrx(ctrls, [0, 1, 1, 0], circ.find_bit(gate.qubits[1])[0], 1)
437
+ out.ucmtrx(
438
+ [circ.find_bit(gate.qubits[0])[0]],
439
+ op,
440
+ circ.find_bit(gate.qubits[1])[0],
441
+ 1,
442
+ )
341
443
 
342
444
  return out
343
445
 
@@ -347,9 +449,9 @@ class QrackCircuit:
347
449
  psi0=None,
348
450
  gate_opts=None,
349
451
  tags=None,
350
- psi0_dtype='complex128',
351
- psi0_tag='PSI0',
352
- bra_site_ind_id='b{}'
452
+ psi0_dtype="complex128",
453
+ psi0_tag="PSI0",
454
+ bra_site_ind_id="b{}",
353
455
  ):
354
456
  """Convert an output file to a Quimb circuit
355
457
 
@@ -380,25 +482,32 @@ class QrackCircuit:
380
482
  basis_gates = ["u", "cx"]
381
483
  qcirc = transpile(qcirc, basis_gates=basis_gates, optimization_level=3)
382
484
 
383
- tcirc = qtn.Circuit(
384
- N=qcirc.num_qubits,
385
- psi0=psi0,
386
- gate_opts=gate_opts,
387
- tags=tags,
388
- psi0_dtype=psi0_dtype,
389
- psi0_tag=psi0_tag,
390
- bra_site_ind_id=bra_site_ind_id
391
- ) if circuit_type == QuimbCircuitType.Circuit else (
392
- qtn.CircuitDense(N=qcirc.num_qubits, psi0=psi0, gate_opts=gate_opts, tags=tags) if circuit_type == QuimbCircuitType.CircuitDense else
393
- qtn.CircuitMPS(
485
+ tcirc = (
486
+ qtn.Circuit(
487
+ N=qcirc.num_qubits,
488
+ psi0=psi0,
489
+ gate_opts=gate_opts,
490
+ tags=tags,
491
+ psi0_dtype=psi0_dtype,
492
+ psi0_tag=psi0_tag,
493
+ bra_site_ind_id=bra_site_ind_id,
494
+ )
495
+ if circuit_type == QuimbCircuitType.Circuit
496
+ else (
497
+ qtn.CircuitDense(
498
+ N=qcirc.num_qubits, psi0=psi0, gate_opts=gate_opts, tags=tags
499
+ )
500
+ if circuit_type == QuimbCircuitType.CircuitDense
501
+ else qtn.CircuitMPS(
394
502
  N=qcirc.num_qubits,
395
503
  psi0=psi0,
396
504
  gate_opts=gate_opts,
397
505
  tags=tags,
398
506
  psi0_dtype=psi0_dtype,
399
507
  psi0_tag=psi0_tag,
400
- bra_site_ind_id=bra_site_ind_id
508
+ bra_site_ind_id=bra_site_ind_id,
401
509
  )
510
+ )
402
511
  )
403
512
  for gate in qcirc.data:
404
513
  o = gate.operation
@@ -407,17 +516,18 @@ class QrackCircuit:
407
516
  ph = float(o.params[1])
408
517
  lm = float(o.params[2])
409
518
 
410
- tcirc.apply_gate('U3', th, ph, lm, qcirc.find_bit(gate.qubits[0])[0])
519
+ tcirc.apply_gate("U3", th, ph, lm, qcirc.find_bit(gate.qubits[0])[0])
411
520
  else:
412
- tcirc.apply_gate('CNOT', qcirc.find_bit(gate.qubits[0])[0], qcirc.find_bit(gate.qubits[1])[0])
521
+ tcirc.apply_gate(
522
+ "CNOT",
523
+ qcirc.find_bit(gate.qubits[0])[0],
524
+ qcirc.find_bit(gate.qubits[1])[0],
525
+ )
413
526
 
414
527
  return tcirc
415
528
 
416
529
  def file_to_tensorcircuit(
417
- filename,
418
- inputs=None,
419
- circuit_params=None,
420
- binding_params=None
530
+ filename, inputs=None, circuit_params=None, binding_params=None
421
531
  ):
422
532
  """Convert an output file to a TensorCircuit circuit
423
533
 
@@ -444,9 +554,11 @@ class QrackCircuit:
444
554
  basis_gates = ["u", "cx"]
445
555
  qcirc = transpile(qcirc, basis_gates=basis_gates, optimization_level=3)
446
556
 
447
- return tc.Circuit.from_qiskit(qcirc, qcirc.num_qubits, inputs, circuit_params, binding_params)
557
+ return tc.Circuit.from_qiskit(
558
+ qcirc, qcirc.num_qubits, inputs, circuit_params, binding_params
559
+ )
448
560
 
449
- def in_from_tensorcircuit(tcirc, enable_instruction = False, enable_inputs = False):
561
+ def in_from_tensorcircuit(tcirc, enable_instruction=False, enable_inputs=False):
450
562
  """Convert a TensorCircuit circuit to a QrackCircuit
451
563
 
452
564
  Accepts a TensorCircuit circuit and outputs an equivalent QrackCircuit
pyqrack/qrack_neuron.py CHANGED
@@ -1,4 +1,4 @@
1
- # (C) Daniel Strano and the Qrack contributors 2017-2023. All rights reserved.
1
+ # (C) Daniel Strano and the Qrack contributors 2017-2025. All rights reserved.
2
2
  #
3
3
  # Use of this source code is governed by an MIT-style license that can be
4
4
  # found in the LICENSE file or at https://opensource.org/licenses/MIT.
@@ -9,6 +9,7 @@ import sys
9
9
  from .qrack_system import Qrack
10
10
  from .neuron_activation_fn import NeuronActivationFn
11
11
 
12
+
12
13
  class QrackNeuron:
13
14
  """Class that exposes the QNeuron class of Qrack
14
15
 
@@ -45,10 +46,10 @@ class QrackNeuron:
45
46
  simulator,
46
47
  controls,
47
48
  target,
48
- activation_fn = NeuronActivationFn.Sigmoid,
49
- alpha = 1.0,
50
- tolerance = sys.float_info.epsilon,
51
- _init = True
49
+ activation_fn=NeuronActivationFn.Sigmoid,
50
+ alpha=1.0,
51
+ tolerance=sys.float_info.epsilon,
52
+ _init=True,
52
53
  ):
53
54
  self.simulator = simulator
54
55
  self.controls = controls
@@ -60,7 +61,15 @@ class QrackNeuron:
60
61
  if not _init:
61
62
  return
62
63
 
63
- self.nid = Qrack.qrack_lib.init_qneuron(simulator.sid, len(controls), self._ulonglong_byref(controls), target, activation_fn, alpha, tolerance)
64
+ self.nid = Qrack.qrack_lib.init_qneuron(
65
+ simulator.sid,
66
+ len(controls),
67
+ self._ulonglong_byref(controls),
68
+ target,
69
+ activation_fn,
70
+ alpha,
71
+ tolerance,
72
+ )
64
73
 
65
74
  self._throw_if_error()
66
75
 
@@ -78,7 +87,14 @@ class QrackNeuron:
78
87
  Raises:
79
88
  RuntimeError: QrackNeuron C++ library raised an exception.
80
89
  """
81
- result = QrackNeuron(self.simulator, self.controls, self.target, self.activation_fn, self.alpha, self.tolerance)
90
+ result = QrackNeuron(
91
+ self.simulator,
92
+ self.controls,
93
+ self.target,
94
+ self.activation_fn,
95
+ self.alpha,
96
+ self.tolerance,
97
+ )
82
98
  self.nid = Qrack.qrack_lib.clone_qneuron(self.simulator.sid)
83
99
  self._throw_if_error()
84
100
  return result
@@ -106,7 +122,9 @@ class QrackNeuron:
106
122
  RuntimeError: QrackSimulator raised an exception.
107
123
  """
108
124
  if len(a) < (1 << len(self.controls)):
109
- raise ValueError("Angles 'a' in QrackNeuron.set_angles() must contain at least (2 ** len(self.controls)) elements.")
125
+ raise ValueError(
126
+ "Angles 'a' in QrackNeuron.set_angles() must contain at least (2 ** len(self.controls)) elements."
127
+ )
110
128
  Qrack.qrack_lib.set_qneuron_angles(self.nid, self._real1_byref(a))
111
129
  self._throw_if_error()
112
130
 
@@ -144,7 +162,7 @@ class QrackNeuron:
144
162
 
145
163
  Nonlinear activation functions can be important to neural net
146
164
  applications, like DNN. The available activation functions are
147
- enumerated in `NeuronActivationFn`.
165
+ enumerated in `NeuronActivationFn`.
148
166
 
149
167
  Raises:
150
168
  RuntimeError: QrackNeuron C++ library raised an exception.