tequila-basic 1.9.8__py3-none-any.whl → 1.9.10__py3-none-any.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.
- tequila/__init__.py +29 -14
- tequila/apps/__init__.py +14 -5
- tequila/apps/_unary_state_prep_impl.py +145 -112
- tequila/apps/adapt/__init__.py +9 -1
- tequila/apps/adapt/adapt.py +154 -113
- tequila/apps/krylov/__init__.py +1 -1
- tequila/apps/krylov/krylov.py +23 -21
- tequila/apps/robustness/helpers.py +10 -6
- tequila/apps/robustness/interval.py +238 -156
- tequila/apps/unary_state_prep.py +29 -23
- tequila/autograd_imports.py +8 -5
- tequila/circuit/__init__.py +2 -1
- tequila/circuit/_gates_impl.py +135 -67
- tequila/circuit/circuit.py +177 -88
- tequila/circuit/compiler.py +114 -105
- tequila/circuit/gates.py +288 -120
- tequila/circuit/gradient.py +35 -23
- tequila/circuit/noise.py +83 -74
- tequila/circuit/postselection.py +120 -0
- tequila/circuit/pyzx.py +10 -6
- tequila/circuit/qasm.py +201 -83
- tequila/circuit/qpic.py +63 -61
- tequila/grouping/binary_rep.py +148 -146
- tequila/grouping/binary_utils.py +84 -75
- tequila/grouping/compile_groups.py +334 -230
- tequila/grouping/ev_utils.py +77 -41
- tequila/grouping/fermionic_functions.py +383 -308
- tequila/grouping/fermionic_methods.py +170 -123
- tequila/grouping/overlapping_methods.py +69 -52
- tequila/hamiltonian/paulis.py +12 -13
- tequila/hamiltonian/paulistring.py +1 -1
- tequila/hamiltonian/qubit_hamiltonian.py +45 -35
- tequila/ml/__init__.py +1 -0
- tequila/ml/interface_torch.py +19 -16
- tequila/ml/ml_api.py +11 -10
- tequila/ml/utils_ml.py +12 -11
- tequila/objective/__init__.py +8 -3
- tequila/objective/braket.py +55 -47
- tequila/objective/objective.py +91 -56
- tequila/objective/qtensor.py +36 -27
- tequila/optimizers/__init__.py +31 -23
- tequila/optimizers/_containers.py +11 -7
- tequila/optimizers/optimizer_base.py +111 -83
- tequila/optimizers/optimizer_gd.py +258 -231
- tequila/optimizers/optimizer_gpyopt.py +56 -42
- tequila/optimizers/optimizer_scipy.py +157 -112
- tequila/quantumchemistry/__init__.py +66 -38
- tequila/quantumchemistry/chemistry_tools.py +394 -203
- tequila/quantumchemistry/encodings.py +121 -13
- tequila/quantumchemistry/madness_interface.py +170 -96
- tequila/quantumchemistry/orbital_optimizer.py +86 -40
- tequila/quantumchemistry/psi4_interface.py +166 -97
- tequila/quantumchemistry/pyscf_interface.py +70 -23
- tequila/quantumchemistry/qc_base.py +866 -414
- tequila/simulators/__init__.py +0 -3
- tequila/simulators/simulator_api.py +258 -106
- tequila/simulators/simulator_aqt.py +102 -0
- tequila/simulators/simulator_base.py +156 -55
- tequila/simulators/simulator_cirq.py +58 -42
- tequila/simulators/simulator_cudaq.py +600 -0
- tequila/simulators/simulator_ddsim.py +390 -0
- tequila/simulators/simulator_mqp.py +30 -0
- tequila/simulators/simulator_pyquil.py +190 -171
- tequila/simulators/simulator_qibo.py +95 -87
- tequila/simulators/simulator_qiskit.py +124 -114
- tequila/simulators/simulator_qlm.py +52 -26
- tequila/simulators/simulator_qulacs.py +85 -59
- tequila/simulators/simulator_spex.py +464 -0
- tequila/simulators/simulator_symbolic.py +6 -5
- tequila/simulators/test_spex_simulator.py +208 -0
- tequila/tools/convenience.py +4 -4
- tequila/tools/qng.py +72 -64
- tequila/tools/random_generators.py +38 -34
- tequila/utils/bitstrings.py +13 -7
- tequila/utils/exceptions.py +19 -5
- tequila/utils/joined_transformation.py +8 -10
- tequila/utils/keymap.py +0 -5
- tequila/utils/misc.py +6 -4
- tequila/version.py +1 -1
- tequila/wavefunction/qubit_wavefunction.py +52 -30
- {tequila_basic-1.9.8.dist-info → tequila_basic-1.9.10.dist-info}/METADATA +23 -17
- tequila_basic-1.9.10.dist-info/RECORD +93 -0
- {tequila_basic-1.9.8.dist-info → tequila_basic-1.9.10.dist-info}/WHEEL +1 -1
- tequila_basic-1.9.8.dist-info/RECORD +0 -86
- {tequila_basic-1.9.8.dist-info → tequila_basic-1.9.10.dist-info/licenses}/LICENSE +0 -0
- {tequila_basic-1.9.8.dist-info → tequila_basic-1.9.10.dist-info}/top_level.txt +0 -0
tequila/circuit/gates.py
CHANGED
@@ -1,16 +1,47 @@
|
|
1
1
|
from tequila.circuit.circuit import QCircuit
|
2
2
|
from tequila.objective.objective import Variable, assign_variable
|
3
3
|
from tequila.circuit import _gates_impl as impl
|
4
|
-
import typing
|
4
|
+
import typing
|
5
|
+
import numbers
|
5
6
|
from tequila.hamiltonian import PauliString, QubitHamiltonian, paulis
|
6
7
|
from tequila.tools import list_assignment
|
7
8
|
import numpy as np
|
8
9
|
import copy
|
9
10
|
|
10
11
|
|
11
|
-
def
|
12
|
-
|
13
|
-
|
12
|
+
def GlobalPhase(
|
13
|
+
angle: typing.Union[typing.Hashable, numbers.Number] = None,
|
14
|
+
control: typing.Union[list, int] = None,
|
15
|
+
) -> QCircuit:
|
16
|
+
"""
|
17
|
+
Create a global phase gate: G(φ) = e^{iφ} * I
|
18
|
+
This adds a global phase to the entire quantum state.
|
19
|
+
|
20
|
+
Parameters
|
21
|
+
----------
|
22
|
+
angle: phase value, numeric or symbolic
|
23
|
+
|
24
|
+
Returns
|
25
|
+
-------
|
26
|
+
QCircuit with a GlobalPhaseGate
|
27
|
+
"""
|
28
|
+
if angle is None:
|
29
|
+
angle = 0
|
30
|
+
|
31
|
+
if control is None or not control:
|
32
|
+
gate_impl = impl.GlobalPhaseGateImpl(phase=angle)
|
33
|
+
return QCircuit.wrap_gate(gate_impl)
|
34
|
+
else:
|
35
|
+
return Phase(target=control[0], control=control[1:], angle=angle)
|
36
|
+
|
37
|
+
|
38
|
+
def Phase(
|
39
|
+
target: typing.Union[list, int],
|
40
|
+
control: typing.Union[list, int] = None,
|
41
|
+
angle: typing.Union[typing.Hashable, numbers.Number] = None,
|
42
|
+
*args,
|
43
|
+
**kwargs,
|
44
|
+
) -> QCircuit:
|
14
45
|
"""
|
15
46
|
Notes
|
16
47
|
----------
|
@@ -41,7 +72,9 @@ def Phase(target: typing.Union[list, int],
|
|
41
72
|
else:
|
42
73
|
raise Exception(
|
43
74
|
"tq.gates.Phase initialization: You gave two angles angle={} and phi={}. Please only use angle".format(
|
44
|
-
angle, kwargs["phi"]
|
75
|
+
angle, kwargs["phi"]
|
76
|
+
)
|
77
|
+
)
|
45
78
|
|
46
79
|
if angle is None:
|
47
80
|
angle = np.pi
|
@@ -52,6 +85,22 @@ def Phase(target: typing.Union[list, int],
|
|
52
85
|
return QCircuit.wrap_gate(gates)
|
53
86
|
|
54
87
|
|
88
|
+
def I(
|
89
|
+
target: typing.Union[list, int], control: typing.Union[list, int] = None, power=None, angle=None, *args, **kwargs
|
90
|
+
) -> QCircuit:
|
91
|
+
"""
|
92
|
+
This function provides a primitive implementation of the identity gate as a place
|
93
|
+
holder gate with no physical effect.
|
94
|
+
The user can add this gate into the circuit and get it also when
|
95
|
+
calling functions regarding the circuit's stats (i.e. gates included)
|
96
|
+
"""
|
97
|
+
# zero generator for a no-operation gate
|
98
|
+
generator = lambda q: 0
|
99
|
+
return _initialize_power_gate(
|
100
|
+
name="I", power=power, angle=angle, target=target, control=control, generator=generator, *args, **kwargs
|
101
|
+
)
|
102
|
+
|
103
|
+
|
55
104
|
def S(target: typing.Union[list, int], control: typing.Union[list, int] = None) -> QCircuit:
|
56
105
|
"""
|
57
106
|
Notes
|
@@ -97,6 +146,7 @@ def T(target: typing.Union[list, int], control: typing.Union[list, int] = None):
|
|
97
146
|
"""
|
98
147
|
return Phase(angle=np.pi / 4, target=target, control=control)
|
99
148
|
|
149
|
+
|
100
150
|
def Rx(angle, target: typing.Union[list, int], control: typing.Union[list, int] = None, assume_real=False) -> QCircuit:
|
101
151
|
"""
|
102
152
|
Notes
|
@@ -177,7 +227,9 @@ def Rz(angle, target: typing.Union[list, int], control: typing.Union[list, int]
|
|
177
227
|
return RotationGate(axis=2, angle=angle, target=target, control=control, assume_real=assume_real)
|
178
228
|
|
179
229
|
|
180
|
-
def X(
|
230
|
+
def X(
|
231
|
+
target: typing.Union[list, int], control: typing.Union[list, int] = None, power=None, angle=None, *args, **kwargs
|
232
|
+
) -> QCircuit:
|
181
233
|
"""
|
182
234
|
Notes
|
183
235
|
----------
|
@@ -206,11 +258,14 @@ def X(target: typing.Union[list, int], control: typing.Union[list, int] = None,
|
|
206
258
|
"""
|
207
259
|
|
208
260
|
generator = lambda q: paulis.X(q) - paulis.I(q)
|
209
|
-
return _initialize_power_gate(
|
210
|
-
|
261
|
+
return _initialize_power_gate(
|
262
|
+
name="X", power=power, angle=angle, target=target, control=control, generator=generator, *args, **kwargs
|
263
|
+
)
|
211
264
|
|
212
265
|
|
213
|
-
def H(
|
266
|
+
def H(
|
267
|
+
target: typing.Union[list, int], control: typing.Union[list, int] = None, power=None, angle=None, *args, **kwargs
|
268
|
+
) -> QCircuit:
|
214
269
|
"""
|
215
270
|
Notes
|
216
271
|
----------
|
@@ -240,11 +295,14 @@ def H(target: typing.Union[list, int], control: typing.Union[list, int] = None,
|
|
240
295
|
"""
|
241
296
|
coef = 1 / np.sqrt(2)
|
242
297
|
generator = lambda q: coef * (paulis.Z(q) + paulis.X(q)) - paulis.I(q)
|
243
|
-
return _initialize_power_gate(
|
244
|
-
|
298
|
+
return _initialize_power_gate(
|
299
|
+
name="H", power=power, angle=angle, target=target, control=control, generator=generator, *args, **kwargs
|
300
|
+
)
|
245
301
|
|
246
302
|
|
247
|
-
def Y(
|
303
|
+
def Y(
|
304
|
+
target: typing.Union[list, int], control: typing.Union[list, int] = None, power=None, angle=None, *args, **kwargs
|
305
|
+
) -> QCircuit:
|
248
306
|
"""
|
249
307
|
Notes
|
250
308
|
----------
|
@@ -273,11 +331,14 @@ def Y(target: typing.Union[list, int], control: typing.Union[list, int] = None,
|
|
273
331
|
|
274
332
|
"""
|
275
333
|
generator = lambda q: paulis.Y(q) - paulis.I(q)
|
276
|
-
return _initialize_power_gate(
|
277
|
-
|
334
|
+
return _initialize_power_gate(
|
335
|
+
name="Y", power=power, angle=angle, target=target, control=control, generator=generator
|
336
|
+
)
|
278
337
|
|
279
338
|
|
280
|
-
def Z(
|
339
|
+
def Z(
|
340
|
+
target: typing.Union[list, int], control: typing.Union[list, int] = None, power=None, angle=None, *args, **kwargs
|
341
|
+
) -> QCircuit:
|
281
342
|
"""
|
282
343
|
Notes
|
283
344
|
----------
|
@@ -306,13 +367,16 @@ def Z(target: typing.Union[list, int], control: typing.Union[list, int] = None,
|
|
306
367
|
|
307
368
|
"""
|
308
369
|
generator = lambda q: paulis.Z(q) - paulis.I(q)
|
309
|
-
return _initialize_power_gate(
|
310
|
-
|
370
|
+
return _initialize_power_gate(
|
371
|
+
name="Z", power=power, angle=angle, target=target, control=control, generator=generator, *args, **kwargs
|
372
|
+
)
|
311
373
|
|
312
374
|
|
313
|
-
def ExpPauli(
|
375
|
+
def ExpPauli(
|
376
|
+
paulistring: typing.Union[PauliString, str, dict], angle, control: typing.Union[list, int] = None, *args, **kwargs
|
377
|
+
):
|
314
378
|
"""Exponentiated Pauligate:
|
315
|
-
|
379
|
+
|
316
380
|
ExpPauli(PauliString, angle) = exp(-i* angle/2* PauliString)
|
317
381
|
|
318
382
|
Parameters
|
@@ -327,11 +391,11 @@ def ExpPauli(paulistring: typing.Union[PauliString, str, dict], angle, control:
|
|
327
391
|
control :
|
328
392
|
control qubits
|
329
393
|
paulistring: typing.Union[PauliString :
|
330
|
-
|
394
|
+
|
331
395
|
str] :
|
332
|
-
|
396
|
+
|
333
397
|
control: typing.Union[list :
|
334
|
-
|
398
|
+
|
335
399
|
int] :
|
336
400
|
(Default value = None)
|
337
401
|
|
@@ -349,9 +413,14 @@ def ExpPauli(paulistring: typing.Union[PauliString, str, dict], angle, control:
|
|
349
413
|
if len(ps.items()) == 1:
|
350
414
|
target, axis = tuple(ps.items())[0]
|
351
415
|
return QCircuit.wrap_gate(
|
352
|
-
impl.RotationGateImpl(
|
416
|
+
impl.RotationGateImpl(
|
417
|
+
axis=axis, target=target, angle=ps.coeff * assign_variable(angle), control=control, *args, **kwargs
|
418
|
+
)
|
419
|
+
)
|
353
420
|
else:
|
354
|
-
return QCircuit.wrap_gate(
|
421
|
+
return QCircuit.wrap_gate(
|
422
|
+
impl.ExponentialPauliGateImpl(paulistring=ps, angle=angle, control=control, *args, **kwargs)
|
423
|
+
)
|
355
424
|
|
356
425
|
|
357
426
|
def Rp(paulistring: typing.Union[PauliString, str], angle, control: typing.Union[list, int] = None, *args, **kwargs):
|
@@ -364,16 +433,21 @@ def Rp(paulistring: typing.Union[PauliString, str], angle, control: typing.Union
|
|
364
433
|
def GenRot(*args, **kwargs):
|
365
434
|
return GeneralizedRotation(*args, **kwargs)
|
366
435
|
|
367
|
-
|
368
|
-
|
369
|
-
|
370
|
-
|
371
|
-
|
436
|
+
|
437
|
+
def GeneralizedRotation(
|
438
|
+
angle: typing.Union[typing.List[typing.Hashable], typing.List[numbers.Real]],
|
439
|
+
generator: QubitHamiltonian,
|
440
|
+
control: typing.Union[list, int] = None,
|
441
|
+
eigenvalues_magnitude: float = 0.5,
|
442
|
+
p0=None,
|
443
|
+
steps: int = 1,
|
444
|
+
assume_real=False,
|
445
|
+
) -> QCircuit:
|
372
446
|
"""
|
373
447
|
|
374
448
|
Notes
|
375
449
|
--------
|
376
|
-
|
450
|
+
|
377
451
|
A gates which is shift-rule differentiable
|
378
452
|
- its generator only has two distinguishable eigenvalues
|
379
453
|
- it is then differentiable by the shift rule
|
@@ -385,7 +459,7 @@ def GeneralizedRotation(angle: typing.Union[typing.List[typing.Hashable], typing
|
|
385
459
|
|
386
460
|
.. math::
|
387
461
|
U_{G}(\\text{angle}) = e^{-i\\frac{\\text{angle}}{2} G}
|
388
|
-
|
462
|
+
|
389
463
|
Parameters
|
390
464
|
----------
|
391
465
|
angle
|
@@ -407,18 +481,27 @@ def GeneralizedRotation(angle: typing.Union[typing.List[typing.Hashable], typing
|
|
407
481
|
"""
|
408
482
|
|
409
483
|
return QCircuit.wrap_gate(
|
410
|
-
impl.GeneralizedRotationImpl(
|
411
|
-
|
412
|
-
|
413
|
-
|
414
|
-
|
415
|
-
|
416
|
-
|
417
|
-
|
418
|
-
|
419
|
-
|
420
|
-
|
421
|
-
|
484
|
+
impl.GeneralizedRotationImpl(
|
485
|
+
angle=assign_variable(angle),
|
486
|
+
generator=generator,
|
487
|
+
control=control,
|
488
|
+
eigenvalues_magnitude=eigenvalues_magnitude,
|
489
|
+
steps=steps,
|
490
|
+
assume_real=assume_real,
|
491
|
+
p0=p0,
|
492
|
+
)
|
493
|
+
)
|
494
|
+
|
495
|
+
|
496
|
+
def Trotterized(
|
497
|
+
generator: QubitHamiltonian = None,
|
498
|
+
steps: int = 1,
|
499
|
+
angle: typing.Union[typing.Hashable, numbers.Real, Variable] = None,
|
500
|
+
control: typing.Union[list, int] = None,
|
501
|
+
randomize=False,
|
502
|
+
*args,
|
503
|
+
**kwargs,
|
504
|
+
) -> QCircuit:
|
422
505
|
"""
|
423
506
|
|
424
507
|
Parameters
|
@@ -453,17 +536,19 @@ def Trotterized(generator: QubitHamiltonian = None,
|
|
453
536
|
if generator is None:
|
454
537
|
if len(kwargs["generators"]) > 1:
|
455
538
|
if "angles" not in kwargs:
|
456
|
-
angles = [angle]*len(kwargs["generators"])
|
539
|
+
angles = [angle] * len(kwargs["generators"])
|
457
540
|
else:
|
458
541
|
angles = kwargs["angles"]
|
459
542
|
result = QCircuit()
|
460
|
-
for angle,g in zip(angles,kwargs["generators"]):
|
543
|
+
for angle, g in zip(angles, kwargs["generators"]):
|
461
544
|
result += Trotterized(generator=g, angle=angle, steps=steps, control=control, randomize=randomize)
|
462
545
|
return result
|
463
546
|
else:
|
464
547
|
generator = kwargs["generators"][0]
|
465
548
|
else:
|
466
|
-
raise Exception(
|
549
|
+
raise Exception(
|
550
|
+
"Trotterized: You gave generators={} and generator={}".format(generator, kwargs["generators"])
|
551
|
+
)
|
467
552
|
|
468
553
|
if "angles" in kwargs:
|
469
554
|
if angle is None:
|
@@ -475,11 +560,22 @@ def Trotterized(generator: QubitHamiltonian = None,
|
|
475
560
|
|
476
561
|
angle = assign_variable(angle)
|
477
562
|
|
478
|
-
return QCircuit.wrap_gate(
|
479
|
-
|
480
|
-
|
481
|
-
|
482
|
-
|
563
|
+
return QCircuit.wrap_gate(
|
564
|
+
impl.TrotterizedGateImpl(
|
565
|
+
generator=generator, angle=angle, steps=steps, control=control, randomize=randomize, **kwargs
|
566
|
+
)
|
567
|
+
)
|
568
|
+
|
569
|
+
|
570
|
+
def SWAP(
|
571
|
+
first: int,
|
572
|
+
second: int,
|
573
|
+
angle: float = None,
|
574
|
+
control: typing.Union[int, list] = None,
|
575
|
+
power: float = None,
|
576
|
+
*args,
|
577
|
+
**kwargs,
|
578
|
+
) -> QCircuit:
|
483
579
|
"""
|
484
580
|
Notes
|
485
581
|
----------
|
@@ -509,17 +605,17 @@ def SWAP(first: int, second: int, angle: float = None, control: typing.Union[int
|
|
509
605
|
assert power is None
|
510
606
|
angle = assign_variable(angle)
|
511
607
|
elif power is not None:
|
512
|
-
angle = assign_variable(power)*np.pi
|
608
|
+
angle = assign_variable(power) * np.pi
|
513
609
|
generator = 0.5 * (paulis.X(target) + paulis.Y(target) + paulis.Z(target) - paulis.I(target))
|
514
610
|
if angle is None or power in [1, 1.0]:
|
515
611
|
return QGate(name="SWAP", target=target, control=control, generator=generator)
|
516
612
|
else:
|
517
|
-
return GeneralizedRotation(angle=angle, control=control, generator=generator,
|
518
|
-
|
519
|
-
|
520
|
-
|
521
|
-
|
522
|
-
|
613
|
+
return GeneralizedRotation(angle=angle, control=control, generator=generator, eigenvalues_magnitude=0.25)
|
614
|
+
|
615
|
+
|
616
|
+
def iSWAP(
|
617
|
+
first: int, second: int, control: typing.Union[int, list] = None, power: float = 1.0, *args, **kwargs
|
618
|
+
) -> QCircuit:
|
523
619
|
"""
|
524
620
|
Notes
|
525
621
|
----------
|
@@ -545,17 +641,27 @@ def iSWAP(first: int, second: int, control: typing.Union[int, list] = None, powe
|
|
545
641
|
"""
|
546
642
|
|
547
643
|
generator = paulis.from_string(f"X({first})X({second}) + Y({first})Y({second})")
|
548
|
-
|
644
|
+
|
549
645
|
p0 = paulis.Projector("|00>") + paulis.Projector("|11>")
|
550
|
-
p0 = p0.map_qubits({0:first, 1:second})
|
646
|
+
p0 = p0.map_qubits({0: first, 1: second})
|
647
|
+
|
648
|
+
gate = QubitExcitationImpl(
|
649
|
+
angle=power * (-np.pi / 2),
|
650
|
+
target=generator.qubits,
|
651
|
+
generator=generator,
|
652
|
+
p0=p0,
|
653
|
+
control=control,
|
654
|
+
compile_options="vanilla",
|
655
|
+
*args,
|
656
|
+
**kwargs,
|
657
|
+
)
|
551
658
|
|
552
|
-
gate = QubitExcitationImpl(angle=power*(-np.pi/2), target=generator.qubits, generator=generator, p0=p0, control=control, compile_options="vanilla", *args, **kwargs)
|
553
|
-
|
554
659
|
return QCircuit.wrap_gate(gate)
|
555
|
-
|
556
|
-
|
557
|
-
def Givens(
|
558
|
-
|
660
|
+
|
661
|
+
|
662
|
+
def Givens(
|
663
|
+
first: int, second: int, control: typing.Union[int, list] = None, angle: float = None, *args, **kwargs
|
664
|
+
) -> QCircuit:
|
559
665
|
"""
|
560
666
|
Notes
|
561
667
|
----------
|
@@ -580,7 +686,9 @@ def Givens(first: int, second: int, control: typing.Union[int, list] = None, ang
|
|
580
686
|
|
581
687
|
"""
|
582
688
|
|
583
|
-
return QubitExcitation(
|
689
|
+
return QubitExcitation(
|
690
|
+
target=[second, first], angle=2 * angle, control=control, *args, **kwargs
|
691
|
+
) # twice the angle since theta is not divided by two in the matrix exponential
|
584
692
|
|
585
693
|
|
586
694
|
"""
|
@@ -801,11 +909,13 @@ def U(theta, phi, lambd, target: typing.Union[list, int], control: typing.Union[
|
|
801
909
|
lambd = assign_variable(lambd)
|
802
910
|
pi_half = assign_variable(np.pi / 2)
|
803
911
|
|
804
|
-
return
|
805
|
-
|
806
|
-
|
807
|
-
|
808
|
-
|
912
|
+
return (
|
913
|
+
Rz(angle=lambd, target=target, control=control)
|
914
|
+
+ Rx(angle=pi_half, target=target, control=control)
|
915
|
+
+ Rz(angle=theta, target=target, control=control)
|
916
|
+
+ Rx(angle=-pi_half, target=target, control=control)
|
917
|
+
+ Rz(angle=phi, target=target, control=control)
|
918
|
+
)
|
809
919
|
|
810
920
|
|
811
921
|
def u1(lambd, target: typing.Union[list, int], control: typing.Union[list, int] = None) -> QCircuit:
|
@@ -913,8 +1023,13 @@ def u3(theta, phi, lambd, target: typing.Union[list, int], control: typing.Union
|
|
913
1023
|
return U(theta=theta, phi=phi, lambd=lambd, target=target, control=control)
|
914
1024
|
|
915
1025
|
|
916
|
-
def QubitExcitation(
|
917
|
-
|
1026
|
+
def QubitExcitation(
|
1027
|
+
angle: typing.Union[numbers.Real, Variable, typing.Hashable],
|
1028
|
+
target: typing.List,
|
1029
|
+
control=None,
|
1030
|
+
assume_real: bool = False,
|
1031
|
+
compile_options="optimize",
|
1032
|
+
):
|
918
1033
|
"""
|
919
1034
|
A Qubit Excitation, as described under "qubit perspective" in https://doi.org/10.1039/D0SC06627C
|
920
1035
|
For the Fermionic operators under corresponding Qubit encodings: Use the chemistry interface
|
@@ -937,18 +1052,31 @@ def QubitExcitation(angle: typing.Union[numbers.Real, Variable, typing.Hashable]
|
|
937
1052
|
"""
|
938
1053
|
try:
|
939
1054
|
assert len(target) % 2 == 0
|
940
|
-
except:
|
1055
|
+
except Exception:
|
941
1056
|
raise Exception("QubitExcitation: Needs an even number of targets")
|
942
1057
|
|
943
|
-
return QCircuit.wrap_gate(
|
1058
|
+
return QCircuit.wrap_gate(
|
1059
|
+
QubitExcitationImpl(
|
1060
|
+
angle=angle, target=target, assume_real=assume_real, compile_options=compile_options, control=control
|
1061
|
+
)
|
1062
|
+
)
|
944
1063
|
|
945
1064
|
|
946
1065
|
"""
|
947
1066
|
Helper Functions
|
948
1067
|
"""
|
949
1068
|
|
950
|
-
|
951
|
-
|
1069
|
+
|
1070
|
+
def _initialize_power_gate(
|
1071
|
+
name: str,
|
1072
|
+
target: typing.Union[list, int],
|
1073
|
+
generator,
|
1074
|
+
control: typing.Union[list, int] = None,
|
1075
|
+
power=None,
|
1076
|
+
angle=None,
|
1077
|
+
*args,
|
1078
|
+
**kwargs,
|
1079
|
+
) -> QCircuit:
|
952
1080
|
target = list_assignment(target)
|
953
1081
|
|
954
1082
|
# allow angle instead of power in initialization for more consistency
|
@@ -963,13 +1091,23 @@ def _initialize_power_gate(name: str, target: typing.Union[list, int], generator
|
|
963
1091
|
if power is None or power in [1, 1.0]:
|
964
1092
|
gates = [impl.QGateImpl(name=name, target=q, control=control, generator=generator(q)) for q in target]
|
965
1093
|
else:
|
966
|
-
gates = [
|
967
|
-
|
1094
|
+
gates = [
|
1095
|
+
impl.PowerGateImpl(
|
1096
|
+
name=name, power=power, target=q, control=control, generator=generator(q), *args, **kwargs
|
1097
|
+
)
|
1098
|
+
for q in target
|
1099
|
+
]
|
968
1100
|
|
969
1101
|
return QCircuit.wrap_gate(gates)
|
970
1102
|
|
971
1103
|
|
972
|
-
def RotationGate(
|
1104
|
+
def RotationGate(
|
1105
|
+
axis: int,
|
1106
|
+
angle: typing.Union[typing.Hashable, numbers.Number],
|
1107
|
+
target: typing.Union[list, int],
|
1108
|
+
control: typing.Union[list, int] = None,
|
1109
|
+
assume_real=False,
|
1110
|
+
):
|
973
1111
|
"""
|
974
1112
|
Notes
|
975
1113
|
----------
|
@@ -997,12 +1135,23 @@ def RotationGate(axis: int, angle: typing.Union[typing.Hashable, numbers.Number]
|
|
997
1135
|
QCircuit object with this RotationGate
|
998
1136
|
"""
|
999
1137
|
target = list_assignment(target)
|
1000
|
-
gates = [
|
1138
|
+
gates = [
|
1139
|
+
impl.RotationGateImpl(axis=axis, angle=angle, target=q, control=control, assume_real=assume_real)
|
1140
|
+
for q in target
|
1141
|
+
]
|
1001
1142
|
|
1002
1143
|
return QCircuit.wrap_gate(gates)
|
1003
1144
|
|
1004
1145
|
|
1005
|
-
def PowerGate(
|
1146
|
+
def PowerGate(
|
1147
|
+
name: str,
|
1148
|
+
target: typing.Union[list, int],
|
1149
|
+
power: float = None,
|
1150
|
+
control: typing.Union[list, int] = None,
|
1151
|
+
generator: QubitHamiltonian = None,
|
1152
|
+
*args,
|
1153
|
+
**kwargs,
|
1154
|
+
):
|
1006
1155
|
"""
|
1007
1156
|
Initialize a (potentially parametrized) gate which is supported on the backend
|
1008
1157
|
|
@@ -1027,13 +1176,16 @@ def PowerGate(name: str, target: typing.Union[list, int], power: float = None, c
|
|
1027
1176
|
|
1028
1177
|
"""
|
1029
1178
|
return QCircuit.wrap_gate(
|
1030
|
-
impl.PowerGateImpl(name=name, power=power, target=target, control=control, generator=generator, *args, **kwargs)
|
1179
|
+
impl.PowerGateImpl(name=name, power=power, target=target, control=control, generator=generator, *args, **kwargs)
|
1180
|
+
)
|
1031
1181
|
|
1032
1182
|
|
1033
|
-
def QGate(
|
1034
|
-
|
1183
|
+
def QGate(
|
1184
|
+
name, target: typing.Union[list, int], control: typing.Union[list, int] = None, generator: QubitHamiltonian = None
|
1185
|
+
):
|
1035
1186
|
return QCircuit.wrap_gate(impl.QGateImpl(name=name, target=target, control=control, generator=generator))
|
1036
1187
|
|
1188
|
+
|
1037
1189
|
"""
|
1038
1190
|
Implementation of specific gates
|
1039
1191
|
Not put into _gates_impl.py for convenience
|
@@ -1042,8 +1194,8 @@ and should all implement a compile function that
|
|
1042
1194
|
returns a QCircuit of primitive tq gates
|
1043
1195
|
"""
|
1044
1196
|
|
1045
|
-
class QubitExcitationImpl(impl.GeneralizedRotationImpl):
|
1046
1197
|
|
1198
|
+
class QubitExcitationImpl(impl.GeneralizedRotationImpl):
|
1047
1199
|
def __init__(self, angle, target, generator=None, p0=None, assume_real=True, control=None, compile_options=None):
|
1048
1200
|
angle = assign_variable(angle)
|
1049
1201
|
|
@@ -1063,9 +1215,18 @@ class QubitExcitationImpl(impl.GeneralizedRotationImpl):
|
|
1063
1215
|
else:
|
1064
1216
|
assert generator is not None
|
1065
1217
|
assert p0 is not None
|
1066
|
-
|
1067
|
-
super().__init__(
|
1068
|
-
|
1218
|
+
|
1219
|
+
super().__init__(
|
1220
|
+
name="QubitExcitation",
|
1221
|
+
angle=angle,
|
1222
|
+
generator=generator,
|
1223
|
+
target=target,
|
1224
|
+
p0=p0,
|
1225
|
+
control=control,
|
1226
|
+
assume_real=assume_real,
|
1227
|
+
steps=1,
|
1228
|
+
)
|
1229
|
+
|
1069
1230
|
if compile_options is None:
|
1070
1231
|
self.compile_options = "optimize"
|
1071
1232
|
elif hasattr(compile_options, "lower"):
|
@@ -1079,40 +1240,44 @@ class QubitExcitationImpl(impl.GeneralizedRotationImpl):
|
|
1079
1240
|
return mapped
|
1080
1241
|
|
1081
1242
|
def compile(self, exponential_pauli=False, *args, **kwargs):
|
1082
|
-
# optimized compiling for
|
1243
|
+
# optimized compiling for n-qubit excitaitons following arxiv:2005.14475
|
1083
1244
|
# Alternative representation in arxiv:2104.05695 (not implemented -> could be added and controlled with optional compile keywords)
|
1084
1245
|
if self.is_controlled():
|
1085
1246
|
control = list(self.control)
|
1086
1247
|
else:
|
1087
1248
|
control = []
|
1088
|
-
if self.compile_options == "optimize" and
|
1089
|
-
|
1090
|
-
|
1091
|
-
|
1092
|
-
|
1093
|
-
|
1094
|
-
|
1095
|
-
|
1096
|
-
U0 += X(target=
|
1097
|
-
|
1098
|
-
|
1099
|
-
|
1100
|
-
U1 = Ry(
|
1249
|
+
if self.compile_options == "optimize" and exponential_pauli:
|
1250
|
+
q1 = self.target[::2]
|
1251
|
+
q2 = self.target[1::2]
|
1252
|
+
n = len(self.target) // 2
|
1253
|
+
U0 = QCircuit()
|
1254
|
+
for i in range(1, n):
|
1255
|
+
U0 += X(target=q1[i], control=q1[0])
|
1256
|
+
U0 += X(target=q2[i], control=q2[0])
|
1257
|
+
U0 += X(target=q2[0], control=q1[0])
|
1258
|
+
for i in range(1, n):
|
1259
|
+
U0 += X(target=q1[i])
|
1260
|
+
U0 += X(target=q2[i])
|
1261
|
+
U1 = Ry(
|
1262
|
+
angle=-self.parameter,
|
1263
|
+
target=q1[0],
|
1264
|
+
control=list(self.target[1:]) + control,
|
1265
|
+
)
|
1101
1266
|
return U0 + U1 + U0.dagger()
|
1102
1267
|
else:
|
1103
1268
|
return Trotterized(angle=self.parameter, generator=self.generator, steps=1, control=self.control)
|
1104
1269
|
|
1105
1270
|
|
1106
1271
|
def _convert_Paulistring(paulistring: typing.Union[PauliString, str, dict]) -> PauliString:
|
1107
|
-
|
1108
|
-
Function that given a paulistring as PauliString structure or
|
1109
|
-
as string or dict or list, returns the corresponding PauliString
|
1272
|
+
"""
|
1273
|
+
Function that given a paulistring as PauliString structure or
|
1274
|
+
as string or dict or list, returns the corresponding PauliString
|
1110
1275
|
structure.
|
1111
1276
|
|
1112
1277
|
|
1113
1278
|
Parameters
|
1114
1279
|
----------
|
1115
|
-
paulistring : typing.Union[PauliString , str, dict]
|
1280
|
+
paulistring : typing.Union[PauliString , str, dict]
|
1116
1281
|
given as PauliString structure or as string or dict or list
|
1117
1282
|
if given as string: Format should be like X(0)Y(3)Z(2)
|
1118
1283
|
if given as list: Format should be like [(0,'X'),(3,'Y'),(2,'Z')]
|
@@ -1121,8 +1286,8 @@ def _convert_Paulistring(paulistring: typing.Union[PauliString, str, dict]) -> P
|
|
1121
1286
|
Returns
|
1122
1287
|
-------
|
1123
1288
|
ps : PauliString
|
1124
|
-
|
1125
|
-
|
1289
|
+
"""
|
1290
|
+
|
1126
1291
|
if isinstance(paulistring, str):
|
1127
1292
|
ps = PauliString.from_string(string=paulistring)
|
1128
1293
|
elif isinstance(paulistring, list):
|
@@ -1131,22 +1296,25 @@ def _convert_Paulistring(paulistring: typing.Union[PauliString, str, dict]) -> P
|
|
1131
1296
|
ps = PauliString(data=paulistring)
|
1132
1297
|
else:
|
1133
1298
|
ps = paulistring
|
1134
|
-
|
1299
|
+
|
1135
1300
|
return ps
|
1136
1301
|
|
1137
|
-
|
1138
|
-
|
1139
|
-
|
1302
|
+
|
1303
|
+
def PauliGate(
|
1304
|
+
paulistring: typing.Union[PauliString, str, dict], control: typing.Union[list, int] = None, *args, **kwargs
|
1305
|
+
) -> QCircuit:
|
1306
|
+
"""
|
1307
|
+
Functions that converts a Pauli string into the corresponding quantum
|
1140
1308
|
circuit.
|
1141
|
-
|
1309
|
+
|
1142
1310
|
Parameters
|
1143
1311
|
----------
|
1144
|
-
paulistring : typing.Union[PauliString , str, dict]
|
1312
|
+
paulistring : typing.Union[PauliString , str, dict]
|
1145
1313
|
given as PauliString structure or as string or dict or list
|
1146
1314
|
if given as string: Format should be like X(0)Y(3)Z(2)
|
1147
1315
|
if given as list: Format should be like [(0,'X'),(3,'Y'),(2,'Z')]
|
1148
1316
|
if given as dict: Format should be like { 0:'X', 3:'Y', 2:'Z' }
|
1149
|
-
|
1317
|
+
|
1150
1318
|
control: typing.Union[list, int] : (Default value = None)
|
1151
1319
|
control qubits
|
1152
1320
|
|
@@ -1158,13 +1326,13 @@ def PauliGate(paulistring: typing.Union[PauliString, str, dict], control: typing
|
|
1158
1326
|
-------
|
1159
1327
|
U : QCircuit object corresponding to the Pauli string.
|
1160
1328
|
|
1161
|
-
|
1162
|
-
|
1329
|
+
"""
|
1330
|
+
|
1163
1331
|
ps = _convert_Paulistring(paulistring)
|
1164
1332
|
|
1165
1333
|
U = QCircuit()
|
1166
1334
|
|
1167
|
-
for k,v in ps.items():
|
1335
|
+
for k, v in ps.items():
|
1168
1336
|
if v.lower() == "x":
|
1169
1337
|
U += X(target=k, control=control, *args, **kwargs)
|
1170
1338
|
elif v.lower() == "y":
|