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
@@ -11,40 +11,44 @@ from tequila.circuit.noise import NoiseModel
11
11
  from tequila.hamiltonian import QubitHamiltonian
12
12
  from tequila.objective import Variable, ExpectationValue
13
13
 
14
- __all__ = ['robustness_interval',
15
- 'RobustnessInterval',
16
- 'SDPInterval',
17
- 'GramianExpectationBound',
18
- 'GramianEigenvalueInterval']
14
+ __all__ = [
15
+ "robustness_interval",
16
+ "RobustnessInterval",
17
+ "SDPInterval",
18
+ "GramianExpectationBound",
19
+ "GramianEigenvalueInterval",
20
+ ]
19
21
 
20
- _EXPECTATION_ALIASES = ['expectation']
21
- _EIGENVALUE_ALIASES = ['eigenvalue', 'eigval']
22
+ _EXPECTATION_ALIASES = ["expectation"]
23
+ _EIGENVALUE_ALIASES = ["eigenvalue", "eigval"]
22
24
 
23
- _GRAMIAN_ALIASES = ['gramian', 'gram']
24
- _METHODS = ['sdp'] + ['best'] + _GRAMIAN_ALIASES
25
+ _GRAMIAN_ALIASES = ["gramian", "gram"]
26
+ _METHODS = ["sdp"] + ["best"] + _GRAMIAN_ALIASES
25
27
 
26
28
 
27
29
  class RobustnessInterval(ABC):
28
- def __init__(self,
29
- fidelity: float,
30
- U: QCircuit = None,
31
- H: QubitHamiltonian = None,
32
- precomputed_stats: Dict[str, Union[List[List[float]], List[float], float]] = None):
30
+ def __init__(
31
+ self,
32
+ fidelity: float,
33
+ U: QCircuit = None,
34
+ H: QubitHamiltonian = None,
35
+ precomputed_stats: Dict[str, Union[List[List[float]], List[float], float]] = None,
36
+ ):
33
37
  self._U = U
34
38
  self._H = H
35
39
 
36
40
  # clean stats keys
37
- self._precomputed_stats = {k.replace(' ', '_'): v for k, v in (precomputed_stats or {}).items()}
41
+ self._precomputed_stats = {k.replace(" ", "_"): v for k, v in (precomputed_stats or {}).items()}
38
42
 
39
- self._pauligroups = self._precomputed_stats.get('pauligroups', [])
40
- self._pauligroups_coeffs = self._precomputed_stats.get('pauligroups_coeffs')
41
- self._pauligroups_eigenvalues = self._precomputed_stats.get('pauligroups_eigenvalues')
42
- self._pauligroups_expectations = self._precomputed_stats.get('pauligroups_expectations')
43
- self._pauligroups_variances = self._precomputed_stats.get('pauligroups_variances')
43
+ self._pauligroups = self._precomputed_stats.get("pauligroups", [])
44
+ self._pauligroups_coeffs = self._precomputed_stats.get("pauligroups_coeffs")
45
+ self._pauligroups_eigenvalues = self._precomputed_stats.get("pauligroups_eigenvalues")
46
+ self._pauligroups_expectations = self._precomputed_stats.get("pauligroups_expectations")
47
+ self._pauligroups_variances = self._precomputed_stats.get("pauligroups_variances")
44
48
 
45
- self._hamiltonian_expectation = self._precomputed_stats.get('hamiltonian_expectations')
46
- self._hamiltonian_variance = self._precomputed_stats.get('hamiltonian_variances')
47
- self._normalization_constant = self._precomputed_stats.get('normalization_const')
49
+ self._hamiltonian_expectation = self._precomputed_stats.get("hamiltonian_expectations")
50
+ self._hamiltonian_variance = self._precomputed_stats.get("hamiltonian_variances")
51
+ self._normalization_constant = self._precomputed_stats.get("normalization_const")
48
52
 
49
53
  self._fidelity = fidelity
