pyqrack-cuda 1.27.0__py3-none-manylinux_2_35_x86_64.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.
@@ -0,0 +1,246 @@
1
+ # (C) Daniel Strano and the Qrack contributors 2017-2023. All rights reserved.
2
+ #
3
+ # Use of this source code is governed by an MIT-style license that can be
4
+ # found in the LICENSE file or at https://opensource.org/licenses/MIT.
5
+
6
+ import ctypes
7
+ import sys
8
+
9
+ from .qrack_system import Qrack
10
+ from .neuron_activation_fn import NeuronActivationFn
11
+
12
+ class QrackNeuron:
13
+ """Class that exposes the QNeuron class of Qrack
14
+
15
+ This model of a "quantum neuron" is based on the concept of a "uniformly controlled"
16
+ rotation of a single output qubit around the Pauli Y axis, and has been developed by
17
+ others. In our case, the primary relevant gate could also be called a
18
+ single-qubit-target multiplexer.
19
+
20
+ (See https://arxiv.org/abs/quant-ph/0407010 for an introduction to "uniformly controlled
21
+ gates.)
22
+
23
+ QrackNeuron is meant to be interchangeable with a single classical neuron, as in
24
+ conventional neural net software. It differs from classical neurons in conventional
25
+ neural nets, in that the "synaptic cleft" is modelled as a single qubit. Hence, this
26
+ neuron can train and predict in superposition.
27
+
28
+ Attributes:
29
+ nid(int): Qrack ID of this neuron
30
+ simulator(QrackSimulator): Simulator instance for all synaptic clefts of the neuron
31
+ controls(list(int)): Indices of all "control" qubits, for neuron input
32
+ target(int): Index of "target" qubit, for neuron output
33
+ tolerance(double): Rounding tolerance
34
+ """
35
+
36
+ def _get_error(self):
37
+ return Qrack.qrack_lib.get_error(self.simulator.sid)
38
+
39
+ def _throw_if_error(self):
40
+ if self._get_error() != 0:
41
+ raise RuntimeError("QrackNeuron C++ library raised exception.")
42
+
43
+ def __init__(
44
+ self,
45
+ simulator,
46
+ controls,
47
+ target,
48
+ activation_fn = NeuronActivationFn.Sigmoid,
49
+ alpha = 1.0,
50
+ tolerance = sys.float_info.epsilon,
51
+ _init = True
52
+ ):
53
+ self.simulator = simulator
54
+ self.controls = controls
55
+ self.target = target
56
+ self.activation_fn = activation_fn
57
+ self.alpha = alpha
58
+ self.tolerance = tolerance
59
+
60
+ self.amp_count = 1 << (len(controls) + 1)
61
+
62
+ if not _init:
63
+ return
64
+
65
+ self.nid = Qrack.qrack_lib.init_qneuron(simulator.sid, len(controls), self._ulonglong_byref(controls), target, activation_fn, alpha, tolerance)
66
+
67
+ self._throw_if_error()
68
+
69
+ def __del__(self):
70
+ if self.nid is not None:
71
+ Qrack.qrack_lib.destroy_qneuron(self.nid)
72
+ self.nid = None
73
+
74
+ def clone(self):
75
+ """Clones this neuron.
76
+
77
+ Create a new, independent neuron instance with identical angles,
78
+ inputs, output, and tolerance, for the same QrackSimulator.
79
+
80
+ Raises:
81
+ RuntimeError: QrackNeuron C++ library raised an exception.
82
+ """
83
+ result = QrackNeuron(self.simulator, self.controls, self.target, self.activation_fn, self.alpha, self.tolerance)
84
+ self.nid = Qrack.qrack_lib.clone_qneuron(self.simulator.sid)
85
+ self._throw_if_error()
86
+ return result
87
+
88
+ def _ulonglong_byref(self, a):
89
+ return (ctypes.c_ulonglong * len(a))(*a)
90
+
91
+ def _real1_byref(self, a):
92
+ # This needs to be c_double, if PyQrack is built with fp64.
93
+ if Qrack.fppow < 6:
94
+ return (ctypes.c_float * len(a))(*a)
95
+ return (ctypes.c_double * len(a))(*a)
96
+
97
+ def set_angles(self, a):
98
+ """Directly sets the neuron parameters.
99
+
100
+ Set all synaptic parameters of the neuron directly, by a list
101
+ enumerated over the integer permutations of input qubits.
102
+
103
+ Args:
104
+ a(list(double)): List of input permutation angles
105
+
106
+ Raises:
107
+ ValueError: Angles 'a' in QrackNeuron.set_angles() must contain at least (2 ** len(self.controls)) elements.
108
+ RuntimeError: QrackSimulator raised an exception.
109
+ """
110
+ if len(a) < (1 << len(self.controls)):
111
+ raise ValueError("Angles 'a' in QrackNeuron.set_angles() must contain at least (2 ** len(self.controls)) elements.")
112
+ Qrack.qrack_lib.set_qneuron_angles(self.nid, self._real1_byref(a))
113
+ self._throw_if_error()
114
+
115
+ def get_angles(self):
116
+ """Directly gets the neuron parameters.
117
+
118
+ Get all synaptic parameters of the neuron directly, as a list
119
+ enumerated over the integer permutations of input qubits.
120
+
121
+ Raises:
122
+ RuntimeError: QrackNeuron C++ library raised an exception.
123
+ """
124
+ ket = self._real1_byref([0.0] * self.amp_count)
125
+ Qrack.qrack_lib.get_qneuron_angles(self.nid, ket)
126
+ self._throw_if_error()
127
+ return list(ket)
128
+
129
+ def set_alpha(self, a):
130
+ """Set the neuron 'alpha' parameter.
131
+
132
+ To enable nonlinear activation, `QrackNeuron` has an 'alpha'
133
+ parameter that is applied as a power to its angles, before
134
+ learning and prediction. This makes the activation function
135
+ sharper (or less sharp).
136
+
137
+ Raises:
138
+ RuntimeError: QrackNeuron C++ library raised an exception.
139
+ """
140
+ self.alpha = a
141
+ Qrack.qrack_lib.set_qneuron_alpha(self.nid, a)
142
+ self._throw_if_error()
143
+
144
+ def set_activation_fn(self, f):
145
+ """Sets the activation function of this QrackNeuron
146
+
147
+ Nonlinear activation functions can be important to neural net
148
+ applications, like DNN. The available activation functions are
149
+ enumerated in `NeuronActivationFn`.
150
+
151
+ Raises:
152
+ RuntimeError: QrackNeuron C++ library raised an exception.
153
+ """
154
+ self.activation_fn = f
155
+ Qrack.qrack_lib.set_qneuron_activation_fn(self.nid, f)
156
+ self._throw_if_error()
157
+
158
+ def predict(self, e=True, r=True):
159
+ """Predict based on training
160
+
161
+ "Predict" the anticipated output, based on input and training.
162
+ By default, "predict()" will initialize the output qubit as by
163
+ resetting to |0> and then acting a Hadamard gate. From that
164
+ state, the method amends the output qubit upon the basis of
165
+ the state of its input qubits, applying a rotation around
166
+ Pauli Y axis according to the angle learned for the input.
167
+
168
+ Args:
169
+ e(bool): If False, predict the opposite
170
+ r(bool): If True, start by resetting the output to 50/50
171
+
172
+ Raises:
173
+ RuntimeError: QrackNeuron C++ library raised an exception.
174
+ """
175
+ result = Qrack.qrack_lib.qneuron_predict(self.nid, e, r)
176
+ self._throw_if_error()
177
+ return result
178
+
179
+ def unpredict(self, e=True):
180
+ """Uncompute a prediction
181
+
182
+ Uncompute a 'prediction' of the anticipated output, based on
183
+ input and training.
184
+
185
+ Args:
186
+ e(bool): If False, unpredict the opposite
187
+
188
+ Raises:
189
+ RuntimeError: QrackNeuron C++ library raised an exception.
190
+ """
191
+ result = Qrack.qrack_lib.qneuron_unpredict(self.nid, e)
192
+ self._throw_if_error()
193
+ return result
194
+
195
+ def learn_cycle(self, e=True):
196
+ """Run a learning cycle
197
+
198
+ A learning cycle consists of predicting a result, saving the
199
+ classical outcome, and uncomputing the prediction.
200
+
201
+ Args:
202
+ e(bool): If False, predict the opposite
203
+
204
+ Raises:
205
+ RuntimeError: QrackNeuron C++ library raised an exception.
206
+ """
207
+ Qrack.qrack_lib.qneuron_learn_cycle(self.nid, e)
208
+ self._throw_if_error()
209
+
210
+ def learn(self, eta, e=True, r=True):
211
+ """Learn from current qubit state
212
+
213
+ "Learn" to associate current inputs with output. Based on
214
+ input qubit states and volatility 'eta,' the input state
215
+ synaptic parameter is updated to prefer the "e" ("expected")
216
+ output.
217
+
218
+ Args:
219
+ eta(double): Training volatility, 0 to 1
220
+ e(bool): If False, predict the opposite
221
+ r(bool): If True, start by resetting the output to 50/50
222
+
223
+ Raises:
224
+ RuntimeError: QrackNeuron C++ library raised an exception.
225
+ """
226
+ Qrack.qrack_lib.qneuron_learn(self.nid, eta, e, r)
227
+ self._throw_if_error()
228
+
229
+ def learn_permutation(self, eta, e=True, r=True):
230
+ """Learn from current classical state
231
+
232
+ Learn to associate current inputs with output, under the
233
+ assumption that the inputs and outputs are "classical."
234
+ Based on input qubit states and volatility 'eta,' the input
235
+ state angle is updated to prefer the "e" ("expected") output.
236
+
237
+ Args:
238
+ eta(double): Training volatility, 0 to 1
239
+ e(bool): If False, predict the opposite
240
+ r(bool): If True, start by resetting the output to 50/50
241
+
242
+ Raises:
243
+ RuntimeError: QrackNeuron C++ library raised an exception.
244
+ """
245
+ Qrack.qrack_lib.qneuron_learn_permutation(self.nid, eta, e, r)
246
+ self._throw_if_error()