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
@@ -1,17 +1,27 @@
1
1
  from tequila import TequilaException
2
2
  from tequila.hamiltonian import QubitHamiltonian, PauliString
3
- from tequila.grouping.binary_utils import get_lagrangian_subspace, binary_symplectic_inner_product, binary_solve, binary_phase, gen_single_qubit_term, largest_first, recursive_largest_first, sorted_insertion_grouping
3
+ from tequila.grouping.binary_utils import (
4
+ get_lagrangian_subspace,
5
+ binary_symplectic_inner_product,
6
+ binary_solve,
7
+ binary_phase,
8
+ gen_single_qubit_term,
9
+ largest_first,
10
+ recursive_largest_first,
11
+ sorted_insertion_grouping,
12
+ )
4
13
  from tequila.grouping.overlapping_methods import OverlappingGroups, OverlappingAuxiliary, get_opt_sample_size
5
14
  import numpy as np
6
15
  import tequila as tq
7
16
  import numbers
8
17
  from copy import deepcopy
9
18
 
19
+
10
20
  class BinaryHamiltonian:
11
21
  def __init__(self, binary_terms):
12
- '''
22
+ """
13
23
  Initiate from a list of Binary Pauli Strings
14
- '''
24
+ """
15
25
  self.binary_terms = binary_terms
16
26
 
17
27
  self.n_qubit = binary_terms[0].get_n_qubit()
@@ -20,21 +30,18 @@ class BinaryHamiltonian:
20
30
 
21
31
  @classmethod
22
32
  def init_from_qubit_hamiltonian(cls, hamiltonian: QubitHamiltonian, n_qubits=None, ignore_const=False):
23
- if ignore_const: #Ignore constant term.
33
+ if ignore_const: # Ignore constant term.
24
34
  Hof = hamiltonian.to_openfermion()
25
35
  if () in Hof.terms:
26
36
  del Hof.terms[()]
27
37
  hamiltonian = QubitHamiltonian.from_openfermion(Hof)
28
38
  if n_qubits is None:
29
- n_qubits = max(hamiltonian.qubits)+1
39
+ n_qubits = max(hamiltonian.qubits) + 1
30
40
  binary_terms = [
31
- BinaryPauliString(
32
- p.binary(n_qubits).binary,
33
- p.binary(n_qubits).coeff) for p in hamiltonian.paulistrings
41
+ BinaryPauliString(p.binary(n_qubits).binary, p.binary(n_qubits).coeff) for p in hamiltonian.paulistrings
34
42
  ]
35
43
  return BinaryHamiltonian(binary_terms)
36
44
 
37
-
38
45
  def get_binary(self):
39
46
  matrix = [p.get_binary() for p in self.binary_terms]
40
47
  return matrix
@@ -44,29 +51,28 @@ class BinaryHamiltonian:
44
51
  return coeff
45
52
 
46
53
  def single_qubit_form(self):
47
- '''
54
+ """
48
55
  Returns
49
56
  ----------
50
57
  hamiltonian : BinaryHamiltonian
51
58
  The original hamiltonian in qubit-wise commuting form
52
- lagrangian_basis : list of BinaryPauliStrings
59
+ lagrangian_basis : list of BinaryPauliStrings
53
60
  Represents the basis of original Hamiltonian
54
- new_basis : list of BinaryPauliStrings
61
+ new_basis : list of BinaryPauliStrings
55
62
  Represents the basis of new Hamiltonian
56
- '''
63
+ """
57
64
  lagrangian_basis = get_lagrangian_subspace(self.get_binary())
58
65
  new_basis = self.get_single_qubit_basis(lagrangian_basis)
59
66
  lagrangian_basis = [BinaryPauliString(p) for p in lagrangian_basis]
60
67
  new_basis = [BinaryPauliString(p) for p in new_basis]
61
- qubit_wise_hamiltonian = self.basis_transform(lagrangian_basis,
62
- new_basis)
68
+ qubit_wise_hamiltonian = self.basis_transform(lagrangian_basis, new_basis)
63
69
  return qubit_wise_hamiltonian, lagrangian_basis, new_basis
64
70
 
65
71
  def z_form(self):
66
- '''
72
+ """
67
73
  Parameters
68
74
  ----------
69
- self : BinaryHamiltonian
75
+ self : BinaryHamiltonian
70
76
  a qubit-wise commuting hamiltonian
71
77
 
72
78
  Modifies
@@ -78,34 +84,34 @@ class BinaryHamiltonian:
78
84
  ----------
79
85
  U : QCircuit
80
86
  the single qubit transformation that rotates each term to z
81
- '''
87
+ """
82
88
  U = tq.QCircuit()