50
54
 
@@ -110,19 +114,19 @@ class RobustnessInterval(ABC):
110
114
 
111
115
 
112
116
  class SDPInterval(RobustnessInterval):
113
-
114
- def __init__(self,
115
- fidelity: float,
116
- U: QCircuit = None,
117
- H: QubitHamiltonian = None,
118
- precomputed_stats: Dict[str, Union[List[List[float]], List[float], float]] = None,
119
- variables=None,
120
- samples=None,
121
- backend=None,
122
- device=None,
123
- noise=None,
124
- group_terms=True):
125
-
117
+ def __init__(
118
+ self,
119
+ fidelity: float,
120
+ U: QCircuit = None,
121
+ H: QubitHamiltonian = None,
122
+ precomputed_stats: Dict[str, Union[List[List[float]], List[float], float]] = None,
123
+ variables=None,
124
+ samples=None,
125
+ backend=None,
126
+ device=None,
127
+ noise=None,
128
+ group_terms=True,
129
+ ):
126
130
  super(SDPInterval, self).__init__(fidelity, U, H, precomputed_stats)
127
131
 
128
132
  self._compute_stats(variables, samples, backend, device, noise, group_terms)
@@ -132,32 +136,34 @@ class SDPInterval(RobustnessInterval):
132
136
 
133
137
  def _sanity_checks(self):
134
138
  if self._fidelity < 0 or self._fidelity > 1:
135
- raise ValueError(f'encountered invalid fidelity; got {self._fidelity}, must be within [0, 1]!')
139
+ raise ValueError(f"encountered invalid fidelity; got {self._fidelity}, must be within [0, 1]!")
136
140
 
137
141
  # make sure that variance for each of the pauligroups is positive
138
142
  if self._pauligroups_variances is not None:
139
143
  for i, group_variance in enumerate(self._pauligroups_variances):
140
144
  if group_variance <= -1e-6:
141
- raise ValueError(f'negative variance encountered: {group_variance}')
145
+ raise ValueError(f"negative variance encountered: {group_variance}")
142
146
  self._pauligroups_variances[i] = max(0.0, group_variance)
143
147
 
144
148
  # make sure that variance of Hamiltonian is positive
145
149
  if self._hamiltonian_variance is not None:
146
150
  if self._hamiltonian_variance <= -1e-6:
147
- raise ValueError(f'negative variance encountered: v={self._hamiltonian_variance}')
151
+ raise ValueError(f"negative variance encountered: v={self._hamiltonian_variance}")
148
152
 
149
153
  self._hamiltonian_variance = max(0.0, float(self._hamiltonian_variance))
150
154
 
151
155
  def _compute_stats(self, variables, samples, backend, device, noise, group_terms):
152
- if None not in [self._pauligroups,
153
- self._pauligroups_coeffs,
154
- self._pauligroups_expectations,
155
- self._pauligroups_eigenvalues]:
156
+ if None not in [
157
+ self._pauligroups,
158
+ self._pauligroups_coeffs,
159
+ self._pauligroups_expectations,
160
+ self._pauligroups_eigenvalues,
161
+ ]:
156
162
  # here stats have been provided; no need to recompute
157
163
  return
158
164
 
159
165
  if self._U is None or self._H is None:
160
- raise ValueError('If U or H is not provided, you must provide precomputed_stats!')
166
+ raise ValueError("If U or H is not provided, you must provide precomputed_stats!")
161
167
 
162
168
  # compute expectation values
163
169
  if group_terms:
@@ -171,8 +177,11 @@ class SDPInterval(RobustnessInterval):
171
177
 
172
178
  # compute expectation values
173
179
  self._pauligroups_expectations = [
174
- simulate(objective=objective, variables=variables, samples=samples, backend=backend, device=device,
175
- noise=noise) for objective in objectives]
180
+ simulate(
181
+ objective=objective, variables=variables, samples=samples, backend=backend, device=device, noise=noise
182
+ )
183
+ for objective in objectives
184
+ ]
176
185
 
