Skip to content

Commit

Permalink
Use eigh, eigsh in NumPyEigensolver (Qiskit/qiskit#6987)
Browse files Browse the repository at this point in the history
* Use eigh, eigsh

* add is_hermitian method

* add is_hermitian method to OperatorBase

* rm unnecessary files

* modify releasenot

* Apply suggestions from code review

Co-authored-by: Jake Lishman <[email protected]>

* fix test name

* Update releasenotes/notes/add-opflow-is-hermitian-method-6a461549e3c6b32c.yaml

Co-authored-by: Jake Lishman <[email protected]>

Co-authored-by: Jake Lishman <[email protected]>
  • Loading branch information
ikkoham and jakelishman authored Oct 13, 2021
1 parent 656aa04 commit 4bdfb8e
Show file tree
Hide file tree
Showing 3 changed files with 34 additions and 16 deletions.
23 changes: 16 additions & 7 deletions qiskit_algorithms/eigen_solvers/numpy_eigen_solver.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,15 +13,16 @@
"""The Eigensolver algorithm."""

import logging
from typing import List, Optional, Union, Tuple, Callable
from typing import Callable, List, Optional, Tuple, Union

import numpy as np
from scipy import sparse as scisparse

from qiskit.opflow import OperatorBase, I, StateFn, ListOp
from qiskit.opflow import I, ListOp, OperatorBase, StateFn
from qiskit.utils.validation import validate_min
from .eigen_solver import Eigensolver, EigensolverResult

from ..exceptions import AlgorithmError
from .eigen_solver import Eigensolver, EigensolverResult

logger = logging.getLogger(__name__)

Expand Down Expand Up @@ -125,11 +126,19 @@ def _solve(self, operator: OperatorBase) -> None:
else:
if self._k >= 2 ** operator.num_qubits - 1:
logger.debug("SciPy doesn't support to get all eigenvalues, using NumPy instead.")
eigval, eigvec = np.linalg.eig(operator.to_matrix())
if operator.is_hermitian():
eigval, eigvec = np.linalg.eigh(operator.to_matrix())
else:
eigval, eigvec = np.linalg.eig(operator.to_matrix())
else:
eigval, eigvec = scisparse.linalg.eigs(
operator.to_spmatrix(), k=self._k, which="SR"
)
if operator.is_hermitian():
eigval, eigvec = scisparse.linalg.eigsh(
operator.to_spmatrix(), k=self._k, which="SA"
)
else:
eigval, eigvec = scisparse.linalg.eigs(
operator.to_spmatrix(), k=self._k, which="SR"
)
indices = np.argsort(eigval)[: self._k]
eigval = eigval[indices]
eigvec = eigvec[:, indices]
Expand Down
9 changes: 6 additions & 3 deletions test/test_numpy_eigen_solver.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,16 +44,18 @@ def test_ce(self):
result = algo.compute_eigenvalues(operator=self.qubit_op, aux_operators=[])
self.assertEqual(len(result.eigenvalues), 1)
self.assertEqual(len(result.eigenstates), 1)
self.assertAlmostEqual(result.eigenvalues[0], -1.85727503 + 0j)
self.assertEqual(result.eigenvalues.dtype, np.float64)
self.assertAlmostEqual(result.eigenvalues[0], -1.85727503)

def test_ce_k4(self):
"""Test for k=4 eigenvalues"""
algo = NumPyEigensolver(k=4)
result = algo.compute_eigenvalues(operator=self.qubit_op, aux_operators=[])
self.assertEqual(len(result.eigenvalues), 4)
self.assertEqual(len(result.eigenstates), 4)
self.assertEqual(result.eigenvalues.dtype, np.float64)
np.testing.assert_array_almost_equal(
result.eigenvalues.real, [-1.85727503, -1.24458455, -0.88272215, -0.22491125]
result.eigenvalues, [-1.85727503, -1.24458455, -0.88272215, -0.22491125]
)

def test_ce_k4_filtered(self):
Expand All @@ -68,7 +70,8 @@ def criterion(x, v, a_v):
result = algo.compute_eigenvalues(operator=self.qubit_op, aux_operators=[])
self.assertEqual(len(result.eigenvalues), 2)
self.assertEqual(len(result.eigenstates), 2)
np.testing.assert_array_almost_equal(result.eigenvalues.real, [-0.88272215, -0.22491125])
self.assertEqual(result.eigenvalues.dtype, np.float64)
np.testing.assert_array_almost_equal(result.eigenvalues, [-0.88272215, -0.22491125])

def test_ce_k4_filtered_empty(self):
"""Test for k=4 eigenvalues with filter always returning False"""
Expand Down
18 changes: 12 additions & 6 deletions test/test_numpy_minimum_eigen_solver.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,8 @@ def test_cme(self):
"""Basic test"""
algo = NumPyMinimumEigensolver()
result = algo.compute_minimum_eigenvalue(operator=self.qubit_op, aux_operators=self.aux_ops)
self.assertAlmostEqual(result.eigenvalue, -1.85727503 + 0j)
self.assertEqual(result.eigenvalue.dtype, np.float64)
self.assertAlmostEqual(result.eigenvalue, -1.85727503)
self.assertEqual(len(result.aux_operator_eigenvalues), 2)
np.testing.assert_array_almost_equal(result.aux_operator_eigenvalues[0], [2, 0])
np.testing.assert_array_almost_equal(result.aux_operator_eigenvalues[1], [0, 0])
Expand All @@ -56,24 +57,28 @@ def test_cme_reuse(self):
# Start with no operator or aux_operators, give via compute method
algo = NumPyMinimumEigensolver()
result = algo.compute_minimum_eigenvalue(operator=self.qubit_op)
self.assertAlmostEqual(result.eigenvalue, -1.85727503 + 0j)
self.assertEqual(result.eigenvalue.dtype, np.float64)
self.assertAlmostEqual(result.eigenvalue, -1.85727503)
self.assertIsNone(result.aux_operator_eigenvalues)

# Add aux_operators and go again
result = algo.compute_minimum_eigenvalue(operator=self.qubit_op, aux_operators=self.aux_ops)
self.assertAlmostEqual(result.eigenvalue, -1.85727503 + 0j)
self.assertEqual(result.eigenvalue.dtype, np.float64)
self.assertAlmostEqual(result.eigenvalue, -1.85727503)
self.assertEqual(len(result.aux_operator_eigenvalues), 2)
np.testing.assert_array_almost_equal(result.aux_operator_eigenvalues[0], [2, 0])
np.testing.assert_array_almost_equal(result.aux_operator_eigenvalues[1], [0, 0])

# "Remove" aux_operators and go again
result = algo.compute_minimum_eigenvalue(operator=self.qubit_op, aux_operators=[])
self.assertAlmostEqual(result.eigenvalue, -1.85727503 + 0j)
self.assertEqual(result.eigenvalue.dtype, np.float64)
self.assertAlmostEqual(result.eigenvalue, -1.85727503)
self.assertIsNone(result.aux_operator_eigenvalues)

# Set aux_operators and go again
result = algo.compute_minimum_eigenvalue(operator=self.qubit_op, aux_operators=self.aux_ops)
self.assertAlmostEqual(result.eigenvalue, -1.85727503 + 0j)
self.assertEqual(result.eigenvalue.dtype, np.float64)
self.assertAlmostEqual(result.eigenvalue, -1.85727503)
self.assertEqual(len(result.aux_operator_eigenvalues), 2)
np.testing.assert_array_almost_equal(result.aux_operator_eigenvalues[0], [2, 0])
np.testing.assert_array_almost_equal(result.aux_operator_eigenvalues[1], [0, 0])
Expand All @@ -93,7 +98,8 @@ def criterion(x, v, a_v):

algo = NumPyMinimumEigensolver(filter_criterion=criterion)
result = algo.compute_minimum_eigenvalue(operator=self.qubit_op, aux_operators=self.aux_ops)
self.assertAlmostEqual(result.eigenvalue, -0.22491125 + 0j)
self.assertEqual(result.eigenvalue.dtype, np.float64)
self.assertAlmostEqual(result.eigenvalue, -0.22491125)
self.assertEqual(len(result.aux_operator_eigenvalues), 2)
np.testing.assert_array_almost_equal(result.aux_operator_eigenvalues[0], [2, 0])
np.testing.assert_array_almost_equal(result.aux_operator_eigenvalues[1], [0, 0])
Expand Down

0 comments on commit 4bdfb8e

Please sign in to comment.