83
89
  non_z = {}
84
90
  for p in self.binary_terms:
85
91
  for qub in range(self.n_qubit):
86
- z_data = {qub: 'z'}
92
+ z_data = {qub: "z"}
87
93
  if p.has_x(qub):
88
94
  p.set_z(qub)
89
- non_z[qub] = 'x'
95
+ non_z[qub] = "x"
90
96
  elif p.has_y(qub):
91
97
  p.set_z(qub)
92
- non_z[qub] = 'y'
93
-
98
+ non_z[qub] = "y"
99
+
94
100
  for qub, term in non_z.items():
95
101
  xy_data = {qub: term}
96
- z_data = {qub: 'z'}
97
- U += tq.gates.ExpPauli(angle = -tq.numpy.pi/2, paulistring=tq.PauliString(z_data))
98
- U += tq.gates.ExpPauli(angle = -tq.numpy.pi/2, paulistring=tq.PauliString(xy_data))
99
- U += tq.gates.ExpPauli(angle = -tq.numpy.pi/2, paulistring=tq.PauliString(z_data))
102
+ z_data = {qub: "z"}
103
+ U += tq.gates.ExpPauli(angle=-tq.numpy.pi / 2, paulistring=tq.PauliString(z_data))
104
+ U += tq.gates.ExpPauli(angle=-tq.numpy.pi / 2, paulistring=tq.PauliString(xy_data))
105
+ U += tq.gates.ExpPauli(angle=-tq.numpy.pi / 2, paulistring=tq.PauliString(z_data))
100
106
 
101
107
  return U
102
108
 
103
- def get_qubit_wise(self, binary = False):
104
- '''
109
+ def get_qubit_wise(self, binary=False):
110
+ """
105
111
  Return the qubit-wise form of the current binary hamiltonian.
106
- And the unitary transformation U,
112
+ And the unitary transformation U,
107
113
  where U = prod_i (1/2) ** (1/2) * (lagrangian_basis[i] + new_basis[i])
108
-
114
+
109
115
  Parameters
110
116
  ----------
111
117
  binary : determines whether the returned qwc hamiltonian is binary or qubit hamiltonian
@@ -117,14 +123,13 @@ class BinaryHamiltonian:
117
123
  The original hamiltonian in qubit-wise commuting form
118
124
  U : QCircuit
119
125
  The unitary circuit that transforms the original hamiltonian into qwc form
120
- '''
126
+ """
121
127
  if not self.is_commuting():
122
- raise TequilaException(
123
- 'Not all terms in the Hamiltonians are commuting.')
128
+ raise TequilaException("Not all terms in the Hamiltonians are commuting.")
124
129
  if self.is_qubit_wise_commuting():
125
130
  qubit_wise_hamiltonian = self
126
131
  qwc_u = tq.QCircuit()
127
- else:
132
+ else:
128
133
  qubit_wise_hamiltonian, lagrangian_basis, new_basis = self.single_qubit_form()
129
134
 
130
135
  # Constructing the unitary that rotates into qubit-wise parts
@@ -132,10 +137,10 @@ class BinaryHamiltonian:
132
137
  for i in range(len(lagrangian_basis)):
133
138
  sigma = lagrangian_basis[i].to_pauli_strings()
134
139
  tau = new_basis[i].to_pauli_strings()
135
- qwc_u += tq.gates.ExpPauli(angle=-tq.numpy.pi/2, paulistring=sigma)
136
- qwc_u += tq.gates.ExpPauli(angle=-tq.numpy.pi/2, paulistring=tau)
137
- qwc_u += tq.gates.ExpPauli(angle=-tq.numpy.pi/2, paulistring=sigma)
138
-
140
+ qwc_u += tq.gates.ExpPauli(angle=-tq.numpy.pi / 2, paulistring=sigma)
141
+ qwc_u += tq.gates.ExpPauli(angle=-tq.numpy.pi / 2, paulistring=tau)
142
+ qwc_u += tq.gates.ExpPauli(angle=-tq.numpy.pi / 2, paulistring=sigma)
143
+
139
144
  single_qub_u = qubit_wise_hamiltonian.z_form()
140
145
  # Return the basis in terms of Binary Hamiltonian
141
146
  if binary:
@@ -144,10 +149,10 @@ class BinaryHamiltonian:
144
149
  return qubit_wise_hamiltonian.to_qubit_hamiltonian(), qwc_u + single_qub_u
145
150
 
146
151
  def get_single_qubit_basis(self, lagrangian_basis):
147
- '''
152
+ """
148
153
  Find the single_qubit_basis such that single_qubit_basis[i] anti-commutes