177
186
  # compute eigenvalues for each term
178
187
  self._pauligroups_eigenvalues = [p_str.compute_eigenvalues() for p_str in self._pauligroups]
@@ -180,23 +189,26 @@ class SDPInterval(RobustnessInterval):
180
189
  def _compute_interval(self) -> Tuple[float, float]:
181
190
  lower_bound, upper_bound = 0.0, 0.0
182
191
 
183
- for p_str, p_coeff, p_eigvals, p_expec in zip(self._pauligroups, self._pauligroups_coeffs,
184
- self._pauligroups_eigenvalues, self._pauligroups_expectations):
185
-
192
+ for p_str, p_coeff, p_eigvals, p_expec in zip(
193
+ self._pauligroups, self._pauligroups_coeffs, self._pauligroups_eigenvalues, self._pauligroups_expectations
194
+ ):
186
195
  min_eigval = min(p_eigvals)
187
196
  max_eigval = max(p_eigvals)
188
197
 
189
- if str(p_str) == 'I' or len(p_str) == 0:
198
+ if str(p_str) == "I" or len(p_str) == 0:
190
199
  pauli_lower_bound = pauli_upper_bound = 1.0
191
200
  else:
192
- expec_normalized = np.clip(2 * (p_expec - min_eigval) / (max_eigval - min_eigval) - 1, -1, 1,
193
- dtype=float)
201
+ expec_normalized = np.clip(
202
+ 2 * (p_expec - min_eigval) / (max_eigval - min_eigval) - 1, -1, 1, dtype=float
203
+ )
194
204
 
195
205
  pauli_lower_bound = (max_eigval - min_eigval) / 2.0 * (
196
- 1 + self._calc_lower_bound(expec_normalized, self.fidelity)) + min_eigval
206
+ 1 + self._calc_lower_bound(expec_normalized, self.fidelity)
207
+ ) + min_eigval
197
208
 
198
209
  pauli_upper_bound = (max_eigval - min_eigval) / 2.0 * (
199
- 1 + self._calc_upper_bound(expec_normalized, self.fidelity)) + min_eigval
210
+ 1 + self._calc_upper_bound(expec_normalized, self.fidelity)
211
+ ) + min_eigval
200
212
 
201
213
  lower_bound += p_coeff * pauli_lower_bound if p_coeff > 0 else p_coeff * pauli_upper_bound
202
214
  upper_bound += p_coeff * pauli_upper_bound if p_coeff > 0 else p_coeff * pauli_lower_bound
@@ -208,36 +220,37 @@ class SDPInterval(RobustnessInterval):
208
220
 
209
221
  @staticmethod
210
222
  def _calc_lower_bound(e, f):
211
- assert -1.0 <= e <= 1.0, 'expectation not normalized to [-1, 1]'
223
+ assert -1.0 <= e <= 1.0, "expectation not normalized to [-1, 1]"
212
224
 
213
225
  if f < 0.5 * (1 - e):
214
226
  return -1.0
215
227
 
216
- return (2 * f - 1) * e - 2 * np.sqrt(f * (1 - f) * (1 - e ** 2))
228
+ return (2 * f - 1) * e - 2 * np.sqrt(f * (1 - f) * (1 - e**2))
217
229
 
218
230
  @staticmethod
219
231
  def _calc_upper_bound(e, f):
220
- assert -1.0 <= e <= 1.0, 'expectation not normalized to [-1, 1]'
232
+ assert -1.0 <= e <= 1.0, "expectation not normalized to [-1, 1]"
221
233
 
222
234
  if f < 0.5 * (1 + e):
223
235
  return 1.0
224
236
 
225
- return (2.0 * f - 1.0) * e + 2.0 * np.sqrt(f * (1.0 - f) * (1.0 - e ** 2))
237
+ return (2.0 * f - 1.0) * e + 2.0 * np.sqrt(f * (1.0 - f) * (1.0 - e**2))
226
238
 
