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
@@ -19,7 +19,7 @@ print("Test: Circuit und Hamiltonian mit Variablen (SPEX vs. Qulacs)")
19
19
  a = tq.Variable("a")
20
20
  b = tq.Variable("b")
21
21
  c = tq.Variable("c")
22
- variables = {"a": np.pi/3, "b": np.pi/4, "c": np.pi/6}
22
+ variables = {"a": np.pi / 3, "b": np.pi / 4, "c": np.pi / 6}
23
23
 
24
24
  # --- Circuitaufbau ---
25
25
  # Erzeuge einen Circuit, der auf 3 Qubits operiert:
@@ -27,9 +27,7 @@ variables = {"a": np.pi/3, "b": np.pi/4, "c": np.pi/6}
27
27
  # - Eine Ry-Rotation auf Qubit 1 (Winkel "b")
28
28
  # - Eine Rz-Rotation auf Qubit 2 (Winkel "c")
29
29
  # - Zusätzlich eine parametrische exponentielle Pauli-Rotation (ExpPauli) auf Qubit 0 und 2 (Pauli-String "X(0)Z(2)")
30
- U = tq.gates.Rx(angle="a", target=(0,)) \
31
- + tq.gates.Ry(angle="b", target=(1,)) \
32
- + tq.gates.Rz(angle="c", target=(2,))
30
+ U = tq.gates.Rx(angle="a", target=(0,)) + tq.gates.Ry(angle="b", target=(1,)) + tq.gates.Rz(angle="c", target=(2,))
33
31
  U += tq.gates.ExpPauli(angle="a", paulistring="X(0)Z(2)")
34
32
 
35
33
  print("\nCircuit U:")
@@ -47,15 +45,15 @@ E = tq.ExpectationValue(U=U, H=H)
47
45
 
48
46
  # --- Simulation mit SPEX ---
49
47
  start = time.time()
50
- wfn_spex = tq.simulate(U, variables, backend='spex')
51
- exp_spex = tq.simulate(E, variables, backend='spex')
48
+ wfn_spex = tq.simulate(U, variables, backend="spex")
49
+ exp_spex = tq.simulate(E, variables, backend="spex")
52
50
  end = time.time()
53
51
  time_spex = end - start
54
52
 
55
53
  # --- Simulation mit Qulacs ---
56
54
  start = time.time()
57
- wfn_qulacs = tq.simulate(U, variables, backend='qulacs')
58
- exp_qulacs = tq.simulate(E, variables, backend='qulacs')
55
+ wfn_qulacs = tq.simulate(U, variables, backend="qulacs")
56
+ exp_qulacs = tq.simulate(E, variables, backend="qulacs")
59
57
  end = time.time()
60
58
  time_qulacs = end - start
61
59
 