149
- with lagrangian_basis[i], and commute for all other cases.
150
- '''
154
+ with lagrangian_basis[i], and commute for all other cases.
155
+ """
151
156
  dim = len(lagrangian_basis)
152
157
 
153
158
  # Free Qubits
@@ -155,46 +160,42 @@ class BinaryHamiltonian:
155
160
  pair = []
156
161
 
157
162
  for i in range(dim):
158
- cur_pair = self.find_single_qubit_pair(lagrangian_basis[i],
159
- free_qub)
163
+ cur_pair = self.find_single_qubit_pair(lagrangian_basis[i], free_qub)
160
164
  for j in range(dim):
161
165
  if i != j:
162
- if binary_symplectic_inner_product(
163
- cur_pair, lagrangian_basis[j] == 1):
164
- lagrangian_basis[j] = (lagrangian_basis[i] +
165
- lagrangian_basis[j]) % 2
166
+ if binary_symplectic_inner_product(cur_pair, lagrangian_basis[j] == 1):
167
+ lagrangian_basis[j] = (lagrangian_basis[i] + lagrangian_basis[j]) % 2
166
168
  pair.append(cur_pair)
167
169
  return pair
168
170
 
169
171
  def find_single_qubit_pair(self, cur_basis, free_qub):
170
- '''
171
- Find the single qubit pair that anti-commute with cur_basis such that the single qubit is in free_qub
172
+ """
173
+ Find the single qubit pair that anti-commute with cur_basis such that the single qubit is in free_qub
172
174
 
173
175
  Return: Binary vectors representing the single qubit pair
174
176
  Modify: Pops the qubit used from free_qub
175
- '''
177
+ """
176
178
  dim = len(cur_basis) // 2
177
179
  for idx, qub in enumerate(free_qub):
178
180
  for term in range(3):
179
181
  pair = gen_single_qubit_term(dim, qub, term)
180
182
  # if anticommute
181
- if (binary_symplectic_inner_product(pair, cur_basis) == 1):
183
+ if binary_symplectic_inner_product(pair, cur_basis) == 1:
182
184
  free_qub.pop(idx)
183
185
  return pair
184
186
 
185
187
  def basis_transform(self, old, new):
186
- '''
188
+ """
187
189
  Transforms the given hamiltonian from the old basis to the new basis.
188
-
190
+
189
191
  Return: The transformed Binary hamiltonian
190
- '''
191
- return BinaryHamiltonian(
192
- [p.basis_transform(old, new) for p in self.binary_terms])
192
+ """
193
+ return BinaryHamiltonian([p.basis_transform(old, new) for p in self.binary_terms])
193
194
 
194
195
  def is_commuting(self):
195
- '''
196
+ """
196
197
  Return whether all terms in the Hamiltonian are commuting