227
239
 
228
240
  class GramianExpectationBound(RobustnessInterval):
229
-
230
- def __init__(self,
231
- fidelity: float,
232
- U: QCircuit = None,
233
- H: QubitHamiltonian = None,
234
- precomputed_stats: Dict[str, Union[List[List[float]], List[float], float]] = None,
235
- variables=None,
236
- samples=None,
237
- backend=None,
238
- device=None,
239
- noise=None,
240
- group_terms=True):
241
+ def __init__(
242
+ self,
243
+ fidelity: float,
244
+ U: QCircuit = None,
245
+ H: QubitHamiltonian = None,
246
+ precomputed_stats: Dict[str, Union[List[List[float]], List[float], float]] = None,
247
+ variables=None,
248
+ samples=None,
249
+ backend=None,
250
+ device=None,
251
+ noise=None,
252
+ group_terms=True,
253
+ ):
241
254
  super(GramianExpectationBound, self).__init__(fidelity, U, H, precomputed_stats)
242
255
 
243
256
  self._compute_stats(variables, samples, backend, device, noise, group_terms)
@@ -249,33 +262,35 @@ class GramianExpectationBound(RobustnessInterval):
249
262
 
250
263
  def _sanity_checks(self):
251
264
  if self._fidelity < 0 or self._fidelity > 1:
252
- raise ValueError(f'encountered invalid fidelity; got {self._fidelity}, must be within [0, 1]!')
265
+ raise ValueError(f"encountered invalid fidelity; got {self._fidelity}, must be within [0, 1]!")
253
266
 
254
267
  # make sure that variance for each of the pauligroups is positive
255
268
  if self._pauligroups_variances is not None:
256
269
  for i, group_variance in enumerate(self._pauligroups_variances):
257
270
  if group_variance <= -1e-6:
258
- raise ValueError(f'negative variance encountered: {group_variance}')
271
+ raise ValueError(f"negative variance encountered: {group_variance}")
259
272
  self._pauligroups_variances[i] = max(0.0, group_variance)
260
273
 
261
274
  # make sure that variance of Hamiltonian is positive
262
275
  if self._hamiltonian_variance is not None:
263
276
  if self._hamiltonian_variance <= -1e-6:
264
- raise ValueError(f'negative variance encountered: v={self._hamiltonian_variance}')
277
+ raise ValueError(f"negative variance encountered: v={self._hamiltonian_variance}")
265
278
 
266
279
  self._hamiltonian_variance = max(0.0, float(self._hamiltonian_variance))
267
280
 
268
281
  def _compute_stats(self, variables, samples, backend, device, noise, group_terms):
269
- if None not in [self._pauligroups,
270
- self._pauligroups_coeffs,
271
- self._pauligroups_expectations,
272
- self._pauligroups_variances,
273
- self._pauligroups_eigenvalues]:
282
+ if None not in [
283
+ self._pauligroups,
284
+ self._pauligroups_coeffs,
285
+ self._pauligroups_expectations,
286
+ self._pauligroups_variances,
287
+ self._pauligroups_eigenvalues,
288
+ ]:
274
289
  # here stats have been provided; no need to recompute
275
290
  return
276
291
 
277
292
  if self._U is None or self._H is None:
278
- raise ValueError('If U or H is not provided, you must provide precomputed_stats!')
293
+ raise ValueError("If U or H is not provided, you must provide precomputed_stats!")
279
294
 
280
295
  if group_terms:
281
296
  # here we group pauli terms into groups of commuting terms
@@ -290,14 +305,18 @@ class GramianExpectationBound(RobustnessInterval):
290
305
  objectives = [ExpectationValue(U=self._U + group.U, H=group.H) for group in self._pauligroups]
