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.
- tequila/__init__.py +29 -14
- tequila/apps/__init__.py +14 -5
- tequila/apps/_unary_state_prep_impl.py +145 -112
- tequila/apps/adapt/__init__.py +9 -1
- tequila/apps/adapt/adapt.py +154 -113
- tequila/apps/krylov/__init__.py +1 -1
- tequila/apps/krylov/krylov.py +23 -21
- tequila/apps/robustness/helpers.py +10 -6
- tequila/apps/robustness/interval.py +238 -156
- tequila/apps/unary_state_prep.py +29 -23
- tequila/autograd_imports.py +8 -5
- tequila/circuit/__init__.py +2 -1
- tequila/circuit/_gates_impl.py +135 -67
- tequila/circuit/circuit.py +163 -79
- tequila/circuit/compiler.py +114 -105
- tequila/circuit/gates.py +288 -120
- tequila/circuit/gradient.py +35 -23
- tequila/circuit/noise.py +83 -74
- tequila/circuit/postselection.py +120 -0
- tequila/circuit/pyzx.py +10 -6
- tequila/circuit/qasm.py +201 -83
- tequila/circuit/qpic.py +63 -61
- tequila/grouping/binary_rep.py +148 -146
- tequila/grouping/binary_utils.py +84 -75
- tequila/grouping/compile_groups.py +334 -230
- tequila/grouping/ev_utils.py +77 -41
- tequila/grouping/fermionic_functions.py +383 -308
- tequila/grouping/fermionic_methods.py +170 -123
- tequila/grouping/overlapping_methods.py +69 -52
- tequila/hamiltonian/paulis.py +12 -13
- tequila/hamiltonian/paulistring.py +1 -1
- tequila/hamiltonian/qubit_hamiltonian.py +45 -35
- tequila/ml/__init__.py +1 -0
- tequila/ml/interface_torch.py +19 -16
- tequila/ml/ml_api.py +11 -10
- tequila/ml/utils_ml.py +12 -11
- tequila/objective/__init__.py +8 -3
- tequila/objective/braket.py +55 -47
- tequila/objective/objective.py +87 -55
- tequila/objective/qtensor.py +36 -27
- tequila/optimizers/__init__.py +31 -23
- tequila/optimizers/_containers.py +11 -7
- tequila/optimizers/optimizer_base.py +111 -83
- tequila/optimizers/optimizer_gd.py +258 -231
- tequila/optimizers/optimizer_gpyopt.py +56 -42
- tequila/optimizers/optimizer_scipy.py +157 -112
- tequila/quantumchemistry/__init__.py +66 -38
- tequila/quantumchemistry/chemistry_tools.py +393 -209
- tequila/quantumchemistry/encodings.py +121 -13
- tequila/quantumchemistry/madness_interface.py +170 -96
- tequila/quantumchemistry/orbital_optimizer.py +86 -41
- tequila/quantumchemistry/psi4_interface.py +166 -97
- tequila/quantumchemistry/pyscf_interface.py +70 -23
- tequila/quantumchemistry/qc_base.py +866 -414
- tequila/simulators/__init__.py +0 -3
- tequila/simulators/simulator_api.py +247 -105
- tequila/simulators/simulator_aqt.py +102 -0
- tequila/simulators/simulator_base.py +147 -53
- tequila/simulators/simulator_cirq.py +58 -42
- tequila/simulators/simulator_cudaq.py +600 -0
- tequila/simulators/simulator_ddsim.py +390 -0
- tequila/simulators/simulator_mqp.py +30 -0
- tequila/simulators/simulator_pyquil.py +190 -171
- tequila/simulators/simulator_qibo.py +95 -87
- tequila/simulators/simulator_qiskit.py +119 -107
- tequila/simulators/simulator_qlm.py +52 -26
- tequila/simulators/simulator_qulacs.py +74 -52
- tequila/simulators/simulator_spex.py +95 -60
- tequila/simulators/simulator_symbolic.py +6 -5
- tequila/simulators/test_spex_simulator.py +8 -11
- tequila/tools/convenience.py +4 -4
- tequila/tools/qng.py +72 -64
- tequila/tools/random_generators.py +38 -34
- tequila/utils/bitstrings.py +7 -7
- tequila/utils/exceptions.py +19 -5
- tequila/utils/joined_transformation.py +8 -10
- tequila/utils/keymap.py +0 -5
- tequila/utils/misc.py +6 -4
- tequila/version.py +1 -1
- tequila/wavefunction/qubit_wavefunction.py +47 -28
- {tequila_basic-1.9.9.dist-info → tequila_basic-1.9.10.dist-info}/METADATA +13 -16
- tequila_basic-1.9.10.dist-info/RECORD +93 -0
- {tequila_basic-1.9.9.dist-info → tequila_basic-1.9.10.dist-info}/WHEEL +1 -1
- tequila_basic-1.9.9.dist-info/RECORD +0 -88
- {tequila_basic-1.9.9.dist-info → tequila_basic-1.9.10.dist-info}/licenses/LICENSE +0 -0
- {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__ = [
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
14
|
+
__all__ = [
|
15
|
+
"robustness_interval",
|
16
|
+
"RobustnessInterval",
|
17
|
+
"SDPInterval",
|
18
|
+
"GramianExpectationBound",
|
19
|
+
"GramianEigenvalueInterval",
|
20
|
+
]
|
19
21
|
|
20
|
-
_EXPECTATION_ALIASES = [
|
21
|
-
_EIGENVALUE_ALIASES = [
|
22
|
+
_EXPECTATION_ALIASES = ["expectation"]
|
23
|
+
_EIGENVALUE_ALIASES = ["eigenvalue", "eigval"]
|
22
24
|
|
23
|
-
_GRAMIAN_ALIASES = [
|
24
|
-
_METHODS = [
|
25
|
+
_GRAMIAN_ALIASES = ["gramian", "gram"]
|
26
|
+
_METHODS = ["sdp"] + ["best"] + _GRAMIAN_ALIASES
|
25
27
|
|
26
28
|
|
27
29
|
class RobustnessInterval(ABC):
|
28
|
-
def __init__(
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
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(
|
41
|
+
self._precomputed_stats = {k.replace(" ", "_"): v for k, v in (precomputed_stats or {}).items()}
|
38
42
|
|
39
|
-
self._pauligroups = self._precomputed_stats.get(
|
40
|
-
self._pauligroups_coeffs = self._precomputed_stats.get(
|
41
|
-
self._pauligroups_eigenvalues = self._precomputed_stats.get(
|
42
|
-
self._pauligroups_expectations = self._precomputed_stats.get(
|
43
|
-
self._pauligroups_variances = self._precomputed_stats.get(
|
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(
|
46
|
-
self._hamiltonian_variance = self._precomputed_stats.get(
|
47
|
-
self._normalization_constant = self._precomputed_stats.get(
|
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
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
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
|
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
|
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
|
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 [
|
153
|
-
|
154
|
-
|
155
|
-
|
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(
|
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(
|
175
|
-
|
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(
|
184
|
-
|
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) ==
|
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(
|
193
|
-
|
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
|
-
|
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
|
-
|
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,
|
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
|
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,
|
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
|
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
|
-
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
|
236
|
-
|
237
|
-
|
238
|
-
|
239
|
-
|
240
|
-
|
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
|
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
|
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
|
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 [
|
270
|
-
|
271
|
-
|
272
|
-
|
273
|
-
|
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(
|
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 = [
|
297
|
-
|
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(
|
315
|
-
|
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(
|
320
|
-
|
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(
|
338
|
-
|
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
|
385
|
+
if fidelity / (1 - fidelity) < variance / (expectation**2):
|
362
386
|
return 0.0
|
363
387
|
|
364
|
-
return
|
365
|
-
|
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
|
-
|
375
|
-
|
376
|
-
|
377
|
-
|
378
|
-
|
379
|
-
|
380
|
-
|
381
|
-
|
382
|
-
|
383
|
-
|
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
|
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
|
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(
|
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(
|
413
|
-
|
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(
|
418
|
-
|
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(
|
441
|
-
|
442
|
-
|
443
|
-
|
444
|
-
|
445
|
-
|
446
|
-
|
447
|
-
|
448
|
-
|
449
|
-
|
450
|
-
|
451
|
-
|
452
|
-
|
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(
|
492
|
-
kind = kind.lower().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(
|
496
|
-
|
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
|
500
|
-
|
501
|
-
if method ==
|
502
|
-
interval = SDPInterval(
|
503
|
-
|
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(
|
510
|
-
|
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(
|
515
|
-
|
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 ==
|
519
|
-
sdp_interval = SDPInterval(
|
520
|
-
|
521
|
-
|
522
|
-
|
523
|
-
|
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(
|
543
|
-
|
544
|
-
|
545
|
-
|
546
|
-
|
547
|
-
|
548
|
-
|
549
|
-
|
550
|
-
|
551
|
-
|
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:
|