197
- '''
198
+ """
198
199
  for i in range(self.n_term):
199
200
  for j in range(i + 1, self.n_term):
200
201
  if not self.binary_terms[i].commute(self.binary_terms[j]):
@@ -202,15 +203,15 @@ class BinaryHamiltonian:
202
203
  return True
203
204
 
204
205
  def is_qubit_wise_commuting(self):
205
- '''
206
- Return whether all terms in the Hamiltonian are qubit-wise commuting
207
- '''
206
+ """
207
+ Return whether all terms in the Hamiltonian are qubit-wise commuting
208
+ """
208
209
  # Keep a dictionary of qubit-wise term found
209
210
  qubit_term = {}
210
211
  for i in range(self.n_term):
211
212
  for qub in range(self.n_qubit):
212
213
  cur_binary_term = self.binary_terms[i].get_binary()
213
- cur_qub_term = (cur_binary_term[qub], cur_binary_term[qub+self.n_qubit])
214
+ cur_qub_term = (cur_binary_term[qub], cur_binary_term[qub + self.n_qubit])
214
215
  if cur_qub_term != (0, 0):
215
216
  if qub not in qubit_term:
216
217
  qubit_term[qub] = cur_qub_term
@@ -218,13 +219,11 @@ class BinaryHamiltonian:
218
219
  if not qubit_term[qub] == cur_qub_term:
219
220
  return False
220
221
  return True
221
-
222
222
 
223
223
  def to_qubit_hamiltonian(self):
224
224
  qub_ham = QubitHamiltonian()
225
225
  for p in self.binary_terms:
226
- qub_ham += QubitHamiltonian.from_paulistrings(
227
- p.to_pauli_strings())
226
+ qub_ham += QubitHamiltonian.from_paulistrings(p.to_pauli_strings())
228
227
  return qub_ham
229
228
 
230
229
  def anti_commutativity_matrix(self):
@@ -234,7 +233,7 @@ class BinaryHamiltonian:
234
233
  """
235
234
  n = self.n_qubit
236
235
  matrix = np.array(self.get_binary())
237
- gram = np.block([[np.zeros((n,n)), np.eye(n)], [np.eye(n), np.zeros((n,n))]])
236
+ gram = np.block([[np.zeros((n, n)), np.eye(n)], [np.eye(n), np.zeros((n, n))]])
238
237
  return matrix @ gram @ matrix.T % 2
239
238
 
240
239
  def commuting_groups(self, options=None):
@@ -246,11 +245,11 @@ class BinaryHamiltonian:
246
245
  Parameters
247
246
  ----------
248
247
  options: dictionary: Dictionary containing user-defined parameters:
249
- key: method, val: 'lf' [largest first J. Chem. Phys. 152, 124114 (2020)], 'rlf' [recursive largest first J. Chem. Phys. 152, 124114 (2020)],
248
+ key: method, val: 'lf' [largest first J. Chem. Phys. 152, 124114 (2020)], 'rlf' [recursive largest first J. Chem. Phys. 152, 124114 (2020)],
250
249
  'si' [sorted insertion Quantum 5, 385 (2021)], 'ics' [iterative coefficient splitting npj Quantum Inf. 9, 14 (2023)]
251
250
  key: condition, val: 'fc' (fully commuting Pauli products are measured together)
252
251
  'qwc' (qubit-wise commuting Pauli products are measured together)
253
- key: cov_dict, val: Dictionary containing {(binary_tuple of pw1, binary_tuple of pw2) : Cov (pw1, pw2)}.
252
+ key: cov_dict, val: Dictionary containing {(binary_tuple of pw1, binary_tuple of pw2) : Cov (pw1, pw2)}.
254
253
  Only covariances for [pw1,pw2]=0 are necessary. This dictionary is necessary for ics.
255
254
  For other methods, if cov_dict is given, the optimal allocation of samples will be returned.
256
255
  key: n_iter, val: integer number of iterations in ics.
@@ -259,18 +258,21 @@ class BinaryHamiltonian:
259
258
  ----------
260
259
  List of BinaryHamiltonian's
261
260
  """
261
+
262
262
  def process_options(options):
263
- method = 'rlf' # Method used for Hamiltonian partitioning.
264
- condition = 'fc' # Commutativitiy condition within a group; either fully commuting (fc) or qubit-wise commuting (qwc).
265
- sample_suggestion = False # Whether to return suggested ratio of samples between groups.
266
- overlap_aux = None # Help variable for overlapping methods.
263
+ method = "rlf" # Method used for Hamiltonian partitioning.
264
+ condition = "fc" # Commutativitiy condition within a group; either fully commuting (fc) or qubit-wise commuting (qwc).
265
+ sample_suggestion = False # Whether to return suggested ratio of samples between groups.
266
+ overlap_aux = None # Help variable for overlapping methods.
267
267
  if options is not None:
268
- if "method" in options: method=options["method"]
269
- if "condition" in options: condition=options["condition"]
268
+ if "method" in options:
269
+ method = options["method"]
270
+ if "condition" in options:
271
+ condition = options["condition"]
270
272
 
271
273
  # If cov_dict is given in options, use the user-defined covariance dictionary.
272
- if "cov_dict" in options:
273
- sample_suggestion = True #Suggested sample size can be given whenever covariances are present.
274
+ if "cov_dict" in options:
275
+ sample_suggestion = True # Suggested sample size can be given whenever covariances are present.
274
276
  if "n_iter" in options:
275
277
  overlap_aux = OverlappingAuxiliary(options["cov_dict"], options["n_iter"])
276
278
  else:
@@ -279,17 +281,20 @@ class BinaryHamiltonian:
279
281
  # (TODO) Compute default HF/CISD covariances if cov_dict is not given.
280
282
  overlap_aux = None
281
283
  return method, condition, overlap_aux, sample_suggestion
282
-
284
+
283
285
  def method_class(method, condition):
284
286
  """
285
287
  Return the class that the method belongs to: One from Minimum clique cover (mcc)
286
- and Greedy grouping algorithms.
288
+ and Greedy grouping algorithms.
287
289
  """
288
- if (method == 'lf' or method == 'rlf'):
289
- mc = 'mcc'
290
- if condition != "fc": raise TequilaException(f"Combination of options={{method:{method},condition:{condition}}} is not valid. E.g., lf and rlf can only return fully commuting fragments, i.e., condition=fc is necessary.")
291
- elif (method == 'si' or method == 'ics'):
292
- mc = 'greedy'
290
+ if method == "lf" or method == "rlf":
291
+ mc = "mcc"
292
+ if condition != "fc":
293
+ raise TequilaException(
294
+ f"Combination of options={{method:{method},condition:{condition}}} is not valid. E.g., lf and rlf can only return fully commuting fragments, i.e., condition=fc is necessary."
295
+ )
296
+ elif method == "si" or method == "ics":
297
+ mc = "greedy"
293
298
  else:
294
299
  raise TequilaException(f"There is not options={{method:{method}}}")
295
300
  return mc
@@ -298,33 +303,38 @@ class BinaryHamiltonian:
298
303
  n = self.n_term
299
304
 
300
305
  method, condition, overlap_aux, sample_suggestion = process_options(options)
301
- if method_class(method, condition) == 'mcc':
306
+ if method_class(method, condition) == "mcc":
302
307
  cg = self.anti_commutativity_matrix()
303
- if method == 'lf':
308
+ if method == "lf":
304
309
  colors = largest_first(terms, n, cg)
305
- elif method == 'rlf':
310
+ elif method == "rlf":
306
311
  colors = recursive_largest_first(terms, n, cg)
307
312
  groups = [value for key, value in colors.items()]
308
313
  result = [BinaryHamiltonian(value) for key, value in colors.items()]
309
- elif method_class(method, condition) == 'greedy':
310
- if method == 'si': groups = sorted_insertion_grouping(terms, condition)
311
- if method == 'ics':
312
- if overlap_aux == None: raise TequilaException("Overlapping SI grouping requires a dictionary of covariances, call with options={cov_dict:X}, where X is the dictionary.")
314
+ elif method_class(method, condition) == "greedy":
315
+ if method == "si":
316
+ groups = sorted_insertion_grouping(terms, condition)
317
+ if method == "ics":
318
+ if overlap_aux is None:
319
+ raise TequilaException(
320
+ "Overlapping SI grouping requires a dictionary of covariances, call with options={cov_dict:X}, where X is the dictionary."
321
+ )
313
322
  o_groups = OverlappingGroups.init_from_binary_terms(terms, condition)
314
323
  groups = o_groups.optimal_overlapping_groups(overlap_aux)
315
324
  result = [BinaryHamiltonian(group) for group in groups]
316
-
325
+
317
326
  if sample_suggestion:
318
327
  suggested_sample_size = get_opt_sample_size(groups, options["cov_dict"])
319
328
  else:
320
329
  suggested_sample_size = [None] * len(groups)
321
330
  return result, suggested_sample_size
322
331
 
332
+
323
333
  class BinaryPauliString:
324
334
  def __init__(self, binary_vector=np.array([0, 0]), coeff=1.0):
325
- '''
326
- Stores a list of binary vectors and a list of corresponding coefficients.
327
- '''
335
+ """
336
+ Stores a list of binary vectors and a list of corresponding coefficients.
337
+ """
328
338
  self.binary = np.array(binary_vector)
329
339
  self.coeff = coeff
330
340
  self.n_qubit = len(binary_vector) // 2
@@ -332,85 +342,78 @@ class BinaryPauliString:
332
342
  self.is_coeff()
333
343
 
334
344
  def __eq__(self, other):
335
- '''
336
- Check if two BinaryPauliStrings are equivalent.
337
- The size of small is chosen arbitrarily.
338
- '''
345
+ """
346
+ Check if two BinaryPauliStrings are equivalent.
347
+ The size of small is chosen arbitrarily.
348
+ """
339
349
  small = 1e-10
340
350
  return all(self.binary == other.binary) and (np.abs(self.coeff - other.coeff) <= small)
341
351
 
342
352
  def binary_tuple(self):
343
- '''
353
+ """
344
354
  Return binary vector as a tuple. Useful for cov_dict (see overlapping_methods).
345
- '''
355
+ """
346
356
  return tuple(self.binary)
