pyqrack-cpu 1.44.8__py3-none-win_amd64.whl → 1.44.9__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.
Potentially problematic release.
This version of pyqrack-cpu might be problematic. Click here for more details.
- pyqrack/__init__.py +5 -1
- pyqrack/neuron_activation_fn.py +1 -1
- pyqrack/qrack_ace_backend.py +77 -100
- pyqrack/qrack_circuit.py +67 -39
- pyqrack/qrack_neuron.py +25 -8
- pyqrack/qrack_neuron_torch_layer.py +46 -19
- pyqrack/qrack_simulator.py +547 -211
- pyqrack/qrack_stabilizer.py +1 -2
- pyqrack/qrack_system/qrack_lib/qrack_pinvoke.dll +0 -0
- pyqrack/qrack_system/qrack_system.py +161 -119
- pyqrack/stats/load_quantized_data.py +3 -1
- pyqrack/stats/quantize_by_range.py +9 -4
- {pyqrack_cpu-1.44.8.dist-info → pyqrack_cpu-1.44.9.dist-info}/METADATA +1 -1
- pyqrack_cpu-1.44.9.dist-info/RECORD +21 -0
- pyqrack_cpu-1.44.8.dist-info/RECORD +0 -21
- {pyqrack_cpu-1.44.8.dist-info → pyqrack_cpu-1.44.9.dist-info}/LICENSE +0 -0
- {pyqrack_cpu-1.44.8.dist-info → pyqrack_cpu-1.44.9.dist-info}/WHEEL +0 -0
- {pyqrack_cpu-1.44.8.dist-info → pyqrack_cpu-1.44.9.dist-info}/top_level.txt +0 -0
pyqrack/qrack_circuit.py
CHANGED
|
@@ -45,13 +45,22 @@ class QrackCircuit:
|
|
|
45
45
|
cid(int): Qrack ID of this circuit
|
|
46
46
|
"""
|
|
47
47
|
|
|
48
|
-
def __init__(
|
|
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
|
+
):
|
|
49
56
|
if clone_cid < 0:
|
|
50
57
|
self.cid = Qrack.qrack_lib.init_qcircuit(is_collapse, is_near_clifford)
|
|
51
58
|
elif is_inverse:
|
|
52
59
|
self.cid = Qrack.qrack_lib.qcircuit_inverse(clone_cid)
|
|
53
60
|
elif len(past_light_cone) > 0:
|
|
54
|
-
self.cid = Qrack.qrack_lib.qcircuit_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
|
+
)
|
|
55
64
|
else:
|
|
56
65
|
self.cid = Qrack.qrack_lib.init_qcircuit_clone(clone_cid)
|
|
57
66
|
|
|
@@ -74,7 +83,7 @@ class QrackCircuit:
|
|
|
74
83
|
nrm = abs(m[0])
|
|
75
84
|
if (nrm * nrm) < sys.float_info.epsilon:
|
|
76
85
|
phase = 1.0 + 0.0j
|
|
77
|
-
th = math.pi
|
|
86
|
+
th = math.pi
|
|
78
87
|
else:
|
|
79
88
|
phase = m[0] / nrm
|
|
80
89
|
if nrm > 1.0:
|
|
@@ -123,7 +132,7 @@ class QrackCircuit:
|
|
|
123
132
|
Raises:
|
|
124
133
|
RuntimeError: QrackCircuit C++ library raised an exception.
|
|
125
134
|
"""
|
|
126
|
-
return QrackCircuit(clone_cid
|
|
135
|
+
return QrackCircuit(clone_cid=self.cid, is_inverse=False)
|
|
127
136
|
|
|
128
137
|
def inverse(self):
|
|
129
138
|
"""Make a new circuit that is the exact inverse of this circuit
|
|
@@ -131,7 +140,7 @@ class QrackCircuit:
|
|
|
131
140
|
Raises:
|
|
132
141
|
RuntimeError: QrackCircuit C++ library raised an exception.
|
|
133
142
|
"""
|
|
134
|
-
return QrackCircuit(clone_cid
|
|
143
|
+
return QrackCircuit(clone_cid=self.cid, is_inverse=True)
|
|
135
144
|
|
|
136
145
|
def past_light_cone(self, q):
|
|
137
146
|
"""Make a new circuit with just this circuits' past light cone for certain qubits.
|
|
@@ -142,7 +151,7 @@ class QrackCircuit:
|
|
|
142
151
|
Raises:
|
|
143
152
|
RuntimeError: QrackCircuit C++ library raised an exception.
|
|
144
153
|
"""
|
|
145
|
-
return QrackCircuit(clone_cid
|
|
154
|
+
return QrackCircuit(clone_cid=self.cid, is_inverse=False, past_light_cone=q)
|
|
146
155
|
|
|
147
156
|
def get_qubit_count(self):
|
|
148
157
|
"""Get count of qubits in circuit
|
|
@@ -178,7 +187,9 @@ class QrackCircuit:
|
|
|
178
187
|
RuntimeError: QrackSimulator raised an exception.
|
|
179
188
|
"""
|
|
180
189
|
if len(m) < 4:
|
|
181
|
-
raise ValueError(
|
|
190
|
+
raise ValueError(
|
|
191
|
+
"2x2 matrix 'm' in QrackCircuit.mtrx() must contain at least 4 elements."
|
|
192
|
+
)
|
|
182
193
|
Qrack.qrack_lib.qcircuit_append_1qb(self.cid, self._complex_byref(m), q)
|
|
183
194
|
|
|
184
195
|
def ucmtrx(self, c, m, q, p):
|
|
@@ -199,7 +210,9 @@ class QrackCircuit:
|
|
|
199
210
|
RuntimeError: QrackSimulator raised an exception.
|
|
200
211
|
"""
|
|
201
212
|
if len(m) < 4:
|
|
202
|
-
raise ValueError(
|
|
213
|
+
raise ValueError(
|
|
214
|
+
"2x2 matrix 'm' in QrackCircuit.ucmtrx() must contain at least 4 elements."
|
|
215
|
+
)
|
|
203
216
|
Qrack.qrack_lib.qcircuit_append_mc(
|
|
204
217
|
self.cid, self._complex_byref(m), len(c), self._ulonglong_byref(c), q, p
|
|
205
218
|
)
|
|
@@ -233,7 +246,7 @@ class QrackCircuit:
|
|
|
233
246
|
Args:
|
|
234
247
|
filename: Name of file
|
|
235
248
|
"""
|
|
236
|
-
Qrack.qrack_lib.qcircuit_out_to_file(self.cid, filename.encode(
|
|
249
|
+
Qrack.qrack_lib.qcircuit_out_to_file(self.cid, filename.encode("utf-8"))
|
|
237
250
|
|
|
238
251
|
def in_from_file(filename):
|
|
239
252
|
"""Read in optimized circuit from file
|
|
@@ -245,7 +258,7 @@ class QrackCircuit:
|
|
|
245
258
|
filename: Name of file
|
|
246
259
|
"""
|
|
247
260
|
out = QrackCircuit()
|
|
248
|
-
Qrack.qrack_lib.qcircuit_in_from_file(out.cid, filename.encode(
|
|
261
|
+
Qrack.qrack_lib.qcircuit_in_from_file(out.cid, filename.encode("utf-8"))
|
|
249
262
|
|
|
250
263
|
return out
|
|
251
264
|
|
|
@@ -269,7 +282,7 @@ class QrackCircuit:
|
|
|
269
282
|
filename: Name of file
|
|
270
283
|
"""
|
|
271
284
|
tokens = []
|
|
272
|
-
with open(filename,
|
|
285
|
+
with open(filename, "r") as file:
|
|
273
286
|
tokens = file.read().split()
|
|
274
287
|
return int(tokens[1])
|
|
275
288
|
|
|
@@ -309,7 +322,7 @@ class QrackCircuit:
|
|
|
309
322
|
)
|
|
310
323
|
|
|
311
324
|
tokens = []
|
|
312
|
-
with open(filename,
|
|
325
|
+
with open(filename, "r") as file:
|
|
313
326
|
return QrackCircuit.string_to_qiskit_circuit(file.read())
|
|
314
327
|
|
|
315
328
|
def string_to_qiskit_circuit(circ_string):
|
|
@@ -361,8 +374,8 @@ class QrackCircuit:
|
|
|
361
374
|
|
|
362
375
|
mtrx = []
|
|
363
376
|
for _ in range(4):
|
|
364
|
-
amp = tokens[i].replace("(","").replace(")","").split(
|
|
365
|
-
mtrx.append(float(amp[0]) + float(amp[1])*1j)
|
|
377
|
+
amp = tokens[i].replace("(", "").replace(")", "").split(",")
|
|
378
|
+
mtrx.append(float(amp[0]) + float(amp[1]) * 1j)
|
|
366
379
|
i += 1
|
|
367
380
|
|
|
368
381
|
mtrx = QrackCircuit._make_mtrx_unitary(mtrx)
|
|
@@ -375,7 +388,7 @@ class QrackCircuit:
|
|
|
375
388
|
|
|
376
389
|
payloads[key] = op
|
|
377
390
|
|
|
378
|
-
gate_list=[]
|
|
391
|
+
gate_list = []
|
|
379
392
|
for j in range(1 << control_count):
|
|
380
393
|
if j in payloads:
|
|
381
394
|
gate_list.append(payloads[j])
|
|
@@ -421,7 +434,12 @@ class QrackCircuit:
|
|
|
421
434
|
if o.name in ["x", "y", "z", "u"]:
|
|
422
435
|
out.mtrx(op, circ.find_bit(gate.qubits[0])[0])
|
|
423
436
|
else:
|
|
424
|
-
out.ucmtrx(
|
|
437
|
+
out.ucmtrx(
|
|
438
|
+
[circ.find_bit(gate.qubits[0])[0]],
|
|
439
|
+
op,
|
|
440
|
+
circ.find_bit(gate.qubits[1])[0],
|
|
441
|
+
1,
|
|
442
|
+
)
|
|
425
443
|
|
|
426
444
|
return out
|
|
427
445
|
|
|
@@ -431,9 +449,9 @@ class QrackCircuit:
|
|
|
431
449
|
psi0=None,
|
|
432
450
|
gate_opts=None,
|
|
433
451
|
tags=None,
|
|
434
|
-
psi0_dtype=
|
|
435
|
-
psi0_tag=
|
|
436
|
-
bra_site_ind_id=
|
|
452
|
+
psi0_dtype="complex128",
|
|
453
|
+
psi0_tag="PSI0",
|
|
454
|
+
bra_site_ind_id="b{}",
|
|
437
455
|
):
|
|
438
456
|
"""Convert an output file to a Quimb circuit
|
|
439
457
|
|
|
@@ -464,25 +482,32 @@ class QrackCircuit:
|
|
|
464
482
|
basis_gates = ["u", "cx"]
|
|
465
483
|
qcirc = transpile(qcirc, basis_gates=basis_gates, optimization_level=3)
|
|
466
484
|
|
|
467
|
-
tcirc =
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
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(
|
|
478
502
|
N=qcirc.num_qubits,
|
|
479
503
|
psi0=psi0,
|
|
480
504
|
gate_opts=gate_opts,
|
|
481
505
|
tags=tags,
|
|
482
506
|
psi0_dtype=psi0_dtype,
|
|
483
507
|
psi0_tag=psi0_tag,
|
|
484
|
-
bra_site_ind_id=bra_site_ind_id
|
|
508
|
+
bra_site_ind_id=bra_site_ind_id,
|
|
485
509
|
)
|
|
510
|
+
)
|
|
486
511
|
)
|
|
487
512
|
for gate in qcirc.data:
|
|
488
513
|
o = gate.operation
|
|
@@ -491,17 +516,18 @@ class QrackCircuit:
|
|
|
491
516
|
ph = float(o.params[1])
|
|
492
517
|
lm = float(o.params[2])
|
|
493
518
|
|
|
494
|
-
tcirc.apply_gate(
|
|
519
|
+
tcirc.apply_gate("U3", th, ph, lm, qcirc.find_bit(gate.qubits[0])[0])
|
|
495
520
|
else:
|
|
496
|
-
tcirc.apply_gate(
|
|
521
|
+
tcirc.apply_gate(
|
|
522
|
+
"CNOT",
|
|
523
|
+
qcirc.find_bit(gate.qubits[0])[0],
|
|
524
|
+
qcirc.find_bit(gate.qubits[1])[0],
|
|
525
|
+
)
|
|
497
526
|
|
|
498
527
|
return tcirc
|
|
499
528
|
|
|
500
529
|
def file_to_tensorcircuit(
|
|
501
|
-
filename,
|
|
502
|
-
inputs=None,
|
|
503
|
-
circuit_params=None,
|
|
504
|
-
binding_params=None
|
|
530
|
+
filename, inputs=None, circuit_params=None, binding_params=None
|
|
505
531
|
):
|
|
506
532
|
"""Convert an output file to a TensorCircuit circuit
|
|
507
533
|
|
|
@@ -528,9 +554,11 @@ class QrackCircuit:
|
|
|
528
554
|
basis_gates = ["u", "cx"]
|
|
529
555
|
qcirc = transpile(qcirc, basis_gates=basis_gates, optimization_level=3)
|
|
530
556
|
|
|
531
|
-
return tc.Circuit.from_qiskit(
|
|
557
|
+
return tc.Circuit.from_qiskit(
|
|
558
|
+
qcirc, qcirc.num_qubits, inputs, circuit_params, binding_params
|
|
559
|
+
)
|
|
532
560
|
|
|
533
|
-
def in_from_tensorcircuit(tcirc, enable_instruction
|
|
561
|
+
def in_from_tensorcircuit(tcirc, enable_instruction=False, enable_inputs=False):
|
|
534
562
|
"""Convert a TensorCircuit circuit to a QrackCircuit
|
|
535
563
|
|
|
536
564
|
Accepts a TensorCircuit circuit and outputs an equivalent QrackCircuit
|
pyqrack/qrack_neuron.py
CHANGED
|
@@ -46,10 +46,10 @@ class QrackNeuron:
|
|
|
46
46
|
simulator,
|
|
47
47
|
controls,
|
|
48
48
|
target,
|
|
49
|
-
activation_fn
|
|
50
|
-
alpha
|
|
51
|
-
tolerance
|
|
52
|
-
_init
|
|
49
|
+
activation_fn=NeuronActivationFn.Sigmoid,
|
|
50
|
+
alpha=1.0,
|
|
51
|
+
tolerance=sys.float_info.epsilon,
|
|
52
|
+
_init=True,
|
|
53
53
|
):
|
|
54
54
|
self.simulator = simulator
|
|
55
55
|
self.controls = controls
|
|
@@ -61,7 +61,15 @@ class QrackNeuron:
|
|
|
61
61
|
if not _init:
|
|
62
62
|
return
|
|
63
63
|
|
|
64
|
-
self.nid = Qrack.qrack_lib.init_qneuron(
|
|
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
|
+
)
|
|
65
73
|
|
|
66
74
|
self._throw_if_error()
|
|
67
75
|
|
|
@@ -79,7 +87,14 @@ class QrackNeuron:
|
|
|
79
87
|
Raises:
|
|
80
88
|
RuntimeError: QrackNeuron C++ library raised an exception.
|
|
81
89
|
"""
|
|
82
|
-
result = QrackNeuron(
|
|
90
|
+
result = QrackNeuron(
|
|
91
|
+
self.simulator,
|
|
92
|
+
self.controls,
|
|
93
|
+
self.target,
|
|
94
|
+
self.activation_fn,
|
|
95
|
+
self.alpha,
|
|
96
|
+
self.tolerance,
|
|
97
|
+
)
|
|
83
98
|
self.nid = Qrack.qrack_lib.clone_qneuron(self.simulator.sid)
|
|
84
99
|
self._throw_if_error()
|
|
85
100
|
return result
|
|
@@ -107,7 +122,9 @@ class QrackNeuron:
|
|
|
107
122
|
RuntimeError: QrackSimulator raised an exception.
|
|
108
123
|
"""
|
|
109
124
|
if len(a) < (1 << len(self.controls)):
|
|
110
|
-
raise ValueError(
|
|
125
|
+
raise ValueError(
|
|
126
|
+
"Angles 'a' in QrackNeuron.set_angles() must contain at least (2 ** len(self.controls)) elements."
|
|
127
|
+
)
|
|
111
128
|
Qrack.qrack_lib.set_qneuron_angles(self.nid, self._real1_byref(a))
|
|
112
129
|
self._throw_if_error()
|
|
113
130
|
|
|
@@ -145,7 +162,7 @@ class QrackNeuron:
|
|
|
145
162
|
|
|
146
163
|
Nonlinear activation functions can be important to neural net
|
|
147
164
|
applications, like DNN. The available activation functions are
|
|
148
|
-
enumerated in `NeuronActivationFn`.
|
|
165
|
+
enumerated in `NeuronActivationFn`.
|
|
149
166
|
|
|
150
167
|
Raises:
|
|
151
168
|
RuntimeError: QrackNeuron C++ library raised an exception.
|
|
@@ -24,7 +24,7 @@ from itertools import chain, combinations
|
|
|
24
24
|
def powerset(iterable):
|
|
25
25
|
"powerset([1,2,3]) --> () (1,) (2,) (3,) (1,2) (1,3) (2,3,) (1,2,3)"
|
|
26
26
|
s = list(iterable)
|
|
27
|
-
return chain.from_iterable(combinations(s, r) for r in range(len(s)+1))
|
|
27
|
+
return chain.from_iterable(combinations(s, r) for r in range(len(s) + 1))
|
|
28
28
|
|
|
29
29
|
|
|
30
30
|
class QrackTorchNeuron(nn.Module if _IS_TORCH_AVAILABLE else object):
|
|
@@ -33,6 +33,7 @@ class QrackTorchNeuron(nn.Module if _IS_TORCH_AVAILABLE else object):
|
|
|
33
33
|
Attributes:
|
|
34
34
|
neuron(QrackNeuron): QrackNeuron backing this torch wrapper
|
|
35
35
|
"""
|
|
36
|
+
|
|
36
37
|
def __init__(self, neuron: QrackNeuron):
|
|
37
38
|
super().__init__()
|
|
38
39
|
self.neuron = neuron
|
|
@@ -46,6 +47,7 @@ class QrackTorchNeuron(nn.Module if _IS_TORCH_AVAILABLE else object):
|
|
|
46
47
|
|
|
47
48
|
class QrackNeuronFunction(Function if _IS_TORCH_AVAILABLE else object):
|
|
48
49
|
"""Static forward/backward/apply functions for QrackTorchNeuron"""
|
|
50
|
+
|
|
49
51
|
@staticmethod
|
|
50
52
|
def forward(ctx, neuron):
|
|
51
53
|
# Save for backward
|
|
@@ -56,7 +58,11 @@ class QrackNeuronFunction(Function if _IS_TORCH_AVAILABLE else object):
|
|
|
56
58
|
final_prob = neuron.simulator.prob(neuron.target)
|
|
57
59
|
ctx.delta = final_prob - init_prob
|
|
58
60
|
|
|
59
|
-
return
|
|
61
|
+
return (
|
|
62
|
+
torch.tensor([ctx.delta], dtype=torch.float32)
|
|
63
|
+
if _IS_TORCH_AVAILABLE
|
|
64
|
+
else ctx.delta
|
|
65
|
+
)
|
|
60
66
|
|
|
61
67
|
@staticmethod
|
|
62
68
|
def backward(ctx, grad_output):
|
|
@@ -69,13 +75,22 @@ class QrackNeuronFunction(Function if _IS_TORCH_AVAILABLE else object):
|
|
|
69
75
|
|
|
70
76
|
grad = reverse_delta - ctx.delta
|
|
71
77
|
|
|
72
|
-
return
|
|
78
|
+
return (
|
|
79
|
+
torch.tensor([grad], dtype=torch.float32) if _IS_TORCH_AVAILABLE else grad
|
|
80
|
+
)
|
|
73
81
|
|
|
74
82
|
|
|
75
83
|
class QrackNeuronTorchLayer(nn.Module if _IS_TORCH_AVAILABLE else object):
|
|
76
84
|
"""Torch layer wrapper for QrackNeuron (with power set of neurons between inputs and outputs)"""
|
|
77
|
-
|
|
78
|
-
|
|
85
|
+
|
|
86
|
+
def __init__(
|
|
87
|
+
self,
|
|
88
|
+
simulator,
|
|
89
|
+
input_indices,
|
|
90
|
+
output_indices,
|
|
91
|
+
activation=int(NeuronActivationFn.Generalized_Logistic),
|
|
92
|
+
parameters=None,
|
|
93
|
+
):
|
|
79
94
|
"""
|
|
80
95
|
Initialize a QrackNeuron layer for PyTorch with a power set of neurons connecting inputs to outputs.
|
|
81
96
|
The inputs and outputs must take the form of discrete, binary features (loaded manually into the backing QrackSimulator)
|
|
@@ -92,26 +107,40 @@ class QrackNeuronTorchLayer(nn.Module if _IS_TORCH_AVAILABLE else object):
|
|
|
92
107
|
self.input_indices = input_indices
|
|
93
108
|
self.output_indices = output_indices
|
|
94
109
|
self.activation = NeuronActivationFn(activation)
|
|
95
|
-
self.fn =
|
|
110
|
+
self.fn = (
|
|
111
|
+
QrackNeuronFunction.apply
|
|
112
|
+
if _IS_TORCH_AVAILABLE
|
|
113
|
+
else lambda x: QrackNeuronFunction.forward(object(), x)
|
|
114
|
+
)
|
|
96
115
|
|
|
97
116
|
# Create neurons from all powerset input combinations, projecting to coherent output qubits
|
|
98
|
-
self.neurons = nn.ModuleList(
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
117
|
+
self.neurons = nn.ModuleList(
|
|
118
|
+
[
|
|
119
|
+
QrackTorchNeuron(
|
|
120
|
+
QrackNeuron(simulator, list(input_subset), output_id, activation)
|
|
121
|
+
)
|
|
122
|
+
for input_subset in powerset(input_indices)
|
|
123
|
+
for output_id in output_indices
|
|
124
|
+
]
|
|
125
|
+
)
|
|
103
126
|
|
|
104
127
|
# Set Qrack's internal parameters:
|
|
105
128
|
param_count = 0
|
|
106
129
|
for neuron_wrapper in self.neurons:
|
|
107
130
|
neuron = neuron_wrapper.neuron
|
|
108
131
|
p_count = 1 << len(neuron.controls)
|
|
109
|
-
neuron.set_angles(
|
|
132
|
+
neuron.set_angles(
|
|
133
|
+
parameters[param_count : (param_count + p_count + 1)]
|
|
134
|
+
if parameters
|
|
135
|
+
else ([0.0] * p_count)
|
|
136
|
+
)
|
|
110
137
|
param_count += p_count
|
|
111
138
|
|
|
112
139
|
self.weights = nn.ParameterList()
|
|
113
140
|
for pid in range(param_count):
|
|
114
|
-
self.weights.append(
|
|
141
|
+
self.weights.append(
|
|
142
|
+
nn.Parameter(torch.tensor(parameters[pid] if parameters else 0.0))
|
|
143
|
+
)
|
|
115
144
|
|
|
116
145
|
def forward(self, _):
|
|
117
146
|
# Assume quantum outputs should overwrite the simulator state
|
|
@@ -125,7 +154,9 @@ class QrackNeuronTorchLayer(nn.Module if _IS_TORCH_AVAILABLE else object):
|
|
|
125
154
|
for neuron_wrapper in self.neurons:
|
|
126
155
|
neuron = neuron_wrapper.neuron
|
|
127
156
|
p_count = 1 << len(neuron.controls)
|
|
128
|
-
angles = [
|
|
157
|
+
angles = [
|
|
158
|
+
w.item() for w in self.weights[param_count : (param_count + p_count)]
|
|
159
|
+
]
|
|
129
160
|
neuron.set_angles(angles)
|
|
130
161
|
param_count += p_count
|
|
131
162
|
|
|
@@ -134,10 +165,6 @@ class QrackNeuronTorchLayer(nn.Module if _IS_TORCH_AVAILABLE else object):
|
|
|
134
165
|
self.fn(neuron_wrapper.neuron)
|
|
135
166
|
|
|
136
167
|
# These are classical views over quantum state; simulator still maintains full coherence
|
|
137
|
-
outputs = [
|
|
138
|
-
self.simulator.prob(output_id)
|
|
139
|
-
for output_id in self.output_indices
|
|
140
|
-
]
|
|
168
|
+
outputs = [self.simulator.prob(output_id) for output_id in self.output_indices]
|
|
141
169
|
|
|
142
170
|
return torch.tensor(outputs, dtype=torch.float32)
|
|
143
|
-
|