tequila-basic 1.9.9__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.
Files changed (86) hide show
  1. tequila/__init__.py +29 -14
  2. tequila/apps/__init__.py +14 -5
  3. tequila/apps/_unary_state_prep_impl.py +145 -112
  4. tequila/apps/adapt/__init__.py +9 -1
  5. tequila/apps/adapt/adapt.py +154 -113
  6. tequila/apps/krylov/__init__.py +1 -1
  7. tequila/apps/krylov/krylov.py +23 -21
  8. tequila/apps/robustness/helpers.py +10 -6
  9. tequila/apps/robustness/interval.py +238 -156
  10. tequila/apps/unary_state_prep.py +29 -23
  11. tequila/autograd_imports.py +8 -5
  12. tequila/circuit/__init__.py +2 -1
  13. tequila/circuit/_gates_impl.py +135 -67
  14. tequila/circuit/circuit.py +163 -79
  15. tequila/circuit/compiler.py +114 -105
  16. tequila/circuit/gates.py +288 -120
  17. tequila/circuit/gradient.py +35 -23
  18. tequila/circuit/noise.py +83 -74
  19. tequila/circuit/postselection.py +120 -0
  20. tequila/circuit/pyzx.py +10 -6
  21. tequila/circuit/qasm.py +201 -83
  22. tequila/circuit/qpic.py +63 -61
  23. tequila/grouping/binary_rep.py +148 -146
  24. tequila/grouping/binary_utils.py +84 -75
  25. tequila/grouping/compile_groups.py +334 -230
  26. tequila/grouping/ev_utils.py +77 -41
  27. tequila/grouping/fermionic_functions.py +383 -308
  28. tequila/grouping/fermionic_methods.py +170 -123
  29. tequila/grouping/overlapping_methods.py +69 -52
  30. tequila/hamiltonian/paulis.py +12 -13
  31. tequila/hamiltonian/paulistring.py +1 -1
  32. tequila/hamiltonian/qubit_hamiltonian.py +45 -35
  33. tequila/ml/__init__.py +1 -0
  34. tequila/ml/interface_torch.py +19 -16
  35. tequila/ml/ml_api.py +11 -10
  36. tequila/ml/utils_ml.py +12 -11
  37. tequila/objective/__init__.py +8 -3
  38. tequila/objective/braket.py +55 -47
  39. tequila/objective/objective.py +87 -55
  40. tequila/objective/qtensor.py +36 -27
  41. tequila/optimizers/__init__.py +31 -23
  42. tequila/optimizers/_containers.py +11 -7
  43. tequila/optimizers/optimizer_base.py +111 -83
  44. tequila/optimizers/optimizer_gd.py +258 -231
  45. tequila/optimizers/optimizer_gpyopt.py +56 -42
  46. tequila/optimizers/optimizer_scipy.py +157 -112
  47. tequila/quantumchemistry/__init__.py +66 -38
  48. tequila/quantumchemistry/chemistry_tools.py +393 -209
  49. tequila/quantumchemistry/encodings.py +121 -13
  50. tequila/quantumchemistry/madness_interface.py +170 -96
  51. tequila/quantumchemistry/orbital_optimizer.py +86 -41
  52. tequila/quantumchemistry/psi4_interface.py +166 -97
  53. tequila/quantumchemistry/pyscf_interface.py +70 -23
  54. tequila/quantumchemistry/qc_base.py +866 -414
  55. tequila/simulators/__init__.py +0 -3
  56. tequila/simulators/simulator_api.py +247 -105
  57. tequila/simulators/simulator_aqt.py +102 -0
  58. tequila/simulators/simulator_base.py +147 -53
  59. tequila/simulators/simulator_cirq.py +58 -42
  60. tequila/simulators/simulator_cudaq.py +600 -0
  61. tequila/simulators/simulator_ddsim.py +390 -0
  62. tequila/simulators/simulator_mqp.py +30 -0
  63. tequila/simulators/simulator_pyquil.py +190 -171
  64. tequila/simulators/simulator_qibo.py +95 -87
  65. tequila/simulators/simulator_qiskit.py +119 -107
  66. tequila/simulators/simulator_qlm.py +52 -26
  67. tequila/simulators/simulator_qulacs.py +74 -52
  68. tequila/simulators/simulator_spex.py +95 -60
  69. tequila/simulators/simulator_symbolic.py +6 -5
  70. tequila/simulators/test_spex_simulator.py +8 -11
  71. tequila/tools/convenience.py +4 -4
  72. tequila/tools/qng.py +72 -64
  73. tequila/tools/random_generators.py +38 -34
  74. tequila/utils/bitstrings.py +7 -7
  75. tequila/utils/exceptions.py +19 -5
  76. tequila/utils/joined_transformation.py +8 -10
  77. tequila/utils/keymap.py +0 -5
  78. tequila/utils/misc.py +6 -4
  79. tequila/version.py +1 -1
  80. tequila/wavefunction/qubit_wavefunction.py +47 -28
  81. {tequila_basic-1.9.9.dist-info → tequila_basic-1.9.10.dist-info}/METADATA +13 -16
  82. tequila_basic-1.9.10.dist-info/RECORD +93 -0
  83. {tequila_basic-1.9.9.dist-info → tequila_basic-1.9.10.dist-info}/WHEEL +1 -1
  84. tequila_basic-1.9.9.dist-info/RECORD +0 -88
  85. {tequila_basic-1.9.9.dist-info → tequila_basic-1.9.10.dist-info}/licenses/LICENSE +0 -0
  86. {tequila_basic-1.9.9.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, numbers
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 Phase(target: typing.Union[list, int],
12
- control: typing.Union[list, int] = None, angle: typing.Union[typing.Hashable, numbers.Number] = None, *args,
13
- **kwargs) -> QCircuit:
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(target: typing.Union[list, int], control: typing.Union[list, int] = None, power=None, angle=None, *args, **kwargs) -> QCircuit:
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(name="X", power=power, angle=angle, target=target, control=control,
210
- generator=generator, *args, **kwargs)
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(target: typing.Union[list, int], control: typing.Union[list, int] = None, power=None, angle=None, *args, **kwargs) -> QCircuit:
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(name="H", power=power, angle=angle, target=target, control=control,
244
- generator=generator, *args, **kwargs)
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(target: typing.Union[list, int], control: typing.Union[list, int] = None, power=None, angle=None, *args, **kwargs) -> QCircuit:
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(name="Y", power=power, angle=angle, target=target, control=control,
277
- generator=generator)
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(target: typing.Union[list, int], control: typing.Union[list, int] = None, power=None, angle=None, *args, **kwargs) -> QCircuit:
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(name="Z", power=power, angle=angle, target=target, control=control,
310
- generator=generator, *args, **kwargs)
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(paulistring: typing.Union[PauliString, str, dict], angle, control: typing.Union[list, int] = None, *args, **kwargs):
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(axis=axis, target=target, angle=ps.coeff * assign_variable(angle), control=control, *args, **kwargs))
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(impl.ExponentialPauliGateImpl(paulistring=ps, angle=angle, control=control, *args, **kwargs))
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
- def GeneralizedRotation(angle: typing.Union[typing.List[typing.Hashable], typing.List[numbers.Real]],
368
- generator: QubitHamiltonian,
369
- control: typing.Union[list, int] = None,
370
- eigenvalues_magnitude: float = 0.5, p0=None,
371
- steps: int = 1, assume_real=False) -> QCircuit:
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(angle=assign_variable(angle), generator=generator, control=control,
411
- eigenvalues_magnitude=eigenvalues_magnitude, steps=steps, assume_real=assume_real, p0=p0))
412
-
413
-
414
-
415
-
416
- def Trotterized(generator: QubitHamiltonian = None,
417
- steps: int = 1,
418
- angle: typing.Union[typing.Hashable, numbers.Real, Variable] = None,
419
- control: typing.Union[list, int] = None,
420
- randomize=False,
421
- *args, **kwargs) -> QCircuit:
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("Trotterized: You gave generators={} and generator={}".format(generator, kwargs["generators"]))
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(impl.TrotterizedGateImpl(generator=generator, angle=angle, steps=steps, control=control, randomize=randomize, **kwargs))
479
-
480
-
481
- def SWAP(first: int, second: int, angle: float = None, control: typing.Union[int, list] = None, power: float = None, *args,
482
- **kwargs) -> QCircuit:
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
- eigenvalues_magnitude=0.25)
519
-
520
-
521
- def iSWAP(first: int, second: int, control: typing.Union[int, list] = None, power: float = 1.0, *args,
522
- **kwargs) -> QCircuit:
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(first: int, second: int, control: typing.Union[int, list] = None, angle: float = None, *args,
558
- **kwargs) -> QCircuit:
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(target=[second,first], angle=2*angle, control=control, *args, **kwargs) # twice the angle since theta is not divided by two in the matrix exponential
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 Rz(angle=lambd, target=target, control=control) + \
805
- Rx(angle=pi_half, target=target, control=control) + \
806
- Rz(angle=theta, target=target, control=control) + \
807
- Rx(angle=-pi_half, target=target, control=control) + \
808
- Rz(angle=phi, target=target, control=control)
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(angle: typing.Union[numbers.Real, Variable, typing.Hashable], target: typing.List, control=None,
917
- assume_real: bool = False, compile_options="optimize"):
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(QubitExcitationImpl(angle=angle, target=target, assume_real=assume_real, compile_options=compile_options, control=control))
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
- def _initialize_power_gate(name: str, target: typing.Union[list, int], generator,
951
- control: typing.Union[list, int] = None, power=None, angle=None, *args, **kwargs) -> QCircuit:
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 = [impl.PowerGateImpl(name=name, power=power, target=q, control=control, generator=generator(q), *args, **kwargs) for q in
967
- target]
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(axis: int, angle: typing.Union[typing.Hashable, numbers.Number], target: typing.Union[list, int], control: typing.Union[list, int] = None, assume_real=False):
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 = [impl.RotationGateImpl(axis=axis, angle=angle, target=q, control=control, assume_real=assume_real) for q in target]
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(name: str, target: typing.Union[list, int], power: float = None, control: typing.Union[list, int] = None, generator: QubitHamiltonian = None, *args, **kwargs):
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(name, target: typing.Union[list, int], control: typing.Union[list, int] = None,
1034
- generator: QubitHamiltonian = None):
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__(name="QubitExcitation", angle=angle, generator=generator, target=target, p0=p0, control=control, assume_real=assume_real, steps=1)
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 single and double qubit excitaitons following arxiv:2005.14475
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 len(self.target) == 2 and exponential_pauli:
1089
- p,q = self.target
1090
- U0 = X(target=p, control=q)
1091
- U1 = Ry(angle=self.parameter, target=q, control=[p]+control)
1092
- return U0 + U1 + U0
1093
- elif self.compile_options == "optimize" and len(self.target) == 4 and exponential_pauli:
1094
- p,r,q,s = self.target
1095
- U0 = X(target=q, control=p)
1096
- U0 += X(target=s, control=r)
1097
- U0 += X(target=r, control=p)
1098
- U0 += X(target=q)
1099
- U0 += X(target=s)
1100
- U1 = Ry(angle=-self.parameter, target=p, control=[q,r,s]+control)
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
- def PauliGate(paulistring: typing.Union[PauliString, str, dict], control: typing.Union[list, int] = None, *args, **kwargs) -> QCircuit:
1138
- '''
1139
- Functions that converts a Pauli string into the corresponding quantum
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":