347
357
 
348
358
  def is_binary(self):
349
359
  if not isinstance(self.binary, np.ndarray):
350
360
  raise TequilaException(
351
- 'Unknown representation of binary vector. Got ' +
352
- str(self.binary) + ' with type ' + type(self.binary))
361
+ "Unknown representation of binary vector. Got " + str(self.binary) + " with type " + type(self.binary)
362
+ )
353
363
  if not all([x == 1 or x == 0 for x in self.binary]):
354
- raise TequilaException(
355
- 'Not all number in the binary vector is 0 or 1. Got ' +
356
- str(self.binary))
364
+ raise TequilaException("Not all number in the binary vector is 0 or 1. Got " + str(self.binary))
357
365
 
358
366
  def is_coeff(self):
359
367
  if not isinstance(self.coeff, numbers.Number):
360
- raise TequilaException('Unknown coefficients. Got ' +
361
- str(self.coeff))
368
+ raise TequilaException("Unknown coefficients. Got " + str(self.coeff))
362
369
 
363
370
  def qubit_wise_commute(self, other):
364
- '''
365
- Determine whether the corresponding pauli-strings of
366
- the two binary vectors are qubit-wise commuting.
367
- '''
368
- qubit_term = {} #Dictionary of qubit terms in self.
371
+ """
372
+ Determine whether the corresponding pauli-strings of
373
+ the two binary vectors are qubit-wise commuting.
374
+ """
375
+ qubit_term = {} # Dictionary of qubit terms in self.
369
376
  for qub in range(self.n_qubit):