291
306
  self._pauligroups_expectations = [
292
307
  simulate(objective, variables=variables, samples=samples, backend=backend, device=device, noise=noise)
293
- for objective in objectives]
308
+ for objective in objectives
309
+ ]
294
310
 
295
311
  # variance
296
- objectives = [ExpectationValue(U=self._U + group.U, H=(group.H - e) ** 2) for group, e in
297
- zip(self._pauligroups, self._pauligroups_expectations)]
312
+ objectives = [
313
+ ExpectationValue(U=self._U + group.U, H=(group.H - e) ** 2)
314
+ for group, e in zip(self._pauligroups, self._pauligroups_expectations)
315
+ ]
298
316
  self._pauligroups_variances = [
299
317
  simulate(objective, variables=variables, samples=samples, backend=backend, device=device, noise=noise)
300
- for objective in objectives]
318
+ for objective in objectives
319
+ ]
301
320
 
302
321
  else:
303
322
  # here we compute stats for the entire hamiltonian and add a const s.t. it is ≥ 0
@@ -306,18 +325,21 @@ class GramianExpectationBound(RobustnessInterval):
306
325
  const_pauli_terms = [i for i, pstr in enumerate(pauli_strings) if len(pstr) == 0]
307
326
 
308
327
  self._normalization_constant = -np.sum([pauli_coeffs[i] for i in const_pauli_terms])
309
- self._normalization_constant += np.sum([
310
- np.abs(pauli_coeffs[i]) for i in set(range(len(pauli_coeffs))) - set(const_pauli_terms)])
328
+ self._normalization_constant += np.sum(
329
+ [np.abs(pauli_coeffs[i]) for i in set(range(len(pauli_coeffs))) - set(const_pauli_terms)]
330
+ )
311
331
 
312
332
  # compute expectation
313
333
  objective = ExpectationValue(U=self._U, H=self._H)
314
- self._hamiltonian_expectation = simulate(objective, variables=variables, samples=samples, backend=backend,
315
- device=device, noise=noise)
334
+ self._hamiltonian_expectation = simulate(
335
+ objective, variables=variables, samples=samples, backend=backend, device=device, noise=noise
336
+ )
316
337
 
317
338
  # compute variance
318
339
  objective = ExpectationValue(U=self._U, H=(self._H - self._hamiltonian_expectation) ** 2)
319
- self._hamiltonian_variance = simulate(objective, variables=variables, samples=samples, backend=backend,
320
- device=device, noise=noise)
340
+ self._hamiltonian_variance = simulate(
341
+ objective, variables=variables, samples=samples, backend=backend, device=device, noise=noise
342
+ )
321
343
 
322
344
  def _compute_interval(self, group_terms) -> float:
323
345
  if group_terms:
@@ -328,14 +350,16 @@ class GramianExpectationBound(RobustnessInterval):
328
350
 
329
351
  def _compute_bound_hamiltonian(self) -> float:
330
352
  bound = -self._normalization_constant + self._calc_lower_bound(
331
- self._normalization_constant + self._hamiltonian_expectation, self._hamiltonian_variance, self.fidelity)
353
+ self._normalization_constant + self._hamiltonian_expectation, self._hamiltonian_variance, self.fidelity
354
+ )
332
355
  return bound
333
356
 
334
357
  def _compute_bound_grouped(self) -> float:
335
358
  bound = 0.0
336
359
 
337
- for eigvals, expec, variance in zip(self._pauligroups_eigenvalues, self._pauligroups_expectations,
338
- self._pauligroups_variances):
360
+ for eigvals, expec, variance in zip(
361
+ self._pauligroups_eigenvalues, self._pauligroups_expectations, self._pauligroups_variances
362
+ ):
339
363
  min_eigval = min(eigvals)
340
364
  expec_pos = np.clip(expec - min_eigval, 0, None, dtype=float)
341
365
  bound += min_eigval + self._calc_lower_bound(expec_pos, variance, self.fidelity)