@@ -70,11 +68,10 @@ print("\nErwartungswert (SPEX backend):", exp_spex, f"(Simulationszeit: {time_sp
70
68
  print("Erwartungswert (Qulacs backend):", exp_qulacs, f"(Simulationszeit: {time_qulacs:.3f}s)")
71
69
 
72
70
  # Optional: Vergleiche das innere Produkt der beiden Wavefunctions (Quadrat des Betrags)
73
- inner_prod = np.abs(wfn_spex.inner(wfn_qulacs))**2
71
+ inner_prod = np.abs(wfn_spex.inner(wfn_qulacs)) ** 2
74
72
  print("\nInneres Produkt (Quadrat) zwischen SPEX und Qulacs:", inner_prod)
75
73
 
76
74
 
77
-
78
75
  """
79
76
  print("\nTest: 1")
80
77
  U = tq.gates.ExpPauli(paulistring=PauliString({0: "X", 1: "Z"}), angle=np.pi / 2)
@@ -208,4 +205,4 @@ for n in range(1, 15):
208
205
 
209
206
  E_qulacs = None
210
207
 
211
- """
208
+ """
@@ -12,7 +12,7 @@ def list_assignment(o):
12
12
  """
13
13
  if o is None:
14
14
  return []
15
- elif isinstance(o,tuple):
15
+ elif isinstance(o, tuple):
16
16
  return o
17
17
  elif hasattr(o, "__get_item__"):
18
18
  return list(o)
@@ -22,14 +22,14 @@ def list_assignment(o):
22
22
  return [o]
23
23
 
24
24
 
25
- def number_to_string(number: complex, precision: int = 4, threshold: float = 1.e-6) -> str:
25
+ def number_to_string(number: complex, precision: int = 4, threshold: float = 1.0e-6) -> str:
26
26
  if not isinstance(number, numbers.Number):
27
27
  return str(number)
28
28
 
29
29
  number = complex(number)
30
30
  real = number.real
31
31
  imag = number.imag
32
- prec = '{:+.' + str(precision) + 'f}'
32
+ prec = "{:+." + str(precision) + "f}"
33
33
 
34
34
  if isclose(real, 0.0, atol=threshold):
35
35
  return prec.format(imag) + "i"
@@ -37,7 +37,7 @@ def number_to_string(number: complex, precision: int = 4, threshold: float = 1.e
37
37
  return prec.format(real)
38
38
  else:
39
39
  r, theta = polar(number)
40
- return prec.format(r) + ('e^(' + prec).format(theta / pi) + 'πi)'
40
+ return prec.format(r) + ("e^(" + prec).format(theta / pi) + "πi)"
41
41
 
42
42
 
43
43
  if __name__ == "__main__":
tequila/tools/qng.py CHANGED
@@ -5,15 +5,19 @@ from tequila.circuit.circuit import QCircuit
5
5
  from tequila.simulators.simulator_api import compile_objective
6
6
  from tequila.circuit.gradient import __grad_inner
7
7
  from tequila.autograd_imports import jax
8
- from tequila.circuit.compiler import compile_controlled_rotation, compile_power_gate, \
9
- compile_trotterized_gate, compile_controlled_phase, compile_multitarget
8
+ from tequila.circuit.compiler import (
9
+ compile_controlled_rotation,
10
+ compile_power_gate,
11
+ compile_trotterized_gate,
12
+ compile_controlled_phase,
13
+ compile_multitarget,
14
+ )
10
15
  import typing
11
16
  import numpy
12
17
  import copy
13
18
 
14
19
 
15
20
  class QngMatrix:
16
-
17
21
  """
18
22
  A callable class which is meant to be used for calculating the inverse qgt of an expectationvalue.
19
23
 
@@ -40,18 +44,18 @@ class QngMatrix:
40
44
  d = 0
41
45
  for block in self.blocks:
42
46
  d += len(block)
43
- return (d,d)
47
+ return (d, d)
44
48
 
45
- def __init__(self,blocks):
49
+ def __init__(self, blocks):
46
50
  """
47
51
  Parameters
48
52
  ----------
49
53
  blocks: list:
50
54
  list of list of lists. the blocks of the qgt.
51
55
  """
52
- self.blocks= blocks
56
+ self.blocks = blocks
53
57
 
54
- def __call__(self, variables,samples=None) -> numpy.ndarray:
58
+ def __call__(self, variables, samples=None) -> numpy.ndarray:
55
59
  """
56
60
  from the blocks provided, evaluate all qgt terms, then calculate the pseudo-inverse, and return it.
57
61
  Parameters
@@ -71,22 +75,21 @@ class QngMatrix:
71
75
  # displace our running index of position, as we enumerate through a block
72
76
  # d_v does this. If you only provide one block (the whole QGT), this won't matter
73
77
  for block in self.blocks:
74
-
75
- d_v_temp = 0 # how much to increment d_v by when done with the block at hand.
78
+ d_v_temp = 0 # how much to increment d_v by when done with the block at hand.
76
79
  for i, row in enumerate(block):
77
80
  for j, term in enumerate(row):
78
81
  if i <= j:
79
82
  # if its an objective, call it. Else, it is a float.
80
83
  try:
81
- output[i + d_v][j + d_v] = term(variables=variables,samples=samples)
82
- except:
84
+ output[i + d_v][j + d_v] = term(variables=variables, samples=samples)
85
+ except Exception:
83
86
  output[i + d_v][j + d_v] = term
84
87
  else:
85
88
  output[i + d_v][j + d_v] = output[j + d_v][i + d_v]
86
89
  d_v_temp += 1
87
90
  d_v += d_v_temp
88
91
 
89
- back = numpy.linalg.pinv(output) # return the pseudo_inverse of the matrix!
92
+ back = numpy.linalg.pinv(output) # return the pseudo_inverse of the matrix!
90
93
  return back
91
94
 
92
95
 
@@ -104,7 +107,7 @@ class CallableVector:
104
107
  def dim(self):
105
108
  return (len(self._vector),)
106
109
 
107
- def __init__(self,vector):
110
+ def __init__(self, vector):
108
111
  """
109
112
  init.
110
113
  Parameters
@@ -133,7 +136,7 @@ class CallableVector:
133
136
 
134
137
  output = numpy.empty(self.dim)
135
138
  for i, entry in enumerate(self._vector):
136
- if hasattr(entry, '__call__'):
139
+ if hasattr(entry, "__call__"):
137
140
  output[i] = entry(variables, samples=samples)
138
141
  else:
139
142
  output[i] = entry
@@ -155,24 +158,23 @@ def get_generator(gate) -> paulis.QubitHamiltonian:
155
158
 
156
159
  """
157
160
 
158
- if gate.name.lower() == 'rx':
161
+ if gate.name.lower() == "rx":
159
162
  gen = paulis.X(gate.target[0])
160
- elif gate.name.lower() == 'ry':
163
+ elif gate.name.lower() == "ry":
161
164
  gen = paulis.Y(gate.target[0])
162
- elif gate.name.lower() == 'rz':
165
+ elif gate.name.lower() == "rz":
163
166
  gen = paulis.Z(gate.target[0])
164
- elif gate.name.lower() == 'phase':
167
+ elif gate.name.lower() == "phase":
165
168
  gen = paulis.Qm(gate.target[0])
166
169
  else:
167
170
  print(gate.name.lower())
168
- raise TequilaException('cant get the generator of a non Gaussian gate, you fool!')
171
+ raise TequilaException("cant get the generator of a non Gaussian gate, you fool!")
169
172
  return gen
170
173
 
171
174
 
172
- def stokes_block(expectation, initial_values=None, samples=None, device=None,
173
- backend=None,
174
- noise=None) -> typing.List[typing.List[typing.List[typing.Union[float,Objective]]]]:
175
-
175
+ def stokes_block(
176
+ expectation, initial_values=None, samples=None, device=None, backend=None, noise=None
177
+ ) -> typing.List[typing.List[typing.List[typing.Union[float, Objective]]]]:
176
178
  """
177
179
  returns the blocks of the layerwise block-diagonal approximation to the qgt.
178
180
  The default for all qng-based optimizations, as a method for obtaining the qgt.
@@ -207,7 +209,7 @@ def stokes_block(expectation, initial_values=None, samples=None, device=None,
207
209
  # rebuild the sub circuits used in the expectation values that populate the QGT
208
210
  sub = [QCircuit.from_moments(moments[:i]) for i in range(1, len(moments), 2)]
209
211
  # this is the list of just the moments which are parametrized.
210
- parametric_moms = [moments[i] for i in range(1, len(moments)+1, 2)]
212
+ parametric_moms = [moments[i] for i in range(1, len(moments) + 1, 2)]
211
213
  generators = []
212
214
  # generators is a list of lists, ultimately, where each sublist is all the generators in order
213
215
  # for a given parametric layer (if said layer is
@@ -238,13 +240,15 @@ def stokes_block(expectation, initial_values=None, samples=None, device=None,
238
240
  for q, gen2 in enumerate(g_set):
239
241
  ### make sure you compile the objectives! otherwise this bad boy will not run
240
242
  if k == q:
241
- arg = (ExpectationValue(U=sub[i], H=gen1 * gen1) - ExpectationValue(U=sub[i], H=gen1)**2)/4
243
+ arg = (ExpectationValue(U=sub[i], H=gen1 * gen1) - ExpectationValue(U=sub[i], H=gen1) ** 2) / 4
242
244
  else:
243
- arg = (ExpectationValue(U=sub[i], H=gen1 * gen2) - ExpectationValue(U=sub[i], H=gen1) *
244
- ExpectationValue(U=sub[i], H=gen2)) / 4
245
- block[k][q] = compile_objective(arg, variables=initial_values, samples=samples,
246
- backend=backend, device=device,
247
- noise=noise)
245
+ arg = (
246
+ ExpectationValue(U=sub[i], H=gen1 * gen2)
247
+ - ExpectationValue(U=sub[i], H=gen1) * ExpectationValue(U=sub[i], H=gen2)
248
+ ) / 4
249
+ block[k][q] = compile_objective(
250
+ arg, variables=initial_values, samples=samples, backend=backend, device=device, noise=noise
251
+ )
248
252
  blocks.append(block)
249
253
  return blocks
250
254
 
@@ -270,18 +274,18 @@ def qng_circuit_grad(E: ExpectationValueImpl) -> typing.List[Objective]:
270
274
  unitary = E.U
271
275
 
272
276
  # fast return if possible
273
- out=[]
277
+ out = []
274
278
  for i, g in enumerate(unitary.gates):
275
- if g.is_parametrized():
279
+ if g.is_parameterized():
276
280
  if g.is_controlled():
277
281
  raise TequilaException("controlled gate in qng circuit gradient: Compiler was not called")
278
282
  if hasattr(g, "eigenvalues_magnitude"):
279
- if hasattr(g._parameter,'extract_variables'):
283
+ if hasattr(g._parameter, "extract_variables"):
280
284
  shifter = qng_grad_gaussian(unitary, g, i, hamiltonian)
281
285
  out.append(shifter)
282
286
  else:
283
287
  print(g, type(g))
284
- raise TequilaException('No shift found for gate {}'.format(g))
288
+ raise TequilaException("No shift found for gate {}".format(g))
285
289
  if out is None:
286
290
  raise TequilaException("caught a dead circuit in qng gradient")
287
291
  return out
@@ -336,8 +340,9 @@ def qng_grad_gaussian(unitary, g, i, hamiltonian) -> Objective:
336
340
  return dOinc
337
341
 
338
342
 
339
- def subvector_procedure(e_val, initial_values=None, samples=None, device=None,
340
- backend=None, noise=None) -> CallableVector:
343
+ def subvector_procedure(
344
+ e_val, initial_values=None, samples=None, device=None, backend=None, noise=None
345
+ ) -> CallableVector:
341
346
  """
342
347
  take an expectation value and return its (qng style) gradient as a CallableVector.
343
348
 
@@ -364,9 +369,11 @@ def subvector_procedure(e_val, initial_values=None, samples=None, device=None,
364
369
  vect = qng_circuit_grad(e_val)
365
370
  out = []
366
371
  for entry in vect:
367
- out.append(compile_objective(entry, variables=initial_values, samples=samples, device=device,
368
- backend=backend,
369
- noise=noise))
372
+ out.append(
373
+ compile_objective(
374
+ entry, variables=initial_values, samples=samples, device=device, backend=backend, noise=noise
375
+ )
376
+ )
370
377
  return CallableVector(out)
371
378
 
372
379
 
@@ -384,10 +391,10 @@ def get_self_pars(U) -> typing.List:
384
391
  list eg. of Objectives and Variables; the self-parameters of a circuit.
385
392
  """
386
393
 
387
- out=[]
394
+ out = []
388
395
  for g in U.gates:
389
- if g.is_parametrized():
390
- if hasattr(g._parameter,'extract_variables'):
396
+ if g.is_parameterized():
397
+ if hasattr(g._parameter, "extract_variables"):
391
398
  out.append(g._parameter)
392
399
  return out
393
400
 
@@ -416,13 +423,12 @@ def qng_dict(argument, matrix, subvector, mapping, positional) -> typing.Dict:
416
423
  dict containing information used to obtain the qng of some argument of an objective.
417
424
 
418
425
  """
419
- return {'arg': argument, 'matrix': matrix, 'vector': subvector, 'mapping': mapping, 'positional': positional}
420
-
426
+ return {"arg": argument, "matrix": matrix, "vector": subvector, "mapping": mapping, "positional": positional}
421
427
 
422
- def get_qng_combos(objective, func=stokes_block,
423
- initial_values=None, samples=None,
424
- backend=None, device=None, noise=None) -> typing.List[typing.Dict]:
425
428
 
429
+ def get_qng_combos(
430
+ objective, func=stokes_block, initial_values=None, samples=None, backend=None, device=None, noise=None
431
+ ) -> typing.List[typing.Dict]:
426
432
  """
427
433
  get all the objects needed to evaluate the qng for some objective; return them in a list of dictionaries.
428
434
 
@@ -459,7 +465,7 @@ def get_qng_combos(objective, func=stokes_block,
459
465
  compiled = compile_power_gate(gate=compiled)
460
466
  compiled = compile_controlled_phase(gate=compiled)
461
467
  compiled = compile_controlled_rotation(gate=compiled)
462
- for i,arg in enumerate(compiled.args):
468
+ for i, arg in enumerate(compiled.args):
463
469
  if not isinstance(arg, ExpectationValueImpl):
464
470
  # this is a variable, no QNG involved
465
471
  mat = QngMatrix([[[1]]])
@@ -467,13 +473,15 @@ def get_qng_combos(objective, func=stokes_block,
467
473
  mapping = {0: {v: __grad_inner(arg, v) for v in var_list}}
468
474
  else:
469
475
  # if the arg is an expectationvalue, we need to build some qngs and mappings!
470
- blocks = func(arg, initial_values=initial_values, samples=samples, device=device,
471
- backend=backend, noise=noise)
476
+ blocks = func(
477
+ arg, initial_values=initial_values, samples=samples, device=device, backend=backend, noise=noise
478
+ )
472
479
 
473
480
  mat = QngMatrix(blocks)
474
481
 
475
- vec = subvector_procedure(arg, initial_values=initial_values, samples=samples, device=device,
476
- backend=backend, noise=noise)
482
+ vec = subvector_procedure(
483
+ arg, initial_values=initial_values, samples=samples, device=device, backend=backend, noise=noise
484
+ )
477
485
 
478
486
  mapping = {}
479
487
  self_pars = get_self_pars(arg.U)
@@ -482,25 +490,25 @@ def get_qng_combos(objective, func=stokes_block,
482
490
  for v in p.extract_variables():
483
491
  gi = __grad_inner(p, v)
484
492
  if isinstance(gi, Objective):
485
- g = compile_objective(gi, variables=initial_values, samples=samples, device=device,
486
- backend=backend, noise=noise)
493
+ g = compile_objective(
494
+ gi, variables=initial_values, samples=samples, device=device, backend=backend, noise=noise
495
+ )
487
496
  else:
488
497
  g = gi
489
498
  indict[v] = g
490
499
  mapping[j] = indict
491
500
 
492
-
493
501
  pos_arg = jax.grad(compiled.transformation, i)
494
502
  p = Objective(compiled.args, transformation=pos_arg)
495
503
 
496
- pos = compile_objective(p, variables=initial_values, samples=samples, device=device,
497
- backend=backend, noise=noise)
504
+ pos = compile_objective(
505
+ p, variables=initial_values, samples=samples, device=device, backend=backend, noise=noise
506
+ )
498
507
  combos.append(qng_dict(arg, mat, vec, mapping, pos))
499
508
  return combos
500
509
 
501
510
 
502
511
  def evaluate_qng(combos, variables, samples=None) -> list:
503
-
504
512
  """
505
513
  actually evaluate the terms of a qng.
506
514
  Parameters
@@ -520,17 +528,17 @@ def evaluate_qng(combos, variables, samples=None) -> list:
520
528
  """
521
529
  gd = {v: 0 for v in variables.keys()}
522
530
  for c in combos:
523
- qgt = c['matrix']
524
- vec = c['vector']
525
- m = c['mapping']
526
- pos = c['positional']
531
+ qgt = c["matrix"]
532
+ vec = c["vector"]
533
+ m = c["mapping"]
534
+ pos = c["positional"]
527
535
  marco = qgt(variables, samples=samples)
528
536
  polo = vec(variables, samples=samples)
529
537
  ev = numpy.dot(marco, polo)
530
538
  for i, val in enumerate(ev):
531
539
  maps = m[i]
532
540
  for k in maps.keys():
533
- gd[k] += (val*maps[k]*pos)(variables=variables, samples=samples)
541
+ gd[k] += (val * maps[k] * pos)(variables=variables, samples=samples)
534
542
 
535
543
  out = [v for v in gd.values()]
536
544
  return out
@@ -547,7 +555,7 @@ class QNGVector:
547
555
 
548
556
  """
549
557
 
550
- def __init__(self,combos):
558
+ def __init__(self, combos):
551
559
  """
552
560
  init.
553
561
  Parameters
@@ -4,8 +4,10 @@ from tequila.circuit.circuit import QCircuit
4
4
  from tequila.hamiltonian.qubit_hamiltonian import QubitHamiltonian
5
5
  from scipy.stats import unitary_group, ortho_group
6
6
 
7
- def make_random_circuit(n_qubits: int, rotation_gates: list=['rx', 'ry', 'rz'], n_rotations: int=None,
8
- enable_controls: bool=None) -> QCircuit:
7
+
8
+ def make_random_circuit(
9
+ n_qubits: int, rotation_gates: list = ["rx", "ry", "rz"], n_rotations: int = None, enable_controls: bool = None
10
+ ) -> QCircuit:
9
11
  """Function that creates a circuit with random rotations or random control rotations.
10
12
 
11
13
  Args:
@@ -15,37 +17,38 @@ def make_random_circuit(n_qubits: int, rotation_gates: list=['rx', 'ry', 'rz'],
15
17
  enable_controls (bool): Boolean that switch on controls. Default to None.
16
18
 
17
19
  Returns:
18
- QCircuit: Random quantum circuit consiting of the given rotations gates
20
+ QCircuit: Random quantum circuit consiting of the given rotations gates
19
21
  and their controlled versions
20
22
  """
21
23
  if n_rotations is None:
22
- n_rotations = np.random.randint(n_qubits, high=n_qubits*3)
24
+ n_rotations = np.random.randint(n_qubits, high=n_qubits * 3)
23
25
 
24
26
  gates_list = [np.random.choice(rotation_gates) for i in range(n_rotations)]
25
-
26
- angles = 2*np.pi * np.random.rand(n_rotations)
27
-
27
+
28
+ angles = 2 * np.pi * np.random.rand(n_rotations)
29
+
28
30
  circ = QCircuit()
29
31
  for i, angle in enumerate(angles):
30
- target = i%n_qubits
32
+ target = i % n_qubits
31
33
  if enable_controls:
32
34
  controls = [i for i in circ.qubits if i != target]
33
35
  control = np.random.choice(controls + [None])
34
- else:
36
+ else:
35
37
  control = None
36
38
 
37
- if gates_list[i]=='rx':
39
+ if gates_list[i] == "rx":
38
40
  circ += gates.Rx(angle=angle, target=target, control=control)
39
-
40
- elif gates_list[i]=='ry':
41
+
42
+ elif gates_list[i] == "ry":
41
43
  circ += gates.Ry(angle=angle, target=target, control=control)
42
-
43
- elif gates_list[i]=='rz':
44
+
45
+ elif gates_list[i] == "rz":
44
46
  circ += gates.Rz(angle=angle, target=target, control=control)
45
-
47
+
46
48
  return circ
47
49
 
48
- def make_random_hamiltonian(n_qubits: int , paulis: list=['X','Y','Z'], n_ps: int = None) -> QubitHamiltonian:
50
+
51
+ def make_random_hamiltonian(n_qubits: int, paulis: list = ["X", "Y", "Z"], n_ps: int = None) -> QubitHamiltonian:
49
52
  """Function that creates a random Hamiltonian, given the list
50
53
  of Pauli ops. to use and the number of Pauli strings.
51
54
 
@@ -58,27 +61,28 @@ def make_random_hamiltonian(n_qubits: int , paulis: list=['X','Y','Z'], n_ps: in
58
61
  tq.QubitHamiltonian: Random Hamiltonian
59
62
  """
60
63
  if n_ps is None:
61
- n_ps = np.random.randint(1, high=2*n_qubits+1)
62
-
63
- ham = ''
64
+ n_ps = np.random.randint(1, high=2 * n_qubits + 1)
65
+
66
+ ham = ""
64
67
  for ps in range(n_ps):
65
- coeff = '{}*'.format(round(np.random.sample(),2))
66
- pauli_str = ''
68
+ coeff = "{}*".format(round(np.random.sample(), 2))
69
+ pauli_str = ""
67
70
  for qb in range(n_qubits):
68
- pauli_str += '{}({})'.format(np.random.choice(paulis), qb)
69
-
70
- if ps < n_ps-1:
71
- pauli_str += '+'
72
-
73
- ham += coeff+pauli_str
74
-
75
- #print(ham)
76
-
71
+ pauli_str += "{}({})".format(np.random.choice(paulis), qb)
72
+
73
+ if ps < n_ps - 1:
74
+ pauli_str += "+"
75
+
76
+ ham += coeff + pauli_str
77
+
78
+ # print(ham)
79
+
77
80
  H = QubitHamiltonian(ham)
78
81
  return H
79
82
 
80
- def generate_random_unitary(size, complex = False):
81
- '''
83
+
84
+ def generate_random_unitary(size, complex=False):
85
+ """
82
86
  Generates a random unitary (or furthermore orthogonal if complex is False) matrix of a specified size.
83
87
 
84
88
  Parameters:
@@ -87,8 +91,8 @@ def generate_random_unitary(size, complex = False):
87
91
 
88
92
  Returns:
89
93
  - numpy.ndarray: A randomly generated unitary matrix.
90
- '''
94
+ """
91
95
  if complex:
92
96
  return unitary_group.rvs(size)
93
97
  else:
94
- return ortho_group.rvs(size)
98
+ return ortho_group.rvs(size)
@@ -43,14 +43,14 @@ class BitString:
43
43
  @property
44
44
  def binary(self):
45
45
  if self.numbering is BitNumbering.MSB:
46
- return format(self._value, 'b').zfill(self.nbits)
46
+ return format(self._value, "b").zfill(self.nbits)
47
47
  else:
48
- return format(self._value, 'b').zfill(self.nbits)[::-1]
48
+ return format(self._value, "b").zfill(self.nbits)[::-1]
49
49
 
50
50
  @binary.setter
51
51
  def binary(self, other: str):
52
- assert (isinstance(other, str))
53
- if other.startswith('0b'):
52
+ assert isinstance(other, str)
53
+ if other.startswith("0b"):
54
54
  other = other[2:]
55
55
  if self.numbering == BitNumbering.LSB:
56
56
  self._value = int(other[::-1], 2)
@@ -178,7 +178,6 @@ class BitString:
178
178
 
179
179
 
180
180
  class BitStringLSB(BitString):
181
-
182
181
  @property
183
182
  def numbering(self) -> BitNumbering:
184
183
  return BitNumbering.LSB
@@ -197,8 +196,9 @@ def reverse_int_bits(x: int, nbits: int) -> int:
197
196
  return x >> (32 - nbits)
198
197
 
199
198
 
200
- def initialize_bitstring(integer: int, nbits: int = None, numbering_in: BitNumbering = BitNumbering.MSB,
201
- numbering_out: BitNumbering = None):
199
+ def initialize_bitstring(
200
+ integer: int, nbits: int = None, numbering_in: BitNumbering = BitNumbering.MSB, numbering_out: BitNumbering = None
201
+ ):
202
202
  if numbering_out is None:
203
203
  numbering_out = numbering_in
204
204
 
@@ -31,9 +31,16 @@ class TequilaParameterError(TequilaException):
31
31
  """
32
32
 
33
33
  def __init__(self, parameter_name, parameter_class, parameter_value, called_from=""):
34
- self.message = "OpenVQE ParameterError:" + called_from + " unknown parameter value: " + str(
35
- parameter_name) + "=" + str(
36
- parameter_value) + " for " + str(parameter_class)
34
+ self.message = (
35
+ "OpenVQE ParameterError:"
36
+ + called_from
37
+ + " unknown parameter value: "
38
+ + str(parameter_name)
39
+ + "="
40
+ + str(parameter_value)
41
+ + " for "
42
+ + str(parameter_class)
43
+ )
37
44
 
38
45
 
39
46
  class TequilaTypeError(TequilaException):
@@ -42,5 +49,12 @@ class TequilaTypeError(TequilaException):
42
49
  """
43
50
 
44
51
  def __init__(self, attr, type, expected):
45
- self.message = "OpenVQE TypeError: " + "excpected type: " + str(expected) + " but got type " + str(
46
- type) + " for attribute " + str(attr)
52
+ self.message = (
53
+ "OpenVQE TypeError: "
54
+ + "excpected type: "
55
+ + str(expected)
56
+ + " but got type "
57
+ + str(type)
58
+ + " for attribute "
59
+ + str(attr)
60
+ )
@@ -1,12 +1,12 @@
1
1
  class JoinedTransformation:
2
- '''
2
+ """
3
3
  class structure used to construct,track, and permit differentiation of the computation required
4
4
  by mathematical operations on ExpectationValues,Variables and Objectives thereof.
5
5
  JoinedTransformations allow operations to be combined.
6
- '''
6
+ """
7
7
 
8
8
  def __init__(self, left, right, split, op):
9
- '''
9
+ """
10
10
  :param left: Callable: the lefthand operation, one level down
11
11
  :param right: Callable: the righthand operation, one level down
12
12
  :param split: Int: the position in the call method, at which lefthand and righthand arguments split
@@ -15,21 +15,21 @@ class JoinedTransformation:
15
15
  Example: split 2, left = numpy.add, right= numpy.subtract, op = numpy.multiply, call on list of length 4:
16
16
  then the Joined Transform performs the following computation when called:
17
17
  np.Multiply(np.add(arg_0,arg_1),np.subtract(arg_2,arg_3))
18
- '''
18
+ """
19
19
  self.split = split
20
20
  self.left = left
21
21
  self.right = right
22
22
  self.op = op
23
23
 
24
24
  def __call__(self, *args, **kwargs):
25
- '''
25
+ """
26
26
 
27
27
  :param args: iter: the arguments to the transformation.
28
28
  :param kwargs: dict: keyword arguments to the transformation. Must be uniform.
29
29
  :return: a number, the result of the calculation.
30
- '''
31
- E_left = args[:self.split]
32
- E_right = args[self.split:]
30
+ """
31
+ E_left = args[: self.split]
32
+ E_right = args[self.split :]
33
33
  if self.op is None:
34
34
  if len(args) == 1:
35
35
  return args[0]
@@ -39,13 +39,11 @@ class JoinedTransformation:
39
39
  print(len(args))
40
40
  return self.op(*args)
41
41
  else:
42
-
43
42
  return self.op(self.left(*E_left, **kwargs), *E_right)
44
43
  if self.left is None:
45
44
  if self.right is None:
46
45
  return self.op(*args)
47
46
  else:
48
-
49
47
  return self.op(*E_left, self.right(*E_right, **kwargs))
50
48
  else:
51
49
  return self.op(self.left(*E_left, **kwargs), self.right(*E_right, **kwargs))