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.
- pyqrack/__init__.py +13 -0
- pyqrack/neuron_activation_fn.py +21 -0
- pyqrack/pauli.py +19 -0
- pyqrack/qrack_circuit.py +472 -0
- pyqrack/qrack_cl_precompile/Linux/2_35/qrack_cl_precompile +0 -0
- pyqrack/qrack_neuron.py +246 -0
- pyqrack/qrack_simulator.py +3530 -0
- pyqrack/qrack_system/__init__.py +9 -0
- pyqrack/qrack_system/qrack_lib/Linux/2_35/libqrack.a +0 -0
- pyqrack/qrack_system/qrack_lib/Linux/2_35/libqrack_pinvoke.so +0 -0
- pyqrack/qrack_system/qrack_lib/Linux/2_35/libqrack_pinvoke.so.9.6.0 +0 -0
- pyqrack/qrack_system/qrack_system.py +1063 -0
- pyqrack/quimb_circuit_type.py +17 -0
- pyqrack/util/__init__.py +8 -0
- pyqrack/util/convert_qiskit_circuit_to_qasm_experiment.py +61 -0
- pyqrack_cuda-1.27.0.dist-info/LICENSE +21 -0
- pyqrack_cuda-1.27.0.dist-info/METADATA +62 -0
- pyqrack_cuda-1.27.0.dist-info/RECORD +20 -0
- pyqrack_cuda-1.27.0.dist-info/WHEEL +5 -0
- pyqrack_cuda-1.27.0.dist-info/top_level.txt +1 -0
@@ -0,0 +1,3530 @@
|
|
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 copy
|
7
|
+
import ctypes
|
8
|
+
import math
|
9
|
+
import re
|
10
|
+
from .qrack_system import Qrack
|
11
|
+
from .pauli import Pauli
|
12
|
+
|
13
|
+
_IS_QISKIT_AVAILABLE = True
|
14
|
+
try:
|
15
|
+
from qiskit.circuit import QuantumRegister, Qubit
|
16
|
+
from qiskit.circuit.quantumcircuit import QuantumCircuit
|
17
|
+
from qiskit.compiler import transpile
|
18
|
+
from qiskit.qobj.qasm_qobj import QasmQobjExperiment
|
19
|
+
from qiskit.quantum_info.operators.symplectic.clifford import Clifford
|
20
|
+
from .util import convert_qiskit_circuit_to_qasm_experiment
|
21
|
+
except ImportError:
|
22
|
+
_IS_QISKIT_AVAILABLE = False
|
23
|
+
|
24
|
+
_IS_NUMPY_AVAILABLE = True
|
25
|
+
try:
|
26
|
+
import numpy as np
|
27
|
+
except:
|
28
|
+
_IS_NUMPY_AVAILABLE = False
|
29
|
+
|
30
|
+
|
31
|
+
class QrackSimulator:
|
32
|
+
"""Interface for all the QRack functionality.
|
33
|
+
|
34
|
+
Attributes:
|
35
|
+
qubitCount(int): Number of qubits that are to be simulated.
|
36
|
+
sid(int): Corresponding simulator id.
|
37
|
+
"""
|
38
|
+
|
39
|
+
def _get_error(self):
|
40
|
+
return Qrack.qrack_lib.get_error(self.sid)
|
41
|
+
|
42
|
+
def _throw_if_error(self):
|
43
|
+
if self._get_error() != 0:
|
44
|
+
raise RuntimeError("QrackSimulator C++ library raised exception.")
|
45
|
+
|
46
|
+
def __init__(
|
47
|
+
self,
|
48
|
+
qubitCount=-1,
|
49
|
+
cloneSid=-1,
|
50
|
+
isTensorNetwork=True,
|
51
|
+
isSchmidtDecomposeMulti=True,
|
52
|
+
isSchmidtDecompose=True,
|
53
|
+
isStabilizerHybrid=False,
|
54
|
+
isBinaryDecisionTree=False,
|
55
|
+
isPaged=True,
|
56
|
+
isCpuGpuHybrid=True,
|
57
|
+
isOpenCL=True,
|
58
|
+
isHostPointer=False,
|
59
|
+
pyzxCircuit=None,
|
60
|
+
qiskitCircuit=None,
|
61
|
+
):
|
62
|
+
self.sid = None
|
63
|
+
|
64
|
+
if pyzxCircuit is not None:
|
65
|
+
qubitCount = pyzxCircuit.qubits
|
66
|
+
elif qiskitCircuit is not None and qubitCount < 0:
|
67
|
+
raise RuntimeError(
|
68
|
+
"Must specify qubitCount with qiskitCircuit parameter in QrackSimulator constructor!"
|
69
|
+
)
|
70
|
+
|
71
|
+
if qubitCount > -1 and cloneSid > -1:
|
72
|
+
raise RuntimeError(
|
73
|
+
"Cannot clone a QrackSimulator and specify its qubit length at the same time, in QrackSimulator constructor!"
|
74
|
+
)
|
75
|
+
|
76
|
+
self.is_tensor_network = isTensorNetwork
|
77
|
+
|
78
|
+
if cloneSid > -1:
|
79
|
+
self.sid = Qrack.qrack_lib.init_clone(cloneSid)
|
80
|
+
else:
|
81
|
+
if qubitCount < 0:
|
82
|
+
qubitCount = 0
|
83
|
+
|
84
|
+
self.sid = Qrack.qrack_lib.init_count_type(
|
85
|
+
qubitCount,
|
86
|
+
isTensorNetwork,
|
87
|
+
isSchmidtDecomposeMulti,
|
88
|
+
isSchmidtDecompose,
|
89
|
+
isStabilizerHybrid,
|
90
|
+
isBinaryDecisionTree,
|
91
|
+
isPaged,
|
92
|
+
False,
|
93
|
+
isCpuGpuHybrid,
|
94
|
+
isOpenCL,
|
95
|
+
isHostPointer,
|
96
|
+
)
|
97
|
+
|
98
|
+
self._throw_if_error()
|
99
|
+
|
100
|
+
if pyzxCircuit is not None:
|
101
|
+
self.run_pyzx_gates(pyzxCircuit.gates)
|
102
|
+
elif qiskitCircuit is not None:
|
103
|
+
self.run_qiskit_circuit(qiskitCircuit)
|
104
|
+
|
105
|
+
def __del__(self):
|
106
|
+
if self.sid is not None:
|
107
|
+
Qrack.qrack_lib.destroy(self.sid)
|
108
|
+
self.sid = None
|
109
|
+
|
110
|
+
def _int_byref(self, a):
|
111
|
+
return (ctypes.c_int * len(a))(*a)
|
112
|
+
|
113
|
+
def _ulonglong_byref(self, a):
|
114
|
+
return (ctypes.c_ulonglong * len(a))(*a)
|
115
|
+
|
116
|
+
def _double_byref(self, a):
|
117
|
+
return (ctypes.c_double * len(a))(*a)
|
118
|
+
|
119
|
+
def _complex_byref(self, a):
|
120
|
+
t = [(c.real, c.imag) for c in a]
|
121
|
+
return self._double_byref([float(item) for sublist in t for item in sublist])
|
122
|
+
|
123
|
+
def _real1_byref(self, a):
|
124
|
+
# This needs to be c_double, if PyQrack is built with fp64.
|
125
|
+
if Qrack.fppow < 6:
|
126
|
+
return (ctypes.c_float * len(a))(*a)
|
127
|
+
return (ctypes.c_double * len(a))(*a)
|
128
|
+
|
129
|
+
def _bool_byref(self, a):
|
130
|
+
return (ctypes.c_bool * len(a))(*a)
|
131
|
+
|
132
|
+
def _qrack_complex_byref(self, a):
|
133
|
+
t = [(c.real, c.imag) for c in a]
|
134
|
+
return self._real1_byref([float(item) for sublist in t for item in sublist])
|
135
|
+
|
136
|
+
def _to_ubyte(self, nv, v):
|
137
|
+
c = math.floor((nv - 1) / 8) + 1
|
138
|
+
b = (ctypes.c_ubyte * (c * (1 << nv)))()
|
139
|
+
n = 0
|
140
|
+
for u in v:
|
141
|
+
for _ in range(c):
|
142
|
+
b[n] = u & 0xFF
|
143
|
+
u >>= 8
|
144
|
+
n += 1
|
145
|
+
|
146
|
+
return b
|
147
|
+
|
148
|
+
def _to_ulonglong(self, m, v):
|
149
|
+
b = (ctypes.c_ulonglong * (m * len(v)))()
|
150
|
+
n = 0
|
151
|
+
for u in v:
|
152
|
+
for _ in range(m):
|
153
|
+
b[n] = u & 0xFFFFFFFFFFFFFFFF
|
154
|
+
u >>= 64
|
155
|
+
n += 1
|
156
|
+
|
157
|
+
return b
|
158
|
+
|
159
|
+
# See https://stackoverflow.com/questions/5389507/iterating-over-every-two-elements-in-a-list#answer-30426000
|
160
|
+
def _pairwise(self, it):
|
161
|
+
it = iter(it)
|
162
|
+
while True:
|
163
|
+
try:
|
164
|
+
yield next(it), next(it)
|
165
|
+
except StopIteration:
|
166
|
+
# no more elements in the iterator
|
167
|
+
return
|
168
|
+
|
169
|
+
# non-quantum
|
170
|
+
def seed(self, s):
|
171
|
+
Qrack.qrack_lib.seed(self.sid, s)
|
172
|
+
self._throw_if_error()
|
173
|
+
|
174
|
+
def set_concurrency(self, p):
|
175
|
+
Qrack.qrack_lib.set_concurrency(self.sid, p)
|
176
|
+
self._throw_if_error()
|
177
|
+
|
178
|
+
# standard gates
|
179
|
+
|
180
|
+
## single-qubits gates
|
181
|
+
def x(self, q):
|
182
|
+
"""Applies X gate.
|
183
|
+
|
184
|
+
Applies the Pauli “X” operator to the qubit at position “q.”
|
185
|
+
The Pauli “X” operator is equivalent to a logical “NOT.”
|
186
|
+
|
187
|
+
Args:
|
188
|
+
q: the qubit number on which the gate is applied to.
|
189
|
+
|
190
|
+
Raises:
|
191
|
+
RuntimeError: QrackSimulator raised an exception.
|
192
|
+
"""
|
193
|
+
Qrack.qrack_lib.X(self.sid, q)
|
194
|
+
self._throw_if_error()
|
195
|
+
|
196
|
+
def y(self, q):
|
197
|
+
"""Applies Y gate.
|
198
|
+
|
199
|
+
Applies the Pauli “Y” operator to the qubit at “q.”
|
200
|
+
The Pauli “Y” operator is equivalent to a logical “NOT" with
|
201
|
+
permutation phase.
|
202
|
+
|
203
|
+
Args:
|
204
|
+
q: the qubit number on which the gate is applied to.
|
205
|
+
|
206
|
+
Raises:
|
207
|
+
RuntimeError: QrackSimulator raised an exception.
|
208
|
+
"""
|
209
|
+
Qrack.qrack_lib.Y(self.sid, q)
|
210
|
+
self._throw_if_error()
|
211
|
+
|
212
|
+
def z(self, q):
|
213
|
+
"""Applies Z gate.
|
214
|
+
|
215
|
+
Applies the Pauli “Z” operator to the qubit at “q.”
|
216
|
+
The Pauli “Z” operator flips the phase of `|1>`
|
217
|
+
|
218
|
+
Args:
|
219
|
+
q: the qubit number on which the gate is applied to.
|
220
|
+
|
221
|
+
Raises:
|
222
|
+
RuntimeError: QrackSimulator raised an exception.
|
223
|
+
"""
|
224
|
+
Qrack.qrack_lib.Z(self.sid, q)
|
225
|
+
self._throw_if_error()
|
226
|
+
|
227
|
+
def h(self, q):
|
228
|
+
"""Applies H gate.
|
229
|
+
|
230
|
+
Applies the Hadarmard operator to the qubit at “q.”
|
231
|
+
|
232
|
+
Args:
|
233
|
+
q: the qubit number on which the gate is applied to.
|
234
|
+
|
235
|
+
Raises:
|
236
|
+
RuntimeError: QrackSimulator raised an exception.
|
237
|
+
"""
|
238
|
+
Qrack.qrack_lib.H(self.sid, q)
|
239
|
+
self._throw_if_error()
|
240
|
+
|
241
|
+
def s(self, q):
|
242
|
+
"""Applies S gate.
|
243
|
+
|
244
|
+
Applies the 1/4 phase rotation to the qubit at “q.”
|
245
|
+
|
246
|
+
Args:
|
247
|
+
q: the qubit number on which the gate is applied to.
|
248
|
+
|
249
|
+
Raises:
|
250
|
+
RuntimeError: QrackSimulator raised an exception.
|
251
|
+
"""
|
252
|
+
Qrack.qrack_lib.S(self.sid, q)
|
253
|
+
self._throw_if_error()
|
254
|
+
|
255
|
+
def t(self, q):
|
256
|
+
"""Applies T gate.
|
257
|
+
|
258
|
+
Applies the 1/8 phase rotation to the qubit at “q.”
|
259
|
+
|
260
|
+
Args:
|
261
|
+
q: the qubit number on which the gate is applied to.
|
262
|
+
|
263
|
+
Raises:
|
264
|
+
RuntimeError: QrackSimulator raised an exception.
|
265
|
+
"""
|
266
|
+
Qrack.qrack_lib.T(self.sid, q)
|
267
|
+
self._throw_if_error()
|
268
|
+
|
269
|
+
def adjs(self, q):
|
270
|
+
"""Adjoint of S gate
|
271
|
+
|
272
|
+
Applies the gate equivalent to the inverse of S gate.
|
273
|
+
|
274
|
+
Args:
|
275
|
+
q: the qubit number on which the gate is applied to.
|
276
|
+
|
277
|
+
Raises:
|
278
|
+
RuntimeError: QrackSimulator raised an exception.
|
279
|
+
"""
|
280
|
+
Qrack.qrack_lib.AdjS(self.sid, q)
|
281
|
+
self._throw_if_error()
|
282
|
+
|
283
|
+
def adjt(self, q):
|
284
|
+
"""Adjoint of T gate
|
285
|
+
|
286
|
+
Applies the gate equivalent to the inverse of T gate.
|
287
|
+
|
288
|
+
Args:
|
289
|
+
q: the qubit number on which the gate is applied to.
|
290
|
+
|
291
|
+
Raises:
|
292
|
+
RuntimeError: QrackSimulator raised an exception.
|
293
|
+
"""
|
294
|
+
Qrack.qrack_lib.AdjT(self.sid, q)
|
295
|
+
self._throw_if_error()
|
296
|
+
|
297
|
+
def u(self, q, th, ph, la):
|
298
|
+
"""General unitary gate.
|
299
|
+
|
300
|
+
Applies a gate guaranteed to be unitary.
|
301
|
+
Spans all possible single bit unitary gates.
|
302
|
+
|
303
|
+
`U(theta, phi, lambda) = RZ(phi + pi/2)RX(theta)RZ(lambda - pi/2)`
|
304
|
+
|
305
|
+
Args:
|
306
|
+
q: the qubit number on which the gate is applied to.
|
307
|
+
th: theta
|
308
|
+
ph: phi
|
309
|
+
la: lambda
|
310
|
+
|
311
|
+
Raises:
|
312
|
+
RuntimeError: QrackSimulator raised an exception.
|
313
|
+
"""
|
314
|
+
Qrack.qrack_lib.U(
|
315
|
+
self.sid, q, ctypes.c_double(th), ctypes.c_double(ph), ctypes.c_double(la)
|
316
|
+
)
|
317
|
+
self._throw_if_error()
|
318
|
+
|
319
|
+
def mtrx(self, m, q):
|
320
|
+
"""Operation from matrix.
|
321
|
+
|
322
|
+
Applies arbitrary operation defined by the given matrix.
|
323
|
+
|
324
|
+
Args:
|
325
|
+
m: row-major complex list representing the operator.
|
326
|
+
q: the qubit number on which the gate is applied to.
|
327
|
+
|
328
|
+
Raises:
|
329
|
+
ValueError: 2x2 matrix 'm' in QrackSimulator.mtrx() must contain at least 4 elements.
|
330
|
+
RuntimeError: QrackSimulator raised an exception.
|
331
|
+
"""
|
332
|
+
if len(m) < 4:
|
333
|
+
raise ValueError("2x2 matrix 'm' in QrackSimulator.mtrx() must contain at least 4 elements.")
|
334
|
+
Qrack.qrack_lib.Mtrx(self.sid, self._complex_byref(m), q)
|
335
|
+
self._throw_if_error()
|
336
|
+
|
337
|
+
def r(self, b, ph, q):
|
338
|
+
"""Rotation gate.
|
339
|
+
|
340
|
+
Rotate the qubit along the given pauli basis by the given angle.
|
341
|
+
|
342
|
+
|
343
|
+
Args:
|
344
|
+
b: Pauli basis
|
345
|
+
ph: rotation angle
|
346
|
+
q: the qubit number on which the gate is applied to
|
347
|
+
|
348
|
+
Raises:
|
349
|
+
RuntimeError: QrackSimulator raised an exception.
|
350
|
+
"""
|
351
|
+
Qrack.qrack_lib.R(self.sid, ctypes.c_ulonglong(b), ctypes.c_double(ph), q)
|
352
|
+
self._throw_if_error()
|
353
|
+
|
354
|
+
def exp(self, b, ph, q):
|
355
|
+
"""Arbitrary exponentiation
|
356
|
+
|
357
|
+
`exp(b, theta) = e^{i*theta*[b_0 . b_1 ...]}`
|
358
|
+
where `.` is the tensor product.
|
359
|
+
|
360
|
+
|
361
|
+
Args:
|
362
|
+
b: Pauli basis
|
363
|
+
ph: coefficient of exponentiation
|
364
|
+
q: the qubit number on which the gate is applied to
|
365
|
+
|
366
|
+
Raises:
|
367
|
+
RuntimeError: QrackSimulator raised an exception.
|
368
|
+
"""
|
369
|
+
if len(b) != len(q):
|
370
|
+
raise RuntimeError("Lengths of list parameters are mismatched.")
|
371
|
+
Qrack.qrack_lib.Exp(
|
372
|
+
self.sid,
|
373
|
+
len(b),
|
374
|
+
self._ulonglong_byref(b),
|
375
|
+
ctypes.c_double(ph),
|
376
|
+
self._ulonglong_byref(q),
|
377
|
+
)
|
378
|
+
self._throw_if_error()
|
379
|
+
|
380
|
+
## multi-qubit gates
|
381
|
+
def mcx(self, c, q):
|
382
|
+
"""Multi-controlled X gate
|
383
|
+
|
384
|
+
If all controlled qubits are `|1>` then the target qubit is flipped.
|
385
|
+
|
386
|
+
Args:
|
387
|
+
c: list of controlled qubits.
|
388
|
+
q: target qubit.
|
389
|
+
|
390
|
+
Raises:
|
391
|
+
RuntimeError: QrackSimulator raised an exception.
|
392
|
+
"""
|
393
|
+
Qrack.qrack_lib.MCX(self.sid, len(c), self._ulonglong_byref(c), q)
|
394
|
+
self._throw_if_error()
|
395
|
+
|
396
|
+
def mcy(self, c, q):
|
397
|
+
"""Multi-controlled Y gate
|
398
|
+
|
399
|
+
If all controlled qubits are `|1>` then the Pauli "Y" gate is applied to
|
400
|
+
the target qubit.
|
401
|
+
|
402
|
+
Args:
|
403
|
+
c: list of controlled qubits.
|
404
|
+
q: target qubit.
|
405
|
+
|
406
|
+
Raises:
|
407
|
+
RuntimeError: QrackSimulator raised an exception.
|
408
|
+
"""
|
409
|
+
Qrack.qrack_lib.MCY(self.sid, len(c), self._ulonglong_byref(c), q)
|
410
|
+
self._throw_if_error()
|
411
|
+
|
412
|
+
def mcz(self, c, q):
|
413
|
+
"""Multi-controlled Z gate
|
414
|
+
|
415
|
+
If all controlled qubits are `|1>` then the Pauli "Z" gate is applied to
|
416
|
+
the target qubit.
|
417
|
+
|
418
|
+
Args:
|
419
|
+
c: list of controlled qubits.
|
420
|
+
q: target qubit.
|
421
|
+
|
422
|
+
Raises:
|
423
|
+
RuntimeError: QrackSimulator raised an exception.
|
424
|
+
"""
|
425
|
+
Qrack.qrack_lib.MCZ(self.sid, len(c), self._ulonglong_byref(c), q)
|
426
|
+
self._throw_if_error()
|
427
|
+
|
428
|
+
def mch(self, c, q):
|
429
|
+
"""Multi-controlled H gate
|
430
|
+
|
431
|
+
If all controlled qubits are `|1>` then the Hadarmard gate is applied to
|
432
|
+
the target qubit.
|
433
|
+
|
434
|
+
Args:
|
435
|
+
c: list of controlled qubits.
|
436
|
+
q: target qubit.
|
437
|
+
|
438
|
+
Raises:
|
439
|
+
RuntimeError: QrackSimulator raised an exception.
|
440
|
+
"""
|
441
|
+
Qrack.qrack_lib.MCH(self.sid, len(c), self._ulonglong_byref(c), q)
|
442
|
+
self._throw_if_error()
|
443
|
+
|
444
|
+
def mcs(self, c, q):
|
445
|
+
"""Multi-controlled S gate
|
446
|
+
|
447
|
+
If all controlled qubits are `|1>` then the "S" gate is applied to
|
448
|
+
the target qubit.
|
449
|
+
|
450
|
+
Args:
|
451
|
+
c: list of controlled qubits.
|
452
|
+
q: target qubit.
|
453
|
+
|
454
|
+
Raises:
|
455
|
+
RuntimeError: QrackSimulator raised an exception.
|
456
|
+
"""
|
457
|
+
Qrack.qrack_lib.MCS(self.sid, len(c), self._ulonglong_byref(c), q)
|
458
|
+
self._throw_if_error()
|
459
|
+
|
460
|
+
def mct(self, c, q):
|
461
|
+
"""Multi-controlled T gate
|
462
|
+
|
463
|
+
If all controlled qubits are `|1>` then the "T" gate is applied to
|
464
|
+
the target qubit.
|
465
|
+
|
466
|
+
Args:
|
467
|
+
c: list of controlled qubits.
|
468
|
+
q: target qubit.
|
469
|
+
|
470
|
+
Raises:
|
471
|
+
RuntimeError: QrackSimulator raised an exception.
|
472
|
+
"""
|
473
|
+
Qrack.qrack_lib.MCT(self.sid, len(c), self._ulonglong_byref(c), q)
|
474
|
+
self._throw_if_error()
|
475
|
+
|
476
|
+
def mcadjs(self, c, q):
|
477
|
+
"""Multi-controlled adjs gate
|
478
|
+
|
479
|
+
If all controlled qubits are `|1>` then the adjs gate is applied to
|
480
|
+
the target qubit.
|
481
|
+
|
482
|
+
Args:
|
483
|
+
c: list of controlled qubits.
|
484
|
+
q: target qubit.
|
485
|
+
|
486
|
+
Raises:
|
487
|
+
RuntimeError: QrackSimulator raised an exception.
|
488
|
+
"""
|
489
|
+
Qrack.qrack_lib.MCAdjS(self.sid, len(c), self._ulonglong_byref(c), q)
|
490
|
+
self._throw_if_error()
|
491
|
+
|
492
|
+
def mcadjt(self, c, q):
|
493
|
+
"""Multi-controlled adjt gate
|
494
|
+
|
495
|
+
If all controlled qubits are `|1>` then the adjt gate is applied to
|
496
|
+
the target qubit.
|
497
|
+
|
498
|
+
Args:
|
499
|
+
c: list of controlled qubits.
|
500
|
+
q: target qubit.
|
501
|
+
|
502
|
+
Raises:
|
503
|
+
RuntimeError: QrackSimulator raised an exception.
|
504
|
+
"""
|
505
|
+
Qrack.qrack_lib.MCAdjT(self.sid, len(c), self._ulonglong_byref(c), q)
|
506
|
+
self._throw_if_error()
|
507
|
+
|
508
|
+
def mcu(self, c, q, th, ph, la):
|
509
|
+
"""Multi-controlled arbitraty unitary
|
510
|
+
|
511
|
+
If all controlled qubits are `|1>` then the unitary gate described by
|
512
|
+
parameters is applied to the target qubit.
|
513
|
+
|
514
|
+
Args:
|
515
|
+
c: list of controlled qubits.
|
516
|
+
q: target qubit.
|
517
|
+
th: theta
|
518
|
+
ph: phi
|
519
|
+
la: lambda
|
520
|
+
|
521
|
+
Raises:
|
522
|
+
RuntimeError: QrackSimulator raised an exception.
|
523
|
+
"""
|
524
|
+
Qrack.qrack_lib.MCU(
|
525
|
+
self.sid,
|
526
|
+
len(c),
|
527
|
+
self._ulonglong_byref(c),
|
528
|
+
q,
|
529
|
+
ctypes.c_double(th),
|
530
|
+
ctypes.c_double(ph),
|
531
|
+
ctypes.c_double(la),
|
532
|
+
)
|
533
|
+
self._throw_if_error()
|
534
|
+
|
535
|
+
def mcmtrx(self, c, m, q):
|
536
|
+
"""Multi-controlled arbitrary operator
|
537
|
+
|
538
|
+
If all controlled qubits are `|1>` then the arbitrary operation by
|
539
|
+
parameters is applied to the target qubit.
|
540
|
+
|
541
|
+
Args:
|
542
|
+
c: list of controlled qubits
|
543
|
+
m: row-major complex list representing the operator.
|
544
|
+
q: target qubit
|
545
|
+
|
546
|
+
Raises:
|
547
|
+
ValueError: 2x2 matrix 'm' in QrackSimulator.mcmtrx() must contain at least 4 elements.
|
548
|
+
RuntimeError: QrackSimulator raised an exception.
|
549
|
+
"""
|
550
|
+
if len(m) < 4:
|
551
|
+
raise ValueError("2x2 matrix 'm' in QrackSimulator.mcmtrx() must contain at least 4 elements.")
|
552
|
+
Qrack.qrack_lib.MCMtrx(
|
553
|
+
self.sid, len(c), self._ulonglong_byref(c), self._complex_byref(m), q
|
554
|
+
)
|
555
|
+
self._throw_if_error()
|
556
|
+
|
557
|
+
def macx(self, c, q):
|
558
|
+
"""Anti multi-controlled X gate
|
559
|
+
|
560
|
+
If all controlled qubits are `|0>` then the target qubit is flipped.
|
561
|
+
|
562
|
+
Args:
|
563
|
+
c: list of controlled qubits.
|
564
|
+
q: target qubit.
|
565
|
+
|
566
|
+
Raises:
|
567
|
+
RuntimeError: QrackSimulator raised an exception.
|
568
|
+
"""
|
569
|
+
Qrack.qrack_lib.MACX(self.sid, len(c), self._ulonglong_byref(c), q)
|
570
|
+
self._throw_if_error()
|
571
|
+
|
572
|
+
def macy(self, c, q):
|
573
|
+
"""Anti multi-controlled Y gate
|
574
|
+
|
575
|
+
If all controlled qubits are `|0>` then the Pauli "Y" gate is applied to
|
576
|
+
the target qubit.
|
577
|
+
|
578
|
+
Args:
|
579
|
+
c: list of controlled qubits.
|
580
|
+
q: target qubit.
|
581
|
+
|
582
|
+
Raises:
|
583
|
+
RuntimeError: QrackSimulator raised an exception.
|
584
|
+
"""
|
585
|
+
Qrack.qrack_lib.MACY(self.sid, len(c), self._ulonglong_byref(c), q)
|
586
|
+
self._throw_if_error()
|
587
|
+
|
588
|
+
def macz(self, c, q):
|
589
|
+
"""Anti multi-controlled Z gate
|
590
|
+
|
591
|
+
If all controlled qubits are `|0>` then the Pauli "Z" gate is applied to
|
592
|
+
the target qubit.
|
593
|
+
|
594
|
+
Args:
|
595
|
+
c: list of controlled qubits.
|
596
|
+
q: target qubit.
|
597
|
+
|
598
|
+
Raises:
|
599
|
+
RuntimeError: QrackSimulator raised an exception.
|
600
|
+
"""
|
601
|
+
Qrack.qrack_lib.MACZ(self.sid, len(c), self._ulonglong_byref(c), q)
|
602
|
+
self._throw_if_error()
|
603
|
+
|
604
|
+
def mach(self, c, q):
|
605
|
+
"""Anti multi-controlled H gate
|
606
|
+
|
607
|
+
If all controlled qubits are `|0>` then the Hadarmard gate is applied to
|
608
|
+
the target qubit.
|
609
|
+
|
610
|
+
Args:
|
611
|
+
c: list of controlled qubits.
|
612
|
+
q: target qubit.
|
613
|
+
|
614
|
+
Raises:
|
615
|
+
RuntimeError: QrackSimulator raised an exception.
|
616
|
+
"""
|
617
|
+
Qrack.qrack_lib.MACH(self.sid, len(c), self._ulonglong_byref(c), q)
|
618
|
+
self._throw_if_error()
|
619
|
+
|
620
|
+
def macs(self, c, q):
|
621
|
+
"""Anti multi-controlled S gate
|
622
|
+
|
623
|
+
If all controlled qubits are `|0>` then the "S" gate is applied to
|
624
|
+
the target qubit.
|
625
|
+
|
626
|
+
Args:
|
627
|
+
c: list of controlled qubits.
|
628
|
+
q: target qubit.
|
629
|
+
|
630
|
+
Raises:
|
631
|
+
RuntimeError: QrackSimulator raised an exception.
|
632
|
+
"""
|
633
|
+
Qrack.qrack_lib.MACS(self.sid, len(c), self._ulonglong_byref(c), q)
|
634
|
+
self._throw_if_error()
|
635
|
+
|
636
|
+
def mact(self, c, q):
|
637
|
+
"""Anti multi-controlled T gate
|
638
|
+
|
639
|
+
If all controlled qubits are `|0>` then the "T" gate is applied to
|
640
|
+
the target qubit.
|
641
|
+
|
642
|
+
Args:
|
643
|
+
c: list of controlled qubits.
|
644
|
+
q: target qubit.
|
645
|
+
|
646
|
+
Raises:
|
647
|
+
RuntimeError: QrackSimulator raised an exception.
|
648
|
+
"""
|
649
|
+
Qrack.qrack_lib.MACT(self.sid, len(c), self._ulonglong_byref(c), q)
|
650
|
+
self._throw_if_error()
|
651
|
+
|
652
|
+
def macadjs(self, c, q):
|
653
|
+
"""Anti multi-controlled adjs gate
|
654
|
+
|
655
|
+
If all controlled qubits are `|0>` then the adjs gate is applied to
|
656
|
+
the target qubit.
|
657
|
+
|
658
|
+
Args:
|
659
|
+
c: list of controlled qubits.
|
660
|
+
q: target qubit.
|
661
|
+
|
662
|
+
Raises:
|
663
|
+
RuntimeError: QrackSimulator raised an exception.
|
664
|
+
"""
|
665
|
+
Qrack.qrack_lib.MACAdjS(self.sid, len(c), self._ulonglong_byref(c), q)
|
666
|
+
self._throw_if_error()
|
667
|
+
|
668
|
+
def macadjt(self, c, q):
|
669
|
+
"""Anti multi-controlled adjt gate
|
670
|
+
|
671
|
+
If all controlled qubits are `|0>` then the adjt gate is applied to
|
672
|
+
the target qubit.
|
673
|
+
|
674
|
+
Args:
|
675
|
+
c: list of controlled qubits.
|
676
|
+
q: target qubit.
|
677
|
+
|
678
|
+
Raises:
|
679
|
+
RuntimeError: QrackSimulator raised an exception.
|
680
|
+
"""
|
681
|
+
Qrack.qrack_lib.MACAdjT(self.sid, len(c), self._ulonglong_byref(c), q)
|
682
|
+
self._throw_if_error()
|
683
|
+
|
684
|
+
def macu(self, c, q, th, ph, la):
|
685
|
+
"""Anti multi-controlled arbitraty unitary
|
686
|
+
|
687
|
+
If all controlled qubits are `|0>` then the unitary gate described by
|
688
|
+
parameters is applied to the target qubit.
|
689
|
+
|
690
|
+
Args:
|
691
|
+
c: list of controlled qubits.
|
692
|
+
q: target qubit.
|
693
|
+
th: theta
|
694
|
+
ph: phi
|
695
|
+
la: lambda
|
696
|
+
|
697
|
+
Raises:
|
698
|
+
RuntimeError: QrackSimulator raised an exception.
|
699
|
+
"""
|
700
|
+
Qrack.qrack_lib.MACU(
|
701
|
+
self.sid,
|
702
|
+
len(c),
|
703
|
+
self._ulonglong_byref(c),
|
704
|
+
q,
|
705
|
+
ctypes.c_double(th),
|
706
|
+
ctypes.c_double(ph),
|
707
|
+
ctypes.c_double(la),
|
708
|
+
)
|
709
|
+
self._throw_if_error()
|
710
|
+
|
711
|
+
def macmtrx(self, c, m, q):
|
712
|
+
"""Anti multi-controlled arbitraty operator
|
713
|
+
|
714
|
+
If all controlled qubits are `|0>` then the arbitrary operation by
|
715
|
+
parameters is applied to the target qubit.
|
716
|
+
|
717
|
+
Args:
|
718
|
+
c: list of controlled qubits.
|
719
|
+
m: row-major complex matrix which defines the operator.
|
720
|
+
q: target qubit.
|
721
|
+
|
722
|
+
Raises:
|
723
|
+
ValueError: 2x2 matrix 'm' in QrackSimulator.macmtrx() must contain at least 4 elements.
|
724
|
+
RuntimeError: QrackSimulator raised an exception.
|
725
|
+
"""
|
726
|
+
if len(m) < 4:
|
727
|
+
raise ValueError("2x2 matrix 'm' in QrackSimulator.macmtrx() must contain at least 4 elements.")
|
728
|
+
Qrack.qrack_lib.MACMtrx(
|
729
|
+
self.sid, len(c), self._ulonglong_byref(c), self._complex_byref(m), q
|
730
|
+
)
|
731
|
+
self._throw_if_error()
|
732
|
+
|
733
|
+
def ucmtrx(self, c, m, q, p):
|
734
|
+
"""Multi-controlled arbitrary operator with arbitrary controls
|
735
|
+
|
736
|
+
If all control qubits match 'p' permutation by bit order, then the arbitrary
|
737
|
+
operation by parameters is applied to the target qubit.
|
738
|
+
|
739
|
+
Args:
|
740
|
+
c: list of control qubits
|
741
|
+
m: row-major complex list representing the operator.
|
742
|
+
q: target qubit
|
743
|
+
p: permutation of list of control qubits
|
744
|
+
|
745
|
+
Raises:
|
746
|
+
ValueError: 2x2 matrix 'm' in QrackSimulator.ucmtrx() must contain at least 4 elements.
|
747
|
+
RuntimeError: QrackSimulator raised an exception.
|
748
|
+
"""
|
749
|
+
if len(m) < 4:
|
750
|
+
raise ValueError("2x2 matrix 'm' in QrackSimulator.ucmtrx() must contain at least 4 elements.")
|
751
|
+
Qrack.qrack_lib.UCMtrx(
|
752
|
+
self.sid, len(c), self._ulonglong_byref(c), self._complex_byref(m), q, p
|
753
|
+
)
|
754
|
+
self._throw_if_error()
|
755
|
+
|
756
|
+
def multiplex1_mtrx(self, c, q, m):
|
757
|
+
"""Multiplex gate
|
758
|
+
|
759
|
+
A multiplex gate with a single target and an arbitrary number of
|
760
|
+
controls.
|
761
|
+
|
762
|
+
Args:
|
763
|
+
c: list of controlled qubits.
|
764
|
+
m: row-major complex matrix which defines the operator.
|
765
|
+
q: target qubit.
|
766
|
+
|
767
|
+
Raises:
|
768
|
+
ValueError: Multiplex matrix 'm' in QrackSimulator.multiplex1_mtrx() must contain at least 4 elements.
|
769
|
+
RuntimeError: QrackSimulator raised an exception.
|
770
|
+
"""
|
771
|
+
if len(m) < ((1 << len(c)) * 4):
|
772
|
+
raise ValueError("Multiplex matrix 'm' in QrackSimulator.multiplex1_mtrx() must contain at least (4 * 2 ** len(c)) elements.")
|
773
|
+
Qrack.qrack_lib.Multiplex1Mtrx(
|
774
|
+
self.sid, len(c), self._ulonglong_byref(c), q, self._complex_byref(m)
|
775
|
+
)
|
776
|
+
self._throw_if_error()
|
777
|
+
|
778
|
+
def mx(self, q):
|
779
|
+
"""Multi X-gate
|
780
|
+
|
781
|
+
Applies the Pauli “X” operator on all qubits.
|
782
|
+
|
783
|
+
Args:
|
784
|
+
q: list of qubits to apply X on.
|
785
|
+
|
786
|
+
Raises:
|
787
|
+
RuntimeError: QrackSimulator raised an exception.
|
788
|
+
"""
|
789
|
+
Qrack.qrack_lib.MX(self.sid, len(q), self._ulonglong_byref(q))
|
790
|
+
self._throw_if_error()
|
791
|
+
|
792
|
+
def my(self, q):
|
793
|
+
"""Multi Y-gate
|
794
|
+
|
795
|
+
Applies the Pauli “Y” operator on all qubits.
|
796
|
+
|
797
|
+
Args:
|
798
|
+
q: list of qubits to apply Y on.
|
799
|
+
|
800
|
+
Raises:
|
801
|
+
RuntimeError: QrackSimulator raised an exception.
|
802
|
+
"""
|
803
|
+
Qrack.qrack_lib.MY(self.sid, len(q), self._ulonglong_byref(q))
|
804
|
+
self._throw_if_error()
|
805
|
+
|
806
|
+
def mz(self, q):
|
807
|
+
"""Multi Z-gate
|
808
|
+
|
809
|
+
Applies the Pauli “Z” operator on all qubits.
|
810
|
+
|
811
|
+
Args:
|
812
|
+
q: list of qubits to apply Z on.
|
813
|
+
|
814
|
+
Raises:
|
815
|
+
RuntimeError: QrackSimulator raised an exception.
|
816
|
+
"""
|
817
|
+
Qrack.qrack_lib.MZ(self.sid, len(q), self._ulonglong_byref(q))
|
818
|
+
self._throw_if_error()
|
819
|
+
|
820
|
+
def mcr(self, b, ph, c, q):
|
821
|
+
"""Multi-controlled arbitrary rotation.
|
822
|
+
|
823
|
+
If all controlled qubits are `|1>` then the arbitrary rotation by
|
824
|
+
parameters is applied to the target qubit.
|
825
|
+
|
826
|
+
Args:
|
827
|
+
b: Pauli basis
|
828
|
+
ph: coefficient of exponentiation.
|
829
|
+
c: list of controlled qubits.
|
830
|
+
q: the qubit number on which the gate is applied to.
|
831
|
+
|
832
|
+
Raises:
|
833
|
+
RuntimeError: QrackSimulator raised an exception.
|
834
|
+
"""
|
835
|
+
Qrack.qrack_lib.MCR(
|
836
|
+
self.sid,
|
837
|
+
ctypes.c_ulonglong(b),
|
838
|
+
ctypes.c_double(ph),
|
839
|
+
len(c),
|
840
|
+
self._ulonglong_byref(c),
|
841
|
+
q,
|
842
|
+
)
|
843
|
+
self._throw_if_error()
|
844
|
+
|
845
|
+
def mcexp(self, b, ph, cs, q):
|
846
|
+
"""Multi-controlled arbitrary exponentiation
|
847
|
+
|
848
|
+
If all controlled qubits are `|1>` then the target qubit is
|
849
|
+
exponentiated an pauli basis basis with coefficient.
|
850
|
+
|
851
|
+
Args:
|
852
|
+
b: Pauli basis
|
853
|
+
ph: coefficient of exponentiation.
|
854
|
+
q: the qubit number on which the gate is applied to.
|
855
|
+
|
856
|
+
Raises:
|
857
|
+
RuntimeError: QrackSimulator raised an exception.
|
858
|
+
"""
|
859
|
+
if len(b) != len(q):
|
860
|
+
raise RuntimeError("Lengths of list parameters are mismatched.")
|
861
|
+
Qrack.qrack_lib.MCExp(
|
862
|
+
self.sid,
|
863
|
+
len(b),
|
864
|
+
self._ulonglong_byref(b),
|
865
|
+
ctypes.c_double(ph),
|
866
|
+
len(cs),
|
867
|
+
self._ulonglong_byref(cs),
|
868
|
+
self._ulonglong_byref(q),
|
869
|
+
)
|
870
|
+
self._throw_if_error()
|
871
|
+
|
872
|
+
def swap(self, qi1, qi2):
|
873
|
+
"""Swap Gate
|
874
|
+
|
875
|
+
Swaps the qubits at two given positions.
|
876
|
+
|
877
|
+
Args:
|
878
|
+
qi1: First position of qubit.
|
879
|
+
qi2: Second position of qubit.
|
880
|
+
|
881
|
+
Raises:
|
882
|
+
RuntimeError: QrackSimulator raised an exception.
|
883
|
+
"""
|
884
|
+
Qrack.qrack_lib.SWAP(self.sid, qi1, qi2)
|
885
|
+
self._throw_if_error()
|
886
|
+
|
887
|
+
def iswap(self, qi1, qi2):
|
888
|
+
"""Swap Gate with phase.
|
889
|
+
|
890
|
+
Swaps the qubits at two given positions.
|
891
|
+
If the bits are different then there is additional phase of `i`.
|
892
|
+
|
893
|
+
Args:
|
894
|
+
qi1: First position of qubit.
|
895
|
+
qi2: Second position of qubit.
|
896
|
+
|
897
|
+
Raises:
|
898
|
+
RuntimeError: QrackSimulator raised an exception.
|
899
|
+
"""
|
900
|
+
Qrack.qrack_lib.ISWAP(self.sid, qi1, qi2)
|
901
|
+
self._throw_if_error()
|
902
|
+
|
903
|
+
def adjiswap(self, qi1, qi2):
|
904
|
+
"""Swap Gate with phase.
|
905
|
+
|
906
|
+
Swaps the qubits at two given positions.
|
907
|
+
If the bits are different then there is additional phase of `-i`.
|
908
|
+
|
909
|
+
Args:
|
910
|
+
qi1: First position of qubit.
|
911
|
+
qi2: Second position of qubit.
|
912
|
+
|
913
|
+
Raises:
|
914
|
+
RuntimeError: QrackSimulator raised an exception.
|
915
|
+
"""
|
916
|
+
Qrack.qrack_lib.AdjISWAP(self.sid, qi1, qi2)
|
917
|
+
self._throw_if_error()
|
918
|
+
|
919
|
+
def fsim(self, th, ph, qi1, qi2):
|
920
|
+
"""Fsim gate.
|
921
|
+
|
922
|
+
The 2-qubit “fSim” gate
|
923
|
+
Useful in the simulation of particles with fermionic statistics
|
924
|
+
|
925
|
+
Args:
|
926
|
+
qi1: First position of qubit.
|
927
|
+
qi2: Second position of qubit.
|
928
|
+
|
929
|
+
Raises:
|
930
|
+
RuntimeError: QrackSimulator raised an exception.
|
931
|
+
"""
|
932
|
+
Qrack.qrack_lib.FSim(
|
933
|
+
self.sid, ctypes.c_double(th), ctypes.c_double(ph), qi1, qi2
|
934
|
+
)
|
935
|
+
self._throw_if_error()
|
936
|
+
|
937
|
+
def cswap(self, c, qi1, qi2):
|
938
|
+
"""Controlled-swap Gate
|
939
|
+
|
940
|
+
Swaps the qubits at two given positions if the control qubits are `|1>`
|
941
|
+
|
942
|
+
Args:
|
943
|
+
c: list of controlled qubits.
|
944
|
+
qi1: First position of qubit.
|
945
|
+
qi2: Second position of qubit.
|
946
|
+
|
947
|
+
Raises:
|
948
|
+
RuntimeError: QrackSimulator raised an exception.
|
949
|
+
"""
|
950
|
+
Qrack.qrack_lib.CSWAP(self.sid, len(c), self._ulonglong_byref(c), qi1, qi2)
|
951
|
+
self._throw_if_error()
|
952
|
+
|
953
|
+
def acswap(self, c, qi1, qi2):
|
954
|
+
"""Anti controlled-swap Gate
|
955
|
+
|
956
|
+
Swaps the qubits at two given positions if the control qubits are `|0>`
|
957
|
+
|
958
|
+
Args:
|
959
|
+
c: list of controlled qubits.
|
960
|
+
qi1: First position of qubit.
|
961
|
+
qi2: Second position of qubit.
|
962
|
+
|
963
|
+
Raises:
|
964
|
+
RuntimeError: QrackSimulator raised an exception.
|
965
|
+
"""
|
966
|
+
Qrack.qrack_lib.ACSWAP(self.sid, len(c), self._ulonglong_byref(c), qi1, qi2)
|
967
|
+
self._throw_if_error()
|
968
|
+
|
969
|
+
# standard operations
|
970
|
+
def m(self, q):
|
971
|
+
"""Measurement gate
|
972
|
+
|
973
|
+
Measures the qubit at "q" and returns Boolean value.
|
974
|
+
This operator is not unitary & is probabilistic in nature.
|
975
|
+
|
976
|
+
Args:
|
977
|
+
q: qubit to measure
|
978
|
+
|
979
|
+
Raises:
|
980
|
+
RuntimeError: QrackSimulator raised an exception.
|
981
|
+
|
982
|
+
Returns:
|
983
|
+
Measurement result.
|
984
|
+
"""
|
985
|
+
result = Qrack.qrack_lib.M(self.sid, q)
|
986
|
+
self._throw_if_error()
|
987
|
+
return result
|
988
|
+
|
989
|
+
def force_m(self, q, r):
|
990
|
+
"""Force-Measurement gate
|
991
|
+
|
992
|
+
Acts as if the measurement is applied and the result obtained is `r`
|
993
|
+
|
994
|
+
Args:
|
995
|
+
q: qubit to measure
|
996
|
+
r: the required result
|
997
|
+
|
998
|
+
Raises:
|
999
|
+
RuntimeError: QrackSimulator raised an exception.
|
1000
|
+
|
1001
|
+
Returns:
|
1002
|
+
Measurement result.
|
1003
|
+
"""
|
1004
|
+
result = Qrack.qrack_lib.ForceM(self.sid, q, r)
|
1005
|
+
self._throw_if_error()
|
1006
|
+
return result
|
1007
|
+
|
1008
|
+
def m_all(self):
|
1009
|
+
"""Measure-all gate
|
1010
|
+
|
1011
|
+
Measures measures all qubits.
|
1012
|
+
This operator is not unitary & is probabilistic in nature.
|
1013
|
+
|
1014
|
+
Raises:
|
1015
|
+
RuntimeError: QrackSimulator raised an exception.
|
1016
|
+
|
1017
|
+
Returns:
|
1018
|
+
Measurement result of all qubits.
|
1019
|
+
"""
|
1020
|
+
result = Qrack.qrack_lib.MAll(self.sid)
|
1021
|
+
self._throw_if_error()
|
1022
|
+
return result
|
1023
|
+
|
1024
|
+
def measure_pauli(self, b, q):
|
1025
|
+
"""Pauli Measurement gate
|
1026
|
+
|
1027
|
+
Measures the qubit at "q" with the given pauli basis.
|
1028
|
+
This operator is not unitary & is probabilistic in nature.
|
1029
|
+
|
1030
|
+
Args:
|
1031
|
+
b: Pauli basis
|
1032
|
+
q: qubit to measure
|
1033
|
+
|
1034
|
+
Raises:
|
1035
|
+
RuntimeError: QrackSimulator raised an exception.
|
1036
|
+
|
1037
|
+
Returns:
|
1038
|
+
Measurement result.
|
1039
|
+
"""
|
1040
|
+
if len(b) != len(q):
|
1041
|
+
raise RuntimeError("Lengths of list parameters are mismatched.")
|
1042
|
+
result = Qrack.qrack_lib.Measure(
|
1043
|
+
self.sid, len(b), self._int_byref(b), self._ulonglong_byref(q)
|
1044
|
+
)
|
1045
|
+
self._throw_if_error()
|
1046
|
+
return result
|
1047
|
+
|
1048
|
+
def measure_shots(self, q, s):
|
1049
|
+
"""Multi-shot measurement operator
|
1050
|
+
|
1051
|
+
Measures the qubit at "q" with the given pauli basis.
|
1052
|
+
This operator is not unitary & is probabilistic in nature.
|
1053
|
+
|
1054
|
+
Args:
|
1055
|
+
q: list of qubits to measure
|
1056
|
+
s: number of shots
|
1057
|
+
|
1058
|
+
Raises:
|
1059
|
+
RuntimeError: QrackSimulator raised an exception.
|
1060
|
+
|
1061
|
+
Returns:
|
1062
|
+
list of measurement result.
|
1063
|
+
"""
|
1064
|
+
m = self._ulonglong_byref([0] * s)
|
1065
|
+
Qrack.qrack_lib.MeasureShots(self.sid, len(q), self._ulonglong_byref(q), s, m)
|
1066
|
+
self._throw_if_error()
|
1067
|
+
return [m[i] for i in range(s)]
|
1068
|
+
|
1069
|
+
def reset_all(self):
|
1070
|
+
"""Reset gate
|
1071
|
+
|
1072
|
+
Resets all qubits to `|0>`
|
1073
|
+
|
1074
|
+
Raises:
|
1075
|
+
RuntimeError: QrackSimulator raised an exception.
|
1076
|
+
"""
|
1077
|
+
Qrack.qrack_lib.ResetAll(self.sid)
|
1078
|
+
self._throw_if_error()
|
1079
|
+
|
1080
|
+
# arithmetic-logic-unit (ALU)
|
1081
|
+
def _split_longs(self, a):
|
1082
|
+
"""Split operation
|
1083
|
+
|
1084
|
+
Splits the given integer into 64 bit numbers.
|
1085
|
+
|
1086
|
+
|
1087
|
+
Args:
|
1088
|
+
a: number to split
|
1089
|
+
|
1090
|
+
Raises:
|
1091
|
+
RuntimeError: QrackSimulator raised an exception.
|
1092
|
+
|
1093
|
+
Returns:
|
1094
|
+
list of split numbers.
|
1095
|
+
"""
|
1096
|
+
aParts = []
|
1097
|
+
if a == 0:
|
1098
|
+
aParts.append(0)
|
1099
|
+
while a > 0:
|
1100
|
+
aParts.append(a & 0xFFFFFFFFFFFFFFFF)
|
1101
|
+
a = a >> 64
|
1102
|
+
return aParts
|
1103
|
+
|
1104
|
+
def _split_longs_2(self, a, m):
|
1105
|
+
"""Split simultanoues operation
|
1106
|
+
|
1107
|
+
Splits 2 integers into same number of 64 bit numbers.
|
1108
|
+
|
1109
|
+
Args:
|
1110
|
+
a: first number to split
|
1111
|
+
m: second number to split
|
1112
|
+
|
1113
|
+
Raises:
|
1114
|
+
RuntimeError: QrackSimulator raised an exception.
|
1115
|
+
|
1116
|
+
Returns:
|
1117
|
+
pair of lists of split numbers.
|
1118
|
+
"""
|
1119
|
+
aParts = []
|
1120
|
+
mParts = []
|
1121
|
+
if a == 0 and m == 0:
|
1122
|
+
aParts.append(0)
|
1123
|
+
mParts.append(0)
|
1124
|
+
while a > 0 or m > 0:
|
1125
|
+
aParts.append(a & 0xFFFFFFFFFFFFFFFF)
|
1126
|
+
a = a >> 64
|
1127
|
+
mParts.append(m & 0xFFFFFFFFFFFFFFFF)
|
1128
|
+
m = m >> 64
|
1129
|
+
return aParts, mParts
|
1130
|
+
|
1131
|
+
def add(self, a, q):
|
1132
|
+
"""Add integer to qubit
|
1133
|
+
|
1134
|
+
Adds the given integer to the given set of qubits.
|
1135
|
+
|
1136
|
+
Args:
|
1137
|
+
a: first number to split
|
1138
|
+
q: list of qubits to add the number
|
1139
|
+
|
1140
|
+
Raises:
|
1141
|
+
RuntimeError: QrackSimulator raised an exception.
|
1142
|
+
"""
|
1143
|
+
aParts = self._split_longs(a)
|
1144
|
+
Qrack.qrack_lib.ADD(
|
1145
|
+
self.sid,
|
1146
|
+
len(aParts),
|
1147
|
+
self._ulonglong_byref(aParts),
|
1148
|
+
len(q),
|
1149
|
+
self._ulonglong_byref(q),
|
1150
|
+
)
|
1151
|
+
self._throw_if_error()
|
1152
|
+
|
1153
|
+
def sub(self, a, q):
|
1154
|
+
"""Subtract integer to qubit
|
1155
|
+
|
1156
|
+
Subtracts the given integer to the given set of qubits.
|
1157
|
+
|
1158
|
+
Args:
|
1159
|
+
a: first number to split
|
1160
|
+
q: list of qubits to subtract the number
|
1161
|
+
|
1162
|
+
Raises:
|
1163
|
+
RuntimeError: QrackSimulator raised an exception.
|
1164
|
+
"""
|
1165
|
+
aParts = self._split_longs(a)
|
1166
|
+
Qrack.qrack_lib.SUB(
|
1167
|
+
self.sid,
|
1168
|
+
len(aParts),
|
1169
|
+
self._ulonglong_byref(aParts),
|
1170
|
+
len(q),
|
1171
|
+
self._ulonglong_byref(q),
|
1172
|
+
)
|
1173
|
+
self._throw_if_error()
|
1174
|
+
|
1175
|
+
def adds(self, a, s, q):
|
1176
|
+
"""Signed Addition integer to qubit
|
1177
|
+
|
1178
|
+
Signed Addition of the given integer to the given set of qubits,
|
1179
|
+
if there is an overflow the resultant will become negative.
|
1180
|
+
|
1181
|
+
Args:
|
1182
|
+
a: number to add
|
1183
|
+
s: qubit to store overflow
|
1184
|
+
q: list of qubits to add the number
|
1185
|
+
|
1186
|
+
Raises:
|
1187
|
+
RuntimeError: QrackSimulator raised an exception.
|
1188
|
+
"""
|
1189
|
+
aParts = self._split_longs(a)
|
1190
|
+
Qrack.qrack_lib.ADDS(
|
1191
|
+
self.sid,
|
1192
|
+
len(aParts),
|
1193
|
+
self._ulonglong_byref(aParts),
|
1194
|
+
s,
|
1195
|
+
len(q),
|
1196
|
+
self._ulonglong_byref(q),
|
1197
|
+
)
|
1198
|
+
self._throw_if_error()
|
1199
|
+
|
1200
|
+
def subs(self, a, s, q):
|
1201
|
+
"""Subtract integer to qubit
|
1202
|
+
|
1203
|
+
Subtracts the given integer to the given set of qubits,
|
1204
|
+
if there is an overflow the resultant will become negative.
|
1205
|
+
|
1206
|
+
Args:
|
1207
|
+
a: number to subtract
|
1208
|
+
s: qubit to store overflow
|
1209
|
+
q: list of qubits to subtract the number
|
1210
|
+
|
1211
|
+
Raises:
|
1212
|
+
RuntimeError: QrackSimulator raised an exception.
|
1213
|
+
"""
|
1214
|
+
aParts = self._split_longs(a)
|
1215
|
+
Qrack.qrack_lib.SUBS(
|
1216
|
+
self.sid,
|
1217
|
+
len(aParts),
|
1218
|
+
self._ulonglong_byref(aParts),
|
1219
|
+
s,
|
1220
|
+
len(q),
|
1221
|
+
self._ulonglong_byref(q),
|
1222
|
+
)
|
1223
|
+
self._throw_if_error()
|
1224
|
+
|
1225
|
+
def mul(self, a, q, o):
|
1226
|
+
"""Multiplies integer to qubit
|
1227
|
+
|
1228
|
+
Multiplies the given integer to the given set of qubits.
|
1229
|
+
Carry register is required for maintaining the unitary nature of
|
1230
|
+
operation and must be as long as the input qubit register.
|
1231
|
+
|
1232
|
+
Args:
|
1233
|
+
a: number to multiply
|
1234
|
+
q: list of qubits to multiply the number
|
1235
|
+
o: carry register
|
1236
|
+
|
1237
|
+
Raises:
|
1238
|
+
RuntimeError: QrackSimulator raised an exception.
|
1239
|
+
RuntimeError: QrackSimulator with isTensorNetwork=True option cannot mul()! (Turn off just this option, in the constructor.)
|
1240
|
+
"""
|
1241
|
+
if self.is_tensor_network:
|
1242
|
+
raise RuntimeError("QrackSimulator with isTensorNetwork=True option cannot mul()! (Turn off just this option, in the constructor.)")
|
1243
|
+
|
1244
|
+
if len(q) != len(o):
|
1245
|
+
raise RuntimeError("Lengths of list parameters are mismatched.")
|
1246
|
+
aParts = self._split_longs(a)
|
1247
|
+
Qrack.qrack_lib.MUL(
|
1248
|
+
self.sid,
|
1249
|
+
len(aParts),
|
1250
|
+
self._ulonglong_byref(aParts),
|
1251
|
+
len(q),
|
1252
|
+
self._ulonglong_byref(q),
|
1253
|
+
self._ulonglong_byref(o),
|
1254
|
+
)
|
1255
|
+
self._throw_if_error()
|
1256
|
+
|
1257
|
+
def div(self, a, q, o):
|
1258
|
+
"""Divides qubit by integer
|
1259
|
+
|
1260
|
+
'Divides' the given qubits by the integer.
|
1261
|
+
(This is rather the adjoint of mul().)
|
1262
|
+
Carry register is required for maintaining the unitary nature of
|
1263
|
+
operation.
|
1264
|
+
|
1265
|
+
Args:
|
1266
|
+
a: integer to divide by
|
1267
|
+
q: qubits to divide
|
1268
|
+
o: carry register
|
1269
|
+
|
1270
|
+
Raises:
|
1271
|
+
RuntimeError: QrackSimulator raised an exception.
|
1272
|
+
RuntimeError: QrackSimulator with isTensorNetwork=True option cannot div()! (Turn off just this option, in the constructor.)
|
1273
|
+
"""
|
1274
|
+
if self.is_tensor_network:
|
1275
|
+
raise RuntimeError("QrackSimulator with isTensorNetwork=True option cannot div()! (Turn off just this option, in the constructor.)")
|
1276
|
+
|
1277
|
+
if len(q) != len(o):
|
1278
|
+
raise RuntimeError("Lengths of list parameters are mismatched.")
|
1279
|
+
aParts = self._split_longs(a)
|
1280
|
+
Qrack.qrack_lib.DIV(
|
1281
|
+
self.sid,
|
1282
|
+
len(aParts),
|
1283
|
+
self._ulonglong_byref(aParts),
|
1284
|
+
len(q),
|
1285
|
+
self._ulonglong_byref(q),
|
1286
|
+
self._ulonglong_byref(o),
|
1287
|
+
)
|
1288
|
+
self._throw_if_error()
|
1289
|
+
|
1290
|
+
def muln(self, a, m, q, o):
|
1291
|
+
"""Modulo Multiplication
|
1292
|
+
|
1293
|
+
Modulo Multiplication of the given integer to the given set of qubits
|
1294
|
+
Out-of-place register is required to store the resultant.
|
1295
|
+
|
1296
|
+
Args:
|
1297
|
+
a: number to multiply
|
1298
|
+
m: modulo number
|
1299
|
+
q: list of qubits to multiply the number
|
1300
|
+
o: carry register
|
1301
|
+
|
1302
|
+
Raises:
|
1303
|
+
RuntimeError: QrackSimulator raised an exception.
|
1304
|
+
"""
|
1305
|
+
if len(q) != len(o):
|
1306
|
+
raise RuntimeError("Lengths of list parameters are mismatched.")
|
1307
|
+
aParts, mParts = self._split_longs_2(a, m)
|
1308
|
+
Qrack.qrack_lib.MULN(
|
1309
|
+
self.sid,
|
1310
|
+
len(aParts),
|
1311
|
+
self._ulonglong_byref(aParts),
|
1312
|
+
self._ulonglong_byref(mParts),
|
1313
|
+
len(q),
|
1314
|
+
self._ulonglong_byref(q),
|
1315
|
+
self._ulonglong_byref(o),
|
1316
|
+
)
|
1317
|
+
self._throw_if_error()
|
1318
|
+
|
1319
|
+
def divn(self, a, m, q, o):
|
1320
|
+
"""Modulo Division
|
1321
|
+
|
1322
|
+
'Modulo Division' of the given set of qubits by the given integer
|
1323
|
+
(This is rather the adjoint of muln().)
|
1324
|
+
Out-of-place register is required to retrieve the resultant.
|
1325
|
+
|
1326
|
+
Args:
|
1327
|
+
a: integer by which qubit will be divided
|
1328
|
+
m: modulo integer
|
1329
|
+
q: qubits to divide
|
1330
|
+
o: carry register
|
1331
|
+
|
1332
|
+
Raises:
|
1333
|
+
RuntimeError: QrackSimulator raised an exception.
|
1334
|
+
"""
|
1335
|
+
if len(q) != len(o):
|
1336
|
+
raise RuntimeError("Lengths of list parameters are mismatched.")
|
1337
|
+
aParts, mParts = self._split_longs_2(a, m)
|
1338
|
+
Qrack.qrack_lib.DIVN(
|
1339
|
+
self.sid,
|
1340
|
+
len(aParts),
|
1341
|
+
self._ulonglong_byref(aParts),
|
1342
|
+
self._ulonglong_byref(mParts),
|
1343
|
+
len(q),
|
1344
|
+
self._ulonglong_byref(q),
|
1345
|
+
self._ulonglong_byref(o),
|
1346
|
+
)
|
1347
|
+
self._throw_if_error()
|
1348
|
+
|
1349
|
+
def pown(self, a, m, q, o):
|
1350
|
+
"""Modulo Power
|
1351
|
+
|
1352
|
+
Raises the qubit to the power `a` to which `mod m` is applied to.
|
1353
|
+
Out-of-place register is required to store the resultant.
|
1354
|
+
|
1355
|
+
Args:
|
1356
|
+
a: number in power
|
1357
|
+
m: modulo number
|
1358
|
+
q: list of qubits to exponentiate
|
1359
|
+
o: out-of-place register
|
1360
|
+
|
1361
|
+
Raises:
|
1362
|
+
RuntimeError: QrackSimulator raised an exception.
|
1363
|
+
RuntimeError: QrackSimulator with isTensorNetwork=True option cannot pown()! (Turn off just this option, in the constructor.)
|
1364
|
+
"""
|
1365
|
+
if self.is_tensor_network:
|
1366
|
+
raise RuntimeError("QrackSimulator with isTensorNetwork=True option cannot pown()! (Turn off just this option, in the constructor.)")
|
1367
|
+
|
1368
|
+
if len(q) != len(o):
|
1369
|
+
raise RuntimeError("Lengths of list parameters are mismatched.")
|
1370
|
+
aParts, mParts = self._split_longs_2(a, m)
|
1371
|
+
Qrack.qrack_lib.POWN(
|
1372
|
+
self.sid,
|
1373
|
+
len(aParts),
|
1374
|
+
self._ulonglong_byref(aParts),
|
1375
|
+
self._ulonglong_byref(mParts),
|
1376
|
+
len(q),
|
1377
|
+
self._ulonglong_byref(q),
|
1378
|
+
self._ulonglong_byref(o),
|
1379
|
+
)
|
1380
|
+
self._throw_if_error()
|
1381
|
+
|
1382
|
+
def mcadd(self, a, c, q):
|
1383
|
+
"""Controlled-add
|
1384
|
+
|
1385
|
+
Adds the given integer to the given set of qubits if all controlled
|
1386
|
+
qubits are `|1>`.
|
1387
|
+
|
1388
|
+
Args:
|
1389
|
+
a: number to add.
|
1390
|
+
c: list of controlled qubits.
|
1391
|
+
q: list of qubits to add the number
|
1392
|
+
|
1393
|
+
Raises:
|
1394
|
+
RuntimeError: QrackSimulator raised an exception.
|
1395
|
+
"""
|
1396
|
+
aParts = self._split_longs(a)
|
1397
|
+
Qrack.qrack_lib.MCADD(
|
1398
|
+
self.sid,
|
1399
|
+
len(aParts),
|
1400
|
+
self._ulonglong_byref(aParts),
|
1401
|
+
len(c),
|
1402
|
+
self._ulonglong_byref(c),
|
1403
|
+
len(q),
|
1404
|
+
self._ulonglong_byref(q),
|
1405
|
+
)
|
1406
|
+
self._throw_if_error()
|
1407
|
+
|
1408
|
+
def mcsub(self, a, c, q):
|
1409
|
+
"""Controlled-subtract
|
1410
|
+
|
1411
|
+
Subtracts the given integer to the given set of qubits if all controlled
|
1412
|
+
qubits are `|1>`.
|
1413
|
+
|
1414
|
+
Args:
|
1415
|
+
a: number to subtract.
|
1416
|
+
c: list of controlled qubits.
|
1417
|
+
q: list of qubits to add the number
|
1418
|
+
|
1419
|
+
Raises:
|
1420
|
+
RuntimeError: QrackSimulator raised an exception.
|
1421
|
+
"""
|
1422
|
+
aParts = self._split_longs(a)
|
1423
|
+
Qrack.qrack_lib.MCSUB(
|
1424
|
+
self.sid,
|
1425
|
+
len(aParts),
|
1426
|
+
self._ulonglong_byref(aParts),
|
1427
|
+
len(c),
|
1428
|
+
self._ulonglong_byref(c),
|
1429
|
+
len(q),
|
1430
|
+
self._ulonglong_byref(q),
|
1431
|
+
)
|
1432
|
+
self._throw_if_error()
|
1433
|
+
|
1434
|
+
def mcmul(self, a, c, q, o):
|
1435
|
+
"""Controlled-multiply
|
1436
|
+
|
1437
|
+
Multiplies the given integer to the given set of qubits if all controlled
|
1438
|
+
qubits are `|1>`.
|
1439
|
+
Carry register is required for maintaining the unitary nature of
|
1440
|
+
operation.
|
1441
|
+
|
1442
|
+
Args:
|
1443
|
+
a: number to multiply
|
1444
|
+
c: list of controlled qubits.
|
1445
|
+
q: list of qubits to add the number
|
1446
|
+
o: carry register
|
1447
|
+
|
1448
|
+
Raises:
|
1449
|
+
RuntimeError: QrackSimulator raised an exception.
|
1450
|
+
RuntimeError: QrackSimulator with isTensorNetwork=True option cannot mcmul()! (Turn off just this option, in the constructor.)
|
1451
|
+
"""
|
1452
|
+
if self.is_tensor_network:
|
1453
|
+
raise RuntimeError("QrackSimulator with isTensorNetwork=True option cannot mcmul()! (Turn off just this option, in the constructor.)")
|
1454
|
+
|
1455
|
+
if len(q) != len(o):
|
1456
|
+
raise RuntimeError("Lengths of list parameters are mismatched.")
|
1457
|
+
aParts = self._split_longs(a)
|
1458
|
+
Qrack.qrack_lib.MCMUL(
|
1459
|
+
self.sid,
|
1460
|
+
len(aParts),
|
1461
|
+
self._ulonglong_byref(aParts),
|
1462
|
+
len(c),
|
1463
|
+
self._ulonglong_byref(c),
|
1464
|
+
len(q),
|
1465
|
+
self._ulonglong_byref(q),
|
1466
|
+
)
|
1467
|
+
self._throw_if_error()
|
1468
|
+
|
1469
|
+
def mcdiv(self, a, c, q, o):
|
1470
|
+
"""Controlled-divide.
|
1471
|
+
|
1472
|
+
'Divides' the given qubits by the integer if all controlled
|
1473
|
+
qubits are `|1>`.
|
1474
|
+
(This is rather the adjoint of mcmul().)
|
1475
|
+
Carry register is required for maintaining the unitary nature of
|
1476
|
+
operation.
|
1477
|
+
|
1478
|
+
Args:
|
1479
|
+
a: number to divide by
|
1480
|
+
c: list of controlled qubits.
|
1481
|
+
q: qubits to divide
|
1482
|
+
o: carry register
|
1483
|
+
|
1484
|
+
Raises:
|
1485
|
+
RuntimeError: QrackSimulator raised an exception.
|
1486
|
+
RuntimeError: QrackSimulator with isTensorNetwork=True option cannot mcdiv()! (Turn off just this option, in the constructor.)
|
1487
|
+
"""
|
1488
|
+
if self.is_tensor_network:
|
1489
|
+
raise RuntimeError("QrackSimulator with isTensorNetwork=True option cannot mcdiv()! (Turn off just this option, in the constructor.)")
|
1490
|
+
|
1491
|
+
if len(q) != len(o):
|
1492
|
+
raise RuntimeError("Lengths of list parameters are mismatched.")
|
1493
|
+
aParts = self._split_longs(a)
|
1494
|
+
Qrack.qrack_lib.MCDIV(
|
1495
|
+
self.sid,
|
1496
|
+
len(aParts),
|
1497
|
+
self._ulonglong_byref(aParts),
|
1498
|
+
len(c),
|
1499
|
+
self._ulonglong_byref(c),
|
1500
|
+
len(q),
|
1501
|
+
self._ulonglong_byref(q),
|
1502
|
+
)
|
1503
|
+
self._throw_if_error()
|
1504
|
+
|
1505
|
+
def mcmuln(self, a, c, m, q, o):
|
1506
|
+
"""Controlled-modulo multiplication
|
1507
|
+
|
1508
|
+
Modulo multiplication of the given integer to the given set of qubits
|
1509
|
+
if all controlled qubits are `|1>`.
|
1510
|
+
Out-of-place register is required to store the resultant.
|
1511
|
+
|
1512
|
+
Args:
|
1513
|
+
a: number to multiply
|
1514
|
+
c: list of controlled qubits.
|
1515
|
+
m: modulo number
|
1516
|
+
q: list of qubits to add the number
|
1517
|
+
o: out-of-place output register
|
1518
|
+
|
1519
|
+
Raises:
|
1520
|
+
RuntimeError: QrackSimulator raised an exception.
|
1521
|
+
"""
|
1522
|
+
if len(q) != len(o):
|
1523
|
+
raise RuntimeError("Lengths of list parameters are mismatched.")
|
1524
|
+
aParts, mParts = self._split_longs_2(a, m)
|
1525
|
+
Qrack.qrack_lib.MCMULN(
|
1526
|
+
self.sid,
|
1527
|
+
len(aParts),
|
1528
|
+
self._ulonglong_byref(aParts),
|
1529
|
+
len(c),
|
1530
|
+
self._ulonglong_byref(c),
|
1531
|
+
self._ulonglong_byref(mParts),
|
1532
|
+
len(q),
|
1533
|
+
self._ulonglong_byref(q),
|
1534
|
+
self._ulonglong_byref(o),
|
1535
|
+
)
|
1536
|
+
self._throw_if_error()
|
1537
|
+
|
1538
|
+
def mcdivn(self, a, c, m, q, o):
|
1539
|
+
"""Controlled-divide.
|
1540
|
+
|
1541
|
+
Modulo division of the given qubits by the given number if all
|
1542
|
+
controlled qubits are `|1>`.
|
1543
|
+
(This is rather the adjoint of mcmuln().)
|
1544
|
+
Out-of-place register is required to retrieve the resultant.
|
1545
|
+
|
1546
|
+
Args:
|
1547
|
+
a: number to divide by
|
1548
|
+
c: list of controlled qubits.
|
1549
|
+
m: modulo number
|
1550
|
+
q: qubits to divide
|
1551
|
+
o: carry register
|
1552
|
+
|
1553
|
+
Raises:
|
1554
|
+
RuntimeError: QrackSimulator raised an exception.
|
1555
|
+
"""
|
1556
|
+
if len(q) != len(o):
|
1557
|
+
raise RuntimeError("Lengths of list parameters are mismatched.")
|
1558
|
+
aParts, mParts = self._split_longs_2(a, m)
|
1559
|
+
Qrack.qrack_lib.MCDIVN(
|
1560
|
+
self.sid,
|
1561
|
+
len(aParts),
|
1562
|
+
self._ulonglong_byref(aParts),
|
1563
|
+
len(c),
|
1564
|
+
self._ulonglong_byref(c),
|
1565
|
+
self._ulonglong_byref(mParts),
|
1566
|
+
len(q),
|
1567
|
+
self._ulonglong_byref(q),
|
1568
|
+
self._ulonglong_byref(o),
|
1569
|
+
)
|
1570
|
+
self._throw_if_error()
|
1571
|
+
|
1572
|
+
def mcpown(self, a, c, m, q, o):
|
1573
|
+
"""Controlled-modulo Power
|
1574
|
+
|
1575
|
+
Raises the qubit to the power `a` to which `mod m` is applied to if
|
1576
|
+
all the controlled qubits are set to `|1>`.
|
1577
|
+
Out-of-place register is required to store the resultant.
|
1578
|
+
|
1579
|
+
Args:
|
1580
|
+
a: number in power
|
1581
|
+
c: control qubits
|
1582
|
+
m: modulo number
|
1583
|
+
q: list of qubits to exponentiate
|
1584
|
+
o: out-of-place register
|
1585
|
+
|
1586
|
+
Raises:
|
1587
|
+
RuntimeError: QrackSimulator raised an exception.
|
1588
|
+
RuntimeError: QrackSimulator with isTensorNetwork=True option cannot mcpown()! (Turn off just this option, in the constructor.)
|
1589
|
+
"""
|
1590
|
+
if self.is_tensor_network:
|
1591
|
+
raise RuntimeError("QrackSimulator with isTensorNetwork=True option cannot mcpown()! (Turn off just this option, in the constructor.)")
|
1592
|
+
|
1593
|
+
if len(q) != len(o):
|
1594
|
+
raise RuntimeError("Lengths of list parameters are mismatched.")
|
1595
|
+
aParts, mParts = self._split_longs_2(a, m)
|
1596
|
+
Qrack.qrack_lib.MCPOWN(
|
1597
|
+
self.sid,
|
1598
|
+
len(aParts),
|
1599
|
+
self._ulonglong_byref(aParts),
|
1600
|
+
len(c),
|
1601
|
+
self._ulonglong_byref(c),
|
1602
|
+
self._ulonglong_byref(mParts),
|
1603
|
+
len(q),
|
1604
|
+
self._ulonglong_byref(q),
|
1605
|
+
self._ulonglong_byref(o),
|
1606
|
+
)
|
1607
|
+
self._throw_if_error()
|
1608
|
+
|
1609
|
+
def lda(self, qi, qv, t):
|
1610
|
+
"""Load Accumalator
|
1611
|
+
|
1612
|
+
Quantum counterpart for LDA from MOS-6502 assembly. `t` must be of
|
1613
|
+
the length `2 ** len(qi)`. It loads each list entry index of t into
|
1614
|
+
the qi register and each list entry value into the qv register.
|
1615
|
+
|
1616
|
+
Args:
|
1617
|
+
qi: qubit register for index
|
1618
|
+
qv: qubit register for value
|
1619
|
+
t: list of values
|
1620
|
+
|
1621
|
+
Raises:
|
1622
|
+
RuntimeError: QrackSimulator raised an exception.
|
1623
|
+
RuntimeError: QrackSimulator with isTensorNetwork=True option cannot lda()! (Turn off just this option, in the constructor.)
|
1624
|
+
"""
|
1625
|
+
if self.is_tensor_network:
|
1626
|
+
raise RuntimeError("QrackSimulator with isTensorNetwork=True option cannot lda()! (Turn off just this option, in the constructor.)")
|
1627
|
+
|
1628
|
+
Qrack.qrack_lib.LDA(
|
1629
|
+
self.sid,
|
1630
|
+
len(qi),
|
1631
|
+
self._ulonglong_byref(qi),
|
1632
|
+
len(qv),
|
1633
|
+
self._ulonglong_byref(qv),
|
1634
|
+
self._to_ubyte(len(qv), t),
|
1635
|
+
)
|
1636
|
+
self._throw_if_error()
|
1637
|
+
|
1638
|
+
def adc(self, s, qi, qv, t):
|
1639
|
+
"""Add with Carry
|
1640
|
+
|
1641
|
+
Quantum counterpart for ADC from MOS-6502 assembly. `t` must be of
|
1642
|
+
the length `2 ** len(qi)`.
|
1643
|
+
|
1644
|
+
Args:
|
1645
|
+
qi: qubit register for index
|
1646
|
+
qv: qubit register for value
|
1647
|
+
t: list of values
|
1648
|
+
|
1649
|
+
Raises:
|
1650
|
+
RuntimeError: QrackSimulator raised an exception.
|
1651
|
+
RuntimeError: QrackSimulator with isTensorNetwork=True option cannot adc()! (Turn off just this option, in the constructor.)
|
1652
|
+
"""
|
1653
|
+
if self.is_tensor_network:
|
1654
|
+
raise RuntimeError("QrackSimulator with isTensorNetwork=True option cannot adc()! (Turn off just this option, in the constructor.)")
|
1655
|
+
|
1656
|
+
Qrack.qrack_lib.ADC(
|
1657
|
+
self.sid,
|
1658
|
+
s,
|
1659
|
+
len(qi),
|
1660
|
+
self._ulonglong_byref(qi),
|
1661
|
+
len(qv),
|
1662
|
+
self._ulonglong_byref(qv),
|
1663
|
+
self._to_ubyte(len(qv), t),
|
1664
|
+
)
|
1665
|
+
self._throw_if_error()
|
1666
|
+
|
1667
|
+
def sbc(self, s, qi, qv, t):
|
1668
|
+
"""Subtract with Carry
|
1669
|
+
|
1670
|
+
Quantum counterpart for SBC from MOS-6502 assembly. `t` must be of
|
1671
|
+
the length `2 ** len(qi)`
|
1672
|
+
|
1673
|
+
Args:
|
1674
|
+
qi: qubit register for index
|
1675
|
+
qv: qubit register for value
|
1676
|
+
t: list of values
|
1677
|
+
|
1678
|
+
Raises:
|
1679
|
+
RuntimeError: QrackSimulator raised an exception.
|
1680
|
+
RuntimeError: QrackSimulator with isTensorNetwork=True option cannot sbc()! (Turn off just this option, in the constructor.)
|
1681
|
+
"""
|
1682
|
+
if self.is_tensor_network:
|
1683
|
+
raise RuntimeError("QrackSimulator with isTensorNetwork=True option cannot sbc()! (Turn off just this option, in the constructor.)")
|
1684
|
+
|
1685
|
+
Qrack.qrack_lib.SBC(
|
1686
|
+
self.sid,
|
1687
|
+
s,
|
1688
|
+
len(qi),
|
1689
|
+
self._ulonglong_byref(qi),
|
1690
|
+
len(qv),
|
1691
|
+
self._ulonglong_byref(qv),
|
1692
|
+
self._to_ubyte(len(qv), t),
|
1693
|
+
)
|
1694
|
+
self._throw_if_error()
|
1695
|
+
|
1696
|
+
def hash(self, q, t):
|
1697
|
+
"""Hash function
|
1698
|
+
|
1699
|
+
Replicates the behaviour of LDA without the index register.
|
1700
|
+
For the operation to be unitary, the entries present in `t` must be
|
1701
|
+
unique, and the length of `t` must be `2 ** len(qi)`.
|
1702
|
+
|
1703
|
+
|
1704
|
+
Args:
|
1705
|
+
q: qubit register for value
|
1706
|
+
t: list of values
|
1707
|
+
|
1708
|
+
Raises:
|
1709
|
+
RuntimeError: QrackSimulator raised an exception.
|
1710
|
+
RuntimeError: QrackSimulator with isTensorNetwork=True option cannot hash()! (Turn off just this option, in the constructor.)
|
1711
|
+
"""
|
1712
|
+
if self.is_tensor_network:
|
1713
|
+
raise RuntimeError("QrackSimulator with isTensorNetwork=True option cannot hash()! (Turn off just this option, in the constructor.)")
|
1714
|
+
|
1715
|
+
Qrack.qrack_lib.Hash(
|
1716
|
+
self.sid, len(q), self._ulonglong_byref(q), self._to_ubyte(len(q), t)
|
1717
|
+
)
|
1718
|
+
self._throw_if_error()
|
1719
|
+
|
1720
|
+
# boolean logic gates
|
1721
|
+
def qand(self, qi1, qi2, qo):
|
1722
|
+
"""Logical AND
|
1723
|
+
|
1724
|
+
Logical AND of 2 qubits whose result is stored in the target qubit.
|
1725
|
+
|
1726
|
+
Args:
|
1727
|
+
qi1: qubit 1
|
1728
|
+
qi2: qubit 2
|
1729
|
+
qo: target qubit
|
1730
|
+
|
1731
|
+
Raises:
|
1732
|
+
RuntimeError: QrackSimulator raised an exception.
|
1733
|
+
"""
|
1734
|
+
Qrack.qrack_lib.AND(self.sid, qi1, qi2, qo)
|
1735
|
+
self._throw_if_error()
|
1736
|
+
|
1737
|
+
def qor(self, qi1, qi2, qo):
|
1738
|
+
"""Logical OR
|
1739
|
+
|
1740
|
+
Logical OR of 2 qubits whose result is stored in the target qubit.
|
1741
|
+
|
1742
|
+
Args:
|
1743
|
+
qi1: qubit 1
|
1744
|
+
qi2: qubit 2
|
1745
|
+
qo: target qubit
|
1746
|
+
|
1747
|
+
Raises:
|
1748
|
+
RuntimeError: QrackSimulator raised an exception.
|
1749
|
+
"""
|
1750
|
+
Qrack.qrack_lib.OR(self.sid, qi1, qi2, qo)
|
1751
|
+
self._throw_if_error()
|
1752
|
+
|
1753
|
+
def qxor(self, qi1, qi2, qo):
|
1754
|
+
"""Logical XOR
|
1755
|
+
|
1756
|
+
Logical exlusive-OR of 2 qubits whose result is stored in the target
|
1757
|
+
qubit.
|
1758
|
+
|
1759
|
+
Args:
|
1760
|
+
qi1: qubit 1
|
1761
|
+
qi2: qubit 2
|
1762
|
+
qo: target qubit
|
1763
|
+
|
1764
|
+
Raises:
|
1765
|
+
RuntimeError: QrackSimulator raised an exception.
|
1766
|
+
"""
|
1767
|
+
Qrack.qrack_lib.XOR(self.sid, qi1, qi2, qo)
|
1768
|
+
self._throw_if_error()
|
1769
|
+
|
1770
|
+
def qnand(self, qi1, qi2, qo):
|
1771
|
+
"""Logical NAND
|
1772
|
+
|
1773
|
+
Logical NAND of 2 qubits whose result is stored in the target
|
1774
|
+
qubit.
|
1775
|
+
|
1776
|
+
Args:
|
1777
|
+
qi1: qubit 1
|
1778
|
+
qi2: qubit 2
|
1779
|
+
qo: target qubit
|
1780
|
+
|
1781
|
+
Raises:
|
1782
|
+
RuntimeError: QrackSimulator raised an exception.
|
1783
|
+
"""
|
1784
|
+
Qrack.qrack_lib.NAND(self.sid, qi1, qi2, qo)
|
1785
|
+
self._throw_if_error()
|
1786
|
+
|
1787
|
+
def qnor(self, qi1, qi2, qo):
|
1788
|
+
"""Logical NOR
|
1789
|
+
|
1790
|
+
Logical NOR of 2 qubits whose result is stored in the target
|
1791
|
+
qubit.
|
1792
|
+
|
1793
|
+
Args:
|
1794
|
+
qi1: qubit 1
|
1795
|
+
qi2: qubit 2
|
1796
|
+
qo: target qubit
|
1797
|
+
|
1798
|
+
Raises:
|
1799
|
+
RuntimeError: QrackSimulator raised an exception.
|
1800
|
+
"""
|
1801
|
+
Qrack.qrack_lib.NOR(self.sid, qi1, qi2, qo)
|
1802
|
+
self._throw_if_error()
|
1803
|
+
|
1804
|
+
def qxnor(self, qi1, qi2, qo):
|
1805
|
+
"""Logical XOR
|
1806
|
+
|
1807
|
+
Logical exlusive-NOR of 2 qubits whose result is stored in the target
|
1808
|
+
qubit.
|
1809
|
+
|
1810
|
+
Args:
|
1811
|
+
qi1: qubit 1
|
1812
|
+
qi2: qubit 2
|
1813
|
+
qo: target qubit
|
1814
|
+
|
1815
|
+
Raises:
|
1816
|
+
RuntimeError: QrackSimulator raised an exception.
|
1817
|
+
"""
|
1818
|
+
Qrack.qrack_lib.XNOR(self.sid, qi1, qi2, qo)
|
1819
|
+
self._throw_if_error()
|
1820
|
+
|
1821
|
+
def cland(self, ci, qi, qo):
|
1822
|
+
"""Classical AND
|
1823
|
+
|
1824
|
+
Logical AND with one qubit and one classical bit whose result is
|
1825
|
+
stored in target qubit.
|
1826
|
+
|
1827
|
+
Args:
|
1828
|
+
qi1: qubit 1
|
1829
|
+
qi2: qubit 2
|
1830
|
+
qo: target qubit
|
1831
|
+
|
1832
|
+
Raises:
|
1833
|
+
RuntimeError: QrackSimulator raised an exception.
|
1834
|
+
"""
|
1835
|
+
Qrack.qrack_lib.CLAND(self.sid, ci, qi, qo)
|
1836
|
+
self._throw_if_error()
|
1837
|
+
|
1838
|
+
def clor(self, ci, qi, qo):
|
1839
|
+
"""Classical OR
|
1840
|
+
|
1841
|
+
Logical OR with one qubit and one classical bit whose result is
|
1842
|
+
stored in target qubit.
|
1843
|
+
|
1844
|
+
Args:
|
1845
|
+
qi1: qubit 1
|
1846
|
+
qi2: qubit 2
|
1847
|
+
qo: target qubit
|
1848
|
+
|
1849
|
+
Raises:
|
1850
|
+
RuntimeError: QrackSimulator raised an exception.
|
1851
|
+
"""
|
1852
|
+
Qrack.qrack_lib.CLOR(self.sid, ci, qi, qo)
|
1853
|
+
self._throw_if_error()
|
1854
|
+
|
1855
|
+
def clxor(self, ci, qi, qo):
|
1856
|
+
"""Classical XOR
|
1857
|
+
|
1858
|
+
Logical exlusive-OR with one qubit and one classical bit whose result is
|
1859
|
+
stored in target qubit.
|
1860
|
+
|
1861
|
+
Args:
|
1862
|
+
qi1: qubit 1
|
1863
|
+
qi2: qubit 2
|
1864
|
+
qo: target qubit
|
1865
|
+
|
1866
|
+
Raises:
|
1867
|
+
RuntimeError: QrackSimulator raised an exception.
|
1868
|
+
"""
|
1869
|
+
Qrack.qrack_lib.CLXOR(self.sid, ci, qi, qo)
|
1870
|
+
self._throw_if_error()
|
1871
|
+
|
1872
|
+
def clnand(self, ci, qi, qo):
|
1873
|
+
"""Classical NAND
|
1874
|
+
|
1875
|
+
Logical NAND with one qubit and one classical bit whose result is
|
1876
|
+
stored in target qubit.
|
1877
|
+
|
1878
|
+
Args:
|
1879
|
+
qi1: qubit 1
|
1880
|
+
qi2: qubit 2
|
1881
|
+
qo: target qubit
|
1882
|
+
|
1883
|
+
Raises:
|
1884
|
+
RuntimeError: QrackSimulator raised an exception.
|
1885
|
+
"""
|
1886
|
+
Qrack.qrack_lib.CLNAND(self.sid, ci, qi, qo)
|
1887
|
+
self._throw_if_error()
|
1888
|
+
|
1889
|
+
def clnor(self, ci, qi, qo):
|
1890
|
+
"""Classical NOR
|
1891
|
+
|
1892
|
+
Logical NOR with one qubit and one classical bit whose result is
|
1893
|
+
stored in target qubit.
|
1894
|
+
|
1895
|
+
Args:
|
1896
|
+
qi1: qubit 1
|
1897
|
+
qi2: qubit 2
|
1898
|
+
qo: target qubit
|
1899
|
+
|
1900
|
+
Raises:
|
1901
|
+
RuntimeError: QrackSimulator raised an exception.
|
1902
|
+
"""
|
1903
|
+
Qrack.qrack_lib.CLNOR(self.sid, ci, qi, qo)
|
1904
|
+
self._throw_if_error()
|
1905
|
+
|
1906
|
+
def clxnor(self, ci, qi, qo):
|
1907
|
+
"""Classical XNOR
|
1908
|
+
|
1909
|
+
Logical exlusive-NOR with one qubit and one classical bit whose result is
|
1910
|
+
stored in target qubit.
|
1911
|
+
|
1912
|
+
Args:
|
1913
|
+
qi1: qubit 1
|
1914
|
+
qi2: qubit 2
|
1915
|
+
qo: target qubit
|
1916
|
+
|
1917
|
+
Raises:
|
1918
|
+
RuntimeError: QrackSimulator raised an exception.
|
1919
|
+
"""
|
1920
|
+
Qrack.qrack_lib.CLXNOR(self.sid, ci, qi, qo)
|
1921
|
+
self._throw_if_error()
|
1922
|
+
|
1923
|
+
# Particular Quantum Circuits
|
1924
|
+
|
1925
|
+
## fourier transform
|
1926
|
+
def qft(self, qs):
|
1927
|
+
"""Quantum Fourier Transform
|
1928
|
+
|
1929
|
+
Applies Quantum Fourier Transform on the list of qubits provided.
|
1930
|
+
|
1931
|
+
Args:
|
1932
|
+
qs: list of qubits
|
1933
|
+
|
1934
|
+
Raises:
|
1935
|
+
RuntimeError: QrackSimulator raised an exception.
|
1936
|
+
"""
|
1937
|
+
Qrack.qrack_lib.QFT(self.sid, len(qs), self._ulonglong_byref(qs))
|
1938
|
+
self._throw_if_error()
|
1939
|
+
|
1940
|
+
def iqft(self, qs):
|
1941
|
+
"""Inverse-quantum Fourier Transform
|
1942
|
+
|
1943
|
+
Applies Inverse-quantum Fourier Transform on the list of qubits
|
1944
|
+
provided.
|
1945
|
+
|
1946
|
+
Args:
|
1947
|
+
qs: list of qubits
|
1948
|
+
|
1949
|
+
Raises:
|
1950
|
+
RuntimeError: QrackSimulator raised an exception.
|
1951
|
+
"""
|
1952
|
+
Qrack.qrack_lib.IQFT(self.sid, len(qs), self._ulonglong_byref(qs))
|
1953
|
+
self._throw_if_error()
|
1954
|
+
|
1955
|
+
# pseudo-quantum
|
1956
|
+
|
1957
|
+
## allocate and release
|
1958
|
+
def allocate_qubit(self, qid):
|
1959
|
+
"""Allocate Qubit
|
1960
|
+
|
1961
|
+
Allocate 1 new qubit with the given qubit ID.
|
1962
|
+
|
1963
|
+
Args:
|
1964
|
+
qid: qubit id
|
1965
|
+
|
1966
|
+
Raises:
|
1967
|
+
RuntimeError: QrackSimulator raised an exception.
|
1968
|
+
"""
|
1969
|
+
Qrack.qrack_lib.allocateQubit(self.sid, qid)
|
1970
|
+
self._throw_if_error()
|
1971
|
+
|
1972
|
+
def release(self, q):
|
1973
|
+
"""Release Qubit
|
1974
|
+
|
1975
|
+
Release qubit given by the given qubit ID.
|
1976
|
+
|
1977
|
+
Args:
|
1978
|
+
q: qubit id
|
1979
|
+
|
1980
|
+
Raises:
|
1981
|
+
RuntimeError: QrackSimulator raised an exception.
|
1982
|
+
|
1983
|
+
Returns:
|
1984
|
+
If the qubit was in `|0>` state with small tolerance.
|
1985
|
+
"""
|
1986
|
+
result = Qrack.qrack_lib.release(self.sid, q)
|
1987
|
+
self._throw_if_error()
|
1988
|
+
return result
|
1989
|
+
|
1990
|
+
def num_qubits(self):
|
1991
|
+
"""Get Qubit count
|
1992
|
+
|
1993
|
+
Returns the qubit count of the simulator.
|
1994
|
+
|
1995
|
+
Args:
|
1996
|
+
q: qubit id
|
1997
|
+
|
1998
|
+
Raises:
|
1999
|
+
RuntimeError: QrackSimulator raised an exception.
|
2000
|
+
|
2001
|
+
Returns:
|
2002
|
+
Qubit count of the simulator
|
2003
|
+
"""
|
2004
|
+
result = Qrack.qrack_lib.num_qubits(self.sid)
|
2005
|
+
self._throw_if_error()
|
2006
|
+
return result
|
2007
|
+
|
2008
|
+
## schmidt decomposition
|
2009
|
+
def compose(self, other, q):
|
2010
|
+
"""Compose qubits
|
2011
|
+
|
2012
|
+
Compose quantum description of given qubit with the current system.
|
2013
|
+
|
2014
|
+
Args:
|
2015
|
+
q: qubit id
|
2016
|
+
|
2017
|
+
Raises:
|
2018
|
+
RuntimeError: QrackSimulator raised an exception.
|
2019
|
+
RuntimeError: QrackSimulator with isTensorNetwork=True option cannot compose()! (Turn off just this option, in the constructor.)
|
2020
|
+
"""
|
2021
|
+
if self.is_tensor_network:
|
2022
|
+
raise RuntimeError("QrackSimulator with isTensorNetwork=True option cannot compose()! (Turn off just this option, in the constructor.)")
|
2023
|
+
|
2024
|
+
Qrack.qrack_lib.Compose(self.sid, other.sid, self._ulonglong_byref(q))
|
2025
|
+
self._throw_if_error()
|
2026
|
+
|
2027
|
+
def decompose(self, q):
|
2028
|
+
"""Decompose system
|
2029
|
+
|
2030
|
+
Decompose the given qubit out of the system.
|
2031
|
+
Warning: The qubit subsystem state must be separable, or the behavior
|
2032
|
+
of this method is undefined.
|
2033
|
+
|
2034
|
+
Args:
|
2035
|
+
q: qubit id
|
2036
|
+
|
2037
|
+
Raises:
|
2038
|
+
RuntimeError: QrackSimulator raised an exception.
|
2039
|
+
RuntimeError: QrackSimulator with isTensorNetwork=True option cannot decompose()! (Turn off just this option, in the constructor.)
|
2040
|
+
|
2041
|
+
Returns:
|
2042
|
+
State of the systems.
|
2043
|
+
"""
|
2044
|
+
if self.is_tensor_network:
|
2045
|
+
raise RuntimeError("QrackSimulator with isTensorNetwork=True option cannot decompose()! (Turn off just this option, in the constructor.)")
|
2046
|
+
|
2047
|
+
other = QrackSimulator()
|
2048
|
+
Qrack.qrack_lib.destroy(other.sid)
|
2049
|
+
l = len(q)
|
2050
|
+
other.sid = Qrack.qrack_lib.Decompose(self.sid, l, self._ulonglong_byref(q))
|
2051
|
+
self._throw_if_error()
|
2052
|
+
return other
|
2053
|
+
|
2054
|
+
def dispose(self, q):
|
2055
|
+
"""Dispose qubits
|
2056
|
+
|
2057
|
+
Minimally decompose a set of contiguous bits from the separably
|
2058
|
+
composed unit, and discard the separable bits.
|
2059
|
+
Warning: The qubit subsystem state must be separable, or the behavior
|
2060
|
+
of this method is undefined.
|
2061
|
+
|
2062
|
+
Args:
|
2063
|
+
q: qubit
|
2064
|
+
|
2065
|
+
Raises:
|
2066
|
+
RuntimeError: QrackSimulator raised an exception.
|
2067
|
+
RuntimeError: QrackSimulator with isTensorNetwork=True option cannot dispose()! (Turn off just this option, in the constructor.)
|
2068
|
+
|
2069
|
+
Returns:
|
2070
|
+
State of the systems.
|
2071
|
+
"""
|
2072
|
+
if self.is_tensor_network:
|
2073
|
+
raise RuntimeError("QrackSimulator with isTensorNetwork=True option cannot dispose()! (Turn off just this option, in the constructor.)")
|
2074
|
+
|
2075
|
+
l = len(q)
|
2076
|
+
Qrack.qrack_lib.Dispose(self.sid, l, self._ulonglong_byref(q))
|
2077
|
+
self._throw_if_error()
|
2078
|
+
|
2079
|
+
## miscellaneous
|
2080
|
+
def dump_ids(self):
|
2081
|
+
"""Dump all IDs
|
2082
|
+
|
2083
|
+
Dump all IDs from the selected simulator ID into the callback.
|
2084
|
+
|
2085
|
+
Returns:
|
2086
|
+
List of ids
|
2087
|
+
"""
|
2088
|
+
global ids_list
|
2089
|
+
global ids_list_index
|
2090
|
+
ids_list = [0] * self.num_qubits()
|
2091
|
+
ids_list_index = 0
|
2092
|
+
Qrack.qrack_lib.DumpIds(self.sid, self.dump_ids_callback)
|
2093
|
+
return ids_list
|
2094
|
+
|
2095
|
+
@ctypes.CFUNCTYPE(None, ctypes.c_ulonglong)
|
2096
|
+
def dump_ids_callback(i):
|
2097
|
+
"""C callback function"""
|
2098
|
+
global ids_list
|
2099
|
+
global ids_list_index
|
2100
|
+
ids_list[ids_list_index] = i
|
2101
|
+
ids_list_index = ids_list_index + 1
|
2102
|
+
|
2103
|
+
def dump(self):
|
2104
|
+
"""Dump state vector
|
2105
|
+
|
2106
|
+
Dump state vector from the selected simulator ID into the callback.
|
2107
|
+
|
2108
|
+
Returns:
|
2109
|
+
State vector list
|
2110
|
+
"""
|
2111
|
+
global state_vec_list
|
2112
|
+
global state_vec_list_index
|
2113
|
+
global state_vec_probability
|
2114
|
+
state_vec_list = [complex(0, 0)] * (1 << self.num_qubits())
|
2115
|
+
state_vec_list_index = 0
|
2116
|
+
state_vec_probability = 0
|
2117
|
+
Qrack.qrack_lib.Dump(self.sid, self.dump_callback)
|
2118
|
+
return state_vec_list
|
2119
|
+
|
2120
|
+
@ctypes.CFUNCTYPE(ctypes.c_bool, ctypes.c_double, ctypes.c_double)
|
2121
|
+
def dump_callback(r, i):
|
2122
|
+
"""C callback function"""
|
2123
|
+
global state_vec_list
|
2124
|
+
global state_vec_list_index
|
2125
|
+
global state_vec_probability
|
2126
|
+
state_vec_list[state_vec_list_index] = complex(r, i)
|
2127
|
+
state_vec_list_index = state_vec_list_index + 1
|
2128
|
+
state_vec_probability = state_vec_probability + (r * r) + (i * i)
|
2129
|
+
if (1.0 - state_vec_probability) <= (7.0 / 3 - 4.0 / 3 - 1):
|
2130
|
+
return False
|
2131
|
+
return True
|
2132
|
+
|
2133
|
+
def in_ket(self, ket):
|
2134
|
+
"""Set state vector
|
2135
|
+
|
2136
|
+
Set state vector for the selected simulator ID.
|
2137
|
+
Warning: State vector is not always the internal representation leading
|
2138
|
+
to sub-optimal performance of the method.
|
2139
|
+
|
2140
|
+
Args:
|
2141
|
+
ket: the state vector to which simulator will be set
|
2142
|
+
|
2143
|
+
Raises:
|
2144
|
+
RuntimeError: QrackSimulator raised an exception.
|
2145
|
+
"""
|
2146
|
+
Qrack.qrack_lib.InKet(self.sid, self._qrack_complex_byref(ket))
|
2147
|
+
self._throw_if_error()
|
2148
|
+
|
2149
|
+
def out_ket(self):
|
2150
|
+
"""Set state vector
|
2151
|
+
|
2152
|
+
Returns the raw state vector of the simulator.
|
2153
|
+
Warning: State vector is not always the internal representation leading
|
2154
|
+
to sub-optimal performance of the method.
|
2155
|
+
|
2156
|
+
Raises:
|
2157
|
+
RuntimeError: QrackSimulator raised an exception.
|
2158
|
+
|
2159
|
+
Returns:
|
2160
|
+
list representing the state vector.
|
2161
|
+
"""
|
2162
|
+
amp_count = 1 << self.num_qubits()
|
2163
|
+
ket = self._qrack_complex_byref([complex(0, 0)] * amp_count)
|
2164
|
+
Qrack.qrack_lib.OutKet(self.sid, ket)
|
2165
|
+
self._throw_if_error()
|
2166
|
+
return [complex(r, i) for r, i in self._pairwise(ket)]
|
2167
|
+
|
2168
|
+
def prob_all(self, q):
|
2169
|
+
"""Probabilities of all subset permutations
|
2170
|
+
|
2171
|
+
Get the probabilities of all permutations of the subset.
|
2172
|
+
|
2173
|
+
Args:
|
2174
|
+
q: list of qubit ids
|
2175
|
+
|
2176
|
+
Raises:
|
2177
|
+
RuntimeError: QrackSimulator raised an exception.
|
2178
|
+
|
2179
|
+
Returns:
|
2180
|
+
list representing the state vector.
|
2181
|
+
"""
|
2182
|
+
probs = self._real1_byref([0.0] * (1 << len(q)))
|
2183
|
+
Qrack.qrack_lib.ProbAll(self.sid, len(q), self._ulonglong_byref(q), probs)
|
2184
|
+
self._throw_if_error()
|
2185
|
+
return list(probs)
|
2186
|
+
|
2187
|
+
def variance(self, q):
|
2188
|
+
"""Variance of probabilities of all subset permutations
|
2189
|
+
|
2190
|
+
Get the overall variance of probabilities of all
|
2191
|
+
permutations of the subset.
|
2192
|
+
|
2193
|
+
Args:
|
2194
|
+
q: list of qubit ids
|
2195
|
+
|
2196
|
+
Raises:
|
2197
|
+
RuntimeError: QrackSimulator raised an exception.
|
2198
|
+
|
2199
|
+
Returns:
|
2200
|
+
float variance
|
2201
|
+
"""
|
2202
|
+
result = Qrack.qrack_lib.Variance(self.sid, len(q), self._ulonglong_byref(q))
|
2203
|
+
self._throw_if_error()
|
2204
|
+
return result
|
2205
|
+
|
2206
|
+
def prob(self, q):
|
2207
|
+
"""Probability of `|1>`
|
2208
|
+
|
2209
|
+
Get the probability that a qubit is in the `|1>` state.
|
2210
|
+
|
2211
|
+
Args:
|
2212
|
+
q: qubit id
|
2213
|
+
|
2214
|
+
Raises:
|
2215
|
+
RuntimeError: QrackSimulator raised an exception.
|
2216
|
+
|
2217
|
+
Returns:
|
2218
|
+
probability of qubit being in `|1>`
|
2219
|
+
"""
|
2220
|
+
result = Qrack.qrack_lib.Prob(self.sid, q)
|
2221
|
+
self._throw_if_error()
|
2222
|
+
return result
|
2223
|
+
|
2224
|
+
def prob_rdm(self, q):
|
2225
|
+
"""Probability of `|1>`, (tracing out the reduced
|
2226
|
+
density matrix without stabilizer ancillary qubits)
|
2227
|
+
|
2228
|
+
Get the probability that a qubit is in the `|1>` state.
|
2229
|
+
|
2230
|
+
Args:
|
2231
|
+
q: qubit id
|
2232
|
+
|
2233
|
+
Raises:
|
2234
|
+
RuntimeError: QrackSimulator raised an exception.
|
2235
|
+
|
2236
|
+
Returns:
|
2237
|
+
probability of qubit being in `|1>`
|
2238
|
+
"""
|
2239
|
+
result = Qrack.qrack_lib.ProbRdm(self.sid, q)
|
2240
|
+
self._throw_if_error()
|
2241
|
+
return result
|
2242
|
+
|
2243
|
+
def prob_perm(self, q, c):
|
2244
|
+
"""Probability of permutation
|
2245
|
+
|
2246
|
+
Get the probability that the qubit IDs in "q" have the truth values
|
2247
|
+
in "c", directly corresponding by list index.
|
2248
|
+
|
2249
|
+
Args:
|
2250
|
+
q: list of qubit ids
|
2251
|
+
c: list of qubit truth values bools
|
2252
|
+
|
2253
|
+
Raises:
|
2254
|
+
RuntimeError: QrackSimulator raised an exception.
|
2255
|
+
|
2256
|
+
Returns:
|
2257
|
+
probability that each qubit in "q[i]" has corresponding truth
|
2258
|
+
value in "c[i]", at once
|
2259
|
+
"""
|
2260
|
+
|
2261
|
+
if len(q) != len(c):
|
2262
|
+
raise RuntimeError("prob_perm argument lengths do not match.")
|
2263
|
+
result = Qrack.qrack_lib.PermutationProb(self.sid, len(q), self._ulonglong_byref(q), self._bool_byref(c));
|
2264
|
+
self._throw_if_error()
|
2265
|
+
return result
|
2266
|
+
|
2267
|
+
def prob_perm_rdm(self, q, c, r = True):
|
2268
|
+
"""Probability of permutation, (tracing out the reduced
|
2269
|
+
density matrix without stabilizer ancillary qubits)
|
2270
|
+
|
2271
|
+
Get the probability that the qubit IDs in "q" have the truth
|
2272
|
+
values in "c", directly corresponding by list index.
|
2273
|
+
|
2274
|
+
Args:
|
2275
|
+
q: list of qubit ids
|
2276
|
+
c: list of qubit truth values bools
|
2277
|
+
r: round Rz gates down from T^(1/2)
|
2278
|
+
|
2279
|
+
Raises:
|
2280
|
+
RuntimeError: QrackSimulator raised an exception.
|
2281
|
+
|
2282
|
+
Returns:
|
2283
|
+
probability that each qubit in "q[i]" has corresponding truth
|
2284
|
+
value in "c[i]", at once
|
2285
|
+
"""
|
2286
|
+
|
2287
|
+
if len(q) != len(c):
|
2288
|
+
raise RuntimeError("prob_perm argument lengths do not match.")
|
2289
|
+
result = Qrack.qrack_lib.PermutationProbRdm(self.sid, len(q), self._ulonglong_byref(q), self._bool_byref(c), r);
|
2290
|
+
self._throw_if_error()
|
2291
|
+
return result
|
2292
|
+
|
2293
|
+
def permutation_expectation(self, q):
|
2294
|
+
"""Permutation expectation value
|
2295
|
+
|
2296
|
+
Get the permutation expectation value, based upon the order of
|
2297
|
+
input qubits.
|
2298
|
+
|
2299
|
+
Args:
|
2300
|
+
q: qubits, from low to high
|
2301
|
+
|
2302
|
+
Raises:
|
2303
|
+
RuntimeError: QrackSimulator raised an exception.
|
2304
|
+
|
2305
|
+
Returns:
|
2306
|
+
Expectation value
|
2307
|
+
"""
|
2308
|
+
result = Qrack.qrack_lib.PermutationExpectation(
|
2309
|
+
self.sid, len(q), self._ulonglong_byref(q)
|
2310
|
+
)
|
2311
|
+
self._throw_if_error()
|
2312
|
+
return result
|
2313
|
+
|
2314
|
+
def permutation_expectation_rdm(self, q, r = True):
|
2315
|
+
"""Permutation expectation value, (tracing out the reduced
|
2316
|
+
density matrix without stabilizer ancillary qubits)
|
2317
|
+
|
2318
|
+
Get the permutation expectation value, based upon the order of
|
2319
|
+
input qubits.
|
2320
|
+
|
2321
|
+
Args:
|
2322
|
+
q: qubits, from low to high
|
2323
|
+
r: round Rz gates down from T^(1/2)
|
2324
|
+
|
2325
|
+
Raises:
|
2326
|
+
RuntimeError: QrackSimulator raised an exception.
|
2327
|
+
|
2328
|
+
Returns:
|
2329
|
+
Expectation value
|
2330
|
+
"""
|
2331
|
+
result = Qrack.qrack_lib.PermutationExpectationRdm(
|
2332
|
+
self.sid, len(q), self._ulonglong_byref(q), r
|
2333
|
+
)
|
2334
|
+
self._throw_if_error()
|
2335
|
+
return result
|
2336
|
+
|
2337
|
+
def factorized_expectation(self, q, c):
|
2338
|
+
"""Factorized expectation value
|
2339
|
+
|
2340
|
+
Get the factorized expectation value, where each entry
|
2341
|
+
in "c" is an expectation value for corresponding "q"
|
2342
|
+
being false, then true, repeated for each in "q".
|
2343
|
+
|
2344
|
+
Args:
|
2345
|
+
q: qubits, from low to high
|
2346
|
+
c: qubit falsey/truthy values, from low to high
|
2347
|
+
|
2348
|
+
Raises:
|
2349
|
+
RuntimeError: QrackSimulator raised an exception.
|
2350
|
+
|
2351
|
+
Returns:
|
2352
|
+
Expectation value
|
2353
|
+
"""
|
2354
|
+
m = max([(x.bit_length() + 63) // 64 for x in c])
|
2355
|
+
result = Qrack.qrack_lib.FactorizedExpectation(
|
2356
|
+
self.sid, len(q), self._ulonglong_byref(q), m, self._to_ulonglong(m, c)
|
2357
|
+
)
|
2358
|
+
self._throw_if_error()
|
2359
|
+
return result
|
2360
|
+
|
2361
|
+
def factorized_expectation_rdm(self, q, c, r = True):
|
2362
|
+
"""Factorized expectation value, (tracing out the reduced
|
2363
|
+
density matrix without stabilizer ancillary qubits)
|
2364
|
+
|
2365
|
+
Get the factorized expectation value, where each entry
|
2366
|
+
in "c" is an expectation value for corresponding "q"
|
2367
|
+
being false, then true, repeated for each in "q".
|
2368
|
+
|
2369
|
+
Args:
|
2370
|
+
q: qubits, from low to high
|
2371
|
+
c: qubit falsey/truthy values, from low to high
|
2372
|
+
r: round Rz gates down from T^(1/2)
|
2373
|
+
|
2374
|
+
Raises:
|
2375
|
+
RuntimeError: QrackSimulator raised an exception.
|
2376
|
+
|
2377
|
+
Returns:
|
2378
|
+
Expectation value
|
2379
|
+
"""
|
2380
|
+
m = max([(x.bit_length() + 63) // 64 for x in c])
|
2381
|
+
result = Qrack.qrack_lib.FactorizedExpectationRdm(
|
2382
|
+
self.sid, len(q), self._ulonglong_byref(q), m, self._to_ulonglong(m, c), r
|
2383
|
+
)
|
2384
|
+
self._throw_if_error()
|
2385
|
+
return result
|
2386
|
+
|
2387
|
+
def factorized_expectation_fp(self, q, c):
|
2388
|
+
"""Factorized expectation value (floating-point)
|
2389
|
+
|
2390
|
+
Get the factorized expectation value, where each entry
|
2391
|
+
in "c" is an expectation value for corresponding "q"
|
2392
|
+
being false, then true, repeated for each in "q".
|
2393
|
+
|
2394
|
+
Args:
|
2395
|
+
q: qubits, from low to high
|
2396
|
+
c: qubit falsey/truthy values, from low to high
|
2397
|
+
|
2398
|
+
Raises:
|
2399
|
+
RuntimeError: QrackSimulator raised an exception.
|
2400
|
+
|
2401
|
+
Returns:
|
2402
|
+
Expectation value
|
2403
|
+
"""
|
2404
|
+
result = Qrack.qrack_lib.FactorizedExpectationFp(
|
2405
|
+
self.sid, len(q), self._ulonglong_byref(q), self._real1_byref(c)
|
2406
|
+
)
|
2407
|
+
self._throw_if_error()
|
2408
|
+
return result
|
2409
|
+
|
2410
|
+
def factorized_expectation_fp_rdm(self, q, c, r = True):
|
2411
|
+
"""Factorized expectation value, (tracing out the reduced
|
2412
|
+
density matrix without stabilizer ancillary qubits)
|
2413
|
+
|
2414
|
+
Get the factorized expectation value, where each entry
|
2415
|
+
in "c" is an expectation value for corresponding "q"
|
2416
|
+
being false, then true, repeated for each in "q".
|
2417
|
+
|
2418
|
+
Args:
|
2419
|
+
q: qubits, from low to high
|
2420
|
+
c: qubit falsey/truthy values, from low to high
|
2421
|
+
r: round Rz gates down from T^(1/2)
|
2422
|
+
|
2423
|
+
Raises:
|
2424
|
+
RuntimeError: QrackSimulator raised an exception.
|
2425
|
+
|
2426
|
+
Returns:
|
2427
|
+
Expectation value
|
2428
|
+
"""
|
2429
|
+
result = Qrack.qrack_lib.FactorizedExpectationFpRdm(
|
2430
|
+
self.sid, len(q), self._ulonglong_byref(q), self._real1_byref(c), r
|
2431
|
+
)
|
2432
|
+
self._throw_if_error()
|
2433
|
+
return result
|
2434
|
+
|
2435
|
+
def joint_ensemble_probability(self, b, q):
|
2436
|
+
"""Ensemble probability
|
2437
|
+
|
2438
|
+
Find the joint probability for all specified qubits under the
|
2439
|
+
respective Pauli basis transformations.
|
2440
|
+
|
2441
|
+
Args:
|
2442
|
+
b: pauli basis
|
2443
|
+
q: specified qubits
|
2444
|
+
|
2445
|
+
Raises:
|
2446
|
+
RuntimeError: QrackSimulator raised an exception.
|
2447
|
+
|
2448
|
+
Returns:
|
2449
|
+
Expectation value
|
2450
|
+
"""
|
2451
|
+
if len(b) != len(q):
|
2452
|
+
raise RuntimeError("Lengths of list parameters are mismatched.")
|
2453
|
+
result = Qrack.qrack_lib.JointEnsembleProbability(
|
2454
|
+
self.sid, len(b), self._ulonglong_byref(b), q
|
2455
|
+
)
|
2456
|
+
self._throw_if_error()
|
2457
|
+
return result
|
2458
|
+
|
2459
|
+
def phase_parity(self, la, q):
|
2460
|
+
"""Phase to odd parity
|
2461
|
+
|
2462
|
+
Applies `e^(i*la)` phase factor to all combinations of bits with
|
2463
|
+
odd parity, based upon permutations of qubits.
|
2464
|
+
|
2465
|
+
Args:
|
2466
|
+
la: phase
|
2467
|
+
q: specified qubits
|
2468
|
+
|
2469
|
+
Raises:
|
2470
|
+
RuntimeError: QrackSimulator raised an exception.
|
2471
|
+
RuntimeError: QrackSimulator with isTensorNetwork=True option cannot phase_parity()! (Turn off just this option, in the constructor.)
|
2472
|
+
"""
|
2473
|
+
if self.is_tensor_network:
|
2474
|
+
raise RuntimeError("QrackSimulator with isTensorNetwork=True option cannot phase_parity()! (Turn off just this option, in the constructor.)")
|
2475
|
+
|
2476
|
+
Qrack.qrack_lib.PhaseParity(
|
2477
|
+
self.sid, ctypes.c_double(la), len(q), self._ulonglong_byref(q)
|
2478
|
+
)
|
2479
|
+
self._throw_if_error()
|
2480
|
+
|
2481
|
+
def try_separate_1qb(self, qi1):
|
2482
|
+
"""Manual seperation
|
2483
|
+
|
2484
|
+
Exposes manual control for schmidt decomposition which attempts to
|
2485
|
+
decompose the qubit with possible performance improvement
|
2486
|
+
|
2487
|
+
Args:
|
2488
|
+
qi1: qubit to be decomposed
|
2489
|
+
|
2490
|
+
Raises:
|
2491
|
+
RuntimeError: QrackSimulator raised an exception.
|
2492
|
+
|
2493
|
+
Returns:
|
2494
|
+
State of the qubit.
|
2495
|
+
"""
|
2496
|
+
result = Qrack.qrack_lib.TrySeparate1Qb(self.sid, qi1)
|
2497
|
+
self._throw_if_error()
|
2498
|
+
return result
|
2499
|
+
|
2500
|
+
def try_separate_2qb(self, qi1, qi2):
|
2501
|
+
"""Manual two-qubits seperation
|
2502
|
+
|
2503
|
+
two-qubits counterpart of `try_separate_1qb`.
|
2504
|
+
|
2505
|
+
Args:
|
2506
|
+
qi1: first qubit to be decomposed
|
2507
|
+
qi2: second qubit to be decomposed
|
2508
|
+
|
2509
|
+
Raises:
|
2510
|
+
Runtimeerror: QrackSimulator raised an exception.
|
2511
|
+
|
2512
|
+
Returns:
|
2513
|
+
State of both the qubits.
|
2514
|
+
"""
|
2515
|
+
result = Qrack.qrack_lib.TrySeparate2Qb(self.sid, qi1, qi2)
|
2516
|
+
self._throw_if_error()
|
2517
|
+
return result
|
2518
|
+
|
2519
|
+
def try_separate_tolerance(self, qs, t):
|
2520
|
+
"""Manual multi-qubits seperation
|
2521
|
+
|
2522
|
+
Multi-qubits counterpart of `try_separate_1qb`.
|
2523
|
+
|
2524
|
+
Args:
|
2525
|
+
qs: list of qubits to be decomposed
|
2526
|
+
t: allowed tolerance
|
2527
|
+
|
2528
|
+
Raises:
|
2529
|
+
Runtimeerror: QrackSimulator raised an exception.
|
2530
|
+
|
2531
|
+
Returns:
|
2532
|
+
State of all the qubits.
|
2533
|
+
"""
|
2534
|
+
result = Qrack.qrack_lib.TrySeparateTol(
|
2535
|
+
self.sid, len(qs), self._ulonglong_byref(qs), t
|
2536
|
+
)
|
2537
|
+
self._throw_if_error()
|
2538
|
+
return result
|
2539
|
+
|
2540
|
+
def get_unitary_fidelity(self):
|
2541
|
+
"""Get fidelity estimate
|
2542
|
+
|
2543
|
+
When using "Schmidt decomposition rounding parameter" ("SDRP")
|
2544
|
+
approximate simulation, QrackSimulator() can make an excellent
|
2545
|
+
estimate of its overall fidelity at any time, tested against a
|
2546
|
+
nearest-neighbor variant of quantum volume circuits.
|
2547
|
+
|
2548
|
+
Resetting the fidelity calculation to 1.0 happens automatically
|
2549
|
+
when calling `mall` are can be done manually with
|
2550
|
+
`reset_unitary_fidelity()`.
|
2551
|
+
|
2552
|
+
Raises:
|
2553
|
+
RuntimeError: QrackSimulator raised an exception.
|
2554
|
+
|
2555
|
+
Returns:
|
2556
|
+
Fidelity estimate
|
2557
|
+
"""
|
2558
|
+
result = Qrack.qrack_lib.GetUnitaryFidelity(self.sid)
|
2559
|
+
self._throw_if_error()
|
2560
|
+
return result
|
2561
|
+
|
2562
|
+
def reset_unitary_fidelity(self):
|
2563
|
+
"""Reset fidelity estimate
|
2564
|
+
|
2565
|
+
When using "Schmidt decomposition rounding parameter" ("SDRP")
|
2566
|
+
approximate simulation, QrackSimulator() can make an excellent
|
2567
|
+
estimate of its overall fidelity at any time, tested against a
|
2568
|
+
nearest-neighbor variant of quantum volume circuits.
|
2569
|
+
|
2570
|
+
Resetting the fidelity calculation to 1.0 happens automatically
|
2571
|
+
when calling `m_all` or can be done manually with
|
2572
|
+
`reset_unitary_fidelity()`.
|
2573
|
+
|
2574
|
+
Raises:
|
2575
|
+
RuntimeError: QrackSimulator raised an exception.
|
2576
|
+
"""
|
2577
|
+
Qrack.qrack_lib.ResetUnitaryFidelity(self.sid)
|
2578
|
+
self._throw_if_error()
|
2579
|
+
|
2580
|
+
def set_sdrp(self, sdrp):
|
2581
|
+
"""Set "Schmidt decomposition rounding parameter"
|
2582
|
+
|
2583
|
+
When using "Schmidt decomposition rounding parameter" ("SDRP")
|
2584
|
+
approximate simulation, QrackSimulator() can make an excellent
|
2585
|
+
estimate of its overall fidelity at any time, tested against a
|
2586
|
+
nearest-neighbor variant of quantum volume circuits.
|
2587
|
+
|
2588
|
+
Resetting the fidelity calculation to 1.0 happens automatically
|
2589
|
+
when calling `m_all` or can be done manually with
|
2590
|
+
`reset_unitary_fidelity()`.
|
2591
|
+
|
2592
|
+
Raises:
|
2593
|
+
RuntimeError: QrackSimulator raised an exception.
|
2594
|
+
"""
|
2595
|
+
Qrack.qrack_lib.SetSdrp(self.sid, sdrp)
|
2596
|
+
self._throw_if_error()
|
2597
|
+
|
2598
|
+
def set_ncrp(self, ncrp):
|
2599
|
+
"""Set "Near-Clifford rounding parameter"
|
2600
|
+
|
2601
|
+
When using "near-Clifford rounding parameter" ("NCRP")
|
2602
|
+
approximate simulation, QrackSimulator() can make an excellent
|
2603
|
+
estimate of its overall fidelity after measurement, tested against
|
2604
|
+
a nearest-neighbor variant of quantum volume circuits.
|
2605
|
+
|
2606
|
+
Resetting the fidelity calculation to 1.0 happens automatically
|
2607
|
+
when calling `m_all` or can be done manually with
|
2608
|
+
`reset_unitary_fidelity()`.
|
2609
|
+
|
2610
|
+
Raises:
|
2611
|
+
RuntimeError: QrackSimulator raised an exception.
|
2612
|
+
"""
|
2613
|
+
Qrack.qrack_lib.SetNcrp(self.sid, ncrp)
|
2614
|
+
self._throw_if_error()
|
2615
|
+
|
2616
|
+
def set_reactive_separate(self, irs):
|
2617
|
+
"""Set reactive separation option
|
2618
|
+
|
2619
|
+
If reactive separation is available, then this method turns it off/on.
|
2620
|
+
Note that reactive separation is on by default.
|
2621
|
+
|
2622
|
+
Args:
|
2623
|
+
irs: is aggresively separable
|
2624
|
+
|
2625
|
+
Raises:
|
2626
|
+
RuntimeError: QrackSimulator raised an exception.
|
2627
|
+
"""
|
2628
|
+
Qrack.qrack_lib.SetReactiveSeparate(self.sid, irs)
|
2629
|
+
self._throw_if_error()
|
2630
|
+
|
2631
|
+
def set_t_injection(self, iti):
|
2632
|
+
"""Set t-injection option
|
2633
|
+
|
2634
|
+
If t-injection is available, then this method turns it off/on.
|
2635
|
+
Note that t-injection is on by default.
|
2636
|
+
|
2637
|
+
Args:
|
2638
|
+
iti: use "reverse t-injection gadget"
|
2639
|
+
|
2640
|
+
Raises:
|
2641
|
+
RuntimeError: QrackSimulator raised an exception.
|
2642
|
+
"""
|
2643
|
+
Qrack.qrack_lib.SetTInjection(self.sid, iti)
|
2644
|
+
self._throw_if_error()
|
2645
|
+
|
2646
|
+
def out_to_file(self, filename):
|
2647
|
+
"""Output state to file (stabilizer only!)
|
2648
|
+
|
2649
|
+
Outputs the hybrid stabilizer state to file.
|
2650
|
+
|
2651
|
+
Args:
|
2652
|
+
filename: Name of file
|
2653
|
+
"""
|
2654
|
+
Qrack.qrack_lib.qstabilizer_out_to_file(self.sid, filename.encode('utf-8'))
|
2655
|
+
self._throw_if_error()
|
2656
|
+
|
2657
|
+
def in_from_file(filename, is_binary_decision_tree = False, is_paged = True, is_cpu_gpu_hybrid = True, is_opencl = True, is_host_pointer = False):
|
2658
|
+
"""Input state from file (stabilizer only!)
|
2659
|
+
|
2660
|
+
Reads in a hybrid stabilizer state from file.
|
2661
|
+
|
2662
|
+
Args:
|
2663
|
+
filename: Name of file
|
2664
|
+
"""
|
2665
|
+
qb_count = 1
|
2666
|
+
with open(filename) as f:
|
2667
|
+
qb_count = int(f.readline())
|
2668
|
+
out = QrackSimulator(
|
2669
|
+
qubitCount=qb_count,
|
2670
|
+
isTensorNetwork=False,
|
2671
|
+
isSchmidtDecomposeMulti=False,
|
2672
|
+
isSchmidtDecompose=False,
|
2673
|
+
isStabilizerHybrid=True,
|
2674
|
+
isBinaryDecisionTree=is_binary_decision_tree,
|
2675
|
+
isPaged=is_paged,
|
2676
|
+
isCpuGpuHybrid=is_cpu_gpu_hybrid,
|
2677
|
+
isOpenCL=is_opencl,
|
2678
|
+
isHostPointer=is_host_pointer
|
2679
|
+
)
|
2680
|
+
Qrack.qrack_lib.qstabilizer_in_from_file(out.sid, filename.encode('utf-8'))
|
2681
|
+
out._throw_if_error()
|
2682
|
+
|
2683
|
+
return out
|
2684
|
+
|
2685
|
+
def file_to_qiskit_circuit(filename, is_hardware_encoded=False):
|
2686
|
+
"""Convert an output state file to a Qiskit circuit
|
2687
|
+
|
2688
|
+
Reads in an (optimized) circuit from a file named
|
2689
|
+
according to the "filename" parameter and outputs
|
2690
|
+
a Qiskit circuit.
|
2691
|
+
|
2692
|
+
Args:
|
2693
|
+
filename: Name of file
|
2694
|
+
|
2695
|
+
Raises:
|
2696
|
+
RuntimeErorr: Before trying to file_to_qiskit_circuit() with
|
2697
|
+
QrackCircuit, you must install Qiskit, numpy, and math!
|
2698
|
+
"""
|
2699
|
+
if not (_IS_QISKIT_AVAILABLE and _IS_NUMPY_AVAILABLE):
|
2700
|
+
raise RuntimeError(
|
2701
|
+
"Before trying to file_to_qiskit_circuit() with QrackCircuit, you must install Qiskit, numpy, and math!"
|
2702
|
+
)
|
2703
|
+
|
2704
|
+
lines = []
|
2705
|
+
with open(filename, 'r') as file:
|
2706
|
+
lines = file.readlines()
|
2707
|
+
|
2708
|
+
logical_qubits = int(lines[0])
|
2709
|
+
stabilizer_qubits = int(lines[1])
|
2710
|
+
|
2711
|
+
stabilizer_count = int(lines[2])
|
2712
|
+
|
2713
|
+
reg = QuantumRegister(stabilizer_qubits, name="q")
|
2714
|
+
circ_qubits = [Qubit(reg, i) for i in range(stabilizer_qubits)]
|
2715
|
+
clifford_circ = QuantumCircuit(reg)
|
2716
|
+
line_number = 3
|
2717
|
+
for i in range(stabilizer_count):
|
2718
|
+
shard_map_size = int(lines[line_number])
|
2719
|
+
line_number += 1
|
2720
|
+
|
2721
|
+
shard_map = {}
|
2722
|
+
for j in range(shard_map_size):
|
2723
|
+
line = lines[line_number].split()
|
2724
|
+
line_number += 1
|
2725
|
+
shard_map[int(line[0])] = int(line[1])
|
2726
|
+
|
2727
|
+
sub_reg = []
|
2728
|
+
for index, _ in sorted(shard_map.items(), key=lambda x: x[1]):
|
2729
|
+
sub_reg.append(circ_qubits[index])
|
2730
|
+
|
2731
|
+
line_number += 1
|
2732
|
+
tableau = []
|
2733
|
+
row_count = shard_map_size << 1
|
2734
|
+
for line in lines[line_number:(line_number + row_count)]:
|
2735
|
+
bits = line.split()
|
2736
|
+
if len(bits) != (row_count + 1):
|
2737
|
+
raise QrackException("Invalid Qrack hybrid stabilizer file!")
|
2738
|
+
row = []
|
2739
|
+
for b in range(row_count):
|
2740
|
+
row.append(bool(int(bits[b])))
|
2741
|
+
row.append(bool((int(bits[-1]) >> 1) & 1))
|
2742
|
+
tableau.append(row)
|
2743
|
+
line_number += (shard_map_size << 1)
|
2744
|
+
tableau = np.array(tableau, bool)
|
2745
|
+
|
2746
|
+
clifford = Clifford(tableau, validate=False, copy=False)
|
2747
|
+
circ = clifford.to_circuit()
|
2748
|
+
|
2749
|
+
for instr in circ.data:
|
2750
|
+
qubits = instr.qubits
|
2751
|
+
n_qubits = []
|
2752
|
+
for qubit in qubits:
|
2753
|
+
n_qubits.append(sub_reg[circ.find_bit(qubit)[0]])
|
2754
|
+
instr.qubits = tuple(n_qubits)
|
2755
|
+
clifford_circ.data.append(instr)
|
2756
|
+
del circ
|
2757
|
+
|
2758
|
+
non_clifford_gates = []
|
2759
|
+
g = 0
|
2760
|
+
for line in lines[line_number:]:
|
2761
|
+
i = 0
|
2762
|
+
tokens = line.split()
|
2763
|
+
op = np.zeros((2,2), dtype=complex)
|
2764
|
+
row = []
|
2765
|
+
for _ in range(2):
|
2766
|
+
amp = tokens[i].replace("(","").replace(")","").split(',')
|
2767
|
+
row.append(float(amp[0]) + float(amp[1])*1j)
|
2768
|
+
i = i + 1
|
2769
|
+
l = math.sqrt(np.real(row[0] * np.conj(row[0]) + row[1] * np.conj(row[1])))
|
2770
|
+
op[0][0] = row[0] / l
|
2771
|
+
op[0][1] = row[1] / l
|
2772
|
+
|
2773
|
+
if np.abs(op[0][0] - row[0]) > 1e-5:
|
2774
|
+
print("Warning: gate ", str(g), " might not be unitary!")
|
2775
|
+
if np.abs(op[0][1] - row[1]) > 1e-5:
|
2776
|
+
print("Warning: gate ", str(g), " might not be unitary!")
|
2777
|
+
|
2778
|
+
row = []
|
2779
|
+
for _ in range(2):
|
2780
|
+
amp = tokens[i].replace("(","").replace(")","").split(',')
|
2781
|
+
row.append(float(amp[0]) + float(amp[1])*1j)
|
2782
|
+
i = i + 1
|
2783
|
+
l = math.sqrt(np.real(row[0] * np.conj(row[0]) + row[1] * np.conj(row[1])))
|
2784
|
+
op[1][0] = row[0] / l
|
2785
|
+
op[1][1] = row[1] / l
|
2786
|
+
|
2787
|
+
ph = np.real(np.log(np.linalg.det(op)) / 1j)
|
2788
|
+
|
2789
|
+
op[1][0] = -np.exp(1j * ph) * np.conj(op[0][1])
|
2790
|
+
op[1][1] = np.exp(1j * ph) * np.conj(op[0][0])
|
2791
|
+
|
2792
|
+
if np.abs(op[1][0] - row[0]) > 1e-5:
|
2793
|
+
print("Warning: gate ", str(g), " might not be unitary!")
|
2794
|
+
if np.abs(op[1][1] - row[1]) > 1e-5:
|
2795
|
+
print("Warning: gate ", str(g), " might not be unitary!")
|
2796
|
+
|
2797
|
+
non_clifford_gates.append(op)
|
2798
|
+
g = g + 1
|
2799
|
+
|
2800
|
+
basis_gates = ["rz", "h", "x", "y", "z", "sx", "sxdg", "sy", "sydg", "s", "sdg", "t", "tdg", "cx", "cy", "cz", "swap"]
|
2801
|
+
try:
|
2802
|
+
circ = transpile(clifford_circ, basis_gates=basis_gates, optimization_level=2)
|
2803
|
+
except:
|
2804
|
+
circ = clifford_circ
|
2805
|
+
|
2806
|
+
for i in range(len(non_clifford_gates)):
|
2807
|
+
circ.unitary(non_clifford_gates[i], [i])
|
2808
|
+
|
2809
|
+
if is_hardware_encoded:
|
2810
|
+
for i in range(logical_qubits, stabilizer_qubits, 2):
|
2811
|
+
circ.h(i + 1)
|
2812
|
+
circ.cz(i, i + 1)
|
2813
|
+
circ.h(i + 1)
|
2814
|
+
|
2815
|
+
return circ
|
2816
|
+
|
2817
|
+
def file_to_optimized_qiskit_circuit(filename):
|
2818
|
+
"""Convert an output state file to a Qiskit circuit
|
2819
|
+
|
2820
|
+
Reads in a circuit from a file named according to the "filename"
|
2821
|
+
parameter and outputs a 'hyper-optimized' Qiskit circuit that
|
2822
|
+
favors maximum reduction in gate count and depth at the potential
|
2823
|
+
expense of additional non-Clifford gates. (Ancilla qubits are
|
2824
|
+
left included in the output, though they probably have no gates.)
|
2825
|
+
|
2826
|
+
Args:
|
2827
|
+
filename: Name of file
|
2828
|
+
|
2829
|
+
Raises:
|
2830
|
+
RuntimeErorr: Before trying to file_to_qiskit_circuit() with
|
2831
|
+
QrackCircuit, you must install Qiskit, numpy, and math!
|
2832
|
+
"""
|
2833
|
+
circ = QrackSimulator.file_to_qiskit_circuit(filename)
|
2834
|
+
|
2835
|
+
width = 0
|
2836
|
+
with open(filename, "r", encoding="utf-8") as file:
|
2837
|
+
width = int(file.readline())
|
2838
|
+
|
2839
|
+
sqrt_pi = np.sqrt(1j)
|
2840
|
+
sqrt_ni = np.sqrt(-1j)
|
2841
|
+
sqrt1_2 = 1 / math.sqrt(2)
|
2842
|
+
ident = np.eye(2, dtype=np.complex128)
|
2843
|
+
# passable_gates = ["unitary", "rz", "h", "x", "y", "z", "sx", "sxdg", "sy", "sydg", "s", "sdg", "t", "tdg"]
|
2844
|
+
|
2845
|
+
passed_swaps = []
|
2846
|
+
for i in range(0, circ.width()):
|
2847
|
+
# We might trace out swap, but we want to maintain the iteration order of qubit channels.
|
2848
|
+
non_clifford = np.copy(ident)
|
2849
|
+
j = 0
|
2850
|
+
while j < len(circ.data):
|
2851
|
+
op = circ.data[j].operation
|
2852
|
+
qubits = circ.data[j].qubits
|
2853
|
+
if len(qubits) > 2:
|
2854
|
+
raise RuntimeError("Something went wrong while optimizing circuit! (Found a gate with 3 or more qubits)")
|
2855
|
+
q1 = circ.find_bit(qubits[0])[0]
|
2856
|
+
if (len(qubits) < 2) and (q1 == i):
|
2857
|
+
if op.name == "unitary":
|
2858
|
+
non_clifford = np.matmul(op.params[0], non_clifford)
|
2859
|
+
elif op.name == "rz":
|
2860
|
+
lm = float(op.params[0])
|
2861
|
+
non_clifford = np.matmul([[np.exp(-1j * lm / 2), 0], [0, np.exp(1j * lm / 2)]], non_clifford)
|
2862
|
+
elif op.name == "h":
|
2863
|
+
non_clifford = np.matmul(np.array([[sqrt1_2, sqrt1_2], [sqrt1_2, -sqrt1_2]], np.complex128), non_clifford)
|
2864
|
+
elif op.name == "x":
|
2865
|
+
non_clifford = np.matmul(np.array([[0, 1], [1, 0]], np.complex128), non_clifford)
|
2866
|
+
elif op.name == "y":
|
2867
|
+
non_clifford = np.matmul(np.array([[0, -1j], [1j, 0]], np.complex128), non_clifford)
|
2868
|
+
elif op.name == "z":
|
2869
|
+
non_clifford = np.matmul(np.array([[1, 0], [0, -1]], np.complex128), non_clifford)
|
2870
|
+
elif op.name == "sx":
|
2871
|
+
non_clifford = np.matmul(np.array([[(1+1j)/2, (1-1j)/2], [(1-1j)/2, (1+1j)/2]], np.complex128), non_clifford)
|
2872
|
+
elif op.name == "sxdg":
|
2873
|
+
non_clifford = np.matmul(np.array([[(1-1j)/2, (1+1j)/2], [(1+1j)/2, (1-1j)/2]], np.complex128), non_clifford)
|
2874
|
+
elif op.name == "sy":
|
2875
|
+
non_clifford = np.matmul(np.array([[(1+1j)/2, -(1+1j)/2], [(1+1j)/2, (1+1j)/2]], np.complex128), non_clifford)
|
2876
|
+
elif op.name == "sydg":
|
2877
|
+
non_clifford = np.matmul(np.array([[(1-1j)/2, (1-1j)/2], [(-1+1j)/2, (1-1j)/2]], np.complex128), non_clifford)
|
2878
|
+
elif op.name == "s":
|
2879
|
+
non_clifford = np.matmul(np.array([[1, 0], [0, 1j]], np.complex128), non_clifford)
|
2880
|
+
elif op.name == "sdg":
|
2881
|
+
non_clifford = np.matmul(np.array([[1, 0], [0, -1j]], np.complex128), non_clifford)
|
2882
|
+
elif op.name == "t":
|
2883
|
+
non_clifford = np.matmul(np.array([[1, 0], [0, sqrt_pi]], np.complex128), non_clifford)
|
2884
|
+
elif op.name == "tdg":
|
2885
|
+
non_clifford = np.matmul(np.array([[1, 0], [0, sqrt_ni]], np.complex128), non_clifford)
|
2886
|
+
else:
|
2887
|
+
raise RuntimeError("Something went wrong while optimizing circuit! (Dropped a single-qubit gate.)")
|
2888
|
+
|
2889
|
+
del circ.data[j]
|
2890
|
+
continue
|
2891
|
+
|
2892
|
+
if len(qubits) < 2:
|
2893
|
+
j += 1
|
2894
|
+
continue
|
2895
|
+
|
2896
|
+
q2 = circ.find_bit(qubits[1])[0]
|
2897
|
+
|
2898
|
+
if (i != q1) and (i != q2):
|
2899
|
+
j += 1
|
2900
|
+
continue
|
2901
|
+
|
2902
|
+
if op.name == "swap":
|
2903
|
+
i = (q2 if i == q1 else q1)
|
2904
|
+
|
2905
|
+
if circ.data[j] in passed_swaps:
|
2906
|
+
passed_swaps.remove(circ.data[j])
|
2907
|
+
del circ.data[j]
|
2908
|
+
continue
|
2909
|
+
|
2910
|
+
passed_swaps.append(circ.data[j])
|
2911
|
+
|
2912
|
+
j += 1
|
2913
|
+
continue
|
2914
|
+
|
2915
|
+
if (q1 == i) and ((op.name == "cx") or (op.name == "cy") or (op.name == "cz")):
|
2916
|
+
if (np.isclose(np.abs(non_clifford[0][1]), 0) and np.isclose(np.abs(non_clifford[1][0]), 0)):
|
2917
|
+
# If we're not buffering anything but phase, the blocking gate has no effect, and we're safe to continue.
|
2918
|
+
del circ.data[j]
|
2919
|
+
continue
|
2920
|
+
|
2921
|
+
if (np.isclose(np.abs(non_clifford[0][0]), 0) and np.isclose(np.abs(non_clifford[1][1]), 0)):
|
2922
|
+
# If we're buffering full negation (plus phase), the control qubit can be dropped.
|
2923
|
+
c = QuantumCircuit(1)
|
2924
|
+
if op.name == "cx":
|
2925
|
+
c.x(0)
|
2926
|
+
elif op.name == "cy":
|
2927
|
+
c.y(0)
|
2928
|
+
else:
|
2929
|
+
c.z(0)
|
2930
|
+
instr = c.data[0]
|
2931
|
+
instr.qubits = (qubits[1],)
|
2932
|
+
circ.data[j] = copy.deepcopy(instr)
|
2933
|
+
|
2934
|
+
j += 1
|
2935
|
+
continue
|
2936
|
+
|
2937
|
+
if np.allclose(non_clifford, ident):
|
2938
|
+
# No buffer content to write to circuit definition
|
2939
|
+
non_clifford = np.copy(ident)
|
2940
|
+
break
|
2941
|
+
|
2942
|
+
# We're blocked, so we insert our buffer at this place in the circuit definition.
|
2943
|
+
c = QuantumCircuit(1)
|
2944
|
+
c.unitary(non_clifford, 0)
|
2945
|
+
instr = c.data[0]
|
2946
|
+
instr.qubits = (qubits[0],)
|
2947
|
+
circ.data.insert(j, copy.deepcopy(instr))
|
2948
|
+
|
2949
|
+
non_clifford = np.copy(ident)
|
2950
|
+
break
|
2951
|
+
|
2952
|
+
if (j == len(circ.data)) and not np.allclose(non_clifford, ident):
|
2953
|
+
# We're at the end of the wire, so add the buffer gate.
|
2954
|
+
circ.unitary(non_clifford, i)
|
2955
|
+
|
2956
|
+
passed_swaps.clear()
|
2957
|
+
for i in range(width, circ.width()):
|
2958
|
+
# We might trace out swap, but we want to maintain the iteration order of qubit channels.
|
2959
|
+
non_clifford = np.copy(ident)
|
2960
|
+
j = len(circ.data) - 1
|
2961
|
+
while j >= 0:
|
2962
|
+
op = circ.data[j].operation
|
2963
|
+
qubits = circ.data[j].qubits
|
2964
|
+
if len(qubits) > 2:
|
2965
|
+
raise RuntimeError("Something went wrong while optimizing circuit! (Found a gate with 3 or more qubits.)")
|
2966
|
+
q1 = circ.find_bit(qubits[0])[0]
|
2967
|
+
if (len(qubits) < 2) and (q1 == i):
|
2968
|
+
if op.name == "unitary":
|
2969
|
+
non_clifford = np.matmul(non_clifford, op.params[0])
|
2970
|
+
elif op.name == "rz":
|
2971
|
+
lm = float(op.params[0])
|
2972
|
+
non_clifford = np.matmul(non_clifford, [[np.exp(-1j * lm / 2), 0], [0, np.exp(1j * lm / 2)]])
|
2973
|
+
elif op.name == "h":
|
2974
|
+
non_clifford = np.matmul(non_clifford, np.array([[sqrt1_2, sqrt1_2], [sqrt1_2, -sqrt1_2]], np.complex128))
|
2975
|
+
elif op.name == "x":
|
2976
|
+
non_clifford = np.matmul(non_clifford, np.array([[0, 1], [1, 0]], np.complex128))
|
2977
|
+
elif op.name == "y":
|
2978
|
+
non_clifford = np.matmul(non_clifford, np.array([[0, -1j], [1j, 0]], np.complex128))
|
2979
|
+
elif op.name == "z":
|
2980
|
+
non_clifford = np.matmul(non_clifford, np.array([[1, 0], [0, -1]], np.complex128))
|
2981
|
+
elif op.name == "sx":
|
2982
|
+
non_clifford = np.matmul(non_clifford, np.array([[(1+1j)/2, (1-1j)/2], [(1-1j)/2, (1+1j)/2]], np.complex128))
|
2983
|
+
elif op.name == "sxdg":
|
2984
|
+
non_clifford = np.matmul(non_clifford, np.array([[(1-1j)/2, (1+1j)/2], [(1+1j)/2, (1-1j)/2]], np.complex128))
|
2985
|
+
elif op.name == "sy":
|
2986
|
+
non_clifford = np.matmul(non_clifford, np.array([[(1+1j)/2, -(1+1j)/2], [(1+1j)/2, (1+1j)/2]], np.complex128))
|
2987
|
+
elif op.name == "sydg":
|
2988
|
+
non_clifford = np.matmul(non_clifford, np.array([[(1-1j)/2, (1-1j)/2], [(-1+1j)/2, (1-1j)/2]], np.complex128))
|
2989
|
+
elif op.name == "s":
|
2990
|
+
non_clifford = np.matmul(non_clifford, np.array([[1, 0], [0, 1j]], np.complex128))
|
2991
|
+
elif op.name == "sdg":
|
2992
|
+
non_clifford = np.matmul(non_clifford, np.array([[1, 0], [0, -1j]], np.complex128))
|
2993
|
+
elif op.name == "t":
|
2994
|
+
non_clifford = np.matmul(non_clifford, np.array([[1, 0], [0, sqrt_pi]], np.complex128))
|
2995
|
+
elif op.name == "tdg":
|
2996
|
+
non_clifford = np.matmul(non_clifford, np.array([[1, 0], [0, sqrt_ni]], np.complex128))
|
2997
|
+
else:
|
2998
|
+
raise RuntimeError("Something went wrong while optimizing circuit! (Dropped a single-qubit gate.)")
|
2999
|
+
|
3000
|
+
del circ.data[j]
|
3001
|
+
j -= 1
|
3002
|
+
continue
|
3003
|
+
|
3004
|
+
if len(qubits) < 2:
|
3005
|
+
j -= 1
|
3006
|
+
continue
|
3007
|
+
|
3008
|
+
q2 = circ.find_bit(qubits[1])[0]
|
3009
|
+
|
3010
|
+
if (i != q1) and (i != q2):
|
3011
|
+
j -= 1
|
3012
|
+
continue
|
3013
|
+
|
3014
|
+
if (op.name == "swap") and (q1 >= width) and (q2 >= width):
|
3015
|
+
i = (q2 if i == q1 else q1)
|
3016
|
+
if circ.data[j] in passed_swaps:
|
3017
|
+
passed_swaps.remove(circ.data[j])
|
3018
|
+
del circ.data[j]
|
3019
|
+
else:
|
3020
|
+
passed_swaps.append(circ.data[j])
|
3021
|
+
|
3022
|
+
j -= 1
|
3023
|
+
continue
|
3024
|
+
|
3025
|
+
if (q1 == i) and ((op.name == "cx") or (op.name == "cy") or (op.name == "cz")) and (np.isclose(np.abs(non_clifford[0][1]), 0) and np.isclose(np.abs(non_clifford[1][0]), 0)):
|
3026
|
+
# If we're not buffering anything but phase, this commutes with control, and we're safe to continue.
|
3027
|
+
j -= 1
|
3028
|
+
continue
|
3029
|
+
|
3030
|
+
if (q1 == i) and (op.name == "cx"):
|
3031
|
+
orig_instr = circ.data[j]
|
3032
|
+
del circ.data[j]
|
3033
|
+
|
3034
|
+
h = QuantumCircuit(1)
|
3035
|
+
h.h(0)
|
3036
|
+
instr = h.data[0]
|
3037
|
+
|
3038
|
+
# We're replacing CNOT with CNOT in the opposite direction plus four H gates
|
3039
|
+
instr.qubits = (qubits[0],)
|
3040
|
+
circ.data.insert(j, copy.deepcopy(instr))
|
3041
|
+
instr.qubits = (qubits[1],)
|
3042
|
+
circ.data.insert(j, copy.deepcopy(instr))
|
3043
|
+
orig_instr.qubits = (qubits[1], qubits[0])
|
3044
|
+
circ.data.insert(j, copy.deepcopy(orig_instr))
|
3045
|
+
instr.qubits = (qubits[0],)
|
3046
|
+
circ.data.insert(j, copy.deepcopy(instr))
|
3047
|
+
instr.qubits = (qubits[1],)
|
3048
|
+
circ.data.insert(j, copy.deepcopy(instr))
|
3049
|
+
|
3050
|
+
j += 4
|
3051
|
+
continue
|
3052
|
+
|
3053
|
+
if (q1 == i) or (op.name != "cx"):
|
3054
|
+
if np.allclose(non_clifford, ident):
|
3055
|
+
# No buffer content to write to circuit definition
|
3056
|
+
break
|
3057
|
+
|
3058
|
+
# We're blocked, so we insert our buffer at this place in the circuit definition.
|
3059
|
+
c = QuantumCircuit(1)
|
3060
|
+
c.unitary(non_clifford, 0)
|
3061
|
+
instr = c.data[0]
|
3062
|
+
instr.qubits = (qubits[0],)
|
3063
|
+
circ.data.insert(j + 1, copy.deepcopy(instr))
|
3064
|
+
|
3065
|
+
break
|
3066
|
+
|
3067
|
+
# Re-injection branch (apply gadget to target)
|
3068
|
+
to_inject = np.matmul(non_clifford, np.array([[sqrt1_2, sqrt1_2], [sqrt1_2, -sqrt1_2]]))
|
3069
|
+
if np.allclose(to_inject, ident):
|
3070
|
+
# No buffer content to write to circuit definition
|
3071
|
+
del circ.data[j]
|
3072
|
+
j -= 1
|
3073
|
+
continue
|
3074
|
+
|
3075
|
+
c = QuantumCircuit(1)
|
3076
|
+
c.unitary(to_inject, 0)
|
3077
|
+
instr = c.data[0]
|
3078
|
+
instr.qubits = (qubits[0],)
|
3079
|
+
circ.data[j] = copy.deepcopy(instr)
|
3080
|
+
j -= 1
|
3081
|
+
|
3082
|
+
basis_gates=["u", "rz", "h", "x", "y", "z", "sx", "sxdg", "sy", "sydg", "s", "sdg", "t", "tdg", "cx", "cy", "cz", "swap"]
|
3083
|
+
circ = transpile(circ, basis_gates=basis_gates, optimization_level=2)
|
3084
|
+
|
3085
|
+
#Eliminate unused ancillae
|
3086
|
+
qasm = circ.qasm()
|
3087
|
+
qasm = qasm.replace("qreg q[" + str(circ.width()) + "];", "qreg q[" + str(width) + "];")
|
3088
|
+
highest_index = max([int(x) for x in re.findall(r"\[(.*?)\]", qasm) if x.isdigit()])
|
3089
|
+
if highest_index != width:
|
3090
|
+
qasm = qasm.replace("qreg q[" + str(width) + "];", "qreg q[" + str(highest_index) + "];")
|
3091
|
+
|
3092
|
+
orig_circ = circ
|
3093
|
+
try:
|
3094
|
+
circ = QuantumCircuit.from_qasm_str(qasm)
|
3095
|
+
except:
|
3096
|
+
circ = orig_circ
|
3097
|
+
|
3098
|
+
return circ
|
3099
|
+
|
3100
|
+
def _apply_pyzx_op(self, gate):
|
3101
|
+
if gate.name == "XPhase":
|
3102
|
+
self.r(Pauli.PauliX, math.pi * gate.phase, gate.target)
|
3103
|
+
elif gate.name == "ZPhase":
|
3104
|
+
self.r(Pauli.PauliZ, math.pi * gate.phase, gate.target)
|
3105
|
+
elif gate.name == "Z":
|
3106
|
+
self.z(gate.target)
|
3107
|
+
elif gate.name == "S":
|
3108
|
+
self.s(gate.target)
|
3109
|
+
elif gate.name == "T":
|
3110
|
+
self.t(gate.target)
|
3111
|
+
elif gate.name == "NOT":
|
3112
|
+
self.x(gate.target)
|
3113
|
+
elif gate.name == "HAD":
|
3114
|
+
self.h(gate.target)
|
3115
|
+
elif gate.name == "CNOT":
|
3116
|
+
self.mcx([gate.control], gate.target)
|
3117
|
+
elif gate.name == "CZ":
|
3118
|
+
self.mcz([gate.control], gate.target)
|
3119
|
+
elif gate.name == "CX":
|
3120
|
+
self.h(gate.control)
|
3121
|
+
self.mcx([gate.control], gate.target)
|
3122
|
+
self.h(gate.control)
|
3123
|
+
elif gate.name == "SWAP":
|
3124
|
+
self.swap(gate.control, gate.target)
|
3125
|
+
elif gate.name == "CRZ":
|
3126
|
+
self.mcr(Pauli.PauliZ, math.pi * gate.phase, [gate.control], gate.target)
|
3127
|
+
elif gate.name == "CHAD":
|
3128
|
+
self.mch([gate.control], gate.target)
|
3129
|
+
elif gate.name == "ParityPhase":
|
3130
|
+
self.phase_parity(math.pi * gate.phase, gate.targets)
|
3131
|
+
elif gate.name == "FSim":
|
3132
|
+
self.fsim(gate.theta, gate.phi, gate.control, gate.target)
|
3133
|
+
elif gate.name == "CCZ":
|
3134
|
+
self.mcz([gate.ctrl1, gate.ctrl2], gate.target)
|
3135
|
+
elif gate.name == "Tof":
|
3136
|
+
self.mcx([gate.ctrl1, gate.ctrl2], gate.target)
|
3137
|
+
self._throw_if_error()
|
3138
|
+
|
3139
|
+
def run_pyzx_gates(self, gates):
|
3140
|
+
"""PYZX Gates
|
3141
|
+
|
3142
|
+
Converts PYZX gates to `QRackSimulator` and immediately executes them.
|
3143
|
+
|
3144
|
+
Args:
|
3145
|
+
gates: list of PYZX gates
|
3146
|
+
|
3147
|
+
Raises:
|
3148
|
+
RuntimeError: QrackSimulator raised an exception.
|
3149
|
+
"""
|
3150
|
+
for gate in gates:
|
3151
|
+
self._apply_pyzx_op(gate)
|
3152
|
+
|
3153
|
+
def _apply_op(self, operation):
|
3154
|
+
name = operation.name
|
3155
|
+
|
3156
|
+
if (name == 'id') or (name == 'barrier'):
|
3157
|
+
# Skip measurement logic
|
3158
|
+
return
|
3159
|
+
|
3160
|
+
conditional = getattr(operation, 'conditional', None)
|
3161
|
+
if isinstance(conditional, int):
|
3162
|
+
conditional_bit_set = (self._classical_register >> conditional) & 1
|
3163
|
+
if not conditional_bit_set:
|
3164
|
+
return
|
3165
|
+
elif conditional is not None:
|
3166
|
+
mask = int(conditional.mask, 16)
|
3167
|
+
if mask > 0:
|
3168
|
+
value = self._classical_memory & mask
|
3169
|
+
while (mask & 0x1) == 0:
|
3170
|
+
mask >>= 1
|
3171
|
+
value >>= 1
|
3172
|
+
if value != int(conditional.val, 16):
|
3173
|
+
return
|
3174
|
+
|
3175
|
+
if (name == 'u1') or (name == 'p'):
|
3176
|
+
self._sim.u(operation.qubits[0], 0, 0, float(operation.params[0]))
|
3177
|
+
elif name == 'u2':
|
3178
|
+
self._sim.u(
|
3179
|
+
operation.qubits[0],
|
3180
|
+
math.pi / 2,
|
3181
|
+
float(operation.params[0]),
|
3182
|
+
float(operation.params[1]),
|
3183
|
+
)
|
3184
|
+
elif (name == 'u3') or (name == 'u'):
|
3185
|
+
self._sim.u(
|
3186
|
+
operation.qubits[0],
|
3187
|
+
float(operation.params[0]),
|
3188
|
+
float(operation.params[1]),
|
3189
|
+
float(operation.params[2]),
|
3190
|
+
)
|
3191
|
+
elif (name == 'unitary') and (len(operation.qubits) == 1):
|
3192
|
+
self._sim.mtrx(operation.params[0].flatten(), operation.qubits[0])
|
3193
|
+
elif name == 'r':
|
3194
|
+
self._sim.u(
|
3195
|
+
operation.qubits[0],
|
3196
|
+
float(operation.params[0]),
|
3197
|
+
float(operation.params[1]) - math.pi / 2,
|
3198
|
+
(-1 * float(operation.params[1])) + math.pi / 2,
|
3199
|
+
)
|
3200
|
+
elif name == 'rx':
|
3201
|
+
self._sim.r(Pauli.PauliX, float(operation.params[0]), operation.qubits[0])
|
3202
|
+
elif name == 'ry':
|
3203
|
+
self._sim.r(Pauli.PauliY, float(operation.params[0]), operation.qubits[0])
|
3204
|
+
elif name == 'rz':
|
3205
|
+
self._sim.r(Pauli.PauliZ, float(operation.params[0]), operation.qubits[0])
|
3206
|
+
elif name == 'h':
|
3207
|
+
self._sim.h(operation.qubits[0])
|
3208
|
+
elif name == 'x':
|
3209
|
+
self._sim.x(operation.qubits[0])
|
3210
|
+
elif name == 'y':
|
3211
|
+
self._sim.y(operation.qubits[0])
|
3212
|
+
elif name == 'z':
|
3213
|
+
self._sim.z(operation.qubits[0])
|
3214
|
+
elif name == 's':
|
3215
|
+
self._sim.s(operation.qubits[0])
|
3216
|
+
elif name == 'sdg':
|
3217
|
+
self._sim.adjs(operation.qubits[0])
|
3218
|
+
elif name == 'sx':
|
3219
|
+
self._sim.mtrx(
|
3220
|
+
[(1 + 1j) / 2, (1 - 1j) / 2, (1 - 1j) / 2, (1 + 1j) / 2],
|
3221
|
+
operation.qubits[0],
|
3222
|
+
)
|
3223
|
+
elif name == 'sxdg':
|
3224
|
+
self._sim.mtrx(
|
3225
|
+
[(1 - 1j) / 2, (1 + 1j) / 2, (1 + 1j) / 2, (1 - 1j) / 2],
|
3226
|
+
operation.qubits[0],
|
3227
|
+
)
|
3228
|
+
elif name == 't':
|
3229
|
+
self._sim.t(operation.qubits[0])
|
3230
|
+
elif name == 'tdg':
|
3231
|
+
self._sim.adjt(operation.qubits[0])
|
3232
|
+
elif name == 'cu1':
|
3233
|
+
self._sim.mcu(
|
3234
|
+
operation.qubits[0:1], operation.qubits[1], 0, 0, float(operation.params[0])
|
3235
|
+
)
|
3236
|
+
elif name == 'cu2':
|
3237
|
+
self._sim.mcu(
|
3238
|
+
operation.qubits[0:1],
|
3239
|
+
operation.qubits[1],
|
3240
|
+
math.pi / 2,
|
3241
|
+
float(operation.params[0]),
|
3242
|
+
float(operation.params[1]),
|
3243
|
+
)
|
3244
|
+
elif (name == 'cu3') or (name == 'cu'):
|
3245
|
+
self._sim.mcu(
|
3246
|
+
operation.qubits[0:1],
|
3247
|
+
operation.qubits[1],
|
3248
|
+
float(operation.params[0]),
|
3249
|
+
float(operation.params[1]),
|
3250
|
+
float(operation.params[2]),
|
3251
|
+
)
|
3252
|
+
elif name == 'cx':
|
3253
|
+
self._sim.mcx(operation.qubits[0:1], operation.qubits[1])
|
3254
|
+
elif name == 'cy':
|
3255
|
+
self._sim.mcy(operation.qubits[0:1], operation.qubits[1])
|
3256
|
+
elif name == 'cz':
|
3257
|
+
self._sim.mcz(operation.qubits[0:1], operation.qubits[1])
|
3258
|
+
elif name == 'ch':
|
3259
|
+
self._sim.mch(operation.qubits[0:1], operation.qubits[1])
|
3260
|
+
elif name == 'cp':
|
3261
|
+
self._sim.mcmtrx(
|
3262
|
+
operation.qubits[0:1],
|
3263
|
+
[
|
3264
|
+
1,
|
3265
|
+
0,
|
3266
|
+
0,
|
3267
|
+
math.cos(float(operation.params[0])) + 1j * math.sin(float(operation.params[0])),
|
3268
|
+
],
|
3269
|
+
operation.qubits[1],
|
3270
|
+
)
|
3271
|
+
elif name == 'csx':
|
3272
|
+
self._sim.mcmtrx(
|
3273
|
+
operation.qubits[0:1],
|
3274
|
+
[(1 + 1j) / 2, (1 - 1j) / 2, (1 - 1j) / 2, (1 + 1j) / 2],
|
3275
|
+
operation.qubits[1],
|
3276
|
+
)
|
3277
|
+
elif name == 'csxdg':
|
3278
|
+
self._sim.mcmtrx(
|
3279
|
+
operation.qubits[0:1],
|
3280
|
+
[(1 - 1j) / 2, (1 + 1j) / 2, (1 + 1j) / 2, (1 - 1j) / 2],
|
3281
|
+
operation.qubits[1],
|
3282
|
+
)
|
3283
|
+
elif name == 'dcx':
|
3284
|
+
self._sim.mcx(operation.qubits[0:1], operation.qubits[1])
|
3285
|
+
self._sim.mcx(operation.qubits[1:2], operation.qubits[0])
|
3286
|
+
elif name == 'ccx':
|
3287
|
+
self._sim.mcx(operation.qubits[0:2], operation.qubits[2])
|
3288
|
+
elif name == 'ccy':
|
3289
|
+
self._sim.mcy(operation.qubits[0:2], operation.qubits[2])
|
3290
|
+
elif name == 'ccz':
|
3291
|
+
self._sim.mcz(operation.qubits[0:2], operation.qubits[2])
|
3292
|
+
elif name == 'mcx':
|
3293
|
+
self._sim.mcx(operation.qubits[0:-1], operation.qubits[-1])
|
3294
|
+
elif name == 'mcy':
|
3295
|
+
self._sim.mcy(operation.qubits[0:-1], operation.qubits[-1])
|
3296
|
+
elif name == 'mcz':
|
3297
|
+
self._sim.mcz(operation.qubits[0:-1], operation.qubits[-1])
|
3298
|
+
elif name == 'swap':
|
3299
|
+
self._sim.swap(operation.qubits[0], operation.qubits[1])
|
3300
|
+
elif name == 'iswap':
|
3301
|
+
self._sim.iswap(operation.qubits[0], operation.qubits[1])
|
3302
|
+
elif name == 'iswap_dg':
|
3303
|
+
self._sim.adjiswap(operation.qubits[0], operation.qubits[1])
|
3304
|
+
elif name == 'cswap':
|
3305
|
+
self._sim.cswap(
|
3306
|
+
operation.qubits[0:1], operation.qubits[1], operation.qubits[2]
|
3307
|
+
)
|
3308
|
+
elif name == 'mcswap':
|
3309
|
+
self._sim.cswap(
|
3310
|
+
operation.qubits[:-2], operation.qubits[-2], operation.qubits[-1]
|
3311
|
+
)
|
3312
|
+
elif name == 'reset':
|
3313
|
+
qubits = operation.qubits
|
3314
|
+
for qubit in qubits:
|
3315
|
+
if self._sim.m(qubit):
|
3316
|
+
self._sim.x(qubit)
|
3317
|
+
elif name == 'measure':
|
3318
|
+
qubits = operation.qubits
|
3319
|
+
clbits = operation.memory
|
3320
|
+
cregbits = (
|
3321
|
+
operation.register
|
3322
|
+
if hasattr(operation, 'register')
|
3323
|
+
else len(operation.qubits) * [-1]
|
3324
|
+
)
|
3325
|
+
|
3326
|
+
self._sample_qubits += qubits
|
3327
|
+
self._sample_clbits += clbits
|
3328
|
+
self._sample_cregbits += cregbits
|
3329
|
+
|
3330
|
+
if not self._sample_measure:
|
3331
|
+
for index in range(len(qubits)):
|
3332
|
+
qubit_outcome = self._sim.m(qubits[index])
|
3333
|
+
|
3334
|
+
clbit = clbits[index]
|
3335
|
+
clmask = 1 << clbit
|
3336
|
+
self._classical_memory = (self._classical_memory & (~clmask)) | (
|
3337
|
+
qubit_outcome << clbit
|
3338
|
+
)
|
3339
|
+
|
3340
|
+
cregbit = cregbits[index]
|
3341
|
+
if cregbit < 0:
|
3342
|
+
cregbit = clbit
|
3343
|
+
|
3344
|
+
regbit = 1 << cregbit
|
3345
|
+
self._classical_register = (
|
3346
|
+
self._classical_register & (~regbit)
|
3347
|
+
) | (qubit_outcome << cregbit)
|
3348
|
+
|
3349
|
+
elif name == 'bfunc':
|
3350
|
+
mask = int(operation.mask, 16)
|
3351
|
+
relation = operation.relation
|
3352
|
+
val = int(operation.val, 16)
|
3353
|
+
|
3354
|
+
cregbit = operation.register
|
3355
|
+
cmembit = operation.memory if hasattr(operation, 'memory') else None
|
3356
|
+
|
3357
|
+
compared = (self._classical_register & mask) - val
|
3358
|
+
|
3359
|
+
if relation == '==':
|
3360
|
+
outcome = compared == 0
|
3361
|
+
elif relation == '!=':
|
3362
|
+
outcome = compared != 0
|
3363
|
+
elif relation == '<':
|
3364
|
+
outcome = compared < 0
|
3365
|
+
elif relation == '<=':
|
3366
|
+
outcome = compared <= 0
|
3367
|
+
elif relation == '>':
|
3368
|
+
outcome = compared > 0
|
3369
|
+
elif relation == '>=':
|
3370
|
+
outcome = compared >= 0
|
3371
|
+
else:
|
3372
|
+
raise QrackError('Invalid boolean function relation.')
|
3373
|
+
|
3374
|
+
# Store outcome in register and optionally memory slot
|
3375
|
+
regbit = 1 << cregbit
|
3376
|
+
self._classical_register = (self._classical_register & (~regbit)) | (
|
3377
|
+
int(outcome) << cregbit
|
3378
|
+
)
|
3379
|
+
if cmembit is not None:
|
3380
|
+
membit = 1 << cmembit
|
3381
|
+
self._classical_memory = (self._classical_memory & (~membit)) | (
|
3382
|
+
int(outcome) << cmembit
|
3383
|
+
)
|
3384
|
+
else:
|
3385
|
+
err_msg = 'QrackSimulator encountered unrecognized operation "{0}"'
|
3386
|
+
raise RuntimeError(err_msg.format(operation))
|
3387
|
+
|
3388
|
+
def _add_sample_measure(self, sample_qubits, sample_clbits, num_samples):
|
3389
|
+
"""Generate data samples from current statevector.
|
3390
|
+
|
3391
|
+
Taken almost straight from the terra source code.
|
3392
|
+
|
3393
|
+
Args:
|
3394
|
+
measure_params (list): List of (qubit, clbit) values for
|
3395
|
+
measure instructions to sample.
|
3396
|
+
num_samples (int): The number of data samples to generate.
|
3397
|
+
|
3398
|
+
Returns:
|
3399
|
+
list: A list of data values in hex format.
|
3400
|
+
"""
|
3401
|
+
# Get unique qubits that are actually measured
|
3402
|
+
measure_qubit = [qubit for qubit in sample_qubits]
|
3403
|
+
measure_clbit = [clbit for clbit in sample_clbits]
|
3404
|
+
|
3405
|
+
# Sample and convert to bit-strings
|
3406
|
+
data = []
|
3407
|
+
if num_samples == 1:
|
3408
|
+
sample = self._sim.m_all()
|
3409
|
+
result = 0
|
3410
|
+
for index in range(len(measure_qubit)):
|
3411
|
+
qubit = measure_qubit[index]
|
3412
|
+
qubit_outcome = (sample >> qubit) & 1
|
3413
|
+
result |= qubit_outcome << index
|
3414
|
+
measure_results = [result]
|
3415
|
+
else:
|
3416
|
+
measure_results = self._sim.measure_shots(measure_qubit, num_samples)
|
3417
|
+
|
3418
|
+
for sample in measure_results:
|
3419
|
+
for index in range(len(measure_qubit)):
|
3420
|
+
qubit_outcome = (sample >> index) & 1
|
3421
|
+
clbit = measure_clbit[index]
|
3422
|
+
clmask = 1 << clbit
|
3423
|
+
self._classical_memory = (self._classical_memory & (~clmask)) | (
|
3424
|
+
qubit_outcome << clbit
|
3425
|
+
)
|
3426
|
+
|
3427
|
+
data.append(hex(int(bin(self._classical_memory)[2:], 2)))
|
3428
|
+
|
3429
|
+
return data
|
3430
|
+
|
3431
|
+
def run_qiskit_circuit(self, experiment, shots=1):
|
3432
|
+
if not _IS_QISKIT_AVAILABLE:
|
3433
|
+
raise RuntimeError(
|
3434
|
+
"Before trying to run_qiskit_circuit() with QrackSimulator, you must install Qiskit!"
|
3435
|
+
)
|
3436
|
+
|
3437
|
+
if isinstance(experiment, QuantumCircuit):
|
3438
|
+
experiment = convert_qiskit_circuit_to_qasm_experiment(experiment)
|
3439
|
+
|
3440
|
+
instructions = []
|
3441
|
+
if isinstance(experiment, QasmQobjExperiment):
|
3442
|
+
instructions = experiment.instructions
|
3443
|
+
else:
|
3444
|
+
raise RuntimeError('Unrecognized "run_input" argument specified for run().')
|
3445
|
+
|
3446
|
+
self._shots = shots
|
3447
|
+
self._sample_qubits = []
|
3448
|
+
self._sample_clbits = []
|
3449
|
+
self._sample_cregbits = []
|
3450
|
+
self._sample_measure = True
|
3451
|
+
_data = []
|
3452
|
+
shotsPerLoop = self._shots
|
3453
|
+
shotLoopMax = 1
|
3454
|
+
|
3455
|
+
is_initializing = True
|
3456
|
+
boundary_start = -1
|
3457
|
+
|
3458
|
+
for opcount in range(len(instructions)):
|
3459
|
+
operation = instructions[opcount]
|
3460
|
+
|
3461
|
+
if operation.name == 'id' or operation.name == 'barrier':
|
3462
|
+
continue
|
3463
|
+
|
3464
|
+
if is_initializing and (
|
3465
|
+
(operation.name == 'measure') or (operation.name == 'reset')
|
3466
|
+
):
|
3467
|
+
continue
|
3468
|
+
|
3469
|
+
is_initializing = False
|
3470
|
+
|
3471
|
+
if (operation.name == 'measure') or (operation.name == 'reset'):
|
3472
|
+
if boundary_start == -1:
|
3473
|
+
boundary_start = opcount
|
3474
|
+
|
3475
|
+
if (boundary_start != -1) and (operation.name != 'measure'):
|
3476
|
+
shotsPerLoop = 1
|
3477
|
+
shotLoopMax = self._shots
|
3478
|
+
self._sample_measure = False
|
3479
|
+
break
|
3480
|
+
|
3481
|
+
preamble_memory = 0
|
3482
|
+
preamble_register = 0
|
3483
|
+
preamble_sim = None
|
3484
|
+
|
3485
|
+
if self._sample_measure or boundary_start <= 0:
|
3486
|
+
boundary_start = 0
|
3487
|
+
self._sample_measure = True
|
3488
|
+
shotsPerLoop = self._shots
|
3489
|
+
shotLoopMax = 1
|
3490
|
+
else:
|
3491
|
+
boundary_start -= 1
|
3492
|
+
if boundary_start > 0:
|
3493
|
+
self._sim = self
|
3494
|
+
self._classical_memory = 0
|
3495
|
+
self._classical_register = 0
|
3496
|
+
|
3497
|
+
for operation in instructions[:boundary_start]:
|
3498
|
+
self._apply_op(operation)
|
3499
|
+
|
3500
|
+
preamble_memory = self._classical_memory
|
3501
|
+
preamble_register = self._classical_register
|
3502
|
+
preamble_sim = self._sim
|
3503
|
+
|
3504
|
+
for shot in range(shotLoopMax):
|
3505
|
+
if preamble_sim is None:
|
3506
|
+
self._sim = self
|
3507
|
+
self._classical_memory = 0
|
3508
|
+
self._classical_register = 0
|
3509
|
+
else:
|
3510
|
+
self._sim = QrackSimulator(cloneSid=preamble_sim.sid)
|
3511
|
+
self._classical_memory = preamble_memory
|
3512
|
+
self._classical_register = preamble_register
|
3513
|
+
|
3514
|
+
for operation in instructions[boundary_start:]:
|
3515
|
+
self._apply_op(operation)
|
3516
|
+
|
3517
|
+
if not self._sample_measure and (len(self._sample_qubits) > 0):
|
3518
|
+
_data += [hex(int(bin(self._classical_memory)[2:], 2))]
|
3519
|
+
self._sample_qubits = []
|
3520
|
+
self._sample_clbits = []
|
3521
|
+
self._sample_cregbits = []
|
3522
|
+
|
3523
|
+
if self._sample_measure and (len(self._sample_qubits) > 0):
|
3524
|
+
_data = self._add_sample_measure(
|
3525
|
+
self._sample_qubits, self._sample_clbits, self._shots
|
3526
|
+
)
|
3527
|
+
|
3528
|
+
del self._sim
|
3529
|
+
|
3530
|
+
return _data
|