@@ -358,11 +382,14 @@ class GramianExpectationBound(RobustnessInterval):
358
382
  def _calc_lower_bound(expectation, variance, fidelity):
359
383
  assert expectation >= 0
360
384
 
361
- if fidelity / (1 - fidelity) < variance / (expectation ** 2):
385
+ if fidelity / (1 - fidelity) < variance / (expectation**2):
362
386
  return 0.0
363
387
 
364
- return fidelity * expectation + (1 - fidelity) / expectation * variance - 2 * np.sqrt(
365
- variance * fidelity * (1 - fidelity))
388
+ return (
389
+ fidelity * expectation
390
+ + (1 - fidelity) / expectation * variance
391
+ - 2 * np.sqrt(variance * fidelity * (1 - fidelity))
392
+ )
366
393
 
367
394
  @staticmethod
368
395
  def _calc_upper_bound():
@@ -370,17 +397,18 @@ class GramianExpectationBound(RobustnessInterval):
370
397
 
371
398
 
372
399
  class GramianEigenvalueInterval(RobustnessInterval):
373
-
374
- def __init__(self,
375
- fidelity: float,
376
- U: QCircuit = None,
377
- H: QubitHamiltonian = None,
378
- precomputed_stats: Dict[str, Union[List[List[float]], List[float], float]] = None,
379
- variables=None,
380
- samples=None,
381
- backend=None,
382
- device=None,
383
- noise=None):
400
+ def __init__(
401
+ self,
402
+ fidelity: float,
403
+ U: QCircuit = None,
404
+ H: QubitHamiltonian = None,
405
+ precomputed_stats: Dict[str, Union[List[List[float]], List[float], float]] = None,
406
+ variables=None,
407
+ samples=None,
408
+ backend=None,
409
+ device=None,
410
+ noise=None,
411
+ ):
384
412
  super(GramianEigenvalueInterval, self).__init__(fidelity, U, H, precomputed_stats)
385
413
 
386
414
  self._compute_stats(variables, samples, backend, device, noise)
@@ -391,11 +419,11 @@ class GramianEigenvalueInterval(RobustnessInterval):
391
419
 
392
420
  def _sanity_checks(self):
393
421
  if self._fidelity < 0 or self._fidelity > 1:
394
- raise ValueError(f'encountered invalid fidelity; got {self._fidelity}, must be within [0, 1]!')
422
+ raise ValueError(f"encountered invalid fidelity; got {self._fidelity}, must be within [0, 1]!")
395
423
 
396
424
  # make sure that variance of Hamiltonian is positive
397
425
  if self._hamiltonian_variance <= -1e-6:
398
- raise ValueError(f'negative variance encountered: v={self._hamiltonian_variance}')
426
+ raise ValueError(f"negative variance encountered: v={self._hamiltonian_variance}")
399
427
 
400
428
  self._hamiltonian_variance = max(0.0, float(self._hamiltonian_variance))
401
429
 
@@ -405,17 +433,19 @@ class GramianEigenvalueInterval(RobustnessInterval):
405
433
  return
406
434
 
407
435
  if self._U is None or self._H is None:
408
- raise ValueError('If U or H is not provided, you must provide precomputed_stats!')
436
+ raise ValueError("If U or H is not provided, you must provide precomputed_stats!")
409
437
 
410
438
  # compute expectation
411
439
  objective = ExpectationValue(U=self._U, H=self._H)
412
- self._hamiltonian_expectation = simulate(objective, variables=variables, samples=samples, backend=backend,
413
- device=device, noise=noise)
440
+ self._hamiltonian_expectation = simulate(
441
+ objective, variables=variables, samples=samples, backend=backend, device=device, noise=noise
442
+ )
414
443
 
415
444
  # compute variance
416
445
  objective = ExpectationValue(U=self._U, H=(self._H - self._hamiltonian_expectation) ** 2)
