qharm-eigenbridge 0.0.2__tar.gz → 0.0.3__tar.gz

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 (26) hide show
  1. qharm_eigenbridge-0.0.3/PKG-INFO +77 -0
  2. qharm_eigenbridge-0.0.3/README.md +50 -0
  3. {qharm_eigenbridge-0.0.2 → qharm_eigenbridge-0.0.3}/python/eigenbridge/quantum_solvers.py +136 -35
  4. qharm_eigenbridge-0.0.3/python/qharm_eigenbridge.egg-info/PKG-INFO +77 -0
  5. qharm_eigenbridge-0.0.3/python/qharm_eigenbridge.egg-info/scm_version.json +8 -0
  6. qharm_eigenbridge-0.0.3/tests/unit_tests/test_eigensolvers.py +187 -0
  7. qharm_eigenbridge-0.0.2/PKG-INFO +0 -55
  8. qharm_eigenbridge-0.0.2/README.md +0 -28
  9. qharm_eigenbridge-0.0.2/python/qharm_eigenbridge.egg-info/PKG-INFO +0 -55
  10. qharm_eigenbridge-0.0.2/python/qharm_eigenbridge.egg-info/scm_version.json +0 -8
  11. qharm_eigenbridge-0.0.2/tests/unit_tests/test_eigensolvers.py +0 -82
  12. {qharm_eigenbridge-0.0.2 → qharm_eigenbridge-0.0.3}/.clang-format +0 -0
  13. {qharm_eigenbridge-0.0.2 → qharm_eigenbridge-0.0.3}/.github/workflows/merge.yaml +0 -0
  14. {qharm_eigenbridge-0.0.2 → qharm_eigenbridge-0.0.3}/.github/workflows/pull_request.yaml +0 -0
  15. {qharm_eigenbridge-0.0.2 → qharm_eigenbridge-0.0.3}/.gitignore +0 -0
  16. {qharm_eigenbridge-0.0.2 → qharm_eigenbridge-0.0.3}/.licenserc.yaml +0 -0
  17. {qharm_eigenbridge-0.0.2 → qharm_eigenbridge-0.0.3}/.pre-commit-config.yaml +0 -0
  18. {qharm_eigenbridge-0.0.2 → qharm_eigenbridge-0.0.3}/LICENSE +0 -0
  19. {qharm_eigenbridge-0.0.2 → qharm_eigenbridge-0.0.3}/pyproject.toml +0 -0
  20. {qharm_eigenbridge-0.0.2 → qharm_eigenbridge-0.0.3}/python/eigenbridge/__init__.py +0 -0
  21. {qharm_eigenbridge-0.0.2 → qharm_eigenbridge-0.0.3}/python/qharm_eigenbridge.egg-info/SOURCES.txt +0 -0
  22. {qharm_eigenbridge-0.0.2 → qharm_eigenbridge-0.0.3}/python/qharm_eigenbridge.egg-info/dependency_links.txt +0 -0
  23. {qharm_eigenbridge-0.0.2 → qharm_eigenbridge-0.0.3}/python/qharm_eigenbridge.egg-info/requires.txt +0 -0
  24. {qharm_eigenbridge-0.0.2 → qharm_eigenbridge-0.0.3}/python/qharm_eigenbridge.egg-info/scm_file_list.json +0 -0
  25. {qharm_eigenbridge-0.0.2 → qharm_eigenbridge-0.0.3}/python/qharm_eigenbridge.egg-info/top_level.txt +0 -0
  26. {qharm_eigenbridge-0.0.2 → qharm_eigenbridge-0.0.3}/setup.cfg +0 -0