370
- cur_qub_term = (self.binary[qub], self.binary[qub + self.n_qubit])
377
+ cur_qub_term = (self.binary[qub], self.binary[qub + self.n_qubit])
371
378
  if cur_qub_term != (0, 0):
372
379
  qubit_term[qub] = cur_qub_term
373
380
 
374
381
  for qub in range(other.n_qubit):
375
- cur_qub_term = (other.binary[qub], other.binary[qub + self.n_qubit])
382
+ cur_qub_term = (other.binary[qub], other.binary[qub + self.n_qubit])
376
383
  if cur_qub_term != (0, 0):
377
384
  if qub in qubit_term:
378
- if qubit_term[qub] != cur_qub_term: return False
385
+ if qubit_term[qub] != cur_qub_term:
386
+ return False
379
387
  return True
380
388
 
381
389
  def commute(self, other):
382
- '''
383
- Determine whether the corresponding pauli-strings of
384
- the two binary vectors commute.
385
- '''
386
- inner_product = binary_symplectic_inner_product(
387
- self.binary, other.binary)
390
+ """
391
+ Determine whether the corresponding pauli-strings of
392
+ the two binary vectors commute.
393
+ """
394
+ inner_product = binary_symplectic_inner_product(self.binary, other.binary)
388
395
 
389
396
  if inner_product == 0:
390
397
  return True
391
398
  elif inner_product == 1:
392
399
  return False
393
400
  else:
394
- raise TequilaException('Computed unexpected inner product. Got ' +
395
- str(inner_product))
401
+ raise TequilaException("Computed unexpected inner product. Got " + str(inner_product))
396
402
 
397
403
  def basis_transform(self, old, new):
398
- '''
404
+ """
399
405
  Transform the pauli string from old to new binary basis.
400
406
 
401
407
  Return: Pauli string in the new basis.
402
- '''
403
- old_basis_coeff = binary_solve([p.get_binary() for p in old],
404
- self.binary)
408
+ """
409
+ old_basis_coeff = binary_solve([p.get_binary() for p in old], self.binary)
405
410
  original_pauli_vec = np.zeros(self.n_qubit * 2)
406
411
  new_pauli_vec = np.zeros(self.n_qubit * 2)
407
412
  phase = 1
408
413
  for i, i_coeff in enumerate(old_basis_coeff):
409
414
  if i_coeff == 1:
410
- phase *= binary_phase(original_pauli_vec, old[i].get_binary(),
411
- self.n_qubit)
412
- original_pauli_vec = (original_pauli_vec +
413
- old[i].get_binary()) % 2
415
+ phase *= binary_phase(original_pauli_vec, old[i].get_binary(), self.n_qubit)
416
+ original_pauli_vec = (original_pauli_vec + old[i].get_binary()) % 2
414
417
  new_pauli_vec = (new_pauli_vec + new[i].get_binary()) % 2
415
418
 
416
419
  new_pauli_str = BinaryPauliString(new_pauli_vec)
@@ -431,37 +434,37 @@ class BinaryPauliString:
431
434
 
432
435
  def has_z(self, i):
433
436
  return self.binary[i] == 0 and self.binary[i + self.n_qubit] == 1
434
-
437
+
435
438
  def set_x(self, i):
436
- '''
439
+ """
437
440
  Set the ith qubit to having x
438
- '''
441
+ """
439
442
  self.binary[i] = 1
440
443
  self.binary[i + self.n_qubit] = 0
441
-
444
+
442
445
  def set_y(self, i):
443
- '''
446
+ """
444
447
  Set the ith qubit to having y
445
- '''
448
+ """
446
449
  self.binary[i] = 1
447
450
  self.binary[i + self.n_qubit] = 1
448
451
 
449
452
  def set_z(self, i):
450
- '''
453
+ """
451
454
  Set the ith qubit to having z
452
- '''
455
+ """
453
456
  self.binary[i] = 0
454
457
  self.binary[i + self.n_qubit] = 1
455
-
458
+
456
459
  def to_pauli_strings(self):
457
460
  data = {}
458
461
  for i in range(self.n_qubit):
459
462
  if self.has_x(i):
460
- data[i] = 'X'
463
+ data[i] = "X"
461
464
  elif self.has_y(i):
462
- data[i] = 'Y'
465
+ data[i] = "Y"
463
466
  elif self.has_z(i):
464
- data[i] = 'Z'
467
+ data[i] = "Z"
465
468
  return PauliString(data, self.coeff)
466
469
 
467
470
  def get_coeff(self):
@@ -477,10 +480,9 @@ class BinaryPauliString:
477
480
  return self.n_qubit
478
481
 
479
482
  def term_w_coeff(self, new_coeff):
480
- '''
483
+ """
481
484
  Return BinaryPauliString with a new coefficient.
482
- '''
485
+ """
483
486
  new_term = deepcopy(self)
484
487
  new_term.set_coeff(new_coeff)
485
488
  return new_term
486
-