417
- self._hamiltonian_variance = simulate(objective, variables=variables, samples=samples, backend=backend,
418
- device=device, noise=noise)
446
+ self._hamiltonian_variance = simulate(
447
+ objective, variables=variables, samples=samples, backend=backend, device=device, noise=noise
448
+ )
419
449
 
420
450
  def _compute_interval(self) -> Tuple[float, float]:
421
451
  lower_bound = self._calc_lower_bound(self._hamiltonian_expectation, self._hamiltonian_variance, self.fidelity)
@@ -437,19 +467,21 @@ class GramianEigenvalueInterval(RobustnessInterval):
437
467
  return expectation + np.sqrt(variance) * np.sqrt((1.0 - fidelity) / fidelity)
438
468
 
439
469
 
440
- def robustness_interval(U: QCircuit,
441
- H: QubitHamiltonian,
442
- fidelity: float,
443
- variables: Dict[Union[Variable, Hashable], RealNumber] = None,
444
- kind: str = 'expectation',
445
- method: str = 'best',
446
- group_terms: bool = True,
447
- samples: int = None,
448
- backend: str = None,
449
- noise: Union[str, NoiseModel] = None,
450
- device: str = None,
451
- return_object: bool = False) -> (float, float, float, Union[RobustnessInterval, None]):
452
- """ calculate robustness intervals
470
+ def robustness_interval(
471
+ U: QCircuit,
472
+ H: QubitHamiltonian,
473
+ fidelity: float,
474
+ variables: Dict[Union[Variable, Hashable], RealNumber] = None,
475
+ kind: str = "expectation",
476
+ method: str = "best",
477
+ group_terms: bool = True,
478
+ samples: int = None,
479
+ backend: str = None,
480
+ noise: Union[str, NoiseModel] = None,
481
+ device: str = None,
482
+ return_object: bool = False,
483
+ ) -> (float, float, float, Union[RobustnessInterval, None]):
484
+ """calculate robustness intervals
453
485
 
454
486
  Parameters
455
487
  ---------