@@ -0,0 +1,77 @@
1
+ Metadata-Version: 2.4
2
+ Name: qharm-eigenbridge
3
+ Version: 0.0.3
4
+ Summary: Quantum eigensolver implementation using Qiskit
5
+ Author-email: Jonathan Waldrop <jwaldrop@ameslab.gov>, Mahir Anand <mahiranand@outlook.com>
6
+ Classifier: Development Status :: 4 - Beta
7
+ Classifier: Programming Language :: Python :: 3 :: Only
8
+ Classifier: Programming Language :: Python :: 3.9
9
+ Classifier: Programming Language :: Python :: 3.10
10
+ Classifier: Programming Language :: Python :: 3.11
11
+ Classifier: Programming Language :: Python :: 3.12
12
+ Classifier: Programming Language :: Python :: 3.13
13
+ Classifier: Programming Language :: Python :: 3.14
14
+ Requires-Python: >=3.9
15
+ Description-Content-Type: text/markdown
16
+ License-File: LICENSE
17
+ Requires-Dist: numpy
18
+ Requires-Dist: pybind11
19
+ Requires-Dist: qiskit
20
+ Requires-Dist: qiskit-algorithms
21
+ Requires-Dist: qiskit-aer
22
+ Requires-Dist: qiskit-ibm-runtime
23
+ Provides-Extra: dev
24
+ Requires-Dist: pre-commit; extra == "dev"
25
+ Requires-Dist: pytest; extra == "dev"
26
+ Dynamic: license-file
27
+
28
+ <!--
29
+ ~ Copyright 2026 QHARM
30
+ ~
31
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
32
+ ~ you may not use this file except in compliance with the License.
33
+ ~ You may obtain a copy of the License at
34
+ ~
35
+ ~ http://www.apache.org/licenses/LICENSE-2.0
36
+ ~
37
+ ~ Unless required by applicable law or agreed to in writing, software
38
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
39
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
40
+ ~ See the License for the specific language governing permissions and
41
+ ~ limitations under the License.
42
+ -->
43
+
44
+ # EigenBridge
45
+
46
+ There are two quantum solvers. VQD can return several eigenvalues; QAOA returns only the ground state.
47
+
48
+ VQD -> `run_vqd_eigensolver(matrix, k, use_noise=false)` -> lowest `k` eigenvalues (`k` defaults to all)
49
+ QAOA -> `run_qaoa_eigensolver(matrix, use_noise=false)` -> ground state only
50
+
51
+ **Uncertainties (`uq_values` / `uq_vectors`)**
52
+ - For every VQD/QAOA path (noiseless and noisy), at each final optimized circuit/state,
53
+ `uq_values[i] = sqrt(max(0, ⟨H²⟩ − ⟨H⟩²))`, where ⟨H⟩ is the reported eigenvalue and ⟨H²⟩
54
+ comes from the same estimator on `H @ H` at the same parameters.
55
+ This is the standard deviation of a single measurement of H in the prepared state
56
+ (intrinsic quantum / variational residual variance).
57
+ Exact eigenstates give σ ≈ 0; approximate ansatz states give nonzero σ even without noise.
58
+ - `uq_vectors` uses the same layout as the returned eigenvectors (column `i` = mode `i`).
59
+ For each physical basis index `j`,
60
+ `uq_vectors[j, i] = sqrt(p_j (1 − p_j))` where `p_j = ⟨|j⟩⟨j|⟩` is evaluated with the
61
+ **same estimator / circuit / parameters** as the energy (FakeManila when `use_noise=true`).
62
+ This is the std of a single-shot computational-basis occupation measurement for component `j`.
63
+ Caveat: it can be > 0 even for an exact delocalized eigenstate (unlike σ_H, which is 0 for
64
+ exact energy eigenstates). It is **not** “distance to the classical eigenvector.”
65
+ Unused eigenvector columns stay 0. Reported eigenvectors still come from the ideal
66
+ statevector of the optimized circuit; only the UQ uses the estimator/noise path.
67
+ - Non–power-of-2 dimensions pad to the next power of two and place
68
+ `penalty = max(1.0, Gershgorin row-sum bound)` on unused diagonal entries so pad
69
+ eigenvalues stay outside the original spectrum while avoiding the old 10× entry-scale
70
+ inflation of ⟨H²⟩ on small problems.
71
+ - Noisy VQD keeps exact statevector overlaps; only the energy / projector estimator uses
72
+ FakeManila noise (demo). Expect worse eigenvalues, especially for higher states.
73
+
74
+ Unit tests check that reported `uq_values` / filled `uq_vectors` entries are finite and
75
+ nonnegative (filled columns not identically zero on the demo matrix), and that on the
76
+ demo 3×3 matrix the ground-state interval `[⟨H⟩−σ, ⟨H⟩+σ]` contains the classical ground
77
+ eigenvalue for noisy paths. They do not require noisy eigenvalues to match the classical answer.
@@ -0,0 +1,50 @@
1
+ <!--
2
+ ~ Copyright 2026 QHARM
3
+ ~
4
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
5
+ ~ you may not use this file except in compliance with the License.
6
+ ~ You may obtain a copy of the License at
7
+ ~
8
+ ~ http://www.apache.org/licenses/LICENSE-2.0
9
+ ~
10
+ ~ Unless required by applicable law or agreed to in writing, software
11
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
12
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ ~ See the License for the specific language governing permissions and
14
+ ~ limitations under the License.
15
+ -->
16
+
17
+ # EigenBridge
18
+
19
+ There are two quantum solvers. VQD can return several eigenvalues; QAOA returns only the ground state.
20
+
21
+ VQD -> `run_vqd_eigensolver(matrix, k, use_noise=false)` -> lowest `k` eigenvalues (`k` defaults to all)
22
+ QAOA -> `run_qaoa_eigensolver(matrix, use_noise=false)` -> ground state only
23
+
24
+ **Uncertainties (`uq_values` / `uq_vectors`)**
25
+ - For every VQD/QAOA path (noiseless and noisy), at each final optimized circuit/state,
26
+ `uq_values[i] = sqrt(max(0, ⟨H²⟩ − ⟨H⟩²))`, where ⟨H⟩ is the reported eigenvalue and ⟨H²⟩
27
+ comes from the same estimator on `H @ H` at the same parameters.
28
+ This is the standard deviation of a single measurement of H in the prepared state
29
+ (intrinsic quantum / variational residual variance).
30
+ Exact eigenstates give σ ≈ 0; approximate ansatz states give nonzero σ even without noise.
31
+ - `uq_vectors` uses the same layout as the returned eigenvectors (column `i` = mode `i`).
32
+ For each physical basis index `j`,
33
+ `uq_vectors[j, i] = sqrt(p_j (1 − p_j))` where `p_j = ⟨|j⟩⟨j|⟩` is evaluated with the
34
+ **same estimator / circuit / parameters** as the energy (FakeManila when `use_noise=true`).
35
+ This is the std of a single-shot computational-basis occupation measurement for component `j`.
36
+ Caveat: it can be > 0 even for an exact delocalized eigenstate (unlike σ_H, which is 0 for
37
+ exact energy eigenstates). It is **not** “distance to the classical eigenvector.”
38
+ Unused eigenvector columns stay 0. Reported eigenvectors still come from the ideal
39
+ statevector of the optimized circuit; only the UQ uses the estimator/noise path.
40
+ - Non–power-of-2 dimensions pad to the next power of two and place
41
+ `penalty = max(1.0, Gershgorin row-sum bound)` on unused diagonal entries so pad
42
+ eigenvalues stay outside the original spectrum while avoiding the old 10× entry-scale
43
+ inflation of ⟨H²⟩ on small problems.
44
+ - Noisy VQD keeps exact statevector overlaps; only the energy / projector estimator uses
45
+ FakeManila noise (demo). Expect worse eigenvalues, especially for higher states.
46
+
47
+ Unit tests check that reported `uq_values` / filled `uq_vectors` entries are finite and
48
+ nonnegative (filled columns not identically zero on the demo matrix), and that on the
49
+ demo 3×3 matrix the ground-state interval `[⟨H⟩−σ, ⟨H⟩+σ]` contains the classical ground
50
+ eigenvalue for noisy paths. They do not require noisy eigenvalues to match the classical answer.
@@ -99,7 +99,9 @@ def _matrix_to_observable(flat_matrix, n):
99
99
  if next_pow2 != n:
100
100
  padded_mat = np.zeros((next_pow2, next_pow2))
101
101
  padded_mat[:n, :n] = mat
102
- penalty = 10.0 * max(1.0, float(np.max(np.abs(mat))))
102
+ # Pad unused diagonal with Gershgorin bound so fake eigenvalues stay outside.
103
+ gershgorin = float(np.max(np.sum(np.abs(mat), axis=1)))
104
+ penalty = max(1.0, gershgorin)
103
105
  for i in range(n, next_pow2):
104
106
  padded_mat[i, i] = penalty
105
107
  mat = padded_mat
@@ -119,12 +121,12 @@ def _make_estimator(use_noise):
119
121
  from qiskit_ibm_runtime.fake_provider import FakeManilaV2
120
122
  except ImportError as exc:
121
123
  raise ImportError(
122
- "Noisy QAOA requires qiskit-aer and qiskit-ibm-runtime. "
124
+ "Noisy solvers require qiskit-aer and qiskit-ibm-runtime. "
123
125
  "Install with: pip install qiskit-aer qiskit-ibm-runtime"
124
126
  ) from exc
125
127
 
126
128
  fake_backend = FakeManilaV2()
127
- noise_model = NoiseModel.from_backend(fake_backend, warnings=False)
129
+ noise_model = NoiseModel.from_backend(fake_backend)
128
130
  aer_simulator = AerSimulator(noise_model=noise_model)
129
131
  pass_manager = generate_preset_pass_manager(
130
132
  optimization_level=1, backend=aer_simulator
@@ -147,21 +149,36 @@ def _expect_energy(estimator, circuit, observable, parameters):
147
149
  return float(np.real(evs[0]))
148
150
 
149
151
 
150
- def _energy_diff_uncertainty(circuit, parameters, observable, noisy_estimator):
151
- exact_energy = _expect_energy(
152
- StatevectorEstimator(), circuit, observable, parameters
152
+ def _quantum_variance_std(estimator, circuit, observable, parameters, h_mean):
153
+ # Quantum std of H in this state: sqrt(max(0, <H^2> - <H>^2)).
154
+ h2 = _expect_energy(
155
+ estimator, circuit, observable @ observable, parameters
153
156
  )
154
- noisy_energy = _expect_energy(
155
- noisy_estimator, circuit, observable, parameters
156
- )
157
- # Predicted noise = |E_noisy - E_exact| on the final circuit
158
- return abs(noisy_energy - exact_energy)
157
+ return float(np.sqrt(max(0.0, h2 - h_mean**2)))
158
+
159
+
160
+ def _occupation_stds(estimator, circuit, parameters, n, next_pow2):
161
+ # Occupation std per component: sqrt(p (1 - p)) for basis outcome probability p.
162
+ stds = np.zeros(n, dtype=float)
163
+ for j in range(n):
164
+ proj = np.zeros((next_pow2, next_pow2), dtype=float)
165
+ proj[j, j] = 1.0
166
+ p_j = _expect_energy(
167
+ estimator, circuit, SparsePauliOp.from_operator(proj), parameters
168
+ )
169
+ p_j = min(1.0, max(0.0, p_j))
170
+ stds[j] = float(np.sqrt(max(0.0, p_j - p_j * p_j)))
171
+ return stds
159
172
 
160
173
 
161
- def run_vqd_eigensolver(flat_matrix, n, k=None):
174
+ def run_vqd_eigensolver(flat_matrix, n, k=None, use_noise=False):
162
175
  """
163
176
  Takes a flat matrix of size n*n, and returns the lowest k eigenvalues
164
177
  and matching eigenvectors using VQD.
178
+
179
+ With use_noise=True, only the energy estimator is noisy (FakeManila);
180
+ VQD still recognizes distinct states perfectly.
181
+ Expect worse eigenvalues, especially for k > 1.
165
182
  """
166
183
  if k is None:
167
184
  k = n
@@ -172,9 +189,14 @@ def run_vqd_eigensolver(flat_matrix, n, k=None):
172
189
  num_qubits = int(np.log2(next_pow2))
173
190
 
174
191
  ansatz = EfficientSU2(num_qubits, reps=1, entanglement="linear")
175
- optimizer = SLSQP(maxiter=1000, ftol=1e-9)
176
- estimator = StatevectorEstimator()
192
+ estimator, pass_manager = _make_estimator(use_noise)
193
+ # Keep exact fidelity even under noise: overlaps stay exact; only energy
194
+ # is FakeManila-noisy (same demo style as QAOA).
177
195
  fidelity = _ExactStatevectorFidelity()
196
+ if use_noise:
197
+ optimizer = COBYLA(maxiter=50)
198
+ else:
199
+ optimizer = SLSQP(maxiter=1000, ftol=1e-9)
178
200
 
179
201
  # Overlap weights on the scale of the original matrix, not the padding.
180
202
  beta = 10.0 * max(
@@ -191,7 +213,18 @@ def run_vqd_eigensolver(flat_matrix, n, k=None):
191
213
  rng.uniform(-np.pi, np.pi, ansatz.num_parameters)
192
214
  )
193
215
 
194
- vqd = VQD(estimator, fidelity, ansatz, optimizer, k=k, betas=betas)
216
+ if use_noise:
217
+ vqd = VQD(
218
+ estimator,
219
+ fidelity,
220
+ ansatz,
221
+ optimizer,
222
+ k=k,
223
+ betas=betas,
224
+ transpiler=pass_manager,
225
+ )
226
+ else:
227
+ vqd = VQD(estimator, fidelity, ansatz, optimizer, k=k, betas=betas)
195
228
  vqd.initial_point = initial_points
196
229
 
197
230
  result = vqd.compute_eigenvalues(observable)
@@ -199,13 +232,38 @@ def run_vqd_eigensolver(flat_matrix, n, k=None):
199
232
  eigenvalues = [float(np.real(e)) for e in result.eigenvalues]
200
233
  eigenvectors = np.zeros((n, n), dtype=float)
201
234
  for i in range(k):
235
+ optimal_circuit = result.optimal_circuits[i]
236
+ optimal_parameters = result.optimal_points[i]
202
237
  eigenvectors[:, i] = _statevector_to_real_eigenvector(
203
- result.optimal_circuits[i], result.optimal_points[i], n
238
+ optimal_circuit, optimal_parameters, n
204
239
  )
240
+
205
241
  uq_values = [0.0] * len(eigenvalues)
206
- uq_vectors = [0.0] * (n * n)
242
+ uq_vectors = np.zeros((n, n), dtype=float)
243
+ for i in range(k):
244
+ optimal_circuit = result.optimal_circuits[i]
245
+ optimal_parameters = result.optimal_points[i]
246
+ uq_values[i] = _quantum_variance_std(
247
+ estimator,
248
+ optimal_circuit,
249
+ observable,
250
+ optimal_parameters,
251
+ eigenvalues[i],
252
+ )
253
+ uq_vectors[:, i] = _occupation_stds(
254
+ estimator,
255
+ optimal_circuit,
256
+ optimal_parameters,
257
+ n,
258
+ next_pow2,
259
+ )
207
260
 
208
- return eigenvalues, eigenvectors.ravel().tolist(), uq_values, uq_vectors
261
+ return (
262
+ eigenvalues,
263
+ eigenvectors.ravel().tolist(),
264
+ uq_values,
265
+ uq_vectors.ravel().tolist(),
266
+ )
209
267
 
210
268
 
211
269
  def run_qaoa_eigensolver(flat_matrix, n, use_noise=False, reps=3):
@@ -213,7 +271,7 @@ def run_qaoa_eigensolver(flat_matrix, n, use_noise=False, reps=3):
213
271
  Takes a flat matrix of size n*n, and returns the ground eigenvalue,
214
272
  and matching eigenvector using QAOA.
215
273
  """
216
- observable, _ = _matrix_to_observable(flat_matrix, n)
274
+ observable, next_pow2 = _matrix_to_observable(flat_matrix, n)
217
275
  ansatz = QAOAAnsatz(observable, reps=reps)
218
276
  estimator, pass_manager = _make_estimator(use_noise)
219
277
  if use_noise:
@@ -227,44 +285,87 @@ def run_qaoa_eigensolver(flat_matrix, n, use_noise=False, reps=3):
227
285
 
228
286
  result = vqe.compute_minimum_eigenvalue(observable)
229
287
 
288
+ optimal_circuit = result.optimal_circuit
289
+ optimal_parameters = result.optimal_point
290
+
230
291
  eigenvalues = [float(np.real(result.eigenvalue))]
231
292
  eigenvectors = np.zeros((n, n), dtype=float)
232
293
  eigenvectors[:, 0] = _statevector_to_real_eigenvector(
233
- result.optimal_circuit, result.optimal_point, n
294
+ optimal_circuit, optimal_parameters, n
234
295
  )
235
296
 
236
297
  uq_values = [0.0] * len(eigenvalues)
237
- uq_vectors = [0.0] * (n * n)
238
- if use_noise:
239
- uq_values[0] = _energy_diff_uncertainty(
240
- result.optimal_circuit, result.optimal_point, observable, estimator
241
- )
298
+ uq_vectors = np.zeros((n, n), dtype=float)
299
+ uq_values[0] = _quantum_variance_std(
300
+ estimator,
301
+ optimal_circuit,
302
+ observable,
303
+ optimal_parameters,
304
+ eigenvalues[0],
305
+ )
306
+ uq_vectors[:, 0] = _occupation_stds(
307
+ estimator,
308
+ optimal_circuit,
309
+ optimal_parameters,
310
+ n,
311
+ next_pow2,
312
+ )
242
313
 
243
- return eigenvalues, eigenvectors.ravel().tolist(), uq_values, uq_vectors
314
+ return (
315
+ eigenvalues,
316
+ eigenvectors.ravel().tolist(),
317
+ uq_values,
318
+ uq_vectors.ravel().tolist(),
319
+ )
244
320
 
245
321
 
246
322
  # Quick Test
247
323
  if __name__ == "__main__":
248
324
  # The same 3x3 matrix from the C++ test file
249
325
  test_matrix = [3.0, 5.0, 2.0, 5.0, 1.0, 3.0, 2.0, 3.0, 2.0]
250
- values, vectors = run_vqd_eigensolver(test_matrix, 3)
251
- print(f"VQD Eigenvalues: {values}")
252
- print(f"VQD Eigenvectors: {vectors}")
326
+
327
+ print("=== VQD (noiseless) ===")
328
+ values, vectors, vqd_uq_v, vqd_uq_vec = run_vqd_eigensolver(test_matrix, 3)
329
+ print(f"Eigenvalues: {values}")
330
+ print(f"Eigenvectors: {vectors}")
331
+ print(f"uq_values: {vqd_uq_v}")
332
+ print(f"uq_vectors: {vqd_uq_vec}")
333
+
334
+ try:
335
+ print("\n=== VQD (noise) ===")
336
+ (
337
+ vqd_noisy_values,
338
+ vqd_noisy_vectors,
339
+ vqd_noisy_uq_v,
340
+ vqd_noisy_uq_vec,
341
+ ) = run_vqd_eigensolver(test_matrix, 3, use_noise=True)
342
+ print(f"Eigenvalues: {vqd_noisy_values}")
343
+ print(f"Eigenvectors: {vqd_noisy_vectors}")
344
+ print(f"uq_values: {vqd_noisy_uq_v}")
345
+ print(f"uq_vectors: {vqd_noisy_uq_vec}")
346
+ except ImportError as exc:
347
+ print(f"Skipping noisy VQD demo: {exc}")
348
+
349
+ print("\n=== QAOA (noiseless) ===")
253
350
  qaoa_values, qaoa_vectors, qaoa_uq_v, qaoa_uq_vec = run_qaoa_eigensolver(
254
351
  test_matrix, 3
255
352
  )
256
- print(f"QAOA Eigenvalue: {qaoa_values}")
257
- print(f"QAOA Eigenvector: {qaoa_vectors}")
258
- print(f"QAOA uq_values: {qaoa_uq_v}")
353
+ print(f"Eigenvalue: {qaoa_values}")
354
+ print(f"Eigenvector: {qaoa_vectors}")
355
+ print(f"uq_values: {qaoa_uq_v}")
356
+ print(f"uq_vectors: {qaoa_uq_vec}")
357
+
259
358
  try:
359
+ print("\n=== QAOA (noise) ===")
260
360
  (
261
361
  qaoa_noisy_values,
262
362
  qaoa_noisy_vectors,
263
363
  noisy_uq_v,
264
364
  noisy_uq_vec,
265
365
  ) = run_qaoa_eigensolver(test_matrix, 3, use_noise=True)
266
- print(f"QAOA Eigenvalue (noise): {qaoa_noisy_values}")
267
- print(f"QAOA Eigenvector (noise): {qaoa_noisy_vectors}")
268
- print(f"QAOA uq_values (noise): {noisy_uq_v}")
366
+ print(f"Eigenvalue: {qaoa_noisy_values}")
367
+ print(f"Eigenvector: {qaoa_noisy_vectors}")
368
+ print(f"uq_values: {noisy_uq_v}")
369
+ print(f"uq_vectors: {noisy_uq_vec}")
269
370
  except ImportError as exc:
270
371
  print(f"Skipping noisy QAOA demo: {exc}")
@@ -0,0 +1,77 @@
1
+ Metadata-Version: 2.4
2
+ Name: qharm-eigenbridge
3
+ Version: 0.0.3
4
+ Summary: Quantum eigensolver implementation using Qiskit
5
+ Author-email: Jonathan Waldrop <jwaldrop@ameslab.gov>, Mahir Anand <mahiranand@outlook.com>
6
+ Classifier: Development Status :: 4 - Beta
7
+ Classifier: Programming Language :: Python :: 3 :: Only
8
+ Classifier: Programming Language :: Python :: 3.9
9
+ Classifier: Programming Language :: Python :: 3.10
10
+ Classifier: Programming Language :: Python :: 3.11
11
+ Classifier: Programming Language :: Python :: 3.12
12
+ Classifier: Programming Language :: Python :: 3.13
13
+ Classifier: Programming Language :: Python :: 3.14
14
+ Requires-Python: >=3.9
15
+ Description-Content-Type: text/markdown
16
+ License-File: LICENSE
17
+ Requires-Dist: numpy
18
+ Requires-Dist: pybind11
19
+ Requires-Dist: qiskit
20
+ Requires-Dist: qiskit-algorithms
21
+ Requires-Dist: qiskit-aer
22
+ Requires-Dist: qiskit-ibm-runtime
23
+ Provides-Extra: dev
24
+ Requires-Dist: pre-commit; extra == "dev"
25
+ Requires-Dist: pytest; extra == "dev"
26
+ Dynamic: license-file
27
+
28
+ <!--
29
+ ~ Copyright 2026 QHARM
30
+ ~
31
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
32
+ ~ you may not use this file except in compliance with the License.
33
+ ~ You may obtain a copy of the License at
34
+ ~
35
+ ~ http://www.apache.org/licenses/LICENSE-2.0
36
+ ~
37
+ ~ Unless required by applicable law or agreed to in writing, software
38
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
39
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
40
+ ~ See the License for the specific language governing permissions and
41
+ ~ limitations under the License.
42
+ -->
43
+
44
+ # EigenBridge
45
+
46
+ There are two quantum solvers. VQD can return several eigenvalues; QAOA returns only the ground state.
47
+
48
+ VQD -> `run_vqd_eigensolver(matrix, k, use_noise=false)` -> lowest `k` eigenvalues (`k` defaults to all)
49
+ QAOA -> `run_qaoa_eigensolver(matrix, use_noise=false)` -> ground state only
50
+
51
+ **Uncertainties (`uq_values` / `uq_vectors`)**
52
+ - For every VQD/QAOA path (noiseless and noisy), at each final optimized circuit/state,
53
+ `uq_values[i] = sqrt(max(0, ⟨H²⟩ − ⟨H⟩²))`, where ⟨H⟩ is the reported eigenvalue and ⟨H²⟩
54
+ comes from the same estimator on `H @ H` at the same parameters.
55
+ This is the standard deviation of a single measurement of H in the prepared state
56
+ (intrinsic quantum / variational residual variance).
57
+ Exact eigenstates give σ ≈ 0; approximate ansatz states give nonzero σ even without noise.
58
+ - `uq_vectors` uses the same layout as the returned eigenvectors (column `i` = mode `i`).
59
+ For each physical basis index `j`,
60
+ `uq_vectors[j, i] = sqrt(p_j (1 − p_j))` where `p_j = ⟨|j⟩⟨j|⟩` is evaluated with the
61
+ **same estimator / circuit / parameters** as the energy (FakeManila when `use_noise=true`).
62
+ This is the std of a single-shot computational-basis occupation measurement for component `j`.
63
+ Caveat: it can be > 0 even for an exact delocalized eigenstate (unlike σ_H, which is 0 for
64
+ exact energy eigenstates). It is **not** “distance to the classical eigenvector.”
65
+ Unused eigenvector columns stay 0. Reported eigenvectors still come from the ideal
66
+ statevector of the optimized circuit; only the UQ uses the estimator/noise path.
67
+ - Non–power-of-2 dimensions pad to the next power of two and place
68
+ `penalty = max(1.0, Gershgorin row-sum bound)` on unused diagonal entries so pad
69
+ eigenvalues stay outside the original spectrum while avoiding the old 10× entry-scale
70
+ inflation of ⟨H²⟩ on small problems.
71
+ - Noisy VQD keeps exact statevector overlaps; only the energy / projector estimator uses
72
+ FakeManila noise (demo). Expect worse eigenvalues, especially for higher states.
73
+
74
+ Unit tests check that reported `uq_values` / filled `uq_vectors` entries are finite and
75
+ nonnegative (filled columns not identically zero on the demo matrix), and that on the
76
+ demo 3×3 matrix the ground-state interval `[⟨H⟩−σ, ⟨H⟩+σ]` contains the classical ground
77
+ eigenvalue for noisy paths. They do not require noisy eigenvalues to match the classical answer.
@@ -0,0 +1,8 @@
1
+ {
2
+ "tag": "0.0.3",
3
+ "distance": 0,
4
+ "node": "gb816fc1c82456f18c3537b46b5fbe7c0cd08ccfd",
5
+ "dirty": false,
6
+ "branch": "main",
7
+ "node_date": "2026-09-25"
8
+ }
@@ -0,0 +1,187 @@
1
+ # Copyright 2026 QHARM
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ import unittest
16
+
17
+ import eigenbridge
18
+
19
+
20
+ class TestEigensolvers(unittest.TestCase):
21
+ def setUp(self):
22
+ # Define a 3x3 matrix
23
+ self.flat_matrix = [3.0, 5.0, 2.0, 5.0, 1.0, 3.0, 2.0, 3.0, 2.0]
24
+ # Correct results
25
+ self.correct_eigenvalues = [
26
+ -3.3610452994996525,
27
+ 0.5038738768058354,
28
+ 8.8571714226938152,
29
+ ]
30
+ self.correct_eigenvectors = [
31
+ -0.5518254419285664,
32
+ -0.5057445690691208,
33
+ -0.6631071651682192,
34
+ 0.7984036023978691,
35
+ -0.0906811731252565,
36
+ -0.5952550818924042,
37
+ -0.2409156892326610,
38
+ 0.8579040480716453,
39
+ -0.4538284642723896,
40
+ ]
41
+
42
+ def _assert_finite_nonnegative(self, uq):
43
+ self.assertTrue(uq == uq and abs(uq) != float("inf"))
44
+ self.assertGreaterEqual(uq, 0.0)
45
+
46
+ def _assert_finite_positive(self, uq):
47
+ self._assert_finite_nonnegative(uq)
48
+ self.assertGreater(uq, 0.0)
49
+
50
+ def _check_uq_vectors(self, eigenvectors, uq_vectors, n=3, k_filled=None):
51
+ # uq_vectors: sqrt(p(1-p)) occupation stds; unused columns stay 0.
52
+ self.assertEqual(len(uq_vectors), len(eigenvectors))
53
+ self.assertEqual(len(uq_vectors), n * n)
54
+ for uq in uq_vectors:
55
+ self._assert_finite_nonnegative(uq)
56
+ if k_filled is None:
57
+ k_filled = n
58
+ for col in range(n):
59
+ col_uq = [uq_vectors[row * n + col] for row in range(n)]
60
+ if col < k_filled:
61
+ self.assertGreater(max(col_uq), 0.0)
62
+ else:
63
+ self.assertTrue(all(u == 0.0 for u in col_uq))
64
+
65
+ def _check_results(
66
+ self,
67
+ results,
68
+ val_places=14,
69
+ vec_places=14,
70
+ require_positive_uq=False,
71
+ k_filled=None,
72
+ ):
73
+ # Check the results
74
+ eigenvalues, eigenvectors, uq_values, uq_vectors = results
75
+ for i in zip(eigenvalues, self.correct_eigenvalues):
76
+ self.assertAlmostEqual(i[0], i[1], places=val_places)
77
+ for i in zip(eigenvectors, self.correct_eigenvectors):
78
+ self.assertAlmostEqual(abs(i[0]), abs(i[1]), places=vec_places)
79
+ # Energy UQs for returned modes: >= 0, or > 0 if require_positive_uq.
80
+ n_returned = sum(1 for v in self.correct_eigenvalues if v != 0.0)
81
+ if n_returned == 0:
82
+ n_returned = len(eigenvalues)
83
+ for i, uq in enumerate(uq_values):
84
+ if i < n_returned:
85
+ if require_positive_uq:
86
+ self._assert_finite_positive(uq)
87
+ else:
88
+ self._assert_finite_nonnegative(uq)
89
+ else:
90
+ self.assertEqual(uq, 0.0)
91
+ if k_filled is None:
92
+ k_filled = n_returned
93
+ self._check_uq_vectors(
94
+ eigenvectors, uq_vectors, n=3, k_filled=k_filled
95
+ )
96
+
97
+ def test_vqd_eigensolver(self):
98
+ results = eigenbridge.run_vqd_eigensolver(self.flat_matrix, n=3)
99
+ self._check_results(results, val_places=8, vec_places=4, k_filled=3)
100
+ eigenvalues, _, uq_values, _ = results
101
+ self.assertLessEqual(
102
+ eigenvalues[0] - uq_values[0], self.correct_eigenvalues[0]
103
+ )
104
+ self.assertLessEqual(
105
+ self.correct_eigenvalues[0], eigenvalues[0] + uq_values[0]
106
+ )
107
+
108
+ def test_vqd_eigensolver_noise(self):
109
+ # Does not require eigenvalues to match LAPACK, since Noisy VQD is a demo.
110
+ try:
111
+ (
112
+ eigenvalues,
113
+ eigenvectors,
114
+ uq_values,
115
+ uq_vectors,
116
+ ) = eigenbridge.run_vqd_eigensolver(
117
+ self.flat_matrix, n=3, use_noise=True
118
+ )
119
+ except ImportError as exc:
120
+ self.skipTest(f"Noisy VQD deps missing: {exc}")
121
+
122
+ self.assertEqual(len(eigenvalues), 3)
123
+ self.assertEqual(len(uq_values), 3)
124
+ for uq in uq_values:
125
+ self._assert_finite_positive(uq)
126
+ self._check_uq_vectors(eigenvectors, uq_vectors, n=3, k_filled=3)
127
+ # Sanity check on this demo matrix only — not a universal guarantee.
128
+ self.assertLessEqual(
129
+ eigenvalues[0] - uq_values[0], self.correct_eigenvalues[0]
130
+ )
131
+ self.assertLessEqual(
132
+ self.correct_eigenvalues[0], eigenvalues[0] + uq_values[0]
133
+ )
134
+
135
+ def test_qaoa_eigensolver(self):
136
+ # Adjust the correct eigenvalues and eigenvectors for QAOA's output
137
+ # The QAOA solver will not return all eigenvalues/eigenvectors, so we
138
+ # zero out the ones that are not expected to be returned.
139
+ for i in range(len(self.correct_eigenvalues)):
140
+ if i % 3 != 0:
141
+ self.correct_eigenvalues[i] = 0.0
142
+ for i in range(len(self.correct_eigenvectors)):
143
+ if i % 3 != 0:
144
+ self.correct_eigenvectors[i] = 0.0
145
+ results = eigenbridge.run_qaoa_eigensolver(
146
+ self.flat_matrix, n=3, use_noise=False
147
+ )
148
+ # New gershgorin padding changes the QAOA cost Hamiltonian / landscape slightly
149
+ self._check_results(
150
+ results,
151
+ val_places=0,
152
+ vec_places=0,
153
+ require_positive_uq=True,
154
+ k_filled=1,
155
+ )
156
+ eigenvalues, _, uq_values, _ = results
157
+ self.assertLessEqual(
158
+ eigenvalues[0] - uq_values[0], self.correct_eigenvalues[0]
159
+ )
160
+ self.assertLessEqual(
161
+ self.correct_eigenvalues[0], eigenvalues[0] + uq_values[0]
162
+ )
163
+
164
+ def test_qaoa_eigensolver_noise(self):
165
+ try:
166
+ (
167
+ eigenvalues,
168
+ eigenvectors,
169
+ uq_values,
170
+ uq_vectors,
171
+ ) = eigenbridge.run_qaoa_eigensolver(
172
+ self.flat_matrix, n=3, use_noise=True
173
+ )
174
+ except ImportError as exc:
175
+ self.skipTest(f"Noisy QAOA deps missing: {exc}")
176
+
177
+ self._assert_finite_positive(uq_values[0])
178
+ for uq in uq_values[1:]:
179
+ self.assertEqual(uq, 0.0)
180
+ self._check_uq_vectors(eigenvectors, uq_vectors, n=3, k_filled=1)
181
+ # Sanity check on this demo matrix only, not a universal guarantee.
182
+ self.assertLessEqual(
183
+ eigenvalues[0] - uq_values[0], self.correct_eigenvalues[0]
184
+ )
185
+ self.assertLessEqual(
186
+ self.correct_eigenvalues[0], eigenvalues[0] + uq_values[0]
187
+ )
@@ -1,55 +0,0 @@
1
- Metadata-Version: 2.4
2
- Name: qharm-eigenbridge
3
- Version: 0.0.2
4
- Summary: Quantum eigensolver implementation using Qiskit
5
- Author-email: Jonathan Waldrop <jwaldrop@ameslab.gov>, Mahir Anand <mahiranand@outlook.com>
6
- Classifier: Development Status :: 4 - Beta
7
- Classifier: Programming Language :: Python :: 3 :: Only
8
- Classifier: Programming Language :: Python :: 3.9
9
- Classifier: Programming Language :: Python :: 3.10
10
- Classifier: Programming Language :: Python :: 3.11
11
- Classifier: Programming Language :: Python :: 3.12
12
- Classifier: Programming Language :: Python :: 3.13
13
- Classifier: Programming Language :: Python :: 3.14
14
- Requires-Python: >=3.9
15
- Description-Content-Type: text/markdown
16
- License-File: LICENSE
17
- Requires-Dist: numpy
18
- Requires-Dist: pybind11
19
- Requires-Dist: qiskit
20
- Requires-Dist: qiskit-algorithms
21
- Requires-Dist: qiskit-aer
22
- Requires-Dist: qiskit-ibm-runtime
23
- Provides-Extra: dev
24
- Requires-Dist: pre-commit; extra == "dev"
25
- Requires-Dist: pytest; extra == "dev"
26
- Dynamic: license-file
27
-
28
- <!--
29
- ~ Copyright 2026 QHARM
30
- ~
31
- ~ Licensed under the Apache License, Version 2.0 (the "License");
32
- ~ you may not use this file except in compliance with the License.
33
- ~ You may obtain a copy of the License at
34
- ~
35
- ~ http://www.apache.org/licenses/LICENSE-2.0
36
- ~
37
- ~ Unless required by applicable law or agreed to in writing, software
38
- ~ distributed under the License is distributed on an "AS IS" BASIS,
39
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
40
- ~ See the License for the specific language governing permissions and
41
- ~ limitations under the License.
42
- -->
43
-
44
- # EigenBridge
45
-
46
- There are two quantum solvers. VQD can return several eigenvalues; QAOA returns only the ground state.
47
-
48
- VQD -> `run_vqd_eigensolver(matrix, k)` -> `solve_vqd` -> lowest `k` eigenvalues (`k` defaults to all)
49
- QAOA -> `run_qaoa_eigensolver(matrix, use_noise=false)` -> `solve_qaoa` -> ground state only
50
-
51
- **Uncertainties (`uq_values` / `uq_vectors`)**
52
- - Noiseless solvers (LAPACK, VQD, noiseless QAOA): `uq_* = 0`
53
- - Noisy QAOA (`use_noise=true`): at the final circuit, `uq_values[0] = |E_noisy − E_exact|`; Unused slots and `uq_vectors` stay 0
54
-
55
- The noisy QAOA unit test checks that `uq_values[0] = |E_noisy − E_exact|` (at the final circuit) and `|λ_noisy − λ_LAPACK|` agree within a factor of 10 (ratio < 10).
@@ -1,28 +0,0 @@
1
- <!--
2
- ~ Copyright 2026 QHARM
3
- ~
4
- ~ Licensed under the Apache License, Version 2.0 (the "License");
5
- ~ you may not use this file except in compliance with the License.
6
- ~ You may obtain a copy of the License at
7
- ~
8
- ~ http://www.apache.org/licenses/LICENSE-2.0
9
- ~
10
- ~ Unless required by applicable law or agreed to in writing, software
11
- ~ distributed under the License is distributed on an "AS IS" BASIS,
12
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
- ~ See the License for the specific language governing permissions and
14
- ~ limitations under the License.
15
- -->
16
-
17
- # EigenBridge
18
-
19
- There are two quantum solvers. VQD can return several eigenvalues; QAOA returns only the ground state.
20
-
21
- VQD -> `run_vqd_eigensolver(matrix, k)` -> `solve_vqd` -> lowest `k` eigenvalues (`k` defaults to all)
22
- QAOA -> `run_qaoa_eigensolver(matrix, use_noise=false)` -> `solve_qaoa` -> ground state only
23
-
24
- **Uncertainties (`uq_values` / `uq_vectors`)**
25
- - Noiseless solvers (LAPACK, VQD, noiseless QAOA): `uq_* = 0`
26
- - Noisy QAOA (`use_noise=true`): at the final circuit, `uq_values[0] = |E_noisy − E_exact|`; Unused slots and `uq_vectors` stay 0
27
-
28
- The noisy QAOA unit test checks that `uq_values[0] = |E_noisy − E_exact|` (at the final circuit) and `|λ_noisy − λ_LAPACK|` agree within a factor of 10 (ratio < 10).
@@ -1,55 +0,0 @@
1
- Metadata-Version: 2.4
2
- Name: qharm-eigenbridge
3
- Version: 0.0.2
4
- Summary: Quantum eigensolver implementation using Qiskit
5
- Author-email: Jonathan Waldrop <jwaldrop@ameslab.gov>, Mahir Anand <mahiranand@outlook.com>
6
- Classifier: Development Status :: 4 - Beta
7
- Classifier: Programming Language :: Python :: 3 :: Only
8
- Classifier: Programming Language :: Python :: 3.9
9
- Classifier: Programming Language :: Python :: 3.10
10
- Classifier: Programming Language :: Python :: 3.11
11
- Classifier: Programming Language :: Python :: 3.12
12
- Classifier: Programming Language :: Python :: 3.13
13
- Classifier: Programming Language :: Python :: 3.14
14
- Requires-Python: >=3.9
15
- Description-Content-Type: text/markdown
16
- License-File: LICENSE
17
- Requires-Dist: numpy
18
- Requires-Dist: pybind11
19
- Requires-Dist: qiskit
20
- Requires-Dist: qiskit-algorithms
21
- Requires-Dist: qiskit-aer
22
- Requires-Dist: qiskit-ibm-runtime
23
- Provides-Extra: dev
24
- Requires-Dist: pre-commit; extra == "dev"
25
- Requires-Dist: pytest; extra == "dev"
26
- Dynamic: license-file
27
-
28
- <!--
29
- ~ Copyright 2026 QHARM
30
- ~
31
- ~ Licensed under the Apache License, Version 2.0 (the "License");
32
- ~ you may not use this file except in compliance with the License.
33
- ~ You may obtain a copy of the License at
34
- ~
35
- ~ http://www.apache.org/licenses/LICENSE-2.0
36
- ~
37
- ~ Unless required by applicable law or agreed to in writing, software
38
- ~ distributed under the License is distributed on an "AS IS" BASIS,
39
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
40
- ~ See the License for the specific language governing permissions and
41
- ~ limitations under the License.
42
- -->
43
-
44
- # EigenBridge
45
-
46
- There are two quantum solvers. VQD can return several eigenvalues; QAOA returns only the ground state.
47
-
48
- VQD -> `run_vqd_eigensolver(matrix, k)` -> `solve_vqd` -> lowest `k` eigenvalues (`k` defaults to all)
49
- QAOA -> `run_qaoa_eigensolver(matrix, use_noise=false)` -> `solve_qaoa` -> ground state only
50
-
51
- **Uncertainties (`uq_values` / `uq_vectors`)**
52
- - Noiseless solvers (LAPACK, VQD, noiseless QAOA): `uq_* = 0`
53
- - Noisy QAOA (`use_noise=true`): at the final circuit, `uq_values[0] = |E_noisy − E_exact|`; Unused slots and `uq_vectors` stay 0
54
-
55
- The noisy QAOA unit test checks that `uq_values[0] = |E_noisy − E_exact|` (at the final circuit) and `|λ_noisy − λ_LAPACK|` agree within a factor of 10 (ratio < 10).
@@ -1,8 +0,0 @@
1
- {
2
- "tag": "0.0.2",
3
- "distance": 0,
4
- "node": "g4e9a0a279e66d7ca617ba5c9e3270f3580a2e3f0",
5
- "dirty": false,
6
- "branch": "main",
7
- "node_date": "2026-09-01"
8
- }
@@ -1,82 +0,0 @@
1
- # Copyright 2026 QHARM
2
- #
3
- # Licensed under the Apache License, Version 2.0 (the "License");
4
- # you may not use this file except in compliance with the License.
5
- # You may obtain a copy of the License at
6
- #
7
- # http://www.apache.org/licenses/LICENSE-2.0
8
- #
9
- # Unless required by applicable law or agreed to in writing, software
10
- # distributed under the License is distributed on an "AS IS" BASIS,
11
- # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
- # See the License for the specific language governing permissions and
13
- # limitations under the License.
14
-
15
- import unittest
16
-
17
- import eigenbridge
18
-
19
-
20
- class TestEigensolvers(unittest.TestCase):
21
- def setUp(self):
22
- # Define a 3x3 matrix
23
- self.flat_matrix = [3.0, 5.0, 2.0, 5.0, 1.0, 3.0, 2.0, 3.0, 2.0]
24
- # Correct results
25
- self.correct_eigenvalues = [
26
- -3.3610452994996525,
27
- 0.5038738768058354,
28
- 8.8571714226938152,
29
- ]
30
- self.correct_eigenvectors = [
31
- -0.5518254419285664,
32
- -0.5057445690691208,
33
- -0.6631071651682192,
34
- 0.7984036023978691,
35
- -0.0906811731252565,
36
- -0.5952550818924042,
37
- -0.2409156892326610,
38
- 0.8579040480716453,
39
- -0.4538284642723896,
40
- ]
41
-
42
- def _check_results(
43
- self,
44
- results,
45
- val_places=14,
46
- vec_places=14,
47
- uq_val=1e-16,
48
- uq_vec=1e-16,
49
- ):
50
- # Check the results
51
- eigenvalues, eigenvectors, uq_values, uq_vectors = results
52
- for i in zip(eigenvalues, self.correct_eigenvalues):
53
- self.assertAlmostEqual(i[0], i[1], places=val_places)
54
- for i in zip(eigenvectors, self.correct_eigenvectors):
55
- self.assertAlmostEqual(abs(i[0]), abs(i[1]), places=vec_places)
56
- for i in uq_values:
57
- self.assertEqual(i, uq_val)
58
- for i in uq_vectors:
59
- self.assertEqual(i, uq_vec)
60
-
61
- def test_vqd_eigensolver(self):
62
- results = eigenbridge.run_vqd_eigensolver(self.flat_matrix, n=3)
63
- self._check_results(
64
- results, val_places=8, vec_places=4, uq_val=0.0, uq_vec=0.0
65
- )
66
-
67
- def test_qaoa_eigensolver(self):
68
- # Adjust the correct eigenvalues and eigenvectors for QAOA's output
69
- # The QAOA solver will not return all eigenvalues/eigenvectors, so we
70
- # zero out the ones that are not expected to be returned.
71
- for i in range(len(self.correct_eigenvalues)):
72
- if i % 3 != 0:
73
- self.correct_eigenvalues[i] = 0.0
74
- for i in range(len(self.correct_eigenvectors)):
75
- if i % 3 != 0:
76
- self.correct_eigenvectors[i] = 0.0
77
- results = eigenbridge.run_qaoa_eigensolver(
78
- self.flat_matrix, n=3, use_noise=False
79
- )
80
- self._check_results(
81
- results, val_places=8, vec_places=4, uq_val=0.0, uq_vec=0.0
82
- )