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/__init__.py +13 -6
- pyqrack/neuron_activation_fn.py +2 -2
- pyqrack/pauli.py +1 -1
- pyqrack/qrack_ace_backend.py +1544 -0
- pyqrack/qrack_circuit.py +212 -100
- pyqrack/qrack_neuron.py +27 -9
- pyqrack/qrack_neuron_torch_layer.py +170 -0
- pyqrack/qrack_simulator.py +870 -310
- pyqrack/qrack_stabilizer.py +58 -0
- pyqrack/qrack_system/qrack_cl_precompile/qrack_cl_precompile.exe +0 -0
- pyqrack/qrack_system/qrack_lib/qrack_pinvoke.dll +0 -0
- pyqrack/qrack_system/qrack_system.py +228 -135
- pyqrack/quimb_circuit_type.py +1 -1
- pyqrack/stats/__init__.py +6 -0
- pyqrack/stats/load_quantized_data.py +35 -0
- pyqrack/stats/quantize_by_range.py +56 -0
- {pyqrack-1.29.0.dist-info → pyqrack-1.72.5.dist-info}/LICENSE +1 -1
- pyqrack-1.72.5.dist-info/METADATA +82 -0
- pyqrack-1.72.5.dist-info/RECORD +22 -0
- {pyqrack-1.29.0.dist-info → pyqrack-1.72.5.dist-info}/WHEEL +1 -1
- pyqrack/util/__init__.py +0 -8
- pyqrack/util/convert_qiskit_circuit_to_qasm_experiment.py +0 -61
- pyqrack-1.29.0.dist-info/METADATA +0 -61
- pyqrack-1.29.0.dist-info/RECORD +0 -17
- {pyqrack-1.29.0.dist-info → pyqrack-1.72.5.dist-info}/top_level.txt +0 -0
pyqrack/qrack_circuit.py
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# (C) Daniel Strano and the Qrack contributors 2017-
|
|
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__(
|
|
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(
|
|
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
|
|
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
|
|
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
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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,
|
|
223
|
-
|
|
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
|
|
350
|
+
i += 1
|
|
228
351
|
circ = QuantumCircuit(num_qubits)
|
|
229
352
|
|
|
230
353
|
num_gates = int(tokens[i])
|
|
231
|
-
i
|
|
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
|
|
359
|
+
i += 1
|
|
236
360
|
|
|
237
361
|
control_count = int(tokens[i])
|
|
238
|
-
i
|
|
362
|
+
i += 1
|
|
239
363
|
controls = []
|
|
240
364
|
for j in range(control_count):
|
|
241
365
|
controls.append(int(tokens[i]))
|
|
242
|
-
i
|
|
366
|
+
i += 1
|
|
243
367
|
|
|
244
368
|
payload_count = int(tokens[i])
|
|
245
|
-
i
|
|
369
|
+
i += 1
|
|
246
370
|
payloads = {}
|
|
247
371
|
for j in range(payload_count):
|
|
248
372
|
key = int(tokens[i])
|
|
249
|
-
i
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
for _ in range(
|
|
253
|
-
amp = tokens[i].replace("(","").replace(")","").split(
|
|
254
|
-
|
|
255
|
-
i
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
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(
|
|
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
|
-
|
|
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
|
-
|
|
327
|
-
|
|
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
|
-
|
|
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
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
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=
|
|
351
|
-
psi0_tag=
|
|
352
|
-
bra_site_ind_id=
|
|
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 =
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
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(
|
|
519
|
+
tcirc.apply_gate("U3", th, ph, lm, qcirc.find_bit(gate.qubits[0])[0])
|
|
411
520
|
else:
|
|
412
|
-
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
|
+
)
|
|
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(
|
|
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
|
|
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-
|
|
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
|
|
49
|
-
alpha
|
|
50
|
-
tolerance
|
|
51
|
-
_init
|
|
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(
|
|
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(
|
|
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(
|
|
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.
|