@@ -488,39 +520,83 @@ def robustness_interval(U: QCircuit,
488
520
  expectation of H with U, and the upper bound.
489
521
 
490
522
  """
491
- method = method.lower().replace('_', '').replace(' ', '')
492
- kind = kind.lower().replace('_', '').replace(' ', '')
523
+ method = method.lower().replace("_", "").replace(" ", "")
524
+ kind = kind.lower().replace("_", "").replace(" ", "")
493
525
 
494
526
  if kind not in _EXPECTATION_ALIASES + _EIGENVALUE_ALIASES:
495
- raise ValueError(f'unknown robustness interval type; got {kind}, '
496
- + f'must be one of {_EXPECTATION_ALIASES + _EIGENVALUE_ALIASES}')
527
+ raise ValueError(
528
+ f"unknown robustness interval type; got {kind}, "
529
+ + f"must be one of {_EXPECTATION_ALIASES + _EIGENVALUE_ALIASES}"
530
+ )
497
531
 
498
532
  if method not in _METHODS:
499
- raise ValueError(f'unknown method; got {method}, must be one of {_METHODS}')
500
-
501
- if method == 'sdp':
502
- interval = SDPInterval(U=U, H=H, fidelity=fidelity, variables=variables, backend=backend, noise=noise,
503
- device=device, samples=samples, group_terms=group_terms)
533
+ raise ValueError(f"unknown method; got {method}, must be one of {_METHODS}")
534
+
535
+ if method == "sdp":
536
+ interval = SDPInterval(
537
+ U=U,
538
+ H=H,
539
+ fidelity=fidelity,
540
+ variables=variables,
541
+ backend=backend,
542
+ noise=noise,
543
+ device=device,
544
+ samples=samples,
545
+ group_terms=group_terms,
546
+ )
504
547
  return interval.interval, (interval if return_object else None)
505
548
 
506
549
  if method in _GRAMIAN_ALIASES:
507
-
508
550
  if kind in _EXPECTATION_ALIASES:
509
- interval = GramianExpectationBound(U=U, H=H, fidelity=fidelity, variables=variables, backend=backend,
510
- noise=noise, device=device, samples=samples, group_terms=group_terms)
551
+ interval = GramianExpectationBound(
552
+ U=U,
553
+ H=H,
554
+ fidelity=fidelity,
555
+ variables=variables,
556
+ backend=backend,
557
+ noise=noise,
558
+ device=device,
559
+ samples=samples,
560
+ group_terms=group_terms,
561
+ )
511
562
  return interval.interval, (interval if return_object else None)
512
563
 
513
564
  if kind in _EIGENVALUE_ALIASES:
514
- interval = GramianEigenvalueInterval(U=U, H=H, fidelity=fidelity, variables=variables, backend=backend,
515
- noise=noise, device=device, samples=samples)
565
+ interval = GramianEigenvalueInterval(
566
+ U=U,
567
+ H=H,
568
+ fidelity=fidelity,
569
+ variables=variables,
570
+ backend=backend,
571
+ noise=noise,
572
+ device=device,
573
+ samples=samples,
574
+ )
516
575
  return interval.interval, (interval if return_object else None)
517
576
 
518
- if method == 'best':
519
- sdp_interval = SDPInterval(U=U, H=H, fidelity=fidelity, variables=variables, backend=backend, noise=noise,
520
- device=device, samples=samples, group_terms=True)
521
- gramian_exp_interval = GramianExpectationBound(U=U, H=H, fidelity=fidelity, variables=variables,
522
- backend=backend, noise=noise, device=device, samples=samples,
523
- group_terms=True)
577
+ if method == "best":
578
+ sdp_interval = SDPInterval(
579
+ U=U,
580
+ H=H,
581
+ fidelity=fidelity,
582
+ variables=variables,
583
+ backend=backend,
584
+ noise=noise,
585
+ device=device,
586
+ samples=samples,
587
+ group_terms=True,
588
+ )
589
+ gramian_exp_interval = GramianExpectationBound(
590
+ U=U,
591
+ H=H,
592
+ fidelity=fidelity,
593
+ variables=variables,
594
+ backend=backend,
595
+ noise=noise,
596
+ device=device,
597
+ samples=samples,
598
+ group_terms=True,
599
+ )
524
600
  if kind in _EXPECTATION_ALIASES:
525
601
  max_lower_bound = max([sdp_interval.lower_bound, gramian_exp_interval.lower_bound])
526
602
  min_upper_bound = sdp_interval.upper_bound
@@ -539,16 +615,22 @@ def robustness_interval(U: QCircuit,
539
615
 
540
616
  if kind in _EIGENVALUE_ALIASES:
541
617
  # reuse expectation and variance
542
- gramian_eigv_interval = GramianEigenvalueInterval(U=U, H=H, fidelity=fidelity, variables=variables,
543
- backend=backend, noise=noise, device=device,
544
- samples=samples)
545
-
546
- max_lower_bound = max([sdp_interval.lower_bound,
547
- gramian_exp_interval.lower_bound,
548
- gramian_eigv_interval.lower_bound])
549
-
550
- min_upper_bound = min([sdp_interval.upper_bound,
551
- gramian_eigv_interval.upper_bound])
618
+ gramian_eigv_interval = GramianEigenvalueInterval(
619
+ U=U,
620
+ H=H,
621
+ fidelity=fidelity,
622
+ variables=variables,
623
+ backend=backend,
624
+ noise=noise,
625
+ device=device,
626
+ samples=samples,
627
+ )
628
+
629
+ max_lower_bound = max(
630
+ [sdp_interval.lower_bound, gramian_exp_interval.lower_bound, gramian_eigv_interval.lower_bound]
631
+ )
632
+
633
+ min_upper_bound = min([sdp_interval.upper_bound, gramian_eigv_interval.upper_bound])
552
634
 
553
635
  interval = None
554
636
  if return_object: