pyqrack-cpu-complex128 1.81.0__py3-none-macosx_15_0_x86_64.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,4531 @@
1
+ # (C) Daniel Strano and the Qrack contributors 2017-2025. 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 os
10
+ import re
11
+ from .qrack_system import Qrack
12
+ from .pauli import Pauli
13
+
14
+ _IS_QISKIT_AVAILABLE = True
15
+ try:
16
+ from qiskit.circuit.quantumcircuit import QuantumCircuit
17
+ from qiskit.compiler import transpile
18
+ from qiskit.quantum_info.operators.symplectic.clifford import Clifford
19
+ except ImportError:
20
+ _IS_QISKIT_AVAILABLE = False
21
+
22
+ try:
23
+ from qiskit import qasm3
24
+ except ImportError:
25
+ pass
26
+
27
+ _IS_NUMPY_AVAILABLE = True
28
+ try:
29
+ import numpy as np
30
+ except:
31
+ _IS_NUMPY_AVAILABLE = False
32
+
33
+
34
+ class QrackSimulator:
35
+ """Interface for all the Qrack functionality.
36
+
37
+ Attributes:
38
+ sid(int): Corresponding simulator id.
39
+ """
40
+
41
+ def _get_error(self):
42
+ return Qrack.qrack_lib.get_error(self.sid)
43
+
44
+ def _throw_if_error(self):
45
+ if self._get_error() != 0:
46
+ raise RuntimeError("QrackSimulator C++ library raised exception.")
47
+
48
+ def __init__(
49
+ self,
50
+ qubitCount=-1,
51
+ cloneSid=-1,
52
+ isTensorNetwork=True,
53
+ isSchmidtDecomposeMulti=False,
54
+ isSchmidtDecompose=True,
55
+ isStabilizerHybrid=False,
56
+ isBinaryDecisionTree=False,
57
+ isPaged=True,
58
+ isCpuGpuHybrid=True,
59
+ isOpenCL=True,
60
+ isHostPointer=(True if os.environ.get("PYQRACK_HOST_POINTER_DEFAULT_ON") else False),
61
+ isSparse=False,
62
+ noise=0,
63
+ pyzxCircuit=None,
64
+ qiskitCircuit=None,
65
+ ):
66
+ self.sid = None
67
+
68
+ if pyzxCircuit is not None:
69
+ qubitCount = pyzxCircuit.qubits
70
+ elif qiskitCircuit is not None and qubitCount < 0:
71
+ raise RuntimeError(
72
+ "Must specify qubitCount with qiskitCircuit parameter in QrackSimulator constructor!"
73
+ )
74
+
75
+ if qubitCount > -1 and cloneSid > -1:
76
+ raise RuntimeError(
77
+ "Cannot clone a QrackSimulator and specify its qubit length at the same time, in QrackSimulator constructor!"
78
+ )
79
+
80
+ self.is_tensor_network = isTensorNetwork
81
+ self.is_pure_stabilizer = False
82
+
83
+ if cloneSid > -1:
84
+ self.sid = Qrack.qrack_lib.init_clone(cloneSid)
85
+ else:
86
+ if qubitCount < 0:
87
+ qubitCount = 0
88
+
89
+ self.sid = Qrack.qrack_lib.init_count_type(
90
+ qubitCount,
91
+ isTensorNetwork,
92
+ isSchmidtDecomposeMulti,
93
+ isSchmidtDecompose,
94
+ isStabilizerHybrid,
95
+ isBinaryDecisionTree,
96
+ isPaged,
97
+ (noise > 0),
98
+ isCpuGpuHybrid,
99
+ isOpenCL,
100
+ isHostPointer,
101
+ isSparse,
102
+ )
103
+
104
+ self._throw_if_error()
105
+
106
+ if noise > 0:
107
+ self.set_noise_parameter(noise)
108
+
109
+ if pyzxCircuit is not None:
110
+ self.run_pyzx_gates(pyzxCircuit.gates)
111
+ elif qiskitCircuit is not None:
112
+ self.run_qiskit_circuit(qiskitCircuit)
113
+
114
+ def __del__(self):
115
+ if self.sid is not None:
116
+ Qrack.qrack_lib.destroy(self.sid)
117
+ self.sid = None
118
+
119
+ @staticmethod
120
+ def _int_byref(a):
121
+ return (ctypes.c_int * len(a))(*a)
122
+
123
+ @staticmethod
124
+ def _ulonglong_byref(a):
125
+ return (ctypes.c_ulonglong * len(a))(*a)
126
+
127
+ @staticmethod
128
+ def _longlong_byref(a):
129
+ return (ctypes.c_longlong * len(a))(*a)
130
+
131
+ @staticmethod
132
+ def _double_byref(a):
133
+ return (ctypes.c_double * len(a))(*a)
134
+
135
+ @staticmethod
136
+ def _complex_byref(a):
137
+ t = [(c.real, c.imag) for c in a]
138
+ return QrackSimulator._double_byref([float(item) for sublist in t for item in sublist])
139
+
140
+ @staticmethod
141
+ def _real1_byref(a):
142
+ # This needs to be c_double, if PyQrack is built with fp64.
143
+ if Qrack.fppow < 6:
144
+ return (ctypes.c_float * len(a))(*a)
145
+ return (ctypes.c_double * len(a))(*a)
146
+
147
+ @staticmethod
148
+ def _bool_byref(a):
149
+ return (ctypes.c_bool * len(a))(*a)
150
+
151
+ @staticmethod
152
+ def _qrack_complex_byref(a):
153
+ t = [(c.real, c.imag) for c in a]
154
+ return QrackSimulator._real1_byref([float(item) for sublist in t for item in sublist])
155
+
156
+ @staticmethod
157
+ def _to_ubyte(nv, v):
158
+ c = math.floor((nv - 1) / 8) + 1
159
+ b = (ctypes.c_ubyte * (c * (1 << nv)))()
160
+ n = 0
161
+ for u in v:
162
+ for _ in range(c):
163
+ b[n] = u & 0xFF
164
+ u >>= 8
165
+ n += 1
166
+
167
+ return b
168
+
169
+ @staticmethod
170
+ def _to_ulonglong(m, v):
171
+ b = (ctypes.c_ulonglong * (m * len(v)))()
172
+ n = 0
173
+ for u in v:
174
+ for _ in range(m):
175
+ b[n] = u & 0xFFFFFFFFFFFFFFFF
176
+ u >>= 64
177
+ n += 1
178
+
179
+ return b
180
+
181
+ # See https://stackoverflow.com/questions/5389507/iterating-over-every-two-elements-in-a-list#answer-30426000
182
+ @staticmethod
183
+ def _pairwise(it):
184
+ it = iter(it)
185
+ while True:
186
+ try:
187
+ yield next(it), next(it)
188
+ except StopIteration:
189
+ # no more elements in the iterator
190
+ return
191
+
192
+ # non-quantum
193
+ def seed(self, s):
194
+ Qrack.qrack_lib.seed(self.sid, s)
195
+ self._throw_if_error()
196
+
197
+ def set_concurrency(self, p):
198
+ """Set the CPU parallel thread count"""
199
+ Qrack.qrack_lib.set_concurrency(self.sid, p)
200
+ self._throw_if_error()
201
+
202
+ def set_device(self, d):
203
+ """Set the GPU device ID"""
204
+ Qrack.qrack_lib.set_device(self.sid, d)
205
+ self._throw_if_error()
206
+
207
+ def set_device_list(self, d):
208
+ """Set the GPU device ID"""
209
+ Qrack.qrack_lib.set_device_list(self.sid, len(d), QrackSimulator._longlong_byref(d))
210
+ self._throw_if_error()
211
+
212
+ def clone(self):
213
+ return QrackSimulator(cloneSid=self.sid)
214
+
215
+ # standard gates
216
+
217
+ ## single-qubits gates
218
+ def x(self, q):
219
+ """Applies X gate.
220
+
221
+ Applies the Pauli “X” operator to the qubit at position “q.”
222
+ The Pauli “X” operator is equivalent to a logical “NOT.”
223
+
224
+ Args:
225
+ q: the qubit number on which the gate is applied to.
226
+
227
+ Raises:
228
+ RuntimeError: QrackSimulator raised an exception.
229
+ """
230
+ Qrack.qrack_lib.X(self.sid, q)
231
+ self._throw_if_error()
232
+
233
+ def y(self, q):
234
+ """Applies Y gate.
235
+
236
+ Applies the Pauli “Y” operator to the qubit at “q.”
237
+ The Pauli “Y” operator is equivalent to a logical “NOT" with
238
+ permutation phase.
239
+
240
+ Args:
241
+ q: the qubit number on which the gate is applied to.
242
+
243
+ Raises:
244
+ RuntimeError: QrackSimulator raised an exception.
245
+ """
246
+ Qrack.qrack_lib.Y(self.sid, q)
247
+ self._throw_if_error()
248
+
249
+ def z(self, q):
250
+ """Applies Z gate.
251
+
252
+ Applies the Pauli “Z” operator to the qubit at “q.”
253
+ The Pauli “Z” operator flips the phase of `|1>`
254
+
255
+ Args:
256
+ q: the qubit number on which the gate is applied to.
257
+
258
+ Raises:
259
+ RuntimeError: QrackSimulator raised an exception.
260
+ """
261
+ Qrack.qrack_lib.Z(self.sid, q)
262
+ self._throw_if_error()
263
+
264
+ def h(self, q):
265
+ """Applies H gate.
266
+
267
+ Applies the Hadarmard operator to the qubit at “q.”
268
+
269
+ Args:
270
+ q: the qubit number on which the gate is applied to.
271
+
272
+ Raises:
273
+ RuntimeError: QrackSimulator raised an exception.
274
+ """
275
+ Qrack.qrack_lib.H(self.sid, q)
276
+ self._throw_if_error()
277
+
278
+ def s(self, q):
279
+ """Applies S gate.
280
+
281
+ Applies the 1/4 phase rotation to the qubit at “q.”
282
+
283
+ Args:
284
+ q: the qubit number on which the gate is applied to.
285
+
286
+ Raises:
287
+ RuntimeError: QrackSimulator raised an exception.
288
+ """
289
+ Qrack.qrack_lib.S(self.sid, q)
290
+ self._throw_if_error()
291
+
292
+ def t(self, q):
293
+ """Applies T gate.
294
+
295
+ Applies the 1/8 phase rotation to the qubit at “q.”
296
+
297
+ Args:
298
+ q: the qubit number on which the gate is applied to.
299
+
300
+ Raises:
301
+ RuntimeError: QrackSimulator raised an exception.
302
+ """
303
+ Qrack.qrack_lib.T(self.sid, q)
304
+ self._throw_if_error()
305
+
306
+ def adjs(self, q):
307
+ """Adjoint of S gate
308
+
309
+ Applies the gate equivalent to the inverse of S gate.
310
+
311
+ Args:
312
+ q: the qubit number on which the gate is applied to.
313
+
314
+ Raises:
315
+ RuntimeError: QrackSimulator raised an exception.
316
+ """
317
+ Qrack.qrack_lib.AdjS(self.sid, q)
318
+ self._throw_if_error()
319
+
320
+ def adjt(self, q):
321
+ """Adjoint of T gate
322
+
323
+ Applies the gate equivalent to the inverse of T gate.
324
+
325
+ Args:
326
+ q: the qubit number on which the gate is applied to.
327
+
328
+ Raises:
329
+ RuntimeError: QrackSimulator raised an exception.
330
+ """
331
+ Qrack.qrack_lib.AdjT(self.sid, q)
332
+ self._throw_if_error()
333
+
334
+ def u(self, q, th, ph, la):
335
+ """General unitary gate.
336
+
337
+ Applies a gate guaranteed to be unitary.
338
+ Spans all possible single bit unitary gates.
339
+
340
+ `U(theta, phi, lambda) = RZ(phi + pi/2)RX(theta)RZ(lambda - pi/2)`
341
+
342
+ Args:
343
+ q: the qubit number on which the gate is applied to.
344
+ th: theta
345
+ ph: phi
346
+ la: lambda
347
+
348
+ Raises:
349
+ RuntimeError: QrackSimulator raised an exception.
350
+ """
351
+ Qrack.qrack_lib.U(
352
+ self.sid, q, ctypes.c_double(th), ctypes.c_double(ph), ctypes.c_double(la)
353
+ )
354
+ self._throw_if_error()
355
+
356
+ def mtrx(self, m, q):
357
+ """Operation from matrix.
358
+
359
+ Applies arbitrary operation defined by the given matrix.
360
+
361
+ Args:
362
+ m: row-major complex list representing the operator.
363
+ q: the qubit number on which the gate is applied to.
364
+
365
+ Raises:
366
+ ValueError: 2x2 matrix 'm' in QrackSimulator.mtrx() must contain at least 4 elements.
367
+ RuntimeError: QrackSimulator raised an exception.
368
+ """
369
+ if len(m) < 4:
370
+ raise ValueError(
371
+ "2x2 matrix 'm' in QrackSimulator.mtrx() must contain at least 4 elements."
372
+ )
373
+ Qrack.qrack_lib.Mtrx(self.sid, QrackSimulator._complex_byref(m), q)
374
+ self._throw_if_error()
375
+
376
+ def r(self, b, ph, q):
377
+ """Rotation gate.
378
+
379
+ Rotate the qubit along the given pauli basis by the given angle.
380
+
381
+
382
+ Args:
383
+ b: Pauli basis
384
+ ph: rotation angle
385
+ q: the qubit number on which the gate is applied to
386
+
387
+ Raises:
388
+ RuntimeError: QrackSimulator raised an exception.
389
+ """
390
+ Qrack.qrack_lib.R(self.sid, ctypes.c_ulonglong(b), ctypes.c_double(ph), q)
391
+ self._throw_if_error()
392
+
393
+ def exp(self, b, ph, q):
394
+ """Arbitrary exponentiation
395
+
396
+ `exp(b, theta) = e^{i*theta*[b_0 . b_1 ...]}`
397
+ where `.` is the tensor product.
398
+
399
+
400
+ Args:
401
+ b: Pauli basis
402
+ ph: coefficient of exponentiation
403
+ q: the qubit number on which the gate is applied to
404
+
405
+ Raises:
406
+ RuntimeError: QrackSimulator raised an exception.
407
+ """
408
+ if len(b) != len(q):
409
+ raise RuntimeError("Lengths of list parameters are mismatched.")
410
+ Qrack.qrack_lib.Exp(
411
+ self.sid,
412
+ len(b),
413
+ QrackSimulator._ulonglong_byref(b),
414
+ ctypes.c_double(ph),
415
+ QrackSimulator._ulonglong_byref(q),
416
+ )
417
+ self._throw_if_error()
418
+
419
+ ## multi-qubit gates
420
+ def mcx(self, c, q):
421
+ """Multi-controlled X gate
422
+
423
+ If all controlled qubits are `|1>` then the target qubit is flipped.
424
+
425
+ Args:
426
+ c: list of controlled qubits.
427
+ q: target qubit.
428
+
429
+ Raises:
430
+ RuntimeError: QrackSimulator raised an exception.
431
+ """
432
+ Qrack.qrack_lib.MCX(self.sid, len(c), QrackSimulator._ulonglong_byref(c), q)
433
+ self._throw_if_error()
434
+
435
+ def mcy(self, c, q):
436
+ """Multi-controlled Y gate
437
+
438
+ If all controlled qubits are `|1>` then the Pauli "Y" gate is applied to
439
+ the target qubit.
440
+
441
+ Args:
442
+ c: list of controlled qubits.
443
+ q: target qubit.
444
+
445
+ Raises:
446
+ RuntimeError: QrackSimulator raised an exception.
447
+ """
448
+ Qrack.qrack_lib.MCY(self.sid, len(c), QrackSimulator._ulonglong_byref(c), q)
449
+ self._throw_if_error()
450
+
451
+ def mcz(self, c, q):
452
+ """Multi-controlled Z gate
453
+
454
+ If all controlled qubits are `|1>` then the Pauli "Z" gate is applied to
455
+ the target qubit.
456
+
457
+ Args:
458
+ c: list of controlled qubits.
459
+ q: target qubit.
460
+
461
+ Raises:
462
+ RuntimeError: QrackSimulator raised an exception.
463
+ """
464
+ Qrack.qrack_lib.MCZ(self.sid, len(c), QrackSimulator._ulonglong_byref(c), q)
465
+ self._throw_if_error()
466
+
467
+ def mch(self, c, q):
468
+ """Multi-controlled H gate
469
+
470
+ If all controlled qubits are `|1>` then the Hadarmard gate is applied to
471
+ the target qubit.
472
+
473
+ Args:
474
+ c: list of controlled qubits.
475
+ q: target qubit.
476
+
477
+ Raises:
478
+ RuntimeError: QrackSimulator raised an exception.
479
+ """
480
+ Qrack.qrack_lib.MCH(self.sid, len(c), QrackSimulator._ulonglong_byref(c), q)
481
+ self._throw_if_error()
482
+
483
+ def mcs(self, c, q):
484
+ """Multi-controlled S gate
485
+
486
+ If all controlled qubits are `|1>` then the "S" gate is applied to
487
+ the target qubit.
488
+
489
+ Args:
490
+ c: list of controlled qubits.
491
+ q: target qubit.
492
+
493
+ Raises:
494
+ RuntimeError: QrackSimulator raised an exception.
495
+ """
496
+ Qrack.qrack_lib.MCS(self.sid, len(c), QrackSimulator._ulonglong_byref(c), q)
497
+ self._throw_if_error()
498
+
499
+ def mct(self, c, q):
500
+ """Multi-controlled T gate
501
+
502
+ If all controlled qubits are `|1>` then the "T" gate is applied to
503
+ the target qubit.
504
+
505
+ Args:
506
+ c: list of controlled qubits.
507
+ q: target qubit.
508
+
509
+ Raises:
510
+ RuntimeError: QrackSimulator raised an exception.
511
+ """
512
+ Qrack.qrack_lib.MCT(self.sid, len(c), QrackSimulator._ulonglong_byref(c), q)
513
+ self._throw_if_error()
514
+
515
+ def mcadjs(self, c, q):
516
+ """Multi-controlled adjs gate
517
+
518
+ If all controlled qubits are `|1>` then the adjs gate is applied to
519
+ the target qubit.
520
+
521
+ Args:
522
+ c: list of controlled qubits.
523
+ q: target qubit.
524
+
525
+ Raises:
526
+ RuntimeError: QrackSimulator raised an exception.
527
+ """
528
+ Qrack.qrack_lib.MCAdjS(self.sid, len(c), QrackSimulator._ulonglong_byref(c), q)
529
+ self._throw_if_error()
530
+
531
+ def mcadjt(self, c, q):
532
+ """Multi-controlled adjt gate
533
+
534
+ If all controlled qubits are `|1>` then the adjt gate is applied to
535
+ the target qubit.
536
+
537
+ Args:
538
+ c: list of controlled qubits.
539
+ q: target qubit.
540
+
541
+ Raises:
542
+ RuntimeError: QrackSimulator raised an exception.
543
+ """
544
+ Qrack.qrack_lib.MCAdjT(self.sid, len(c), QrackSimulator._ulonglong_byref(c), q)
545
+ self._throw_if_error()
546
+
547
+ def mcu(self, c, q, th, ph, la):
548
+ """Multi-controlled arbitraty unitary
549
+
550
+ If all controlled qubits are `|1>` then the unitary gate described by
551
+ parameters is applied to the target qubit.
552
+
553
+ Args:
554
+ c: list of controlled qubits.
555
+ q: target qubit.
556
+ th: theta
557
+ ph: phi
558
+ la: lambda
559
+
560
+ Raises:
561
+ RuntimeError: QrackSimulator raised an exception.
562
+ """
563
+ Qrack.qrack_lib.MCU(
564
+ self.sid,
565
+ len(c),
566
+ QrackSimulator._ulonglong_byref(c),
567
+ q,
568
+ ctypes.c_double(th),
569
+ ctypes.c_double(ph),
570
+ ctypes.c_double(la),
571
+ )
572
+ self._throw_if_error()
573
+
574
+ def mcmtrx(self, c, m, q):
575
+ """Multi-controlled arbitrary operator
576
+
577
+ If all controlled qubits are `|1>` then the arbitrary operation by
578
+ parameters is applied to the target qubit.
579
+
580
+ Args:
581
+ c: list of controlled qubits
582
+ m: row-major complex list representing the operator.
583
+ q: target qubit
584
+
585
+ Raises:
586
+ ValueError: 2x2 matrix 'm' in QrackSimulator.mcmtrx() must contain at least 4 elements.
587
+ RuntimeError: QrackSimulator raised an exception.
588
+ """
589
+ if len(m) < 4:
590
+ raise ValueError(
591
+ "2x2 matrix 'm' in QrackSimulator.mcmtrx() must contain at least 4 elements."
592
+ )
593
+ Qrack.qrack_lib.MCMtrx(
594
+ self.sid,
595
+ len(c),
596
+ QrackSimulator._ulonglong_byref(c),
597
+ QrackSimulator._complex_byref(m),
598
+ q,
599
+ )
600
+ self._throw_if_error()
601
+
602
+ def macx(self, c, q):
603
+ """Anti multi-controlled X gate
604
+
605
+ If all controlled qubits are `|0>` then the target qubit is flipped.
606
+
607
+ Args:
608
+ c: list of controlled qubits.
609
+ q: target qubit.
610
+
611
+ Raises:
612
+ RuntimeError: QrackSimulator raised an exception.
613
+ """
614
+ Qrack.qrack_lib.MACX(self.sid, len(c), QrackSimulator._ulonglong_byref(c), q)
615
+ self._throw_if_error()
616
+
617
+ def macy(self, c, q):
618
+ """Anti multi-controlled Y gate
619
+
620
+ If all controlled qubits are `|0>` then the Pauli "Y" gate is applied to
621
+ the target qubit.
622
+
623
+ Args:
624
+ c: list of controlled qubits.
625
+ q: target qubit.
626
+
627
+ Raises:
628
+ RuntimeError: QrackSimulator raised an exception.
629
+ """
630
+ Qrack.qrack_lib.MACY(self.sid, len(c), QrackSimulator._ulonglong_byref(c), q)
631
+ self._throw_if_error()
632
+
633
+ def macz(self, c, q):
634
+ """Anti multi-controlled Z gate
635
+
636
+ If all controlled qubits are `|0>` then the Pauli "Z" gate is applied to
637
+ the target qubit.
638
+
639
+ Args:
640
+ c: list of controlled qubits.
641
+ q: target qubit.
642
+
643
+ Raises:
644
+ RuntimeError: QrackSimulator raised an exception.
645
+ """
646
+ Qrack.qrack_lib.MACZ(self.sid, len(c), QrackSimulator._ulonglong_byref(c), q)
647
+ self._throw_if_error()
648
+
649
+ def mach(self, c, q):
650
+ """Anti multi-controlled H gate
651
+
652
+ If all controlled qubits are `|0>` then the Hadarmard gate is applied to
653
+ the target qubit.
654
+
655
+ Args:
656
+ c: list of controlled qubits.
657
+ q: target qubit.
658
+
659
+ Raises:
660
+ RuntimeError: QrackSimulator raised an exception.
661
+ """
662
+ Qrack.qrack_lib.MACH(self.sid, len(c), QrackSimulator._ulonglong_byref(c), q)
663
+ self._throw_if_error()
664
+
665
+ def macs(self, c, q):
666
+ """Anti multi-controlled S gate
667
+
668
+ If all controlled qubits are `|0>` then the "S" gate is applied to
669
+ the target qubit.
670
+
671
+ Args:
672
+ c: list of controlled qubits.
673
+ q: target qubit.
674
+
675
+ Raises:
676
+ RuntimeError: QrackSimulator raised an exception.
677
+ """
678
+ Qrack.qrack_lib.MACS(self.sid, len(c), QrackSimulator._ulonglong_byref(c), q)
679
+ self._throw_if_error()
680
+
681
+ def mact(self, c, q):
682
+ """Anti multi-controlled T gate
683
+
684
+ If all controlled qubits are `|0>` then the "T" gate is applied to
685
+ the target qubit.
686
+
687
+ Args:
688
+ c: list of controlled qubits.
689
+ q: target qubit.
690
+
691
+ Raises:
692
+ RuntimeError: QrackSimulator raised an exception.
693
+ """
694
+ Qrack.qrack_lib.MACT(self.sid, len(c), QrackSimulator._ulonglong_byref(c), q)
695
+ self._throw_if_error()
696
+
697
+ def macadjs(self, c, q):
698
+ """Anti multi-controlled adjs gate
699
+
700
+ If all controlled qubits are `|0>` then the adjs gate is applied to
701
+ the target qubit.
702
+
703
+ Args:
704
+ c: list of controlled qubits.
705
+ q: target qubit.
706
+
707
+ Raises:
708
+ RuntimeError: QrackSimulator raised an exception.
709
+ """
710
+ Qrack.qrack_lib.MACAdjS(self.sid, len(c), QrackSimulator._ulonglong_byref(c), q)
711
+ self._throw_if_error()
712
+
713
+ def macadjt(self, c, q):
714
+ """Anti multi-controlled adjt gate
715
+
716
+ If all controlled qubits are `|0>` then the adjt gate is applied to
717
+ the target qubit.
718
+
719
+ Args:
720
+ c: list of controlled qubits.
721
+ q: target qubit.
722
+
723
+ Raises:
724
+ RuntimeError: QrackSimulator raised an exception.
725
+ """
726
+ Qrack.qrack_lib.MACAdjT(self.sid, len(c), QrackSimulator._ulonglong_byref(c), q)
727
+ self._throw_if_error()
728
+
729
+ def macu(self, c, q, th, ph, la):
730
+ """Anti multi-controlled arbitraty unitary
731
+
732
+ If all controlled qubits are `|0>` then the unitary gate described by
733
+ parameters is applied to the target qubit.
734
+
735
+ Args:
736
+ c: list of controlled qubits.
737
+ q: target qubit.
738
+ th: theta
739
+ ph: phi
740
+ la: lambda
741
+
742
+ Raises:
743
+ RuntimeError: QrackSimulator raised an exception.
744
+ """
745
+ Qrack.qrack_lib.MACU(
746
+ self.sid,
747
+ len(c),
748
+ QrackSimulator._ulonglong_byref(c),
749
+ q,
750
+ ctypes.c_double(th),
751
+ ctypes.c_double(ph),
752
+ ctypes.c_double(la),
753
+ )
754
+ self._throw_if_error()
755
+
756
+ def macmtrx(self, c, m, q):
757
+ """Anti multi-controlled arbitraty operator
758
+
759
+ If all controlled qubits are `|0>` then the arbitrary operation by
760
+ parameters is applied to the target qubit.
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: 2x2 matrix 'm' in QrackSimulator.macmtrx() must contain at least 4 elements.
769
+ RuntimeError: QrackSimulator raised an exception.
770
+ """
771
+ if len(m) < 4:
772
+ raise ValueError(
773
+ "2x2 matrix 'm' in QrackSimulator.macmtrx() must contain at least 4 elements."
774
+ )
775
+ Qrack.qrack_lib.MACMtrx(
776
+ self.sid,
777
+ len(c),
778
+ QrackSimulator._ulonglong_byref(c),
779
+ QrackSimulator._complex_byref(m),
780
+ q,
781
+ )
782
+ self._throw_if_error()
783
+
784
+ def ucmtrx(self, c, m, q, p):
785
+ """Multi-controlled arbitrary operator with arbitrary controls
786
+
787
+ If all control qubits match 'p' permutation by bit order, then the arbitrary
788
+ operation by parameters is applied to the target qubit.
789
+
790
+ Args:
791
+ c: list of control qubits
792
+ m: row-major complex list representing the operator.
793
+ q: target qubit
794
+ p: permutation of list of control qubits
795
+
796
+ Raises:
797
+ ValueError: 2x2 matrix 'm' in QrackSimulator.ucmtrx() must contain at least 4 elements.
798
+ RuntimeError: QrackSimulator raised an exception.
799
+ """
800
+ if len(m) < 4:
801
+ raise ValueError(
802
+ "2x2 matrix 'm' in QrackSimulator.ucmtrx() must contain at least 4 elements."
803
+ )
804
+ Qrack.qrack_lib.UCMtrx(
805
+ self.sid,
806
+ len(c),
807
+ QrackSimulator._ulonglong_byref(c),
808
+ QrackSimulator._complex_byref(m),
809
+ q,
810
+ p,
811
+ )
812
+ self._throw_if_error()
813
+
814
+ def multiplex1_mtrx(self, c, q, m):
815
+ """Multiplex gate
816
+
817
+ A multiplex gate with a single target and an arbitrary number of
818
+ controls.
819
+
820
+ Args:
821
+ c: list of controlled qubits.
822
+ m: row-major complex matrix which defines the operator.
823
+ q: target qubit.
824
+
825
+ Raises:
826
+ ValueError: Multiplex matrix 'm' in QrackSimulator.multiplex1_mtrx() must contain at least 4 elements.
827
+ RuntimeError: QrackSimulator raised an exception.
828
+ """
829
+ if len(m) < ((1 << len(c)) * 4):
830
+ raise ValueError(
831
+ "Multiplex matrix 'm' in QrackSimulator.multiplex1_mtrx() must contain at least (4 * 2 ** len(c)) elements."
832
+ )
833
+ Qrack.qrack_lib.Multiplex1Mtrx(
834
+ self.sid,
835
+ len(c),
836
+ QrackSimulator._ulonglong_byref(c),
837
+ q,
838
+ QrackSimulator._complex_byref(m),
839
+ )
840
+ self._throw_if_error()
841
+
842
+ def mx(self, q):
843
+ """Multi X-gate
844
+
845
+ Applies the Pauli “X” operator on all qubits.
846
+
847
+ Args:
848
+ q: list of qubits to apply X on.
849
+
850
+ Raises:
851
+ RuntimeError: QrackSimulator raised an exception.
852
+ """
853
+ Qrack.qrack_lib.MX(self.sid, len(q), QrackSimulator._ulonglong_byref(q))
854
+ self._throw_if_error()
855
+
856
+ def my(self, q):
857
+ """Multi Y-gate
858
+
859
+ Applies the Pauli “Y” operator on all qubits.
860
+
861
+ Args:
862
+ q: list of qubits to apply Y on.
863
+
864
+ Raises:
865
+ RuntimeError: QrackSimulator raised an exception.
866
+ """
867
+ Qrack.qrack_lib.MY(self.sid, len(q), QrackSimulator._ulonglong_byref(q))
868
+ self._throw_if_error()
869
+
870
+ def mz(self, q):
871
+ """Multi Z-gate
872
+
873
+ Applies the Pauli “Z” operator on all qubits.
874
+
875
+ Args:
876
+ q: list of qubits to apply Z on.
877
+
878
+ Raises:
879
+ RuntimeError: QrackSimulator raised an exception.
880
+ """
881
+ Qrack.qrack_lib.MZ(self.sid, len(q), QrackSimulator._ulonglong_byref(q))
882
+ self._throw_if_error()
883
+
884
+ def mcr(self, b, ph, c, q):
885
+ """Multi-controlled arbitrary rotation.
886
+
887
+ If all controlled qubits are `|1>` then the arbitrary rotation by
888
+ parameters is applied to the target qubit.
889
+
890
+ Args:
891
+ b: Pauli basis
892
+ ph: coefficient of exponentiation.
893
+ c: list of controlled qubits.
894
+ q: the qubit number on which the gate is applied to.
895
+
896
+ Raises:
897
+ RuntimeError: QrackSimulator raised an exception.
898
+ """
899
+ Qrack.qrack_lib.MCR(
900
+ self.sid,
901
+ ctypes.c_ulonglong(b),
902
+ ctypes.c_double(ph),
903
+ len(c),
904
+ QrackSimulator._ulonglong_byref(c),
905
+ q,
906
+ )
907
+ self._throw_if_error()
908
+
909
+ def mcexp(self, b, ph, cs, q):
910
+ """Multi-controlled arbitrary exponentiation
911
+
912
+ If all controlled qubits are `|1>` then the target qubit is
913
+ exponentiated an pauli basis basis with coefficient.
914
+
915
+ Args:
916
+ b: Pauli basis
917
+ ph: coefficient of exponentiation.
918
+ q: the qubit number on which the gate is applied to.
919
+
920
+ Raises:
921
+ RuntimeError: QrackSimulator raised an exception.
922
+ """
923
+ if len(b) != len(q):
924
+ raise RuntimeError("Lengths of list parameters are mismatched.")
925
+ Qrack.qrack_lib.MCExp(
926
+ self.sid,
927
+ len(b),
928
+ QrackSimulator._ulonglong_byref(b),
929
+ ctypes.c_double(ph),
930
+ len(cs),
931
+ QrackSimulator._ulonglong_byref(cs),
932
+ QrackSimulator._ulonglong_byref(q),
933
+ )
934
+ self._throw_if_error()
935
+
936
+ def swap(self, qi1, qi2):
937
+ """Swap Gate
938
+
939
+ Swaps the qubits at two given positions.
940
+
941
+ Args:
942
+ qi1: First position of qubit.
943
+ qi2: Second position of qubit.
944
+
945
+ Raises:
946
+ RuntimeError: QrackSimulator raised an exception.
947
+ """
948
+ Qrack.qrack_lib.SWAP(self.sid, qi1, qi2)
949
+ self._throw_if_error()
950
+
951
+ def iswap(self, qi1, qi2):
952
+ """Swap Gate with phase.
953
+
954
+ Swaps the qubits at two given positions.
955
+ If the bits are different then there is additional phase of `i`.
956
+
957
+ Args:
958
+ qi1: First position of qubit.
959
+ qi2: Second position of qubit.
960
+
961
+ Raises:
962
+ RuntimeError: QrackSimulator raised an exception.
963
+ """
964
+ Qrack.qrack_lib.ISWAP(self.sid, qi1, qi2)
965
+ self._throw_if_error()
966
+
967
+ def adjiswap(self, qi1, qi2):
968
+ """Swap Gate with phase.
969
+
970
+ Swaps the qubits at two given positions.
971
+ If the bits are different then there is additional phase of `-i`.
972
+
973
+ Args:
974
+ qi1: First position of qubit.
975
+ qi2: Second position of qubit.
976
+
977
+ Raises:
978
+ RuntimeError: QrackSimulator raised an exception.
979
+ """
980
+ Qrack.qrack_lib.AdjISWAP(self.sid, qi1, qi2)
981
+ self._throw_if_error()
982
+
983
+ def fsim(self, th, ph, qi1, qi2):
984
+ """Fsim gate.
985
+
986
+ The 2-qubit “fSim” gate
987
+ Useful in the simulation of particles with fermionic statistics
988
+
989
+ Args:
990
+ qi1: First position of qubit.
991
+ qi2: Second position of qubit.
992
+
993
+ Raises:
994
+ RuntimeError: QrackSimulator raised an exception.
995
+ """
996
+ Qrack.qrack_lib.FSim(self.sid, ctypes.c_double(th), ctypes.c_double(ph), qi1, qi2)
997
+ self._throw_if_error()
998
+
999
+ def cswap(self, c, qi1, qi2):
1000
+ """Controlled-swap Gate
1001
+
1002
+ Swaps the qubits at two given positions if the control qubits are `|1>`
1003
+
1004
+ Args:
1005
+ c: list of controlled qubits.
1006
+ qi1: First position of qubit.
1007
+ qi2: Second position of qubit.
1008
+
1009
+ Raises:
1010
+ RuntimeError: QrackSimulator raised an exception.
1011
+ """
1012
+ Qrack.qrack_lib.CSWAP(self.sid, len(c), QrackSimulator._ulonglong_byref(c), qi1, qi2)
1013
+ self._throw_if_error()
1014
+
1015
+ def acswap(self, c, qi1, qi2):
1016
+ """Anti controlled-swap Gate
1017
+
1018
+ Swaps the qubits at two given positions if the control qubits are `|0>`
1019
+
1020
+ Args:
1021
+ c: list of controlled qubits.
1022
+ qi1: First position of qubit.
1023
+ qi2: Second position of qubit.
1024
+
1025
+ Raises:
1026
+ RuntimeError: QrackSimulator raised an exception.
1027
+ """
1028
+ Qrack.qrack_lib.ACSWAP(self.sid, len(c), QrackSimulator._ulonglong_byref(c), qi1, qi2)
1029
+ self._throw_if_error()
1030
+
1031
+ # standard operations
1032
+ def m(self, q):
1033
+ """Measurement gate
1034
+
1035
+ Measures the qubit at "q" and returns Boolean value.
1036
+ This operator is not unitary & is probabilistic in nature.
1037
+
1038
+ Args:
1039
+ q: qubit to measure
1040
+
1041
+ Raises:
1042
+ RuntimeError: QrackSimulator raised an exception.
1043
+
1044
+ Returns:
1045
+ Measurement result.
1046
+ """
1047
+ result = Qrack.qrack_lib.M(self.sid, q)
1048
+ self._throw_if_error()
1049
+ return result
1050
+
1051
+ def force_m(self, q, r):
1052
+ """Force-Measurement gate
1053
+
1054
+ Acts as if the measurement is applied and the result obtained is `r`
1055
+
1056
+ Args:
1057
+ q: qubit to measure
1058
+ r: the required result
1059
+
1060
+ Raises:
1061
+ RuntimeError: QrackSimulator raised an exception.
1062
+
1063
+ Returns:
1064
+ Measurement result.
1065
+ """
1066
+ result = Qrack.qrack_lib.ForceM(self.sid, q, r)
1067
+ self._throw_if_error()
1068
+ return result
1069
+
1070
+ def m_all(self):
1071
+ """Measure-all gate
1072
+
1073
+ Measures measures all qubits.
1074
+ This operator is not unitary & is probabilistic in nature.
1075
+
1076
+ Raises:
1077
+ RuntimeError: QrackSimulator raised an exception.
1078
+
1079
+ Returns:
1080
+ Measurement result of all qubits.
1081
+ """
1082
+ num_q = self.num_qubits()
1083
+ num_words = (num_q + 63) // 64
1084
+ _r = (ctypes.c_ulonglong * num_words)()
1085
+ Qrack.qrack_lib.MAllLong(self.sid, _r)
1086
+ self._throw_if_error()
1087
+ r = 0
1088
+ for w in range(num_words):
1089
+ r <<= 64
1090
+ r |= _r[w]
1091
+ return r
1092
+
1093
+ def measure_pauli(self, b, q):
1094
+ """Pauli Measurement gate
1095
+
1096
+ Measures the qubit at "q" with the given pauli basis.
1097
+ This operator is not unitary & is probabilistic in nature.
1098
+
1099
+ Args:
1100
+ b: Pauli basis
1101
+ q: qubit to measure
1102
+
1103
+ Raises:
1104
+ RuntimeError: QrackSimulator raised an exception.
1105
+
1106
+ Returns:
1107
+ Measurement result.
1108
+ """
1109
+ if len(b) != len(q):
1110
+ raise RuntimeError("Lengths of list parameters are mismatched.")
1111
+ result = Qrack.qrack_lib.Measure(
1112
+ self.sid, len(b), QrackSimulator._int_byref(b), QrackSimulator._ulonglong_byref(q)
1113
+ )
1114
+ self._throw_if_error()
1115
+ return result
1116
+
1117
+ def measure_shots(self, q, s):
1118
+ """Multi-shot measurement operator
1119
+
1120
+ Measures the qubit at "q" with the given pauli basis.
1121
+ This operator is not unitary & is probabilistic in nature.
1122
+
1123
+ Args:
1124
+ q: list of qubits to measure
1125
+ s: number of shots
1126
+
1127
+ Raises:
1128
+ RuntimeError: QrackSimulator raised an exception.
1129
+
1130
+ Returns:
1131
+ list of measurement result.
1132
+ """
1133
+ m = QrackSimulator._ulonglong_byref([0] * s)
1134
+ Qrack.qrack_lib.MeasureShots(self.sid, len(q), QrackSimulator._ulonglong_byref(q), s, m)
1135
+ self._throw_if_error()
1136
+ return [m[i] for i in range(s)]
1137
+
1138
+ def reset_all(self):
1139
+ """Reset gate
1140
+
1141
+ Resets all qubits to `|0>`
1142
+
1143
+ Raises:
1144
+ RuntimeError: QrackSimulator raised an exception.
1145
+ """
1146
+ Qrack.qrack_lib.ResetAll(self.sid)
1147
+ self._throw_if_error()
1148
+
1149
+ # arithmetic-logic-unit (ALU)
1150
+ @staticmethod
1151
+ def _split_longs(a):
1152
+ """Split operation
1153
+
1154
+ Splits the given integer into 64 bit numbers.
1155
+
1156
+
1157
+ Args:
1158
+ a: number to split
1159
+
1160
+ Raises:
1161
+ RuntimeError: QrackSimulator raised an exception.
1162
+
1163
+ Returns:
1164
+ list of split numbers.
1165
+ """
1166
+ aParts = []
1167
+ if a == 0:
1168
+ aParts.append(0)
1169
+ while a > 0:
1170
+ aParts.append(a & 0xFFFFFFFFFFFFFFFF)
1171
+ a = a >> 64
1172
+ return aParts
1173
+
1174
+ @staticmethod
1175
+ def _split_longs_2(a, m):
1176
+ """Split simultanoues operation
1177
+
1178
+ Splits 2 integers into same number of 64 bit numbers.
1179
+
1180
+ Args:
1181
+ a: first number to split
1182
+ m: second number to split
1183
+
1184
+ Raises:
1185
+ RuntimeError: QrackSimulator raised an exception.
1186
+
1187
+ Returns:
1188
+ pair of lists of split numbers.
1189
+ """
1190
+ aParts = []
1191
+ mParts = []
1192
+ if a == 0 and m == 0:
1193
+ aParts.append(0)
1194
+ mParts.append(0)
1195
+ while a > 0 or m > 0:
1196
+ aParts.append(a & 0xFFFFFFFFFFFFFFFF)
1197
+ a = a >> 64
1198
+ mParts.append(m & 0xFFFFFFFFFFFFFFFF)
1199
+ m = m >> 64
1200
+ return aParts, mParts
1201
+
1202
+ def add(self, a, q):
1203
+ """Add integer to qubit
1204
+
1205
+ Adds the given integer to the given set of qubits.
1206
+
1207
+ Args:
1208
+ a: first number to split
1209
+ q: list of qubits to add the number
1210
+
1211
+ Raises:
1212
+ RuntimeError: QrackSimulator raised an exception.
1213
+ """
1214
+ aParts = QrackSimulator._split_longs(a)
1215
+ Qrack.qrack_lib.ADD(
1216
+ self.sid,
1217
+ len(aParts),
1218
+ QrackSimulator._ulonglong_byref(aParts),
1219
+ len(q),
1220
+ QrackSimulator._ulonglong_byref(q),
1221
+ )
1222
+ self._throw_if_error()
1223
+
1224
+ def sub(self, a, q):
1225
+ """Subtract integer to qubit
1226
+
1227
+ Subtracts the given integer to the given set of qubits.
1228
+
1229
+ Args:
1230
+ a: first number to split
1231
+ q: list of qubits to subtract the number
1232
+
1233
+ Raises:
1234
+ RuntimeError: QrackSimulator raised an exception.
1235
+ """
1236
+ aParts = QrackSimulator._split_longs(a)
1237
+ Qrack.qrack_lib.SUB(
1238
+ self.sid,
1239
+ len(aParts),
1240
+ QrackSimulator._ulonglong_byref(aParts),
1241
+ len(q),
1242
+ QrackSimulator._ulonglong_byref(q),
1243
+ )
1244
+ self._throw_if_error()
1245
+
1246
+ def adds(self, a, s, q):
1247
+ """Signed Addition integer to qubit
1248
+
1249
+ Signed Addition of the given integer to the given set of qubits,
1250
+ if there is an overflow the resultant will become negative.
1251
+
1252
+ Args:
1253
+ a: number to add
1254
+ s: qubit to store overflow
1255
+ q: list of qubits to add the number
1256
+
1257
+ Raises:
1258
+ RuntimeError: QrackSimulator raised an exception.
1259
+ """
1260
+ aParts = QrackSimulator._split_longs(a)
1261
+ Qrack.qrack_lib.ADDS(
1262
+ self.sid,
1263
+ len(aParts),
1264
+ QrackSimulator._ulonglong_byref(aParts),
1265
+ s,
1266
+ len(q),
1267
+ QrackSimulator._ulonglong_byref(q),
1268
+ )
1269
+ self._throw_if_error()
1270
+
1271
+ def subs(self, a, s, q):
1272
+ """Subtract integer to qubit
1273
+
1274
+ Subtracts the given integer to the given set of qubits,
1275
+ if there is an overflow the resultant will become negative.
1276
+
1277
+ Args:
1278
+ a: number to subtract
1279
+ s: qubit to store overflow
1280
+ q: list of qubits to subtract the number
1281
+
1282
+ Raises:
1283
+ RuntimeError: QrackSimulator raised an exception.
1284
+ """
1285
+ aParts = QrackSimulator._split_longs(a)
1286
+ Qrack.qrack_lib.SUBS(
1287
+ self.sid,
1288
+ len(aParts),
1289
+ QrackSimulator._ulonglong_byref(aParts),
1290
+ s,
1291
+ len(q),
1292
+ QrackSimulator._ulonglong_byref(q),
1293
+ )
1294
+ self._throw_if_error()
1295
+
1296
+ def mul(self, a, q, o):
1297
+ """Multiplies integer to qubit
1298
+
1299
+ Multiplies the given integer to the given set of qubits.
1300
+ Carry register is required for maintaining the unitary nature of
1301
+ operation and must be as long as the input qubit register.
1302
+
1303
+ Args:
1304
+ a: number to multiply
1305
+ q: list of qubits to multiply the number
1306
+ o: carry register
1307
+
1308
+ Raises:
1309
+ RuntimeError: QrackSimulator raised an exception.
1310
+ RuntimeError: QrackSimulator with isTensorNetwork=True option cannot mul()! (Turn off just this option, in the constructor.)
1311
+ """
1312
+ if self.is_tensor_network:
1313
+ raise RuntimeError(
1314
+ "QrackSimulator with isTensorNetwork=True option cannot mul()! (Turn off just this option, in the constructor.)"
1315
+ )
1316
+ if self.is_pure_stabilizer:
1317
+ raise RuntimeError(
1318
+ "QrackStabilizer cannot mul()! (Create a QrackSimulator instead, also with isTensorNetwork=False.)"
1319
+ )
1320
+
1321
+ if len(q) != len(o):
1322
+ raise RuntimeError("Lengths of list parameters are mismatched.")
1323
+ aParts = QrackSimulator._split_longs(a)
1324
+ Qrack.qrack_lib.MUL(
1325
+ self.sid,
1326
+ len(aParts),
1327
+ QrackSimulator._ulonglong_byref(aParts),
1328
+ len(q),
1329
+ QrackSimulator._ulonglong_byref(q),
1330
+ QrackSimulator._ulonglong_byref(o),
1331
+ )
1332
+ self._throw_if_error()
1333
+
1334
+ def div(self, a, q, o):
1335
+ """Divides qubit by integer
1336
+
1337
+ 'Divides' the given qubits by the integer.
1338
+ (This is rather the adjoint of mul().)
1339
+ Carry register is required for maintaining the unitary nature of
1340
+ operation.
1341
+
1342
+ Args:
1343
+ a: integer to divide by
1344
+ q: qubits to divide
1345
+ o: carry register
1346
+
1347
+ Raises:
1348
+ RuntimeError: QrackSimulator raised an exception.
1349
+ RuntimeError: QrackSimulator with isTensorNetwork=True option cannot div()! (Turn off just this option, in the constructor.)
1350
+ """
1351
+ if self.is_tensor_network:
1352
+ raise RuntimeError(
1353
+ "QrackSimulator with isTensorNetwork=True option cannot div()! (Turn off just this option, in the constructor.)"
1354
+ )
1355
+ if self.is_pure_stabilizer:
1356
+ raise RuntimeError(
1357
+ "QrackStabilizer cannot div()! (Create a QrackSimulator instead, also with isTensorNetwork=False.)"
1358
+ )
1359
+
1360
+ if len(q) != len(o):
1361
+ raise RuntimeError("Lengths of list parameters are mismatched.")
1362
+ aParts = QrackSimulator._split_longs(a)
1363
+ Qrack.qrack_lib.DIV(
1364
+ self.sid,
1365
+ len(aParts),
1366
+ QrackSimulator._ulonglong_byref(aParts),
1367
+ len(q),
1368
+ QrackSimulator._ulonglong_byref(q),
1369
+ QrackSimulator._ulonglong_byref(o),
1370
+ )
1371
+ self._throw_if_error()
1372
+
1373
+ def muln(self, a, m, q, o):
1374
+ """Modulo Multiplication
1375
+
1376
+ Modulo Multiplication of the given integer to the given set of qubits
1377
+ Out-of-place register is required to store the resultant.
1378
+
1379
+ Args:
1380
+ a: number to multiply
1381
+ m: modulo number
1382
+ q: list of qubits to multiply the number
1383
+ o: carry register
1384
+
1385
+ Raises:
1386
+ RuntimeError: QrackSimulator raised an exception.
1387
+ """
1388
+ if len(q) != len(o):
1389
+ raise RuntimeError("Lengths of list parameters are mismatched.")
1390
+ aParts, mParts = QrackSimulator._split_longs_2(a, m)
1391
+ Qrack.qrack_lib.MULN(
1392
+ self.sid,
1393
+ len(aParts),
1394
+ QrackSimulator._ulonglong_byref(aParts),
1395
+ QrackSimulator._ulonglong_byref(mParts),
1396
+ len(q),
1397
+ QrackSimulator._ulonglong_byref(q),
1398
+ QrackSimulator._ulonglong_byref(o),
1399
+ )
1400
+ self._throw_if_error()
1401
+
1402
+ def divn(self, a, m, q, o):
1403
+ """Modulo Division
1404
+
1405
+ 'Modulo Division' of the given set of qubits by the given integer
1406
+ (This is rather the adjoint of muln().)
1407
+ Out-of-place register is required to retrieve the resultant.
1408
+
1409
+ Args:
1410
+ a: integer by which qubit will be divided
1411
+ m: modulo integer
1412
+ q: qubits to divide
1413
+ o: carry register
1414
+
1415
+ Raises:
1416
+ RuntimeError: QrackSimulator raised an exception.
1417
+ """
1418
+ if len(q) != len(o):
1419
+ raise RuntimeError("Lengths of list parameters are mismatched.")
1420
+ aParts, mParts = QrackSimulator._split_longs_2(a, m)
1421
+ Qrack.qrack_lib.DIVN(
1422
+ self.sid,
1423
+ len(aParts),
1424
+ QrackSimulator._ulonglong_byref(aParts),
1425
+ QrackSimulator._ulonglong_byref(mParts),
1426
+ len(q),
1427
+ QrackSimulator._ulonglong_byref(q),
1428
+ QrackSimulator._ulonglong_byref(o),
1429
+ )
1430
+ self._throw_if_error()
1431
+
1432
+ def pown(self, a, m, q, o):
1433
+ """Modulo Power
1434
+
1435
+ Raises the qubit to the power `a` to which `mod m` is applied to.
1436
+ Out-of-place register is required to store the resultant.
1437
+
1438
+ Args:
1439
+ a: number in power
1440
+ m: modulo number
1441
+ q: list of qubits to exponentiate
1442
+ o: out-of-place register
1443
+
1444
+ Raises:
1445
+ RuntimeError: QrackSimulator raised an exception.
1446
+ RuntimeError: QrackSimulator with isTensorNetwork=True option cannot pown()! (Turn off just this option, in the constructor.)
1447
+ """
1448
+ if self.is_tensor_network:
1449
+ raise RuntimeError(
1450
+ "QrackSimulator with isTensorNetwork=True option cannot pown()! (Turn off just this option, in the constructor.)"
1451
+ )
1452
+ if self.is_pure_stabilizer:
1453
+ raise RuntimeError(
1454
+ "QrackStabilizer cannot pown()! (Create a QrackSimulator instead, also with isTensorNetwork=False.)"
1455
+ )
1456
+
1457
+ if len(q) != len(o):
1458
+ raise RuntimeError("Lengths of list parameters are mismatched.")
1459
+ aParts, mParts = QrackSimulator._split_longs_2(a, m)
1460
+ Qrack.qrack_lib.POWN(
1461
+ self.sid,
1462
+ len(aParts),
1463
+ QrackSimulator._ulonglong_byref(aParts),
1464
+ QrackSimulator._ulonglong_byref(mParts),
1465
+ len(q),
1466
+ QrackSimulator._ulonglong_byref(q),
1467
+ QrackSimulator._ulonglong_byref(o),
1468
+ )
1469
+ self._throw_if_error()
1470
+
1471
+ def mcadd(self, a, c, q):
1472
+ """Controlled-add
1473
+
1474
+ Adds the given integer to the given set of qubits if all controlled
1475
+ qubits are `|1>`.
1476
+
1477
+ Args:
1478
+ a: number to add.
1479
+ c: list of controlled qubits.
1480
+ q: list of qubits to add the number
1481
+
1482
+ Raises:
1483
+ RuntimeError: QrackSimulator raised an exception.
1484
+ """
1485
+ aParts = QrackSimulator._split_longs(a)
1486
+ Qrack.qrack_lib.MCADD(
1487
+ self.sid,
1488
+ len(aParts),
1489
+ QrackSimulator._ulonglong_byref(aParts),
1490
+ len(c),
1491
+ QrackSimulator._ulonglong_byref(c),
1492
+ len(q),
1493
+ QrackSimulator._ulonglong_byref(q),
1494
+ )
1495
+ self._throw_if_error()
1496
+
1497
+ def mcsub(self, a, c, q):
1498
+ """Controlled-subtract
1499
+
1500
+ Subtracts the given integer to the given set of qubits if all controlled
1501
+ qubits are `|1>`.
1502
+
1503
+ Args:
1504
+ a: number to subtract.
1505
+ c: list of controlled qubits.
1506
+ q: list of qubits to add the number
1507
+
1508
+ Raises:
1509
+ RuntimeError: QrackSimulator raised an exception.
1510
+ """
1511
+ aParts = QrackSimulator._split_longs(a)
1512
+ Qrack.qrack_lib.MCSUB(
1513
+ self.sid,
1514
+ len(aParts),
1515
+ QrackSimulator._ulonglong_byref(aParts),
1516
+ len(c),
1517
+ QrackSimulator._ulonglong_byref(c),
1518
+ len(q),
1519
+ QrackSimulator._ulonglong_byref(q),
1520
+ )
1521
+ self._throw_if_error()
1522
+
1523
+ def mcmul(self, a, c, q, o):
1524
+ """Controlled-multiply
1525
+
1526
+ Multiplies the given integer to the given set of qubits if all controlled
1527
+ qubits are `|1>`.
1528
+ Carry register is required for maintaining the unitary nature of
1529
+ operation.
1530
+
1531
+ Args:
1532
+ a: number to multiply
1533
+ c: list of controlled qubits.
1534
+ q: list of qubits to add the number
1535
+ o: carry register
1536
+
1537
+ Raises:
1538
+ RuntimeError: QrackSimulator raised an exception.
1539
+ RuntimeError: QrackSimulator with isTensorNetwork=True option cannot mcmul()! (Turn off just this option, in the constructor.)
1540
+ """
1541
+ if self.is_tensor_network:
1542
+ raise RuntimeError(
1543
+ "QrackSimulator with isTensorNetwork=True option cannot mcmul()! (Turn off just this option, in the constructor.)"
1544
+ )
1545
+ if self.is_pure_stabilizer:
1546
+ raise RuntimeError(
1547
+ "QrackStabilizer cannot mcmul()! (Create a QrackSimulator instead, also with isTensorNetwork=False.)"
1548
+ )
1549
+
1550
+ if len(q) != len(o):
1551
+ raise RuntimeError("Lengths of list parameters are mismatched.")
1552
+ aParts = QrackSimulator._split_longs(a)
1553
+ Qrack.qrack_lib.MCMUL(
1554
+ self.sid,
1555
+ len(aParts),
1556
+ QrackSimulator._ulonglong_byref(aParts),
1557
+ len(c),
1558
+ QrackSimulator._ulonglong_byref(c),
1559
+ len(q),
1560
+ QrackSimulator._ulonglong_byref(q),
1561
+ )
1562
+ self._throw_if_error()
1563
+
1564
+ def mcdiv(self, a, c, q, o):
1565
+ """Controlled-divide.
1566
+
1567
+ 'Divides' the given qubits by the integer if all controlled
1568
+ qubits are `|1>`.
1569
+ (This is rather the adjoint of mcmul().)
1570
+ Carry register is required for maintaining the unitary nature of
1571
+ operation.
1572
+
1573
+ Args:
1574
+ a: number to divide by
1575
+ c: list of controlled qubits.
1576
+ q: qubits to divide
1577
+ o: carry register
1578
+
1579
+ Raises:
1580
+ RuntimeError: QrackSimulator raised an exception.
1581
+ RuntimeError: QrackSimulator with isTensorNetwork=True option cannot mcdiv()! (Turn off just this option, in the constructor.)
1582
+ """
1583
+ if self.is_tensor_network:
1584
+ raise RuntimeError(
1585
+ "QrackSimulator with isTensorNetwork=True option cannot mcdiv()! (Turn off just this option, in the constructor.)"
1586
+ )
1587
+ if self.is_pure_stabilizer:
1588
+ raise RuntimeError(
1589
+ "QrackStabilizer cannot mcdiv()! (Create a QrackSimulator instead, also with isTensorNetwork=False.)"
1590
+ )
1591
+
1592
+ if len(q) != len(o):
1593
+ raise RuntimeError("Lengths of list parameters are mismatched.")
1594
+ aParts = QrackSimulator._split_longs(a)
1595
+ Qrack.qrack_lib.MCDIV(
1596
+ self.sid,
1597
+ len(aParts),
1598
+ QrackSimulator._ulonglong_byref(aParts),
1599
+ len(c),
1600
+ QrackSimulator._ulonglong_byref(c),
1601
+ len(q),
1602
+ QrackSimulator._ulonglong_byref(q),
1603
+ )
1604
+ self._throw_if_error()
1605
+
1606
+ def mcmuln(self, a, c, m, q, o):
1607
+ """Controlled-modulo multiplication
1608
+
1609
+ Modulo multiplication of the given integer to the given set of qubits
1610
+ if all controlled qubits are `|1>`.
1611
+ Out-of-place register is required to store the resultant.
1612
+
1613
+ Args:
1614
+ a: number to multiply
1615
+ c: list of controlled qubits.
1616
+ m: modulo number
1617
+ q: list of qubits to add the number
1618
+ o: out-of-place output register
1619
+
1620
+ Raises:
1621
+ RuntimeError: QrackSimulator raised an exception.
1622
+ """
1623
+ if len(q) != len(o):
1624
+ raise RuntimeError("Lengths of list parameters are mismatched.")
1625
+ aParts, mParts = QrackSimulator._split_longs_2(a, m)
1626
+ Qrack.qrack_lib.MCMULN(
1627
+ self.sid,
1628
+ len(aParts),
1629
+ QrackSimulator._ulonglong_byref(aParts),
1630
+ len(c),
1631
+ QrackSimulator._ulonglong_byref(c),
1632
+ QrackSimulator._ulonglong_byref(mParts),
1633
+ len(q),
1634
+ QrackSimulator._ulonglong_byref(q),
1635
+ QrackSimulator._ulonglong_byref(o),
1636
+ )
1637
+ self._throw_if_error()
1638
+
1639
+ def mcdivn(self, a, c, m, q, o):
1640
+ """Controlled-divide.
1641
+
1642
+ Modulo division of the given qubits by the given number if all
1643
+ controlled qubits are `|1>`.
1644
+ (This is rather the adjoint of mcmuln().)
1645
+ Out-of-place register is required to retrieve the resultant.
1646
+
1647
+ Args:
1648
+ a: number to divide by
1649
+ c: list of controlled qubits.
1650
+ m: modulo number
1651
+ q: qubits to divide
1652
+ o: carry register
1653
+
1654
+ Raises:
1655
+ RuntimeError: QrackSimulator raised an exception.
1656
+ """
1657
+ if len(q) != len(o):
1658
+ raise RuntimeError("Lengths of list parameters are mismatched.")
1659
+ aParts, mParts = QrackSimulator._split_longs_2(a, m)
1660
+ Qrack.qrack_lib.MCDIVN(
1661
+ self.sid,
1662
+ len(aParts),
1663
+ QrackSimulator._ulonglong_byref(aParts),
1664
+ len(c),
1665
+ QrackSimulator._ulonglong_byref(c),
1666
+ QrackSimulator._ulonglong_byref(mParts),
1667
+ len(q),
1668
+ QrackSimulator._ulonglong_byref(q),
1669
+ QrackSimulator._ulonglong_byref(o),
1670
+ )
1671
+ self._throw_if_error()
1672
+
1673
+ def mcpown(self, a, c, m, q, o):
1674
+ """Controlled-modulo Power
1675
+
1676
+ Raises the qubit to the power `a` to which `mod m` is applied to if
1677
+ all the controlled qubits are set to `|1>`.
1678
+ Out-of-place register is required to store the resultant.
1679
+
1680
+ Args:
1681
+ a: number in power
1682
+ c: control qubits
1683
+ m: modulo number
1684
+ q: list of qubits to exponentiate
1685
+ o: out-of-place register
1686
+
1687
+ Raises:
1688
+ RuntimeError: QrackSimulator raised an exception.
1689
+ RuntimeError: QrackSimulator with isTensorNetwork=True option cannot mcpown()! (Turn off just this option, in the constructor.)
1690
+ """
1691
+ if self.is_tensor_network:
1692
+ raise RuntimeError(
1693
+ "QrackSimulator with isTensorNetwork=True option cannot mcpown()! (Turn off just this option, in the constructor.)"
1694
+ )
1695
+ if self.is_pure_stabilizer:
1696
+ raise RuntimeError(
1697
+ "QrackStabilizer cannot mcpown()! (Create a QrackSimulator instead, also with isTensorNetwork=False.)"
1698
+ )
1699
+
1700
+ if len(q) != len(o):
1701
+ raise RuntimeError("Lengths of list parameters are mismatched.")
1702
+ aParts, mParts = QrackSimulator._split_longs_2(a, m)
1703
+ Qrack.qrack_lib.MCPOWN(
1704
+ self.sid,
1705
+ len(aParts),
1706
+ QrackSimulator._ulonglong_byref(aParts),
1707
+ len(c),
1708
+ QrackSimulator._ulonglong_byref(c),
1709
+ QrackSimulator._ulonglong_byref(mParts),
1710
+ len(q),
1711
+ QrackSimulator._ulonglong_byref(q),
1712
+ QrackSimulator._ulonglong_byref(o),
1713
+ )
1714
+ self._throw_if_error()
1715
+
1716
+ def lda(self, qi, qv, t):
1717
+ """Load Accumalator
1718
+
1719
+ Quantum counterpart for LDA from MOS-6502 assembly. `t` must be of
1720
+ the length `2 ** len(qi)`. It loads each list entry index of t into
1721
+ the qi register and each list entry value into the qv register.
1722
+
1723
+ Args:
1724
+ qi: qubit register for index
1725
+ qv: qubit register for value
1726
+ t: list of values
1727
+
1728
+ Raises:
1729
+ RuntimeError: QrackSimulator raised an exception.
1730
+ RuntimeError: QrackSimulator with isTensorNetwork=True option cannot lda()! (Turn off just this option, in the constructor.)
1731
+ """
1732
+ if self.is_tensor_network:
1733
+ raise RuntimeError(
1734
+ "QrackSimulator with isTensorNetwork=True option cannot lda()! (Turn off just this option, in the constructor.)"
1735
+ )
1736
+ if self.is_pure_stabilizer:
1737
+ raise RuntimeError(
1738
+ "QrackStabilizer cannot lda()! (Create a QrackSimulator instead, also with isTensorNetwork=False.)"
1739
+ )
1740
+
1741
+ Qrack.qrack_lib.LDA(
1742
+ self.sid,
1743
+ len(qi),
1744
+ QrackSimulator._ulonglong_byref(qi),
1745
+ len(qv),
1746
+ QrackSimulator._ulonglong_byref(qv),
1747
+ QrackSimulator._to_ubyte(len(qv), t),
1748
+ )
1749
+ self._throw_if_error()
1750
+
1751
+ def adc(self, s, qi, qv, t):
1752
+ """Add with Carry
1753
+
1754
+ Quantum counterpart for ADC from MOS-6502 assembly. `t` must be of
1755
+ the length `2 ** len(qi)`.
1756
+
1757
+ Args:
1758
+ qi: qubit register for index
1759
+ qv: qubit register for value
1760
+ t: list of values
1761
+
1762
+ Raises:
1763
+ RuntimeError: QrackSimulator raised an exception.
1764
+ RuntimeError: QrackSimulator with isTensorNetwork=True option cannot adc()! (Turn off just this option, in the constructor.)
1765
+ """
1766
+ if self.is_tensor_network:
1767
+ raise RuntimeError(
1768
+ "QrackSimulator with isTensorNetwork=True option cannot adc()! (Turn off just this option, in the constructor.)"
1769
+ )
1770
+ if self.is_pure_stabilizer:
1771
+ raise RuntimeError(
1772
+ "QrackStabilizer cannot adc()! (Create a QrackSimulator instead, also with isTensorNetwork=False.)"
1773
+ )
1774
+
1775
+ Qrack.qrack_lib.ADC(
1776
+ self.sid,
1777
+ s,
1778
+ len(qi),
1779
+ QrackSimulator._ulonglong_byref(qi),
1780
+ len(qv),
1781
+ QrackSimulator._ulonglong_byref(qv),
1782
+ QrackSimulator._to_ubyte(len(qv), t),
1783
+ )
1784
+ self._throw_if_error()
1785
+
1786
+ def sbc(self, s, qi, qv, t):
1787
+ """Subtract with Carry
1788
+
1789
+ Quantum counterpart for SBC from MOS-6502 assembly. `t` must be of
1790
+ the length `2 ** len(qi)`
1791
+
1792
+ Args:
1793
+ qi: qubit register for index
1794
+ qv: qubit register for value
1795
+ t: list of values
1796
+
1797
+ Raises:
1798
+ RuntimeError: QrackSimulator raised an exception.
1799
+ RuntimeError: QrackSimulator with isTensorNetwork=True option cannot sbc()! (Turn off just this option, in the constructor.)
1800
+ """
1801
+ if self.is_tensor_network:
1802
+ raise RuntimeError(
1803
+ "QrackSimulator with isTensorNetwork=True option cannot sbc()! (Turn off just this option, in the constructor.)"
1804
+ )
1805
+ if self.is_pure_stabilizer:
1806
+ raise RuntimeError(
1807
+ "QrackStabilizer cannot sbc()! (Create a QrackSimulator instead, also with isTensorNetwork=False.)"
1808
+ )
1809
+
1810
+ Qrack.qrack_lib.SBC(
1811
+ self.sid,
1812
+ s,
1813
+ len(qi),
1814
+ QrackSimulator._ulonglong_byref(qi),
1815
+ len(qv),
1816
+ QrackSimulator._ulonglong_byref(qv),
1817
+ QrackSimulator._to_ubyte(len(qv), t),
1818
+ )
1819
+ self._throw_if_error()
1820
+
1821
+ def hash(self, q, t):
1822
+ """Hash function
1823
+
1824
+ Replicates the behaviour of LDA without the index register.
1825
+ For the operation to be unitary, the entries present in `t` must be
1826
+ unique, and the length of `t` must be `2 ** len(qi)`.
1827
+
1828
+
1829
+ Args:
1830
+ q: qubit register for value
1831
+ t: list of values
1832
+
1833
+ Raises:
1834
+ RuntimeError: QrackSimulator raised an exception.
1835
+ RuntimeError: QrackSimulator with isTensorNetwork=True option cannot hash()! (Turn off just this option, in the constructor.)
1836
+ """
1837
+ if self.is_tensor_network:
1838
+ raise RuntimeError(
1839
+ "QrackSimulator with isTensorNetwork=True option cannot hash()! (Turn off just this option, in the constructor.)"
1840
+ )
1841
+ if self.is_pure_stabilizer:
1842
+ raise RuntimeError(
1843
+ "QrackStabilizer cannot hash()! (Create a QrackSimulator instead, also with isTensorNetwork=False.)"
1844
+ )
1845
+
1846
+ Qrack.qrack_lib.Hash(
1847
+ self.sid,
1848
+ len(q),
1849
+ QrackSimulator._ulonglong_byref(q),
1850
+ QrackSimulator._to_ubyte(len(q), t),
1851
+ )
1852
+ self._throw_if_error()
1853
+
1854
+ # boolean logic gates
1855
+ def qand(self, qi1, qi2, qo):
1856
+ """Logical AND
1857
+
1858
+ Logical AND of 2 qubits whose result is stored in the target qubit.
1859
+
1860
+ Args:
1861
+ qi1: qubit 1
1862
+ qi2: qubit 2
1863
+ qo: target qubit
1864
+
1865
+ Raises:
1866
+ RuntimeError: QrackSimulator raised an exception.
1867
+ """
1868
+ Qrack.qrack_lib.AND(self.sid, qi1, qi2, qo)
1869
+ self._throw_if_error()
1870
+
1871
+ def qor(self, qi1, qi2, qo):
1872
+ """Logical OR
1873
+
1874
+ Logical OR of 2 qubits whose result is stored in the target qubit.
1875
+
1876
+ Args:
1877
+ qi1: qubit 1
1878
+ qi2: qubit 2
1879
+ qo: target qubit
1880
+
1881
+ Raises:
1882
+ RuntimeError: QrackSimulator raised an exception.
1883
+ """
1884
+ Qrack.qrack_lib.OR(self.sid, qi1, qi2, qo)
1885
+ self._throw_if_error()
1886
+
1887
+ def qxor(self, qi1, qi2, qo):
1888
+ """Logical XOR
1889
+
1890
+ Logical exlusive-OR of 2 qubits whose result is stored in the target
1891
+ qubit.
1892
+
1893
+ Args:
1894
+ qi1: qubit 1
1895
+ qi2: qubit 2
1896
+ qo: target qubit
1897
+
1898
+ Raises:
1899
+ RuntimeError: QrackSimulator raised an exception.
1900
+ """
1901
+ Qrack.qrack_lib.XOR(self.sid, qi1, qi2, qo)
1902
+ self._throw_if_error()
1903
+
1904
+ def qnand(self, qi1, qi2, qo):
1905
+ """Logical NAND
1906
+
1907
+ Logical NAND of 2 qubits whose result is stored in the target
1908
+ qubit.
1909
+
1910
+ Args:
1911
+ qi1: qubit 1
1912
+ qi2: qubit 2
1913
+ qo: target qubit
1914
+
1915
+ Raises:
1916
+ RuntimeError: QrackSimulator raised an exception.
1917
+ """
1918
+ Qrack.qrack_lib.NAND(self.sid, qi1, qi2, qo)
1919
+ self._throw_if_error()
1920
+
1921
+ def qnor(self, qi1, qi2, qo):
1922
+ """Logical NOR
1923
+
1924
+ Logical NOR of 2 qubits whose result is stored in the target
1925
+ qubit.
1926
+
1927
+ Args:
1928
+ qi1: qubit 1
1929
+ qi2: qubit 2
1930
+ qo: target qubit
1931
+
1932
+ Raises:
1933
+ RuntimeError: QrackSimulator raised an exception.
1934
+ """
1935
+ Qrack.qrack_lib.NOR(self.sid, qi1, qi2, qo)
1936
+ self._throw_if_error()
1937
+
1938
+ def qxnor(self, qi1, qi2, qo):
1939
+ """Logical XOR
1940
+
1941
+ Logical exlusive-NOR of 2 qubits whose result is stored in the target
1942
+ qubit.
1943
+
1944
+ Args:
1945
+ qi1: qubit 1
1946
+ qi2: qubit 2
1947
+ qo: target qubit
1948
+
1949
+ Raises:
1950
+ RuntimeError: QrackSimulator raised an exception.
1951
+ """
1952
+ Qrack.qrack_lib.XNOR(self.sid, qi1, qi2, qo)
1953
+ self._throw_if_error()
1954
+
1955
+ def cland(self, ci, qi, qo):
1956
+ """Classical AND
1957
+
1958
+ Logical AND with one qubit and one classical bit whose result is
1959
+ stored in target qubit.
1960
+
1961
+ Args:
1962
+ qi1: qubit 1
1963
+ qi2: qubit 2
1964
+ qo: target qubit
1965
+
1966
+ Raises:
1967
+ RuntimeError: QrackSimulator raised an exception.
1968
+ """
1969
+ Qrack.qrack_lib.CLAND(self.sid, ci, qi, qo)
1970
+ self._throw_if_error()
1971
+
1972
+ def clor(self, ci, qi, qo):
1973
+ """Classical OR
1974
+
1975
+ Logical OR with one qubit and one classical bit whose result is
1976
+ stored in target qubit.
1977
+
1978
+ Args:
1979
+ qi1: qubit 1
1980
+ qi2: qubit 2
1981
+ qo: target qubit
1982
+
1983
+ Raises:
1984
+ RuntimeError: QrackSimulator raised an exception.
1985
+ """
1986
+ Qrack.qrack_lib.CLOR(self.sid, ci, qi, qo)
1987
+ self._throw_if_error()
1988
+
1989
+ def clxor(self, ci, qi, qo):
1990
+ """Classical XOR
1991
+
1992
+ Logical exlusive-OR with one qubit and one classical bit whose result is
1993
+ stored in target qubit.
1994
+
1995
+ Args:
1996
+ qi1: qubit 1
1997
+ qi2: qubit 2
1998
+ qo: target qubit
1999
+
2000
+ Raises:
2001
+ RuntimeError: QrackSimulator raised an exception.
2002
+ """
2003
+ Qrack.qrack_lib.CLXOR(self.sid, ci, qi, qo)
2004
+ self._throw_if_error()
2005
+
2006
+ def clnand(self, ci, qi, qo):
2007
+ """Classical NAND
2008
+
2009
+ Logical NAND with one qubit and one classical bit whose result is
2010
+ stored in target qubit.
2011
+
2012
+ Args:
2013
+ qi1: qubit 1
2014
+ qi2: qubit 2
2015
+ qo: target qubit
2016
+
2017
+ Raises:
2018
+ RuntimeError: QrackSimulator raised an exception.
2019
+ """
2020
+ Qrack.qrack_lib.CLNAND(self.sid, ci, qi, qo)
2021
+ self._throw_if_error()
2022
+
2023
+ def clnor(self, ci, qi, qo):
2024
+ """Classical NOR
2025
+
2026
+ Logical NOR with one qubit and one classical bit whose result is
2027
+ stored in target qubit.
2028
+
2029
+ Args:
2030
+ qi1: qubit 1
2031
+ qi2: qubit 2
2032
+ qo: target qubit
2033
+
2034
+ Raises:
2035
+ RuntimeError: QrackSimulator raised an exception.
2036
+ """
2037
+ Qrack.qrack_lib.CLNOR(self.sid, ci, qi, qo)
2038
+ self._throw_if_error()
2039
+
2040
+ def clxnor(self, ci, qi, qo):
2041
+ """Classical XNOR
2042
+
2043
+ Logical exlusive-NOR with one qubit and one classical bit whose result is
2044
+ stored in target qubit.
2045
+
2046
+ Args:
2047
+ qi1: qubit 1
2048
+ qi2: qubit 2
2049
+ qo: target qubit
2050
+
2051
+ Raises:
2052
+ RuntimeError: QrackSimulator raised an exception.
2053
+ """
2054
+ Qrack.qrack_lib.CLXNOR(self.sid, ci, qi, qo)
2055
+ self._throw_if_error()
2056
+
2057
+ # Particular Quantum Circuits
2058
+
2059
+ ## fourier transform
2060
+ def qft(self, qs):
2061
+ """Quantum Fourier Transform
2062
+
2063
+ Applies Quantum Fourier Transform on the list of qubits provided.
2064
+
2065
+ Args:
2066
+ qs: list of qubits
2067
+
2068
+ Raises:
2069
+ RuntimeError: QrackSimulator raised an exception.
2070
+ """
2071
+ Qrack.qrack_lib.QFT(self.sid, len(qs), QrackSimulator._ulonglong_byref(qs))
2072
+ self._throw_if_error()
2073
+
2074
+ def iqft(self, qs):
2075
+ """Inverse-quantum Fourier Transform
2076
+
2077
+ Applies Inverse-quantum Fourier Transform on the list of qubits
2078
+ provided.
2079
+
2080
+ Args:
2081
+ qs: list of qubits
2082
+
2083
+ Raises:
2084
+ RuntimeError: QrackSimulator raised an exception.
2085
+ """
2086
+ Qrack.qrack_lib.IQFT(self.sid, len(qs), QrackSimulator._ulonglong_byref(qs))
2087
+ self._throw_if_error()
2088
+
2089
+ # pseudo-quantum
2090
+
2091
+ ## allocate and release
2092
+ def allocate_qubit(self, qid):
2093
+ """Allocate Qubit
2094
+
2095
+ Allocate 1 new qubit with the given qubit ID.
2096
+
2097
+ Args:
2098
+ qid: qubit id
2099
+
2100
+ Raises:
2101
+ RuntimeError: QrackSimulator raised an exception.
2102
+ """
2103
+ Qrack.qrack_lib.allocateQubit(self.sid, qid)
2104
+ self._throw_if_error()
2105
+
2106
+ def release(self, q):
2107
+ """Release Qubit
2108
+
2109
+ Release qubit given by the given qubit ID.
2110
+
2111
+ Args:
2112
+ q: qubit id
2113
+
2114
+ Raises:
2115
+ RuntimeError: QrackSimulator raised an exception.
2116
+
2117
+ Returns:
2118
+ If the qubit was in `|0>` state with small tolerance.
2119
+ """
2120
+ result = Qrack.qrack_lib.release(self.sid, q)
2121
+ self._throw_if_error()
2122
+ return result
2123
+
2124
+ def num_qubits(self):
2125
+ """Get Qubit count
2126
+
2127
+ Returns the qubit count of the simulator.
2128
+
2129
+ Args:
2130
+ q: qubit id
2131
+
2132
+ Raises:
2133
+ RuntimeError: QrackSimulator raised an exception.
2134
+
2135
+ Returns:
2136
+ Qubit count of the simulator
2137
+ """
2138
+ result = Qrack.qrack_lib.num_qubits(self.sid)
2139
+ self._throw_if_error()
2140
+ return result
2141
+
2142
+ ## schmidt decomposition
2143
+ def compose(self, other, q):
2144
+ """Compose qubits
2145
+
2146
+ Compose quantum description of given qubit with the current system.
2147
+
2148
+ Args:
2149
+ q: qubit id
2150
+
2151
+ Raises:
2152
+ RuntimeError: QrackSimulator raised an exception.
2153
+ RuntimeError: QrackSimulator with isTensorNetwork=True option cannot compose()! (Turn off just this option, in the constructor.)
2154
+ """
2155
+ if self.is_tensor_network:
2156
+ raise RuntimeError(
2157
+ "QrackSimulator with isTensorNetwork=True option cannot compose()! (Turn off just this option, in the constructor.)"
2158
+ )
2159
+
2160
+ Qrack.qrack_lib.Compose(self.sid, other.sid, QrackSimulator._ulonglong_byref(q))
2161
+ self._throw_if_error()
2162
+
2163
+ def decompose(self, q):
2164
+ """Decompose system
2165
+
2166
+ Factorize a set of contiguous bits with minimal fidelity loss.
2167
+
2168
+ Args:
2169
+ q: qubit id
2170
+
2171
+ Raises:
2172
+ RuntimeError: QrackSimulator raised an exception.
2173
+ RuntimeError: QrackSimulator with isTensorNetwork=True option cannot decompose()! (Turn off just this option, in the constructor.)
2174
+
2175
+ Returns:
2176
+ Decomposed subsystem simulator.
2177
+ """
2178
+ if self.is_tensor_network:
2179
+ raise RuntimeError(
2180
+ "QrackSimulator with isTensorNetwork=True option cannot decompose()! (Turn off just this option, in the constructor.)"
2181
+ )
2182
+
2183
+ other = QrackSimulator()
2184
+ Qrack.qrack_lib.destroy(other.sid)
2185
+ l = len(q)
2186
+ other.sid = Qrack.qrack_lib.Decompose(self.sid, l, QrackSimulator._ulonglong_byref(q))
2187
+ self._throw_if_error()
2188
+ return other
2189
+
2190
+ def dispose(self, q):
2191
+ """Dispose qubits
2192
+
2193
+ Factorize a set of contiguous bits with minimal fidelity loss,
2194
+ and discard the separable bits.
2195
+
2196
+ Args:
2197
+ q: qubit
2198
+
2199
+ Raises:
2200
+ RuntimeError: QrackSimulator raised an exception.
2201
+ RuntimeError: QrackSimulator with isTensorNetwork=True option cannot dispose()! (Turn off just this option, in the constructor.)
2202
+ """
2203
+ if self.is_tensor_network:
2204
+ raise RuntimeError(
2205
+ "QrackSimulator with isTensorNetwork=True option cannot dispose()! (Turn off just this option, in the constructor.)"
2206
+ )
2207
+
2208
+ l = len(q)
2209
+ Qrack.qrack_lib.Dispose(self.sid, l, QrackSimulator._ulonglong_byref(q))
2210
+ self._throw_if_error()
2211
+
2212
+ ## miscellaneous
2213
+ def dump_ids(self):
2214
+ """Dump all IDs
2215
+
2216
+ Dump all IDs from the selected simulator ID into the callback.
2217
+
2218
+ Returns:
2219
+ List of ids
2220
+ """
2221
+ global ids_list
2222
+ global ids_list_index
2223
+ ids_list = [0] * self.num_qubits()
2224
+ ids_list_index = 0
2225
+ Qrack.qrack_lib.DumpIds(self.sid, self.dump_ids_callback)
2226
+ return ids_list
2227
+
2228
+ @ctypes.CFUNCTYPE(None, ctypes.c_ulonglong)
2229
+ def dump_ids_callback(i):
2230
+ """C callback function"""
2231
+ global ids_list
2232
+ global ids_list_index
2233
+ ids_list[ids_list_index] = i
2234
+ ids_list_index = ids_list_index + 1
2235
+
2236
+ def dump(self):
2237
+ """Dump state vector
2238
+
2239
+ Dump state vector from the selected simulator ID into the callback.
2240
+
2241
+ Returns:
2242
+ State vector list
2243
+ """
2244
+ global state_vec_list
2245
+ global state_vec_list_index
2246
+ global state_vec_probability
2247
+ state_vec_list = [complex(0, 0)] * (1 << self.num_qubits())
2248
+ state_vec_list_index = 0
2249
+ state_vec_probability = 0
2250
+ Qrack.qrack_lib.Dump(self.sid, self.dump_callback)
2251
+ return state_vec_list
2252
+
2253
+ @ctypes.CFUNCTYPE(ctypes.c_bool, ctypes.c_double, ctypes.c_double)
2254
+ def dump_callback(r, i):
2255
+ """C callback function"""
2256
+ global state_vec_list
2257
+ global state_vec_list_index
2258
+ global state_vec_probability
2259
+ state_vec_list[state_vec_list_index] = complex(r, i)
2260
+ state_vec_list_index = state_vec_list_index + 1
2261
+ state_vec_probability = state_vec_probability + (r * r) + (i * i)
2262
+ if (1.0 - state_vec_probability) <= (7.0 / 3 - 4.0 / 3 - 1):
2263
+ return False
2264
+ return True
2265
+
2266
+ def in_ket(self, ket):
2267
+ """Set state vector
2268
+
2269
+ Set state vector for the selected simulator ID.
2270
+ Warning: State vector is not always the internal representation leading
2271
+ to sub-optimal performance of the method.
2272
+
2273
+ Args:
2274
+ ket: the state vector to which simulator will be set
2275
+
2276
+ Raises:
2277
+ RuntimeError: QrackSimulator raised an exception.
2278
+ """
2279
+ Qrack.qrack_lib.InKet(self.sid, QrackSimulator._qrack_complex_byref(ket))
2280
+ self._throw_if_error()
2281
+
2282
+ def out_ket(self):
2283
+ """Get state vector
2284
+
2285
+ Returns the raw state vector of the simulator.
2286
+ Warning: State vector is not always the internal representation leading
2287
+ to sub-optimal performance of the method.
2288
+
2289
+ Raises:
2290
+ RuntimeError: QrackSimulator raised an exception.
2291
+
2292
+ Returns:
2293
+ list representing the state vector.
2294
+ """
2295
+ amp_count = 1 << self.num_qubits()
2296
+ ket = QrackSimulator._qrack_complex_byref([complex(0, 0)] * amp_count)
2297
+ Qrack.qrack_lib.OutKet(self.sid, ket)
2298
+ self._throw_if_error()
2299
+ return [complex(r, i) for r, i in QrackSimulator._pairwise(ket)]
2300
+
2301
+ def out_probs(self):
2302
+ """Get basis dimension probabilities
2303
+
2304
+ Returns the probabilities of each basis dimension in the state vector
2305
+ of the simulator.
2306
+
2307
+ Raises:
2308
+ RuntimeError: QrackSimulator raised an exception.
2309
+
2310
+ Returns:
2311
+ list representing the basis dimension probabilities.
2312
+ """
2313
+ prob_count = 1 << self.num_qubits()
2314
+ probs = QrackSimulator._real1_byref([0.0] * prob_count)
2315
+ Qrack.qrack_lib.OutProbs(self.sid, probs)
2316
+ self._throw_if_error()
2317
+ return list(probs)
2318
+
2319
+ def out_rdm(self, q):
2320
+ """Get reduced density matrix
2321
+
2322
+ Returns the raw reduced density matrix of the simulator, for the qubit list.
2323
+ Warning: State vector or is not always the internal representation leading
2324
+ to sub-optimal performance of the method.
2325
+
2326
+ Raises:
2327
+ RuntimeError: QrackSimulator raised an exception.
2328
+
2329
+ Returns:
2330
+ flat list structure representing the reduced density matrix.
2331
+ """
2332
+ amp_count = 1 << len(q)
2333
+ sqr_amp_count = amp_count * amp_count
2334
+ flat_rdm = QrackSimulator._qrack_complex_byref([complex(0, 0)] * sqr_amp_count)
2335
+ Qrack.qrack_lib.OutReducedDensityMatrix(
2336
+ self.sid, len(q), QrackSimulator._ulonglong_byref(q), flat_rdm
2337
+ )
2338
+ self._throw_if_error()
2339
+ return [complex(r, i) for r, i in QrackSimulator._pairwise(flat_rdm)]
2340
+
2341
+ def highest_prob_perm(self):
2342
+ """Get the permutation (bit string) with the highest probability
2343
+
2344
+ Returns the single highest-probability bit string in the Hilbert space
2345
+
2346
+ Raises:
2347
+ RuntimeError: QrackSimulator raised an exception.
2348
+
2349
+ Returns:
2350
+ Highest probability dimension index
2351
+ """
2352
+ num_q = self.num_qubits()
2353
+ num_words = (num_q + 63) // 64
2354
+ _r = (ctypes.c_ulonglong * num_words)()
2355
+ Qrack.qrack_lib.HighestProbAll(self.sid, _r)
2356
+ self._throw_if_error()
2357
+ r = 0
2358
+ for w in range(num_words):
2359
+ r <<= 64
2360
+ r |= _r[w]
2361
+ return r
2362
+
2363
+ def highest_n_prob_perm(self, n):
2364
+ """Get the top n permutations (bit strings) with the highest probability
2365
+
2366
+ Returns the top n highest-probability bit strings in the Hilbert space
2367
+
2368
+ Raises:
2369
+ RuntimeError: QrackSimulator raised an exception.
2370
+
2371
+ Returns:
2372
+ Top n highest probability dimension indices
2373
+ """
2374
+ num_q = self.num_qubits()
2375
+ num_words = (num_q + 63) // 64
2376
+ _r = (ctypes.c_ulonglong * (num_words * n))()
2377
+ Qrack.qrack_lib.HighestProbAllN(self.sid, n, _r)
2378
+ self._throw_if_error()
2379
+ r = [0] * n
2380
+ for i in range(n):
2381
+ r[i] = 0
2382
+ for w in range(num_words):
2383
+ r[i] <<= 64
2384
+ r[i] |= _r[(i * num_words) + w]
2385
+ return r
2386
+
2387
+ def prob_all(self, q):
2388
+ """Probabilities of all subset permutations
2389
+
2390
+ Get the probabilities of all permutations of the subset.
2391
+
2392
+ Args:
2393
+ q: list of qubit ids
2394
+
2395
+ Raises:
2396
+ RuntimeError: QrackSimulator raised an exception.
2397
+
2398
+ Returns:
2399
+ list representing the state vector.
2400
+ """
2401
+ probs = QrackSimulator._real1_byref([0.0] * (1 << len(q)))
2402
+ Qrack.qrack_lib.ProbAll(self.sid, len(q), QrackSimulator._ulonglong_byref(q), probs)
2403
+ self._throw_if_error()
2404
+ return list(probs)
2405
+
2406
+ def prob(self, q):
2407
+ """Probability of `|1>`
2408
+
2409
+ Get the probability that a qubit is in the `|1>` state.
2410
+
2411
+ Args:
2412
+ q: qubit id
2413
+
2414
+ Raises:
2415
+ RuntimeError: QrackSimulator raised an exception.
2416
+
2417
+ Returns:
2418
+ probability of qubit being in `|1>`
2419
+ """
2420
+ result = Qrack.qrack_lib.Prob(self.sid, q)
2421
+ self._throw_if_error()
2422
+ return result
2423
+
2424
+ def prob_rdm(self, q):
2425
+ """Probability of `|1>`, (tracing out the reduced
2426
+ density matrix without stabilizer ancillary qubits)
2427
+
2428
+ Get the probability that a qubit is in the `|1>` state.
2429
+
2430
+ Args:
2431
+ q: qubit id
2432
+
2433
+ Raises:
2434
+ RuntimeError: QrackSimulator raised an exception.
2435
+
2436
+ Returns:
2437
+ probability of qubit being in `|1>`
2438
+ """
2439
+ result = Qrack.qrack_lib.ProbRdm(self.sid, q)
2440
+ self._throw_if_error()
2441
+ return result
2442
+
2443
+ def prob_perm(self, q, c):
2444
+ """Probability of permutation
2445
+
2446
+ Get the probability that the qubit IDs in "q" have the truth values
2447
+ in "c", directly corresponding by list index.
2448
+
2449
+ Args:
2450
+ q: list of qubit ids
2451
+ c: list of qubit truth values bools
2452
+
2453
+ Raises:
2454
+ RuntimeError: QrackSimulator raised an exception.
2455
+
2456
+ Returns:
2457
+ probability that each qubit in "q[i]" has corresponding truth
2458
+ value in "c[i]", at once
2459
+ """
2460
+
2461
+ if len(q) != len(c):
2462
+ raise RuntimeError("prob_perm argument lengths do not match.")
2463
+ result = Qrack.qrack_lib.PermutationProb(
2464
+ self.sid, len(q), QrackSimulator._ulonglong_byref(q), QrackSimulator._bool_byref(c)
2465
+ )
2466
+ self._throw_if_error()
2467
+ return result
2468
+
2469
+ def prob_perm_rdm(self, q, c, r=True):
2470
+ """Probability of permutation, (tracing out the reduced
2471
+ density matrix without stabilizer ancillary qubits)
2472
+
2473
+ Get the probability that the qubit IDs in "q" have the truth
2474
+ values in "c", directly corresponding by list index.
2475
+
2476
+ Args:
2477
+ q: list of qubit ids
2478
+ c: list of qubit truth values bools
2479
+ r: round Rz gates down from T^(1/2)
2480
+
2481
+ Raises:
2482
+ RuntimeError: QrackSimulator raised an exception.
2483
+
2484
+ Returns:
2485
+ probability that each qubit in "q[i]" has corresponding truth
2486
+ value in "c[i]", at once
2487
+ """
2488
+
2489
+ if len(q) != len(c):
2490
+ raise RuntimeError("prob_perm argument lengths do not match.")
2491
+ result = Qrack.qrack_lib.PermutationProbRdm(
2492
+ self.sid, len(q), QrackSimulator._ulonglong_byref(q), QrackSimulator._bool_byref(c), r
2493
+ )
2494
+ self._throw_if_error()
2495
+ return result
2496
+
2497
+ def permutation_expectation(self, q):
2498
+ """Permutation expectation value
2499
+
2500
+ Get the permutation expectation value, based upon the order of
2501
+ input qubits.
2502
+
2503
+ Args:
2504
+ q: qubits, from low to high
2505
+
2506
+ Raises:
2507
+ RuntimeError: QrackSimulator raised an exception.
2508
+
2509
+ Returns:
2510
+ Expectation value
2511
+ """
2512
+ result = Qrack.qrack_lib.PermutationExpectation(
2513
+ self.sid, len(q), QrackSimulator._ulonglong_byref(q)
2514
+ )
2515
+ self._throw_if_error()
2516
+ return result
2517
+
2518
+ def permutation_expectation_rdm(self, q, r=True):
2519
+ """Permutation expectation value, (tracing out the reduced
2520
+ density matrix without stabilizer ancillary qubits)
2521
+
2522
+ Get the permutation expectation value, based upon the order of
2523
+ input qubits.
2524
+
2525
+ Args:
2526
+ q: qubits, from low to high
2527
+ r: round Rz gates down from T^(1/2)
2528
+
2529
+ Raises:
2530
+ RuntimeError: QrackSimulator raised an exception.
2531
+
2532
+ Returns:
2533
+ Expectation value
2534
+ """
2535
+ result = Qrack.qrack_lib.PermutationExpectationRdm(
2536
+ self.sid, len(q), QrackSimulator._ulonglong_byref(q), r
2537
+ )
2538
+ self._throw_if_error()
2539
+ return result
2540
+
2541
+ def factorized_expectation(self, q, c):
2542
+ """Factorized expectation value
2543
+
2544
+ Get the factorized expectation value, where each entry
2545
+ in "c" is an expectation value for corresponding "q"
2546
+ being false, then true, repeated for each in "q".
2547
+
2548
+ Args:
2549
+ q: qubits, from low to high
2550
+ c: qubit falsey/truthy values, from low to high
2551
+
2552
+ Raises:
2553
+ RuntimeError: QrackSimulator raised an exception.
2554
+
2555
+ Returns:
2556
+ Expectation value
2557
+ """
2558
+ if (len(q) << 1) != len(c):
2559
+ raise RuntimeError("factorized_expectation argument lengths do not match.")
2560
+ m = max([(x.bit_length() + 63) // 64 for x in c])
2561
+ result = Qrack.qrack_lib.FactorizedExpectation(
2562
+ self.sid,
2563
+ len(q),
2564
+ QrackSimulator._ulonglong_byref(q),
2565
+ m,
2566
+ QrackSimulator._to_ulonglong(m, c),
2567
+ )
2568
+ self._throw_if_error()
2569
+ return result
2570
+
2571
+ def factorized_expectation_rdm(self, q, c, r=True):
2572
+ """Factorized expectation value, (tracing out the reduced
2573
+ density matrix without stabilizer ancillary qubits)
2574
+
2575
+ Get the factorized expectation value, where each entry
2576
+ in "c" is an expectation value for corresponding "q"
2577
+ being false, then true, repeated for each in "q".
2578
+
2579
+ Args:
2580
+ q: qubits, from low to high
2581
+ c: qubit falsey/truthy values, from low to high
2582
+ r: round Rz gates down from T^(1/2)
2583
+
2584
+ Raises:
2585
+ RuntimeError: QrackSimulator raised an exception.
2586
+
2587
+ Returns:
2588
+ Expectation value
2589
+ """
2590
+ if (len(q) << 1) != len(c):
2591
+ raise RuntimeError("factorized_expectation_rdm argument lengths do not match.")
2592
+ m = max([(x.bit_length() + 63) // 64 for x in c])
2593
+ result = Qrack.qrack_lib.FactorizedExpectationRdm(
2594
+ self.sid,
2595
+ len(q),
2596
+ QrackSimulator._ulonglong_byref(q),
2597
+ m,
2598
+ QrackSimulator._to_ulonglong(m, c),
2599
+ r,
2600
+ )
2601
+ self._throw_if_error()
2602
+ return result
2603
+
2604
+ def factorized_expectation_fp(self, q, c):
2605
+ """Factorized expectation value (floating-point)
2606
+
2607
+ Get the factorized expectation value, where each entry
2608
+ in "c" is an expectation value for corresponding "q"
2609
+ being false, then true, repeated for each in "q".
2610
+
2611
+ Args:
2612
+ q: qubits, from low to high
2613
+ c: qubit falsey/truthy values, from low to high
2614
+
2615
+ Raises:
2616
+ RuntimeError: QrackSimulator raised an exception.
2617
+
2618
+ Returns:
2619
+ Expectation value
2620
+ """
2621
+ if (len(q) << 1) != len(c):
2622
+ raise RuntimeError("factorized_expectation_rdm argument lengths do not match.")
2623
+ result = Qrack.qrack_lib.FactorizedExpectationFp(
2624
+ self.sid, len(q), QrackSimulator._ulonglong_byref(q), QrackSimulator._real1_byref(c)
2625
+ )
2626
+ self._throw_if_error()
2627
+ return result
2628
+
2629
+ def factorized_expectation_fp_rdm(self, q, c, r=True):
2630
+ """Factorized expectation value, (tracing out the reduced
2631
+ density matrix without stabilizer ancillary qubits)
2632
+
2633
+ Get the factorized expectation value, where each entry
2634
+ in "c" is an expectation value for corresponding "q"
2635
+ being false, then true, repeated for each in "q".
2636
+
2637
+ Args:
2638
+ q: qubits, from low to high
2639
+ c: qubit falsey/truthy values, from low to high
2640
+ r: round Rz gates down from T^(1/2)
2641
+
2642
+ Raises:
2643
+ RuntimeError: QrackSimulator raised an exception.
2644
+
2645
+ Returns:
2646
+ Expectation value
2647
+ """
2648
+ if (len(q) << 1) != len(c):
2649
+ raise RuntimeError("factorized_expectation_fp_rdm argument lengths do not match.")
2650
+ result = Qrack.qrack_lib.FactorizedExpectationFpRdm(
2651
+ self.sid, len(q), QrackSimulator._ulonglong_byref(q), QrackSimulator._real1_byref(c), r
2652
+ )
2653
+ self._throw_if_error()
2654
+ return result
2655
+
2656
+ def unitary_expectation(self, q, b):
2657
+ """3-parameter unitary tensor product expectation value
2658
+
2659
+ Get the single-qubit (3-parameter) operator
2660
+ expectation value for the array of qubits and bases.
2661
+
2662
+ Args:
2663
+ q: qubits, from low to high
2664
+ b: 3-parameter, single-qubit, unitary bases (flat over wires)
2665
+
2666
+ Raises:
2667
+ RuntimeError: QrackSimulator raised an exception.
2668
+
2669
+ Returns:
2670
+ Expectation value
2671
+ """
2672
+ if (3 * len(q)) != len(b):
2673
+ raise RuntimeError("unitary_expectation argument lengths do not match.")
2674
+ result = Qrack.qrack_lib.UnitaryExpectation(
2675
+ self.sid, len(q), QrackSimulator._ulonglong_byref(q), QrackSimulator._real1_byref(b)
2676
+ )
2677
+ self._throw_if_error()
2678
+ return result
2679
+
2680
+ def matrix_expectation(self, q, b):
2681
+ """Single-qubit operator tensor product expectation value
2682
+
2683
+ Get the single-qubit (3-parameter) operator
2684
+ expectation value for the array of qubits and bases.
2685
+
2686
+ Args:
2687
+ q: qubits, from low to high
2688
+ b: single-qubit (2x2) operator unitary bases (flat over wires)
2689
+
2690
+ Raises:
2691
+ RuntimeError: QrackSimulator raised an exception.
2692
+
2693
+ Returns:
2694
+ Expectation value
2695
+ """
2696
+ if (len(q) << 2) != len(b):
2697
+ raise RuntimeError("matrix_expectation argument lengths do not match.")
2698
+ result = Qrack.qrack_lib.MatrixExpectation(
2699
+ self.sid, len(q), QrackSimulator._ulonglong_byref(q), QrackSimulator._complex_byref(b)
2700
+ )
2701
+ self._throw_if_error()
2702
+ return result
2703
+
2704
+ def unitary_expectation_eigenval(self, q, b, e):
2705
+ """3-parameter unitary tensor product expectation value
2706
+
2707
+ Get the single-qubit (3-parameter) operator
2708
+ expectation value for the array of qubits and bases.
2709
+
2710
+ Args:
2711
+ q: qubits, from low to high
2712
+ b: 3-parameter, single-qubit, unitary bases (flat over wires)
2713
+
2714
+ Raises:
2715
+ RuntimeError: QrackSimulator raised an exception.
2716
+
2717
+ Returns:
2718
+ Expectation value
2719
+ """
2720
+ if (3 * len(q)) != len(b):
2721
+ raise RuntimeError(
2722
+ "unitary_expectation_eigenval qubit and basis argument lengths do not match."
2723
+ )
2724
+ if (len(q) << 1) != len(e):
2725
+ raise RuntimeError(
2726
+ "unitary_expectation_eigenval qubit and eigenvalue argument lengths do not match."
2727
+ )
2728
+ result = Qrack.qrack_lib.UnitaryExpectationEigenVal(
2729
+ self.sid,
2730
+ len(q),
2731
+ QrackSimulator._ulonglong_byref(q),
2732
+ QrackSimulator._real1_byref(b),
2733
+ QrackSimulator._real1_byref(e),
2734
+ )
2735
+ self._throw_if_error()
2736
+ return result
2737
+
2738
+ def matrix_expectation_eigenval(self, q, b, e):
2739
+ """Single-qubit operator tensor product expectation value
2740
+
2741
+ Get the single-qubit (3-parameter) operator
2742
+ expectation value for the array of qubits and bases.
2743
+
2744
+ Args:
2745
+ q: qubits, from low to high
2746
+ b: single-qubit (2x2) operator unitary bases (flat over wires)
2747
+
2748
+ Raises:
2749
+ RuntimeError: QrackSimulator raised an exception.
2750
+
2751
+ Returns:
2752
+ Expectation value
2753
+ """
2754
+ if (len(q) << 2) != len(b):
2755
+ raise RuntimeError(
2756
+ "matrix_expectation_eigenval qubit and basis argument lengths do not match."
2757
+ )
2758
+ if (len(q) << 1) != len(e):
2759
+ raise RuntimeError(
2760
+ "matrix_expectation_eigenval qubit and eigenvalue argument lengths do not match."
2761
+ )
2762
+ result = Qrack.qrack_lib.MatrixExpectationEigenVal(
2763
+ self.sid,
2764
+ len(q),
2765
+ QrackSimulator._ulonglong_byref(q),
2766
+ QrackSimulator._complex_byref(b),
2767
+ QrackSimulator._real1_byref(e),
2768
+ )
2769
+ self._throw_if_error()
2770
+ return result
2771
+
2772
+ def pauli_expectation(self, q, b):
2773
+ """Pauli tensor product expectation value
2774
+
2775
+ Get the Pauli tensor product expectation value,
2776
+ where each entry in "b" is a Pauli observable for
2777
+ corresponding "q", as the product for each in "q".
2778
+
2779
+ Args:
2780
+ q: qubits, from low to high
2781
+ b: qubit Pauli bases
2782
+
2783
+ Raises:
2784
+ RuntimeError: QrackSimulator raised an exception.
2785
+
2786
+ Returns:
2787
+ Expectation value
2788
+ """
2789
+ if len(q) != len(b):
2790
+ raise RuntimeError("pauli_expectation argument lengths do not match.")
2791
+ result = Qrack.qrack_lib.PauliExpectation(
2792
+ self.sid, len(q), QrackSimulator._ulonglong_byref(q), QrackSimulator._ulonglong_byref(b)
2793
+ )
2794
+ self._throw_if_error()
2795
+ return result
2796
+
2797
+ def variance(self, q):
2798
+ """Variance of probabilities of all subset permutations
2799
+
2800
+ Get the overall variance of probabilities of all
2801
+ permutations of the subset.
2802
+
2803
+ Args:
2804
+ q: list of qubit ids
2805
+
2806
+ Raises:
2807
+ RuntimeError: QrackSimulator raised an exception.
2808
+
2809
+ Returns:
2810
+ float variance
2811
+ """
2812
+ result = Qrack.qrack_lib.Variance(self.sid, len(q), QrackSimulator._ulonglong_byref(q))
2813
+ self._throw_if_error()
2814
+ return result
2815
+
2816
+ def variance_rdm(self, q, r=True):
2817
+ """Permutation variance, (tracing out the reduced
2818
+ density matrix without stabilizer ancillary qubits)
2819
+
2820
+ Get the permutation variance, based upon the order of
2821
+ input qubits.
2822
+
2823
+ Args:
2824
+ q: qubits, from low to high
2825
+ r: round Rz gates down from T^(1/2)
2826
+
2827
+ Raises:
2828
+ RuntimeError: QrackSimulator raised an exception.
2829
+
2830
+ Returns:
2831
+ variance
2832
+ """
2833
+ result = Qrack.qrack_lib.VarianceRdm(
2834
+ self.sid, len(q), QrackSimulator._ulonglong_byref(q), r
2835
+ )
2836
+ self._throw_if_error()
2837
+ return result
2838
+
2839
+ def factorized_variance(self, q, c):
2840
+ """Factorized variance
2841
+
2842
+ Get the factorized variance, where each entry
2843
+ in "c" is an variance for corresponding "q"
2844
+ being false, then true, repeated for each in "q".
2845
+
2846
+ Args:
2847
+ q: qubits, from low to high
2848
+ c: qubit falsey/truthy values, from low to high
2849
+
2850
+ Raises:
2851
+ RuntimeError: QrackSimulator raised an exception.
2852
+
2853
+ Returns:
2854
+ variance
2855
+ """
2856
+ if (len(q) << 1) != len(c):
2857
+ raise RuntimeError("factorized_variance argument lengths do not match.")
2858
+ m = max([(x.bit_length() + 63) // 64 for x in c])
2859
+ result = Qrack.qrack_lib.FactorizedVariance(
2860
+ self.sid,
2861
+ len(q),
2862
+ QrackSimulator._ulonglong_byref(q),
2863
+ m,
2864
+ QrackSimulator._to_ulonglong(m, c),
2865
+ )
2866
+ self._throw_if_error()
2867
+ return result
2868
+
2869
+ def factorized_variance_rdm(self, q, c, r=True):
2870
+ """Factorized variance, (tracing out the reduced
2871
+ density matrix without stabilizer ancillary qubits)
2872
+
2873
+ Get the factorized variance, where each entry
2874
+ in "c" is an variance for corresponding "q"
2875
+ being false, then true, repeated for each in "q".
2876
+
2877
+ Args:
2878
+ q: qubits, from low to high
2879
+ c: qubit falsey/truthy values, from low to high
2880
+ r: round Rz gates down from T^(1/2)
2881
+
2882
+ Raises:
2883
+ RuntimeError: QrackSimulator raised an exception.
2884
+
2885
+ Returns:
2886
+ variance
2887
+ """
2888
+ if (len(q) << 1) != len(c):
2889
+ raise RuntimeError("factorized_variance_rdm argument lengths do not match.")
2890
+ m = max([(x.bit_length() + 63) // 64 for x in c])
2891
+ result = Qrack.qrack_lib.FactorizedVarianceRdm(
2892
+ self.sid,
2893
+ len(q),
2894
+ QrackSimulator._ulonglong_byref(q),
2895
+ m,
2896
+ QrackSimulator._to_ulonglong(m, c),
2897
+ r,
2898
+ )
2899
+ self._throw_if_error()
2900
+ return result
2901
+
2902
+ def factorized_variance_fp(self, q, c):
2903
+ """Factorized variance (floating-point)
2904
+
2905
+ Get the factorized variance, where each entry
2906
+ in "c" is an variance for corresponding "q"
2907
+ being false, then true, repeated for each in "q".
2908
+
2909
+ Args:
2910
+ q: qubits, from low to high
2911
+ c: qubit falsey/truthy values, from low to high
2912
+
2913
+ Raises:
2914
+ RuntimeError: QrackSimulator raised an exception.
2915
+
2916
+ Returns:
2917
+ variance
2918
+ """
2919
+ if (len(q) << 1) != len(c):
2920
+ raise RuntimeError("factorized_variance_rdm argument lengths do not match.")
2921
+ result = Qrack.qrack_lib.FactorizedVarianceFp(
2922
+ self.sid, len(q), QrackSimulator._ulonglong_byref(q), QrackSimulator._real1_byref(c)
2923
+ )
2924
+ self._throw_if_error()
2925
+ return result
2926
+
2927
+ def factorized_variance_fp_rdm(self, q, c, r=True):
2928
+ """Factorized variance, (tracing out the reduced
2929
+ density matrix without stabilizer ancillary qubits)
2930
+
2931
+ Get the factorized variance, where each entry
2932
+ in "c" is an variance for corresponding "q"
2933
+ being false, then true, repeated for each in "q".
2934
+
2935
+ Args:
2936
+ q: qubits, from low to high
2937
+ c: qubit falsey/truthy values, from low to high
2938
+ r: round Rz gates down from T^(1/2)
2939
+
2940
+ Raises:
2941
+ RuntimeError: QrackSimulator raised an exception.
2942
+
2943
+ Returns:
2944
+ variance
2945
+ """
2946
+ if (len(q) << 1) != len(c):
2947
+ raise RuntimeError("factorized_variance_fp_rdm argument lengths do not match.")
2948
+ result = Qrack.qrack_lib.FactorizedVarianceFpRdm(
2949
+ self.sid, len(q), QrackSimulator._ulonglong_byref(q), QrackSimulator._real1_byref(c), r
2950
+ )
2951
+ self._throw_if_error()
2952
+ return result
2953
+
2954
+ def unitary_variance(self, q, b):
2955
+ """3-parameter unitary tensor product variance
2956
+
2957
+ Get the single-qubit (3-parameter) operator
2958
+ variance for the array of qubits and bases.
2959
+
2960
+ Args:
2961
+ q: qubits, from low to high
2962
+ b: 3-parameter, single-qubit, unitary bases (flat over wires)
2963
+
2964
+ Raises:
2965
+ RuntimeError: QrackSimulator raised an exception.
2966
+
2967
+ Returns:
2968
+ variance
2969
+ """
2970
+ if (3 * len(q)) != len(b):
2971
+ raise RuntimeError("unitary_variance argument lengths do not match.")
2972
+ result = Qrack.qrack_lib.UnitaryVariance(
2973
+ self.sid, len(q), QrackSimulator._ulonglong_byref(q), QrackSimulator._real1_byref(b)
2974
+ )
2975
+ self._throw_if_error()
2976
+ return result
2977
+
2978
+ def matrix_variance(self, q, b):
2979
+ """Single-qubit operator tensor product variance
2980
+
2981
+ Get the single-qubit (3-parameter) operator
2982
+ variance for the array of qubits and bases.
2983
+
2984
+ Args:
2985
+ q: qubits, from low to high
2986
+ b: single-qubit (2x2) operator unitary bases (flat over wires)
2987
+
2988
+ Raises:
2989
+ RuntimeError: QrackSimulator raised an exception.
2990
+
2991
+ Returns:
2992
+ variance
2993
+ """
2994
+ if (len(q) << 2) != len(b):
2995
+ raise RuntimeError("matrix_variance argument lengths do not match.")
2996
+ result = Qrack.qrack_lib.MatrixVariance(
2997
+ self.sid, len(q), QrackSimulator._ulonglong_byref(q), QrackSimulator._complex_byref(b)
2998
+ )
2999
+ self._throw_if_error()
3000
+ return result
3001
+
3002
+ def unitary_variance_eigenval(self, q, b, e):
3003
+ """3-parameter unitary tensor product variance
3004
+
3005
+ Get the single-qubit (3-parameter) operator
3006
+ variance for the array of qubits and bases.
3007
+
3008
+ Args:
3009
+ q: qubits, from low to high
3010
+ b: 3-parameter, single-qubit, unitary bases (flat over wires)
3011
+
3012
+ Raises:
3013
+ RuntimeError: QrackSimulator raised an exception.
3014
+
3015
+ Returns:
3016
+ variance
3017
+ """
3018
+ if (3 * len(q)) != len(b):
3019
+ raise RuntimeError(
3020
+ "unitary_variance_eigenval qubit and basis argument lengths do not match."
3021
+ )
3022
+ if (len(q) << 1) != len(e):
3023
+ raise RuntimeError(
3024
+ "unitary_variance_eigenval qubit and eigenvalue argument lengths do not match."
3025
+ )
3026
+ result = Qrack.qrack_lib.UnitaryVarianceEigenVal(
3027
+ self.sid,
3028
+ len(q),
3029
+ QrackSimulator._ulonglong_byref(q),
3030
+ QrackSimulator._real1_byref(b),
3031
+ QrackSimulator._real1_byref(e),
3032
+ )
3033
+ self._throw_if_error()
3034
+ return result
3035
+
3036
+ def matrix_variance_eigenval(self, q, b, e):
3037
+ """Single-qubit operator tensor product variance
3038
+
3039
+ Get the single-qubit (3-parameter) operator
3040
+ variance for the array of qubits and bases.
3041
+
3042
+ Args:
3043
+ q: qubits, from low to high
3044
+ b: single-qubit (2x2) operator unitary bases (flat over wires)
3045
+
3046
+ Raises:
3047
+ RuntimeError: QrackSimulator raised an exception.
3048
+
3049
+ Returns:
3050
+ variance
3051
+ """
3052
+ if (len(q) << 2) != len(b):
3053
+ raise RuntimeError(
3054
+ "matrix_variance_eigenval qubit and basis argument lengths do not match."
3055
+ )
3056
+ if (len(q) << 1) != len(e):
3057
+ raise RuntimeError(
3058
+ "matrix_variance_eigenval qubit and eigenvalue argument lengths do not match."
3059
+ )
3060
+ result = Qrack.qrack_lib.MatrixVarianceEigenVal(
3061
+ self.sid,
3062
+ len(q),
3063
+ QrackSimulator._ulonglong_byref(q),
3064
+ QrackSimulator._complex_byref(b),
3065
+ QrackSimulator._real1_byref(e),
3066
+ )
3067
+ self._throw_if_error()
3068
+ return result
3069
+
3070
+ def pauli_variance(self, q, b):
3071
+ """Pauli tensor product variance
3072
+
3073
+ Get the Pauli tensor product variance,
3074
+ where each entry in "b" is a Pauli observable for
3075
+ corresponding "q", as the product for each in "q".
3076
+
3077
+ Args:
3078
+ q: qubits, from low to high
3079
+ b: qubit Pauli bases
3080
+
3081
+ Raises:
3082
+ RuntimeError: QrackSimulator raised an exception.
3083
+
3084
+ Returns:
3085
+ variance
3086
+ """
3087
+ if len(q) != len(b):
3088
+ raise RuntimeError("pauli_variance argument lengths do not match.")
3089
+ result = Qrack.qrack_lib.PauliVariance(
3090
+ self.sid, len(q), QrackSimulator._ulonglong_byref(q), QrackSimulator._ulonglong_byref(b)
3091
+ )
3092
+ self._throw_if_error()
3093
+ return result
3094
+
3095
+ def joint_ensemble_probability(self, b, q):
3096
+ """Ensemble probability
3097
+
3098
+ Find the joint probability for all specified qubits under the
3099
+ respective Pauli basis transformations.
3100
+
3101
+ Args:
3102
+ b: pauli basis
3103
+ q: specified qubits
3104
+
3105
+ Raises:
3106
+ RuntimeError: QrackSimulator raised an exception.
3107
+
3108
+ Returns:
3109
+ Variance
3110
+ """
3111
+ if len(b) != len(q):
3112
+ raise RuntimeError("Lengths of list parameters are mismatched.")
3113
+ result = Qrack.qrack_lib.JointEnsembleProbability(
3114
+ self.sid, len(b), QrackSimulator._ulonglong_byref(b), q
3115
+ )
3116
+ self._throw_if_error()
3117
+ return result
3118
+
3119
+ def phase_parity(self, la, q):
3120
+ """Phase to odd parity
3121
+
3122
+ Applies `e^(i*la)` phase factor to all combinations of bits with
3123
+ odd parity, based upon permutations of qubits.
3124
+
3125
+ Args:
3126
+ la: phase
3127
+ q: specified qubits
3128
+
3129
+ Raises:
3130
+ RuntimeError: QrackSimulator raised an exception.
3131
+ RuntimeError: QrackSimulator with isTensorNetwork=True option cannot phase_parity()! (Turn off just this option, in the constructor.)
3132
+ """
3133
+ if self.is_tensor_network:
3134
+ raise RuntimeError(
3135
+ "QrackSimulator with isTensorNetwork=True option cannot phase_parity()! (Turn off just this option, in the constructor.)"
3136
+ )
3137
+ if self.is_pure_stabilizer:
3138
+ raise RuntimeError(
3139
+ "QrackStabilizer cannot phase_parity()! (Create a QrackSimulator instead, also with isTensorNetwork=False.)"
3140
+ )
3141
+
3142
+ Qrack.qrack_lib.PhaseParity(
3143
+ self.sid, ctypes.c_double(la), len(q), QrackSimulator._ulonglong_byref(q)
3144
+ )
3145
+ self._throw_if_error()
3146
+
3147
+ def phase_root_n(self, n, q):
3148
+ """Phase to root n
3149
+
3150
+ Applies `-2 * math.pi / (2**N)` phase rotation to each qubit.
3151
+
3152
+ Args:
3153
+ n: Phase root
3154
+ q: specified qubits
3155
+
3156
+ Raises:
3157
+ RuntimeError: QrackSimulator raised an exception.
3158
+ RuntimeError: QrackSimulator with isTensorNetwork=True option cannot phase_root_n()! (Turn off just this option, in the constructor.)
3159
+ """
3160
+ if self.is_tensor_network:
3161
+ raise RuntimeError(
3162
+ "QrackSimulator with isTensorNetwork=True option cannot phase_root_n()! (Turn off just this option, in the constructor.)"
3163
+ )
3164
+ if self.is_pure_stabilizer:
3165
+ raise RuntimeError(
3166
+ "QrackStabilizer cannot phase_root_n()! (Create a QrackSimulator instead, also with isTensorNetwork=False.)"
3167
+ )
3168
+
3169
+ Qrack.qrack_lib.PhaseRootN(self.sid, n, len(q), QrackSimulator._ulonglong_byref(q))
3170
+ self._throw_if_error()
3171
+
3172
+ def try_separate_1qb(self, qi1):
3173
+ """Manual seperation
3174
+
3175
+ Exposes manual control for schmidt decomposition which attempts to
3176
+ decompose the qubit with possible performance improvement
3177
+
3178
+ Args:
3179
+ qi1: qubit to be decomposed
3180
+
3181
+ Raises:
3182
+ RuntimeError: QrackSimulator raised an exception.
3183
+
3184
+ Returns:
3185
+ State of the qubit.
3186
+ """
3187
+ result = Qrack.qrack_lib.TrySeparate1Qb(self.sid, qi1)
3188
+ self._throw_if_error()
3189
+ return result
3190
+
3191
+ def try_separate_2qb(self, qi1, qi2):
3192
+ """Manual two-qubits seperation
3193
+
3194
+ two-qubits counterpart of `try_separate_1qb`.
3195
+
3196
+ Args:
3197
+ qi1: first qubit to be decomposed
3198
+ qi2: second qubit to be decomposed
3199
+
3200
+ Raises:
3201
+ Runtimeerror: QrackSimulator raised an exception.
3202
+
3203
+ Returns:
3204
+ State of both the qubits.
3205
+ """
3206
+ result = Qrack.qrack_lib.TrySeparate2Qb(self.sid, qi1, qi2)
3207
+ self._throw_if_error()
3208
+ return result
3209
+
3210
+ def try_separate_tolerance(self, qs, t):
3211
+ """Manual multi-qubits seperation
3212
+
3213
+ Multi-qubits counterpart of `try_separate_1qb`.
3214
+
3215
+ Args:
3216
+ qs: list of qubits to be decomposed
3217
+ t: allowed tolerance
3218
+
3219
+ Raises:
3220
+ Runtimeerror: QrackSimulator raised an exception.
3221
+
3222
+ Returns:
3223
+ State of all the qubits.
3224
+ """
3225
+ result = Qrack.qrack_lib.TrySeparateTol(
3226
+ self.sid, len(qs), QrackSimulator._ulonglong_byref(qs), t
3227
+ )
3228
+ self._throw_if_error()
3229
+ return result
3230
+
3231
+ def separate(self, qs):
3232
+ """Force manual multi-qubits seperation
3233
+
3234
+ Force separation as per `try_separate_tolerance`.
3235
+
3236
+ Args:
3237
+ qs: list of qubits to be decomposed
3238
+
3239
+ Raises:
3240
+ Runtimeerror: QrackSimulator raised an exception.
3241
+ """
3242
+ result = Qrack.qrack_lib.Separate(self.sid, len(qs), QrackSimulator._ulonglong_byref(qs))
3243
+ self._throw_if_error()
3244
+
3245
+ def get_unitary_fidelity(self):
3246
+ """Get fidelity estimate
3247
+
3248
+ When using "Schmidt decomposition rounding parameter" ("SDRP")
3249
+ approximate simulation, QrackSimulator() can make an excellent
3250
+ estimate of its overall fidelity at any time, tested against a
3251
+ nearest-neighbor variant of quantum volume circuits.
3252
+
3253
+ Resetting the fidelity calculation to 1.0 happens automatically
3254
+ when calling `mall` are can be done manually with
3255
+ `reset_unitary_fidelity()`.
3256
+
3257
+ Raises:
3258
+ RuntimeError: QrackSimulator raised an exception.
3259
+
3260
+ Returns:
3261
+ Fidelity estimate
3262
+ """
3263
+ result = Qrack.qrack_lib.GetUnitaryFidelity(self.sid)
3264
+ self._throw_if_error()
3265
+ return result
3266
+
3267
+ def reset_unitary_fidelity(self):
3268
+ """Reset fidelity estimate
3269
+
3270
+ When using "Schmidt decomposition rounding parameter" ("SDRP")
3271
+ approximate simulation, QrackSimulator() can make an excellent
3272
+ estimate of its overall fidelity at any time, tested against a
3273
+ nearest-neighbor variant of quantum volume circuits.
3274
+
3275
+ Resetting the fidelity calculation to 1.0 happens automatically
3276
+ when calling `m_all` or can be done manually with
3277
+ `reset_unitary_fidelity()`.
3278
+
3279
+ Raises:
3280
+ RuntimeError: QrackSimulator raised an exception.
3281
+ """
3282
+ Qrack.qrack_lib.ResetUnitaryFidelity(self.sid)
3283
+ self._throw_if_error()
3284
+
3285
+ def set_sdrp(self, sdrp):
3286
+ """Set "Schmidt decomposition rounding parameter"
3287
+
3288
+ When using "Schmidt decomposition rounding parameter" ("SDRP")
3289
+ approximate simulation, QrackSimulator() can make an excellent
3290
+ estimate of its overall fidelity at any time, tested against a
3291
+ nearest-neighbor variant of quantum volume circuits.
3292
+
3293
+ Resetting the fidelity calculation to 1.0 happens automatically
3294
+ when calling `m_all` or can be done manually with
3295
+ `reset_unitary_fidelity()`.
3296
+
3297
+ Raises:
3298
+ RuntimeError: QrackSimulator raised an exception.
3299
+ """
3300
+ Qrack.qrack_lib.SetSdrp(self.sid, sdrp)
3301
+ self._throw_if_error()
3302
+
3303
+ def set_ncrp(self, ncrp):
3304
+ """Set "Near-Clifford rounding parameter"
3305
+
3306
+ When using "near-Clifford rounding parameter" ("NCRP")
3307
+ approximate simulation, QrackSimulator() can make an excellent
3308
+ estimate of its overall fidelity after measurement, tested against
3309
+ a nearest-neighbor variant of quantum volume circuits.
3310
+
3311
+ Resetting the fidelity calculation to 1.0 happens automatically
3312
+ when calling `m_all` or can be done manually with
3313
+ `reset_unitary_fidelity()`.
3314
+
3315
+ Raises:
3316
+ RuntimeError: QrackSimulator raised an exception.
3317
+ """
3318
+ Qrack.qrack_lib.SetNcrp(self.sid, ncrp)
3319
+ self._throw_if_error()
3320
+
3321
+ def set_reactive_separate(self, irs):
3322
+ """Set reactive separation option
3323
+
3324
+ If reactive separation is available, then this method turns it off/on.
3325
+ Note that reactive separation is on by default.
3326
+
3327
+ Args:
3328
+ irs: is aggresively separable
3329
+
3330
+ Raises:
3331
+ RuntimeError: QrackSimulator raised an exception.
3332
+ """
3333
+ Qrack.qrack_lib.SetReactiveSeparate(self.sid, irs)
3334
+ self._throw_if_error()
3335
+
3336
+ def set_t_injection(self, iti):
3337
+ """Set t-injection option
3338
+
3339
+ If t-injection is available, then this method turns it off/on.
3340
+ Note that t-injection is on by default.
3341
+
3342
+ Args:
3343
+ iti: use "reverse t-injection gadget"
3344
+
3345
+ Raises:
3346
+ RuntimeError: QrackSimulator raised an exception.
3347
+ """
3348
+ Qrack.qrack_lib.SetTInjection(self.sid, iti)
3349
+ self._throw_if_error()
3350
+
3351
+ def set_noise_parameter(self, np):
3352
+ """Set noise parameter option
3353
+
3354
+ If noisy simulation is on, then this set the depolarization
3355
+ parameter per qubit per gate. (Default is 0.01.)
3356
+
3357
+ Args:
3358
+ np: depolarizing noise parameter
3359
+
3360
+ Raises:
3361
+ RuntimeError: QrackSimulator raised an exception.
3362
+ """
3363
+ Qrack.qrack_lib.SetNoiseParameter(self.sid, np)
3364
+ self._throw_if_error()
3365
+
3366
+ def set_ace_max_qb(self, qb):
3367
+ """Set "automatic circuit elision" (ACE) max qubits
3368
+
3369
+ If isSchmidtDecompose=True, maximum entangled subsytem size
3370
+ of this simulator will be capped to 'qb', and entangling
3371
+ gates that would exceed that size are replaced with gate
3372
+ shadows.
3373
+
3374
+ Args:
3375
+ qb: maximum subsystem qubits
3376
+
3377
+ Raises:
3378
+ RuntimeError: QrackSimulator raised an exception.
3379
+ """
3380
+ Qrack.qrack_lib.SetAceMaxQb(self.sid, qb)
3381
+ self._throw_if_error()
3382
+
3383
+ def set_sparse_ace_max_mb(self, mb):
3384
+ """Set sparse "automatic circuit elision" (ACE) max memory
3385
+
3386
+ If isSchmidtDecompose=True, isSparse=True, and
3387
+ isOpenCL=False, maximum subsytem size memory MB of this
3388
+ simulator will be capped to 'mb', and entangling gates
3389
+ that would exceed that size are replaced with gate
3390
+ shadows.
3391
+
3392
+ Args:
3393
+ mb: maximum subsystem memory in MB
3394
+
3395
+ Raises:
3396
+ RuntimeError: QrackSimulator raised an exception.
3397
+ """
3398
+ Qrack.qrack_lib.SetSparseAceMaxMb(self.sid, mb)
3399
+ self._throw_if_error()
3400
+
3401
+ def normalize(self):
3402
+ """Normalize the state
3403
+
3404
+ This should never be necessary to use unless
3405
+ decompose() is "abused." ("Abusing" decompose()
3406
+ might lead to efficient entanglement-breaking
3407
+ channels, though.)
3408
+
3409
+ Raises:
3410
+ RuntimeError: QrackSimulator raised an exception.
3411
+ """
3412
+ Qrack.qrack_lib.Normalize(self.sid)
3413
+ self._throw_if_error()
3414
+
3415
+ def out_to_file(self, filename):
3416
+ """Output state to file (stabilizer only!)
3417
+
3418
+ Outputs the hybrid stabilizer state to file.
3419
+
3420
+ Args:
3421
+ filename: Name of file
3422
+ """
3423
+ Qrack.qrack_lib.qstabilizer_out_to_file(self.sid, filename.encode("utf-8"))
3424
+ self._throw_if_error()
3425
+
3426
+ def in_from_file(
3427
+ filename,
3428
+ is_binary_decision_tree=False,
3429
+ is_paged=True,
3430
+ is_cpu_gpu_hybrid=False,
3431
+ is_opencl=True,
3432
+ is_host_pointer=False,
3433
+ is_noisy=False,
3434
+ ):
3435
+ """Input state from file (stabilizer only!)
3436
+
3437
+ Reads in a hybrid stabilizer state from file.
3438
+
3439
+ Args:
3440
+ filename: Name of file
3441
+ """
3442
+ qb_count = 1
3443
+ with open(filename) as f:
3444
+ qb_count = int(f.readline())
3445
+ out = QrackSimulator(
3446
+ qubitCount=qb_count,
3447
+ isTensorNetwork=False,
3448
+ isSchmidtDecomposeMulti=False,
3449
+ isSchmidtDecompose=False,
3450
+ isStabilizerHybrid=True,
3451
+ isBinaryDecisionTree=is_binary_decision_tree,
3452
+ isPaged=is_paged,
3453
+ isCpuGpuHybrid=is_cpu_gpu_hybrid,
3454
+ isOpenCL=is_opencl,
3455
+ isHostPointer=is_host_pointer,
3456
+ isNoisy=is_noisy,
3457
+ )
3458
+ Qrack.qrack_lib.qstabilizer_in_from_file(out.sid, filename.encode("utf-8"))
3459
+ out._throw_if_error()
3460
+
3461
+ return out
3462
+
3463
+ def file_to_qiskit_circuit(filename, is_hardware_encoded=False):
3464
+ """Convert an output state file to a Qiskit circuit
3465
+
3466
+ Reads in an (optimized) circuit from a file named
3467
+ according to the "filename" parameter and outputs
3468
+ a Qiskit circuit.
3469
+
3470
+ Args:
3471
+ filename: Name of file
3472
+
3473
+ Raises:
3474
+ RuntimeErorr: Before trying to file_to_qiskit_circuit() with
3475
+ QrackCircuit, you must install Qiskit, numpy, and math!
3476
+ """
3477
+ if not (_IS_QISKIT_AVAILABLE and _IS_NUMPY_AVAILABLE):
3478
+ raise RuntimeError(
3479
+ "Before trying to file_to_qiskit_circuit() with QrackCircuit, you must install Qiskit, numpy, and math!"
3480
+ )
3481
+
3482
+ lines = []
3483
+ with open(filename, "r") as file:
3484
+ lines = file.readlines()
3485
+
3486
+ logical_qubits = int(lines[0])
3487
+ stabilizer_qubits = int(lines[1])
3488
+
3489
+ stabilizer_count = int(lines[2])
3490
+
3491
+ clifford_circ = None
3492
+ line_number = 3
3493
+ for i in range(stabilizer_count):
3494
+ shard_map_size = int(lines[line_number])
3495
+ line_number += 1
3496
+
3497
+ shard_map = {}
3498
+ for j in range(shard_map_size):
3499
+ line = lines[line_number].split()
3500
+ line_number += 1
3501
+ shard_map[int(line[0])] = int(line[1])
3502
+
3503
+ line_number += 1
3504
+ tableau = []
3505
+ row_count = shard_map_size << 1
3506
+ for line in lines[line_number : (line_number + row_count)]:
3507
+ bits = line.split()
3508
+ if len(bits) != (row_count + 1):
3509
+ raise QrackException("Invalid Qrack hybrid stabilizer file!")
3510
+ row = []
3511
+ for b in range(row_count):
3512
+ row.append(bool(int(bits[b])))
3513
+ row.append(bool((int(bits[-1]) >> 1) & 1))
3514
+ tableau.append(row)
3515
+ line_number += shard_map_size << 1
3516
+ tableau = np.array(tableau, bool)
3517
+
3518
+ clifford = Clifford(tableau, validate=False, copy=False)
3519
+ clifford_circ = clifford.to_circuit()
3520
+ clifford_circ = QrackSimulator._reorder_qubits(clifford_circ, shard_map)
3521
+
3522
+ non_clifford_gates = []
3523
+ g = 0
3524
+ for line in lines[line_number:]:
3525
+ i = 0
3526
+ tokens = line.split()
3527
+ op = np.zeros((2, 2), dtype=complex)
3528
+ row = []
3529
+ for _ in range(2):
3530
+ amp = tokens[i].replace("(", "").replace(")", "").split(",")
3531
+ row.append(float(amp[0]) + float(amp[1]) * 1j)
3532
+ i = i + 1
3533
+ l = math.sqrt(np.real(row[0] * np.conj(row[0]) + row[1] * np.conj(row[1])))
3534
+ op[0][0] = row[0] / l
3535
+ op[0][1] = row[1] / l
3536
+
3537
+ if np.abs(op[0][0] - row[0]) > 1e-5:
3538
+ print("Warning: gate ", str(g), " might not be unitary!")
3539
+ if np.abs(op[0][1] - row[1]) > 1e-5:
3540
+ print("Warning: gate ", str(g), " might not be unitary!")
3541
+
3542
+ row = []
3543
+ for _ in range(2):
3544
+ amp = tokens[i].replace("(", "").replace(")", "").split(",")
3545
+ row.append(float(amp[0]) + float(amp[1]) * 1j)
3546
+ i = i + 1
3547
+ l = math.sqrt(np.real(row[0] * np.conj(row[0]) + row[1] * np.conj(row[1])))
3548
+ op[1][0] = row[0] / l
3549
+ op[1][1] = row[1] / l
3550
+
3551
+ ph = np.real(np.log(np.linalg.det(op)) / 1j)
3552
+
3553
+ op[1][0] = -np.exp(1j * ph) * np.conj(op[0][1])
3554
+ op[1][1] = np.exp(1j * ph) * np.conj(op[0][0])
3555
+
3556
+ if np.abs(op[1][0] - row[0]) > 1e-5:
3557
+ print("Warning: gate ", str(g), " might not be unitary!")
3558
+ if np.abs(op[1][1] - row[1]) > 1e-5:
3559
+ print("Warning: gate ", str(g), " might not be unitary!")
3560
+
3561
+ non_clifford_gates.append(op)
3562
+ g = g + 1
3563
+
3564
+ basis_gates = [
3565
+ "rz",
3566
+ "h",
3567
+ "x",
3568
+ "y",
3569
+ "z",
3570
+ "sx",
3571
+ "sxdg",
3572
+ "s",
3573
+ "sdg",
3574
+ "t",
3575
+ "tdg",
3576
+ "cx",
3577
+ "cy",
3578
+ "cz",
3579
+ "swap",
3580
+ ]
3581
+ try:
3582
+ circ = transpile(clifford_circ, basis_gates=basis_gates, optimization_level=2)
3583
+ except:
3584
+ circ = clifford_circ
3585
+
3586
+ for i in range(len(non_clifford_gates)):
3587
+ circ.unitary(non_clifford_gates[i], [i])
3588
+
3589
+ if is_hardware_encoded:
3590
+ for i in range(logical_qubits, stabilizer_qubits, 2):
3591
+ circ.h(i + 1)
3592
+ circ.cz(i, i + 1)
3593
+ circ.h(i + 1)
3594
+
3595
+ return circ
3596
+
3597
+ def _reorder_qubits(circuit, mapping):
3598
+ """
3599
+ Reorders qubits in the circuit according to the given mapping using SWAP gates.
3600
+ (Thanks to "Elara," an OpenAI GPT, for this implementation)
3601
+
3602
+ Parameters:
3603
+ - circuit (QuantumCircuit): The circuit to modify.
3604
+ - mapping (dict): Dictionary mapping internal qubit indices to logical qubit indices.
3605
+
3606
+ Returns:
3607
+ - QuantumCircuit: The modified circuit with qubits reordered.
3608
+ """
3609
+ swaps = []
3610
+
3611
+ # Determine swaps to fix the order
3612
+ for logical_index in sorted(mapping):
3613
+ internal_index = mapping[logical_index]
3614
+ if logical_index != internal_index:
3615
+ swaps.append((logical_index, internal_index))
3616
+ # Update the reverse mapping for subsequent swaps
3617
+ mapping[logical_index] = logical_index
3618
+ mapping[internal_index] = internal_index
3619
+
3620
+ # Apply the swaps to the circuit
3621
+ for qubit1, qubit2 in swaps:
3622
+ circuit.swap(qubit1, qubit2)
3623
+
3624
+ return circuit
3625
+
3626
+ def file_to_optimized_qiskit_circuit(filename):
3627
+ """Convert an output state file to a Qiskit circuit
3628
+
3629
+ Reads in a circuit from a file named according to the "filename"
3630
+ parameter and outputs a 'hyper-optimized' Qiskit circuit that
3631
+ favors maximum reduction in gate count and depth at the potential
3632
+ expense of additional non-Clifford gates. (Ancilla qubits are
3633
+ left included in the output, though they probably have no gates.)
3634
+
3635
+ Args:
3636
+ filename: Name of file
3637
+
3638
+ Raises:
3639
+ RuntimeErorr: Before trying to file_to_qiskit_circuit() with
3640
+ QrackCircuit, you must install Qiskit, numpy, and math!
3641
+ """
3642
+ circ = QrackSimulator.file_to_qiskit_circuit(filename)
3643
+
3644
+ width = 0
3645
+ with open(filename, "r", encoding="utf-8") as file:
3646
+ width = int(file.readline())
3647
+
3648
+ sqrt_pi = np.sqrt(1j)
3649
+ sqrt_ni = np.sqrt(-1j)
3650
+ sqrt1_2 = 1 / math.sqrt(2)
3651
+ ident = np.eye(2, dtype=np.complex128)
3652
+ # passable_gates = ["unitary", "rz", "h", "x", "y", "z", "sx", "sxdg", "s", "sdg", "t", "tdg"]
3653
+
3654
+ passed_swaps = []
3655
+ for i in range(0, circ.width()):
3656
+ # We might trace out swap, but we want to maintain the iteration order of qubit channels.
3657
+ non_clifford = np.copy(ident)
3658
+ j = 0
3659
+ while j < len(circ.data):
3660
+ op = circ.data[j].operation
3661
+ qubits = circ.data[j].qubits
3662
+ if len(qubits) > 2:
3663
+ raise RuntimeError(
3664
+ "Something went wrong while optimizing circuit! (Found a gate with 3 or more qubits)"
3665
+ )
3666
+ q1 = circ.find_bit(qubits[0])[0]
3667
+ if (len(qubits) < 2) and (q1 == i):
3668
+ if op.name == "unitary":
3669
+ non_clifford = np.matmul(op.params[0], non_clifford)
3670
+ elif op.name == "rz":
3671
+ lm = float(op.params[0])
3672
+ non_clifford = np.matmul(
3673
+ [[np.exp(-1j * lm / 2), 0], [0, np.exp(1j * lm / 2)]],
3674
+ non_clifford,
3675
+ )
3676
+ elif op.name == "h":
3677
+ non_clifford = np.matmul(
3678
+ np.array([[sqrt1_2, sqrt1_2], [sqrt1_2, -sqrt1_2]], np.complex128),
3679
+ non_clifford,
3680
+ )
3681
+ elif op.name == "x":
3682
+ non_clifford = np.matmul(
3683
+ np.array([[0, 1], [1, 0]], np.complex128), non_clifford
3684
+ )
3685
+ elif op.name == "y":
3686
+ non_clifford = np.matmul(
3687
+ np.array([[0, -1j], [1j, 0]], np.complex128), non_clifford
3688
+ )
3689
+ elif op.name == "z":
3690
+ non_clifford = np.matmul(
3691
+ np.array([[1, 0], [0, -1]], np.complex128), non_clifford
3692
+ )
3693
+ elif op.name == "sx":
3694
+ non_clifford = np.matmul(
3695
+ np.array(
3696
+ [
3697
+ [(1 + 1j) / 2, (1 - 1j) / 2],
3698
+ [(1 - 1j) / 2, (1 + 1j) / 2],
3699
+ ],
3700
+ np.complex128,
3701
+ ),
3702
+ non_clifford,
3703
+ )
3704
+ elif op.name == "sxdg":
3705
+ non_clifford = np.matmul(
3706
+ np.array(
3707
+ [
3708
+ [(1 - 1j) / 2, (1 + 1j) / 2],
3709
+ [(1 + 1j) / 2, (1 - 1j) / 2],
3710
+ ],
3711
+ np.complex128,
3712
+ ),
3713
+ non_clifford,
3714
+ )
3715
+ elif op.name == "sy":
3716
+ non_clifford = np.matmul(
3717
+ np.array(
3718
+ [
3719
+ [(1 + 1j) / 2, -(1 + 1j) / 2],
3720
+ [(1 + 1j) / 2, (1 + 1j) / 2],
3721
+ ],
3722
+ np.complex128,
3723
+ ),
3724
+ non_clifford,
3725
+ )
3726
+ elif op.name == "sydg":
3727
+ non_clifford = np.matmul(
3728
+ np.array(
3729
+ [
3730
+ [(1 - 1j) / 2, (1 - 1j) / 2],
3731
+ [(-1 + 1j) / 2, (1 - 1j) / 2],
3732
+ ],
3733
+ np.complex128,
3734
+ ),
3735
+ non_clifford,
3736
+ )
3737
+ elif op.name == "s":
3738
+ non_clifford = np.matmul(
3739
+ np.array([[1, 0], [0, 1j]], np.complex128), non_clifford
3740
+ )
3741
+ elif op.name == "sdg":
3742
+ non_clifford = np.matmul(
3743
+ np.array([[1, 0], [0, -1j]], np.complex128), non_clifford
3744
+ )
3745
+ elif op.name == "t":
3746
+ non_clifford = np.matmul(
3747
+ np.array([[1, 0], [0, sqrt_pi]], np.complex128),
3748
+ non_clifford,
3749
+ )
3750
+ elif op.name == "tdg":
3751
+ non_clifford = np.matmul(
3752
+ np.array([[1, 0], [0, sqrt_ni]], np.complex128),
3753
+ non_clifford,
3754
+ )
3755
+ else:
3756
+ raise RuntimeError(
3757
+ "Something went wrong while optimizing circuit! (Dropped a single-qubit gate.)"
3758
+ )
3759
+
3760
+ del circ.data[j]
3761
+ continue
3762
+
3763
+ if len(qubits) < 2:
3764
+ j += 1
3765
+ continue
3766
+
3767
+ q2 = circ.find_bit(qubits[1])[0]
3768
+
3769
+ if (i != q1) and (i != q2):
3770
+ j += 1
3771
+ continue
3772
+
3773
+ if op.name == "swap":
3774
+ i = q2 if i == q1 else q1
3775
+
3776
+ if circ.data[j] in passed_swaps:
3777
+ passed_swaps.remove(circ.data[j])
3778
+ del circ.data[j]
3779
+ continue
3780
+
3781
+ passed_swaps.append(circ.data[j])
3782
+
3783
+ j += 1
3784
+ continue
3785
+
3786
+ if (q1 == i) and ((op.name == "cx") or (op.name == "cy") or (op.name == "cz")):
3787
+ if np.isclose(np.abs(non_clifford[0][1]), 0) and np.isclose(
3788
+ np.abs(non_clifford[1][0]), 0
3789
+ ):
3790
+ # If we're not buffering anything but phase, the blocking gate has no effect, and we're safe to continue.
3791
+ del circ.data[j]
3792
+ continue
3793
+
3794
+ if np.isclose(np.abs(non_clifford[0][0]), 0) and np.isclose(
3795
+ np.abs(non_clifford[1][1]), 0
3796
+ ):
3797
+ # If we're buffering full negation (plus phase), the control qubit can be dropped.
3798
+ c = QuantumCircuit(circ.qubits)
3799
+ if op.name == "cx":
3800
+ c.x(qubits[1])
3801
+ elif op.name == "cy":
3802
+ c.y(qubits[1])
3803
+ else:
3804
+ c.z(qubits[1])
3805
+ circ.data[j] = copy.deepcopy(c.data[0])
3806
+
3807
+ j += 1
3808
+ continue
3809
+
3810
+ if np.allclose(non_clifford, ident):
3811
+ # No buffer content to write to circuit definition
3812
+ non_clifford = np.copy(ident)
3813
+ break
3814
+
3815
+ # We're blocked, so we insert our buffer at this place in the circuit definition.
3816
+ c = QuantumCircuit(circ.qubits)
3817
+ c.unitary(non_clifford, qubits[0])
3818
+ circ.data.insert(j, copy.deepcopy(c.data[0]))
3819
+
3820
+ non_clifford = np.copy(ident)
3821
+ break
3822
+
3823
+ if (j == len(circ.data)) and not np.allclose(non_clifford, ident):
3824
+ # We're at the end of the wire, so add the buffer gate.
3825
+ circ.unitary(non_clifford, i)
3826
+
3827
+ passed_swaps.clear()
3828
+ for i in range(width, circ.width()):
3829
+ # We might trace out swap, but we want to maintain the iteration order of qubit channels.
3830
+ non_clifford = np.copy(ident)
3831
+ j = len(circ.data) - 1
3832
+ while j >= 0:
3833
+ op = circ.data[j].operation
3834
+ qubits = circ.data[j].qubits
3835
+ if len(qubits) > 2:
3836
+ raise RuntimeError(
3837
+ "Something went wrong while optimizing circuit! (Found a gate with 3 or more qubits.)"
3838
+ )
3839
+ q1 = circ.find_bit(qubits[0])[0]
3840
+ if (len(qubits) < 2) and (q1 == i):
3841
+ if op.name == "unitary":
3842
+ non_clifford = np.matmul(non_clifford, op.params[0])
3843
+ elif op.name == "rz":
3844
+ lm = float(op.params[0])
3845
+ non_clifford = np.matmul(
3846
+ non_clifford,
3847
+ [[np.exp(-1j * lm / 2), 0], [0, np.exp(1j * lm / 2)]],
3848
+ )
3849
+ elif op.name == "h":
3850
+ non_clifford = np.matmul(
3851
+ non_clifford,
3852
+ np.array([[sqrt1_2, sqrt1_2], [sqrt1_2, -sqrt1_2]], np.complex128),
3853
+ )
3854
+ elif op.name == "x":
3855
+ non_clifford = np.matmul(
3856
+ non_clifford, np.array([[0, 1], [1, 0]], np.complex128)
3857
+ )
3858
+ elif op.name == "y":
3859
+ non_clifford = np.matmul(
3860
+ non_clifford, np.array([[0, -1j], [1j, 0]], np.complex128)
3861
+ )
3862
+ elif op.name == "z":
3863
+ non_clifford = np.matmul(
3864
+ non_clifford, np.array([[1, 0], [0, -1]], np.complex128)
3865
+ )
3866
+ elif op.name == "sx":
3867
+ non_clifford = np.matmul(
3868
+ non_clifford,
3869
+ np.array(
3870
+ [
3871
+ [(1 + 1j) / 2, (1 - 1j) / 2],
3872
+ [(1 - 1j) / 2, (1 + 1j) / 2],
3873
+ ],
3874
+ np.complex128,
3875
+ ),
3876
+ )
3877
+ elif op.name == "sxdg":
3878
+ non_clifford = np.matmul(
3879
+ non_clifford,
3880
+ np.array(
3881
+ [
3882
+ [(1 - 1j) / 2, (1 + 1j) / 2],
3883
+ [(1 + 1j) / 2, (1 - 1j) / 2],
3884
+ ],
3885
+ np.complex128,
3886
+ ),
3887
+ )
3888
+ elif op.name == "sy":
3889
+ non_clifford = np.matmul(
3890
+ non_clifford,
3891
+ np.array(
3892
+ [
3893
+ [(1 + 1j) / 2, -(1 + 1j) / 2],
3894
+ [(1 + 1j) / 2, (1 + 1j) / 2],
3895
+ ],
3896
+ np.complex128,
3897
+ ),
3898
+ )
3899
+ elif op.name == "sydg":
3900
+ non_clifford = np.matmul(
3901
+ non_clifford,
3902
+ np.array(
3903
+ [
3904
+ [(1 - 1j) / 2, (1 - 1j) / 2],
3905
+ [(-1 + 1j) / 2, (1 - 1j) / 2],
3906
+ ],
3907
+ np.complex128,
3908
+ ),
3909
+ )
3910
+ elif op.name == "s":
3911
+ non_clifford = np.matmul(
3912
+ non_clifford, np.array([[1, 0], [0, 1j]], np.complex128)
3913
+ )
3914
+ elif op.name == "sdg":
3915
+ non_clifford = np.matmul(
3916
+ non_clifford, np.array([[1, 0], [0, -1j]], np.complex128)
3917
+ )
3918
+ elif op.name == "t":
3919
+ non_clifford = np.matmul(
3920
+ non_clifford,
3921
+ np.array([[1, 0], [0, sqrt_pi]], np.complex128),
3922
+ )
3923
+ elif op.name == "tdg":
3924
+ non_clifford = np.matmul(
3925
+ non_clifford,
3926
+ np.array([[1, 0], [0, sqrt_ni]], np.complex128),
3927
+ )
3928
+ else:
3929
+ raise RuntimeError(
3930
+ "Something went wrong while optimizing circuit! (Dropped a single-qubit gate.)"
3931
+ )
3932
+
3933
+ del circ.data[j]
3934
+ j -= 1
3935
+ continue
3936
+
3937
+ if len(qubits) < 2:
3938
+ j -= 1
3939
+ continue
3940
+
3941
+ q2 = circ.find_bit(qubits[1])[0]
3942
+
3943
+ if (i != q1) and (i != q2):
3944
+ j -= 1
3945
+ continue
3946
+
3947
+ if (op.name == "swap") and (q1 >= width) and (q2 >= width):
3948
+ i = q2 if i == q1 else q1
3949
+ if circ.data[j] in passed_swaps:
3950
+ passed_swaps.remove(circ.data[j])
3951
+ del circ.data[j]
3952
+ else:
3953
+ passed_swaps.append(circ.data[j])
3954
+
3955
+ j -= 1
3956
+ continue
3957
+
3958
+ if (
3959
+ (q1 == i)
3960
+ and ((op.name == "cx") or (op.name == "cy") or (op.name == "cz"))
3961
+ and (
3962
+ np.isclose(np.abs(non_clifford[0][1]), 0)
3963
+ and np.isclose(np.abs(non_clifford[1][0]), 0)
3964
+ )
3965
+ ):
3966
+ # If we're not buffering anything but phase, this commutes with control, and we're safe to continue.
3967
+ j -= 1
3968
+ continue
3969
+
3970
+ if (q1 == i) and (op.name == "cx"):
3971
+ orig_instr = circ.data[j]
3972
+ del circ.data[j]
3973
+
3974
+ # We're replacing CNOT with CNOT in the opposite direction plus four H gates
3975
+ rep = QuantumCircuit(circ.qubits)
3976
+ rep.h(qubits[0])
3977
+ circ.data.insert(j, copy.deepcopy(rep.data[0]))
3978
+ rep.h(qubits[1])
3979
+ circ.data.insert(j, copy.deepcopy(rep.data[1]))
3980
+ rep.cx(qubits[1], qubits[0])
3981
+ circ.data.insert(j, copy.deepcopy(rep.data[2]))
3982
+ rep.h(qubits[0])
3983
+ circ.data.insert(j, copy.deepcopy(rep.data[3]))
3984
+ rep.h(qubits[1])
3985
+ circ.data.insert(j, copy.deepcopy(rep.data[4]))
3986
+
3987
+ j += 4
3988
+ continue
3989
+
3990
+ if (q1 == i) or (op.name != "cx"):
3991
+ if np.allclose(non_clifford, ident):
3992
+ # No buffer content to write to circuit definition
3993
+ break
3994
+
3995
+ # We're blocked, so we insert our buffer at this place in the circuit definition.
3996
+ c = QuantumCircuit(circ.qubits)
3997
+ c.unitary(non_clifford, qubits[0])
3998
+ circ.data.insert(j + 1, copy.deepcopy(c.data[0]))
3999
+
4000
+ break
4001
+
4002
+ # Re-injection branch (apply gadget to target)
4003
+ to_inject = np.matmul(
4004
+ non_clifford, np.array([[sqrt1_2, sqrt1_2], [sqrt1_2, -sqrt1_2]])
4005
+ )
4006
+ if np.allclose(to_inject, ident):
4007
+ # No buffer content to write to circuit definition
4008
+ del circ.data[j]
4009
+ j -= 1
4010
+ continue
4011
+
4012
+ c = QuantumCircuit(circ.qubits)
4013
+ c.unitary(to_inject, qubits[0])
4014
+ circ.data.insert(j, copy.deepcopy(c.data[0]))
4015
+ j -= 1
4016
+
4017
+ basis_gates = [
4018
+ "u",
4019
+ "rz",
4020
+ "h",
4021
+ "x",
4022
+ "y",
4023
+ "z",
4024
+ "sx",
4025
+ "sxdg",
4026
+ "s",
4027
+ "sdg",
4028
+ "t",
4029
+ "tdg",
4030
+ "cx",
4031
+ "cy",
4032
+ "cz",
4033
+ "swap",
4034
+ ]
4035
+ circ = transpile(circ, basis_gates=basis_gates, optimization_level=2)
4036
+
4037
+ # Eliminate unused ancillae
4038
+ try:
4039
+ qasm = qasm3.dumps(circ)
4040
+ except:
4041
+ qasm = circ.qasm()
4042
+ qasm = qasm.replace("qreg q[" + str(circ.width()) + "];", "qreg q[" + str(width) + "];")
4043
+ highest_index = max([int(x) for x in re.findall(r"\[(.*?)\]", qasm) if x.isdigit()])
4044
+ if highest_index != width:
4045
+ qasm = qasm.replace(
4046
+ "qreg q[" + str(width) + "];", "qreg q[" + str(highest_index) + "];"
4047
+ )
4048
+
4049
+ orig_circ = circ
4050
+ try:
4051
+ circ = QuantumCircuit.from_qasm_str(qasm)
4052
+ except:
4053
+ circ = orig_circ
4054
+
4055
+ return circ
4056
+
4057
+ def _apply_pyzx_op(self, gate):
4058
+ if gate.name == "XPhase":
4059
+ self.r(Pauli.PauliX, math.pi * gate.phase, gate.target)
4060
+ elif gate.name == "ZPhase":
4061
+ self.r(Pauli.PauliZ, math.pi * gate.phase, gate.target)
4062
+ elif gate.name == "Z":
4063
+ self.z(gate.target)
4064
+ elif gate.name == "S":
4065
+ self.s(gate.target)
4066
+ elif gate.name == "T":
4067
+ self.t(gate.target)
4068
+ elif gate.name == "NOT":
4069
+ self.x(gate.target)
4070
+ elif gate.name == "HAD":
4071
+ self.h(gate.target)
4072
+ elif gate.name == "CNOT":
4073
+ self.mcx([gate.control], gate.target)
4074
+ elif gate.name == "CZ":
4075
+ self.mcz([gate.control], gate.target)
4076
+ elif gate.name == "CX":
4077
+ self.h(gate.control)
4078
+ self.mcx([gate.control], gate.target)
4079
+ self.h(gate.control)
4080
+ elif gate.name == "SWAP":
4081
+ self.swap(gate.control, gate.target)
4082
+ elif gate.name == "CRZ":
4083
+ self.mcr(Pauli.PauliZ, math.pi * gate.phase, [gate.control], gate.target)
4084
+ elif gate.name == "CHAD":
4085
+ self.mch([gate.control], gate.target)
4086
+ elif gate.name == "ParityPhase":
4087
+ self.phase_parity(math.pi * gate.phase, gate.targets)
4088
+ elif gate.name == "FSim":
4089
+ self.fsim(gate.theta, gate.phi, gate.control, gate.target)
4090
+ elif gate.name == "CCZ":
4091
+ self.mcz([gate.ctrl1, gate.ctrl2], gate.target)
4092
+ elif gate.name == "Tof":
4093
+ self.mcx([gate.ctrl1, gate.ctrl2], gate.target)
4094
+ self._throw_if_error()
4095
+
4096
+ def run_pyzx_gates(self, gates):
4097
+ """PYZX Gates
4098
+
4099
+ Converts PYZX gates to `QRackSimulator` and immediately executes them.
4100
+
4101
+ Args:
4102
+ gates: list of PYZX gates
4103
+
4104
+ Raises:
4105
+ RuntimeError: QrackSimulator raised an exception.
4106
+ """
4107
+ for gate in gates:
4108
+ self._apply_pyzx_op(gate)
4109
+
4110
+ def _apply_op(self, operation):
4111
+ name = operation.name
4112
+
4113
+ if (name == "id") or (name == "barrier"):
4114
+ # Skip measurement logic
4115
+ return
4116
+
4117
+ conditional = getattr(operation, "conditional", None)
4118
+ if isinstance(conditional, int):
4119
+ conditional_bit_set = (self._classical_register >> conditional) & 1
4120
+ if not conditional_bit_set:
4121
+ return
4122
+ elif conditional is not None:
4123
+ mask = int(conditional.mask, 16)
4124
+ if mask > 0:
4125
+ value = self._classical_memory & mask
4126
+ while (mask & 0x1) == 0:
4127
+ mask >>= 1
4128
+ value >>= 1
4129
+ if value != int(conditional.val, 16):
4130
+ return
4131
+
4132
+ if (name == "u1") or (name == "p"):
4133
+ self._sim.u(operation.qubits[0]._index, 0, 0, float(operation.params[0]))
4134
+ elif name == "u2":
4135
+ self._sim.u(
4136
+ operation.qubits[0]._index,
4137
+ math.pi / 2,
4138
+ float(operation.params[0]),
4139
+ float(operation.params[1]),
4140
+ )
4141
+ elif (name == "u3") or (name == "u"):
4142
+ self._sim.u(
4143
+ operation.qubits[0]._index,
4144
+ float(operation.params[0]),
4145
+ float(operation.params[1]),
4146
+ float(operation.params[2]),
4147
+ )
4148
+ elif (name == "unitary") and (len(operation.qubits) == 1):
4149
+ self._sim.mtrx(operation.params[0].flatten(), operation.qubits[0]._index)
4150
+ elif name == "r":
4151
+ self._sim.u(
4152
+ operation.qubits[0]._index,
4153
+ float(operation.params[0]),
4154
+ float(operation.params[1]) - math.pi / 2,
4155
+ (-1 * float(operation.params[1])) + math.pi / 2,
4156
+ )
4157
+ elif name == "rx":
4158
+ self._sim.r(Pauli.PauliX, float(operation.params[0]), operation.qubits[0]._index)
4159
+ elif name == "ry":
4160
+ self._sim.r(Pauli.PauliY, float(operation.params[0]), operation.qubits[0]._index)
4161
+ elif name == "rz":
4162
+ self._sim.r(Pauli.PauliZ, float(operation.params[0]), operation.qubits[0]._index)
4163
+ elif name == "h":
4164
+ self._sim.h(operation.qubits[0]._index)
4165
+ elif name == "x":
4166
+ self._sim.x(operation.qubits[0]._index)
4167
+ elif name == "y":
4168
+ self._sim.y(operation.qubits[0]._index)
4169
+ elif name == "z":
4170
+ self._sim.z(operation.qubits[0]._index)
4171
+ elif name == "s":
4172
+ self._sim.s(operation.qubits[0]._index)
4173
+ elif name == "sdg":
4174
+ self._sim.adjs(operation.qubits[0]._index)
4175
+ elif name == "sx":
4176
+ self._sim.mtrx(
4177
+ [(1 + 1j) / 2, (1 - 1j) / 2, (1 - 1j) / 2, (1 + 1j) / 2],
4178
+ operation.qubits[0]._index,
4179
+ )
4180
+ elif name == "sxdg":
4181
+ self._sim.mtrx(
4182
+ [(1 - 1j) / 2, (1 + 1j) / 2, (1 + 1j) / 2, (1 - 1j) / 2],
4183
+ operation.qubits[0]._index,
4184
+ )
4185
+ elif name == "t":
4186
+ self._sim.t(operation.qubits[0]._index)
4187
+ elif name == "tdg":
4188
+ self._sim.adjt(operation.qubits[0]._index)
4189
+ elif name == "cu1":
4190
+ self._sim.mcu(
4191
+ [q._index for q in operation.qubits[0:1]],
4192
+ operation.qubits[1]._index,
4193
+ 0,
4194
+ 0,
4195
+ float(operation.params[0]),
4196
+ )
4197
+ elif name == "cu2":
4198
+ self._sim.mcu(
4199
+ [q._index for q in operation.qubits[0:1]],
4200
+ operation.qubits[1]._index,
4201
+ math.pi / 2,
4202
+ float(operation.params[0]),
4203
+ float(operation.params[1]),
4204
+ )
4205
+ elif (name == "cu3") or (name == "cu"):
4206
+ self._sim.mcu(
4207
+ [q._index for q in operation.qubits[0:1]],
4208
+ operation.qubits[1]._index,
4209
+ float(operation.params[0]),
4210
+ float(operation.params[1]),
4211
+ float(operation.params[2]),
4212
+ )
4213
+ elif name == "cx":
4214
+ self._sim.mcx([q._index for q in operation.qubits[0:1]], operation.qubits[1]._index)
4215
+ elif name == "cy":
4216
+ self._sim.mcy([q._index for q in operation.qubits[0:1]], operation.qubits[1]._index)
4217
+ elif name == "cz":
4218
+ self._sim.mcz([q._index for q in operation.qubits[0:1]], operation.qubits[1]._index)
4219
+ elif name == "ch":
4220
+ self._sim.mch([q._index for q in operation.qubits[0:1]], operation.qubits[1]._index)
4221
+ elif name == "cp":
4222
+ self._sim.mcmtrx(
4223
+ [q._index for q in operation.qubits[0:1]],
4224
+ [
4225
+ 1,
4226
+ 0,
4227
+ 0,
4228
+ math.cos(float(operation.params[0]))
4229
+ + 1j * math.sin(float(operation.params[0])),
4230
+ ],
4231
+ operation.qubits[1]._index,
4232
+ )
4233
+ elif name == "csx":
4234
+ self._sim.mcmtrx(
4235
+ [q._index for q in operation.qubits[0:1]],
4236
+ [(1 + 1j) / 2, (1 - 1j) / 2, (1 - 1j) / 2, (1 + 1j) / 2],
4237
+ operation.qubits[1]._index,
4238
+ )
4239
+ elif name == "csxdg":
4240
+ self._sim.mcmtrx(
4241
+ [q._index for q in operation.qubits[0:1]],
4242
+ [(1 - 1j) / 2, (1 + 1j) / 2, (1 + 1j) / 2, (1 - 1j) / 2],
4243
+ operation.qubits[1]._index,
4244
+ )
4245
+ elif name == "dcx":
4246
+ self._sim.mcx([q._index for q in operation.qubits[0:1]], operation.qubits[1]._index)
4247
+ self._sim.mcx(operation.qubits[1:2]._index, operation.qubits[0]._index)
4248
+ elif name == "ccx":
4249
+ self._sim.mcx([q._index for q in operation.qubits[0:2]], operation.qubits[2]._index)
4250
+ elif name == "ccy":
4251
+ self._sim.mcy([q._index for q in operation.qubits[0:2]], operation.qubits[2]._index)
4252
+ elif name == "ccz":
4253
+ self._sim.mcz([q._index for q in operation.qubits[0:2]], operation.qubits[2]._index)
4254
+ elif name == "mcx":
4255
+ self._sim.mcx([q._index for q in operation.qubits[0:-1]], operation.qubits[-1]._index)
4256
+ elif name == "mcy":
4257
+ self._sim.mcy([q._index for q in operation.qubits[0:-1]], operation.qubits[-1]._index)
4258
+ elif name == "mcz":
4259
+ self._sim.mcz([q._index for q in operation.qubits[0:-1]], operation.qubits[-1]._index)
4260
+ elif name == "swap":
4261
+ self._sim.swap(operation.qubits[0]._index, operation.qubits[1]._index)
4262
+ elif name == "iswap":
4263
+ self._sim.iswap(operation.qubits[0]._index, operation.qubits[1]._index)
4264
+ elif name == "iswap_dg":
4265
+ self._sim.adjiswap(operation.qubits[0]._index, operation.qubits[1]._index)
4266
+ elif name == "cswap":
4267
+ self._sim.cswap(
4268
+ [q._index for q in operation.qubits[0:1]],
4269
+ operation.qubits[1]._index,
4270
+ operation.qubits[2]._index,
4271
+ )
4272
+ elif name == "mcswap":
4273
+ self._sim.cswap(
4274
+ [q._index for q in operation.qubits[:-2]],
4275
+ operation.qubits[-2]._index,
4276
+ operation.qubits[-1]._index,
4277
+ )
4278
+ elif name == "reset":
4279
+ qubits = operation.qubits
4280
+ for qubit in qubits:
4281
+ if self._sim.m(qubit._index):
4282
+ self._sim.x(qubit._index)
4283
+ elif name == "measure":
4284
+ qubits = operation.qubits
4285
+ clbits = operation.clbits
4286
+ cregbits = (
4287
+ operation.register
4288
+ if hasattr(operation, "register")
4289
+ else len(operation.qubits) * [-1]
4290
+ )
4291
+
4292
+ self._sample_qubits += qubits
4293
+ self._sample_clbits += clbits
4294
+ self._sample_cregbits += cregbits
4295
+
4296
+ if not self._sample_measure:
4297
+ for index in range(len(qubits)):
4298
+ qubit_outcome = self._sim.m(qubits[index]._index)
4299
+
4300
+ clbit = clbits[index]
4301
+ clmask = 1 << clbit
4302
+ self._classical_memory = (self._classical_memory & (~clmask)) | (
4303
+ qubit_outcome << clbit
4304
+ )
4305
+
4306
+ cregbit = cregbits[index]
4307
+ if cregbit < 0:
4308
+ cregbit = clbit
4309
+
4310
+ regbit = 1 << cregbit
4311
+ self._classical_register = (self._classical_register & (~regbit)) | (
4312
+ qubit_outcome << cregbit
4313
+ )
4314
+
4315
+ elif name == "bfunc":
4316
+ mask = int(operation.mask, 16)
4317
+ relation = operation.relation
4318
+ val = int(operation.val, 16)
4319
+
4320
+ cregbit = operation.register
4321
+ cmembit = operation.memory if hasattr(operation, "memory") else None
4322
+
4323
+ compared = (self._classical_register & mask) - val
4324
+
4325
+ if relation == "==":
4326
+ outcome = compared == 0
4327
+ elif relation == "!=":
4328
+ outcome = compared != 0
4329
+ elif relation == "<":
4330
+ outcome = compared < 0
4331
+ elif relation == "<=":
4332
+ outcome = compared <= 0
4333
+ elif relation == ">":
4334
+ outcome = compared > 0
4335
+ elif relation == ">=":
4336
+ outcome = compared >= 0
4337
+ else:
4338
+ raise QrackError("Invalid boolean function relation.")
4339
+
4340
+ # Store outcome in register and optionally memory slot
4341
+ regbit = 1 << cregbit
4342
+ self._classical_register = (self._classical_register & (~regbit)) | (
4343
+ int(outcome) << cregbit
4344
+ )
4345
+ if cmembit is not None:
4346
+ membit = 1 << cmembit
4347
+ self._classical_memory = (self._classical_memory & (~membit)) | (
4348
+ int(outcome) << cmembit
4349
+ )
4350
+ else:
4351
+ err_msg = 'QrackSimulator encountered unrecognized operation "{0}"'
4352
+ raise RuntimeError(err_msg.format(operation))
4353
+
4354
+ def _add_sample_measure(self, sample_qubits, sample_clbits, num_samples):
4355
+ """Generate data samples from current statevector.
4356
+
4357
+ Taken almost straight from the terra source code.
4358
+
4359
+ Args:
4360
+ measure_params (list): List of (qubit, clbit) values for
4361
+ measure instructions to sample.
4362
+ num_samples (int): The number of data samples to generate.
4363
+
4364
+ Returns:
4365
+ list: A list of data values in hex format.
4366
+ """
4367
+ # Get unique qubits that are actually measured
4368
+ measure_qubit = [qubit for qubit in sample_qubits]
4369
+ measure_clbit = [clbit for clbit in sample_clbits]
4370
+
4371
+ # Sample and convert to bit-strings
4372
+ if num_samples == 1:
4373
+ sample = self._sim.m_all()
4374
+ result = 0
4375
+ for index in range(len(measure_qubit)):
4376
+ qubit = measure_qubit[index]._index
4377
+ qubit_outcome = (sample >> qubit) & 1
4378
+ result |= qubit_outcome << index
4379
+ measure_results = [result]
4380
+ else:
4381
+ measure_results = self._sim.measure_shots(
4382
+ [q._index for q in measure_qubit], num_samples
4383
+ )
4384
+
4385
+ data = []
4386
+ for sample in measure_results:
4387
+ for index in range(len(measure_qubit)):
4388
+ qubit_outcome = (sample >> index) & 1
4389
+ clbit = measure_clbit[index]._index
4390
+ clmask = 1 << clbit
4391
+ self._classical_memory = (self._classical_memory & (~clmask)) | (
4392
+ qubit_outcome << clbit
4393
+ )
4394
+
4395
+ data.append(bin(self._classical_memory)[2:].zfill(self.num_qubits()))
4396
+
4397
+ return data
4398
+
4399
+ def run_qiskit_circuit(self, experiment, shots=1):
4400
+ if not _IS_QISKIT_AVAILABLE:
4401
+ raise RuntimeError(
4402
+ "Before trying to run_qiskit_circuit() with QrackSimulator, you must install Qiskit!"
4403
+ )
4404
+
4405
+ instructions = []
4406
+ if isinstance(experiment, QuantumCircuit):
4407
+ instructions = experiment.data
4408
+ else:
4409
+ raise RuntimeError('Unrecognized "run_input" argument specified for run().')
4410
+
4411
+ self._shots = shots
4412
+ self._sample_qubits = []
4413
+ self._sample_clbits = []
4414
+ self._sample_cregbits = []
4415
+ self._sample_measure = True
4416
+ _data = []
4417
+ shotLoopMax = 1
4418
+
4419
+ is_initializing = True
4420
+ boundary_start = -1
4421
+
4422
+ for opcount in range(len(instructions)):
4423
+ operation = instructions[opcount]
4424
+
4425
+ if operation.name == "id" or operation.name == "barrier":
4426
+ continue
4427
+
4428
+ if is_initializing and ((operation.name == "measure") or (operation.name == "reset")):
4429
+ continue
4430
+
4431
+ is_initializing = False
4432
+
4433
+ if (operation.name == "measure") or (operation.name == "reset"):
4434
+ if boundary_start == -1:
4435
+ boundary_start = opcount
4436
+
4437
+ if (boundary_start != -1) and (operation.name != "measure"):
4438
+ shotsPerLoop = 1
4439
+ shotLoopMax = self._shots
4440
+ self._sample_measure = False
4441
+ break
4442
+
4443
+ preamble_memory = 0
4444
+ preamble_register = 0
4445
+ preamble_sim = None
4446
+
4447
+ if self._sample_measure or boundary_start <= 0:
4448
+ boundary_start = 0
4449
+ self._sample_measure = True
4450
+ shotsPerLoop = self._shots
4451
+ shotLoopMax = 1
4452
+ else:
4453
+ boundary_start -= 1
4454
+ if boundary_start > 0:
4455
+ self._sim = self
4456
+ self._classical_memory = 0
4457
+ self._classical_register = 0
4458
+
4459
+ for operation in instructions[:boundary_start]:
4460
+ self._apply_op(operation)
4461
+
4462
+ preamble_memory = self._classical_memory
4463
+ preamble_register = self._classical_register
4464
+ preamble_sim = self._sim
4465
+
4466
+ for shot in range(shotLoopMax):
4467
+ if preamble_sim is None:
4468
+ self._sim = self
4469
+ self._classical_memory = 0
4470
+ self._classical_register = 0
4471
+ else:
4472
+ self._sim = QrackSimulator(cloneSid=preamble_sim.sid)
4473
+ self._classical_memory = preamble_memory
4474
+ self._classical_register = preamble_register
4475
+
4476
+ for operation in instructions[boundary_start:]:
4477
+ self._apply_op(operation)
4478
+
4479
+ if not self._sample_measure and (len(self._sample_qubits) > 0):
4480
+ _data += [bin(self._classical_memory)[2:].zfill(self.num_qubits())]
4481
+ self._sample_qubits = []
4482
+ self._sample_clbits = []
4483
+ self._sample_cregbits = []
4484
+
4485
+ if self._sample_measure and (len(self._sample_qubits) > 0):
4486
+ _data = self._add_sample_measure(self._sample_qubits, self._sample_clbits, self._shots)
4487
+
4488
+ del self._sim
4489
+
4490
+ return _data
4491
+
4492
+ @staticmethod
4493
+ def get_qiskit_basis_gates():
4494
+ return [
4495
+ "id",
4496
+ "u",
4497
+ "u1",
4498
+ "u2",
4499
+ "u3",
4500
+ "r",
4501
+ "rx",
4502
+ "ry",
4503
+ "rz",
4504
+ "h",
4505
+ "x",
4506
+ "y",
4507
+ "z",
4508
+ "s",
4509
+ "sdg",
4510
+ "sx",
4511
+ "sxdg",
4512
+ "p",
4513
+ "t",
4514
+ "tdg",
4515
+ "cu",
4516
+ "cu1",
4517
+ "cu3",
4518
+ "cx",
4519
+ "cy",
4520
+ "cz",
4521
+ "ch",
4522
+ "cp",
4523
+ "csx",
4524
+ "ccx",
4525
+ "ccz",
4526
+ "swap",
4527
+ "iswap",
4528
+ "cswap",
4529
+ "reset",
4530
+ "measure",
4531
+ ]