Repository: Qiskit/qiskit

Issue:
`NumPyEigensolver` does not support all `BaseOperator` instances.
### Environment

- **Qiskit Terra version**: 3ce1737b
- **Python version**: 3.10.6
- **Operating system**: macOS 13.0


### What is happening?

`NumPyEigensolver` and by extension `NumPyMinimumEigensolver` do not support all `BaseOperator` instances, in particular `SparsePauliOp`. This is because it requires the `data` attribute, which `Operator` exposes but e.g. `SparsePauliOp` does not. 

### How can we reproduce the issue?

```python
from qiskit.algorithms.eigensolvers import NumPyEigensolver
from qiskit.quantum_info import SparsePauliOp

op = SparsePauliOp("Z")
npe = NumPyEigensolver()
result = npe.compute_eigenvalues(op)
```

Output:
```
Traceback (most recent call last):
  File "/Users/declanmillar/Projects/qiskit/qiskit-terra/test.py", line 10, in <module>
    result = npe.compute_eigenvalues(op)
  File "/Users/declanmillar/Projects/qiskit/qiskit-terra/qiskit/algorithms/eigensolvers/numpy_eigensolver.py", line 248, in compute_eigenvalues
    self._solve(operator)
  File "/Users/declanmillar/Projects/qiskit/qiskit-terra/qiskit/algorithms/eigensolvers/numpy_eigensolver.py", line 144, in _solve
    if operator.data.all() == operator.data.conj().T.all():
AttributeError: 'SparsePauliOp' object has no attribute 'data'
```

### What should happen?

The code should compute the eigenvalues without error, similarly to:

```python
from qiskit.algorithms.eigensolvers import NumPyEigensolver
from qiskit.quantum_info import SparsePauliOp
from qiskit.opflow import PauliSumOp

op = SparsePauliOp("Z")
op = PauliSumOp(op)
npe = NumPyEigensolver()
result = npe.compute_eigenvalues(op)
```

or:

```python
from qiskit.algorithms.eigensolvers import NumPyEigensolver
from qiskit.quantum_info import SparsePauliOp, Operator

op = SparsePauliOp("Z")
op = Operator(op.to_matrix())
npe = NumPyEigensolver()
result = npe.compute_eigenvalues(op)
```

### Any suggestions?

Generalize the computation inside `NumPyEigensolver` to avoid the `data` attribute, perhaps via `to_matrix()` or, if possible, a sparse implementation that works for `BaseOperator` instances.


Discussion:
I'm happy to work on this issue myself.

Resolving patch:
diff --git a/qiskit/algorithms/eigensolvers/numpy_eigensolver.py b/qiskit/algorithms/eigensolvers/numpy_eigensolver.py
--- a/qiskit/algorithms/eigensolvers/numpy_eigensolver.py
+++ b/qiskit/algorithms/eigensolvers/numpy_eigensolver.py
@@ -20,11 +20,12 @@
 from scipy import sparse as scisparse
 
 from qiskit.opflow import PauliSumOp
+from qiskit.quantum_info import SparsePauliOp, Statevector
 from qiskit.quantum_info.operators.base_operator import BaseOperator
-from qiskit.quantum_info import Statevector
 from qiskit.utils.validation import validate_min
 
 from .eigensolver import Eigensolver, EigensolverResult
+from ..exceptions import AlgorithmError
 from ..list_or_dict import ListOrDict
 
 logger = logging.getLogger(__name__)
@@ -53,12 +54,12 @@ def __init__(
     ) -> None:
         """
         Args:
-            k: number of eigenvalues are to be computed, with a min. value of 1.
-            filter_criterion: callable that allows to filter eigenvalues/eigenstates. Only feasible
+            k: Number of eigenvalues are to be computed, with a minimum value of 1.
+            filter_criterion: Callable that allows to filter eigenvalues/eigenstates. Only feasible
                 eigenstates are returned in the results. The callable has the signature
                 ``filter(eigenstate, eigenvalue, aux_values)`` and must return a boolean to indicate
                 whether to keep this value in the final returned result or not. If the number of
-                elements that satisfies the criterion is smaller than `k`, then the returned list will
+                elements that satisfies the criterion is smaller than ``k``, then the returned list will
                 have fewer elements and can even be empty.
         """
         validate_min("k", k, 1)
@@ -69,8 +70,6 @@ def __init__(
 
         self._filter_criterion = filter_criterion
 
-        self._ret = NumPyEigensolverResult()
-
     @property
     def k(self) -> int:
         """Return k (number of eigenvalues requested)."""
@@ -109,15 +108,30 @@ def _check_set_k(self, operator: BaseOperator | PauliSumOp) -> None:
             else:
                 self._k = self._in_k
 
-    def _solve(self, operator: BaseOperator | PauliSumOp) -> None:
+    def _solve(self, operator: BaseOperator | PauliSumOp) -> tuple[np.ndarray, np.ndarray]:
         if isinstance(operator, PauliSumOp):
-            sp_mat = operator.to_spmatrix()
+            op_matrix = operator.to_spmatrix()
+        else:
+            try:
+                op_matrix = operator.to_matrix(sparse=True)
+            except TypeError:
+                logger.debug(
+                    "WARNING: operator of type `%s` does not support sparse matrices. "
+                    "Trying dense computation",
+                    type(operator),
+                )
+            try:
+                op_matrix = operator.to_matrix()
+            except AttributeError as ex:
+                raise AlgorithmError(f"Unsupported operator type `{type(operator)}`.") from ex
+
+        if isinstance(op_matrix, scisparse.csr_matrix):
             # If matrix is diagonal, the elements on the diagonal are the eigenvalues. Solve by sorting.
-            if scisparse.csr_matrix(sp_mat.diagonal()).nnz == sp_mat.nnz:
-                diag = sp_mat.diagonal()
+            if scisparse.csr_matrix(op_matrix.diagonal()).nnz == op_matrix.nnz:
+                diag = op_matrix.diagonal()
                 indices = np.argsort(diag)[: self._k]
                 eigval = diag[indices]
-                eigvec = np.zeros((sp_mat.shape[0], self._k))
+                eigvec = np.zeros((op_matrix.shape[0], self._k))
                 for i, idx in enumerate(indices):
                     eigvec[idx, i] = 1.0
             else:
@@ -125,53 +139,33 @@ def _solve(self, operator: BaseOperator | PauliSumOp) -> None:
                     logger.debug(
                         "SciPy doesn't support to get all eigenvalues, using NumPy instead."
                     )
-                    if operator.is_hermitian():
-                        eigval, eigvec = np.linalg.eigh(operator.to_matrix())
-                    else:
-                        eigval, eigvec = np.linalg.eig(operator.to_matrix())
+                    eigval, eigvec = self._solve_dense(operator.to_matrix())
                 else:
-                    if operator.is_hermitian():
-                        eigval, eigvec = scisparse.linalg.eigsh(sp_mat, k=self._k, which="SA")
-                    else:
-                        eigval, eigvec = scisparse.linalg.eigs(sp_mat, k=self._k, which="SR")
-
-                indices = np.argsort(eigval)[: self._k]
-                eigval = eigval[indices]
-                eigvec = eigvec[:, indices]
+                    eigval, eigvec = self._solve_sparse(op_matrix, self._k)
         else:
-            logger.debug("SciPy not supported, using NumPy instead.")
-
-            if operator.data.all() == operator.data.conj().T.all():
-                eigval, eigvec = np.linalg.eigh(operator.data)
-            else:
-                eigval, eigvec = np.linalg.eig(operator.data)
-
-            indices = np.argsort(eigval)[: self._k]
-            eigval = eigval[indices]
-            eigvec = eigvec[:, indices]
-
-        self._ret.eigenvalues = eigval
-        self._ret.eigenstates = eigvec.T
+            # Sparse SciPy matrix not supported, use dense NumPy computation.
+            eigval, eigvec = self._solve_dense(operator.to_matrix())
 
-    def _get_ground_state_energy(self, operator: BaseOperator | PauliSumOp) -> None:
-        if self._ret.eigenvalues is None or self._ret.eigenstates is None:
-            self._solve(operator)
+        indices = np.argsort(eigval)[: self._k]
+        eigval = eigval[indices]
+        eigvec = eigvec[:, indices]
+        return eigval, eigvec.T
 
-    def _get_energies(
-        self,
-        operator: BaseOperator | PauliSumOp,
-        aux_operators: ListOrDict[BaseOperator | PauliSumOp] | None,
-    ) -> None:
-        if self._ret.eigenvalues is None or self._ret.eigenstates is None:
-            self._solve(operator)
+    @staticmethod
+    def _solve_sparse(op_matrix: scisparse.csr_matrix, k: int) -> tuple[np.ndarray, np.ndarray]:
+        if (op_matrix != op_matrix.H).nnz == 0:
+            # Operator is Hermitian
+            return scisparse.linalg.eigsh(op_matrix, k=k, which="SA")
+        else:
+            return scisparse.linalg.eigs(op_matrix, k=k, which="SR")
 
-        if aux_operators is not None:
-            aux_op_vals = []
-            for i in range(self._k):
-                aux_op_vals.append(
-                    self._eval_aux_operators(aux_operators, self._ret.eigenstates[i])
-                )
-            self._ret.aux_operators_evaluated = aux_op_vals
+    @staticmethod
+    def _solve_dense(op_matrix: np.ndarray) -> tuple[np.ndarray, np.ndarray]:
+        if op_matrix.all() == op_matrix.conj().T.all():
+            # Operator is Hermitian
+            return np.linalg.eigh(op_matrix)
+        else:
+            return np.linalg.eig(op_matrix)
 
     @staticmethod
     def _eval_aux_operators(
@@ -190,25 +184,42 @@ def _eval_aux_operators(
         else:
             values = {}
             key_op_iterator = aux_operators.items()
+
         for key, operator in key_op_iterator:
             if operator is None:
                 continue
-            value = 0.0
+
+            if operator.num_qubits is None or operator.num_qubits < 1:
+                logger.info(
+                    "The number of qubits of the %s operator must be greater than zero.", key
+                )
+                continue
+
+            op_matrix = None
             if isinstance(operator, PauliSumOp):
                 if operator.coeff != 0:
-                    mat = operator.to_spmatrix()
-                    # Terra doesn't support sparse yet, so do the matmul directly if so
-                    # This is necessary for the particle_hole and other chemistry tests because the
-                    # pauli conversions are 2^12th large and will OOM error if not sparse.
-                    if isinstance(mat, scisparse.spmatrix):
-                        value = mat.dot(wavefn).dot(np.conj(wavefn))
-                    else:
-                        value = (
-                            Statevector(wavefn).expectation_value(operator.primitive)
-                            * operator.coeff
-                        )
+                    op_matrix = operator.to_spmatrix()
             else:
+                try:
+                    op_matrix = operator.to_matrix(sparse=True)
+                except TypeError:
+                    logger.debug(
+                        "WARNING: operator of type `%s` does not support sparse matrices. "
+                        "Trying dense computation",
+                        type(operator),
+                    )
+                try:
+                    op_matrix = operator.to_matrix()
+                except AttributeError as ex:
+                    raise AlgorithmError(f"Unsupported operator type {type(operator)}.") from ex
+
+            if isinstance(op_matrix, scisparse.csr_matrix):
+                value = op_matrix.dot(wavefn).dot(np.conj(wavefn))
+            elif isinstance(op_matrix, np.ndarray):
                 value = Statevector(wavefn).expectation_value(operator)
+            else:
+                value = 0.0
+
             value = value if np.abs(value) > threshold else 0.0
             # The value gets wrapped into a tuple: (mean, metadata).
             # The metadata includes variance (and, for other eigensolvers, shots).
@@ -225,8 +236,12 @@ def compute_eigenvalues(
 
         super().compute_eigenvalues(operator, aux_operators)
 
+        if operator.num_qubits is None or operator.num_qubits < 1:
+            raise AlgorithmError("The number of qubits of the operator must be greater than zero.")
+
         self._check_set_k(operator)
-        zero_op = PauliSumOp.from_list([("I", 1)]).tensorpower(operator.num_qubits) * 0.0
+
+        zero_op = SparsePauliOp(["I" * operator.num_qubits], coeffs=[0.0])
         if isinstance(aux_operators, list) and len(aux_operators) > 0:
             # For some reason Chemistry passes aux_ops with 0 qubits and paulis sometimes.
             aux_operators = [zero_op if op == 0 else op for op in aux_operators]
@@ -244,49 +259,51 @@ def compute_eigenvalues(
             # need to consider all elements if a filter is set
             self._k = 2**operator.num_qubits
 
-        self._ret = NumPyEigensolverResult()
-        self._solve(operator)
+        eigvals, eigvecs = self._solve(operator)
 
         # compute energies before filtering, as this also evaluates the aux operators
-        self._get_energies(operator, aux_operators)
+        if aux_operators is not None:
+            aux_op_vals = [
+                self._eval_aux_operators(aux_operators, eigvecs[i]) for i in range(self._k)
+            ]
+        else:
+            aux_op_vals = None
 
         # if a filter is set, loop over the given values and only keep
         if self._filter_criterion:
-
-            eigvecs = []
-            eigvals = []
-            aux_ops = []
-            cnt = 0
-            for i in range(len(self._ret.eigenvalues)):
-                eigvec = self._ret.eigenstates[i]
-                eigval = self._ret.eigenvalues[i]
-                if self._ret.aux_operators_evaluated is not None:
-                    aux_op = self._ret.aux_operators_evaluated[i]
+            filt_eigvals = []
+            filt_eigvecs = []
+            filt_aux_op_vals = []
+            count = 0
+            for i, (eigval, eigvec) in enumerate(zip(eigvals, eigvecs)):
+                if aux_op_vals is not None:
+                    aux_op_val = aux_op_vals[i]
                 else:
-                    aux_op = None
-                if self._filter_criterion(eigvec, eigval, aux_op):
-                    cnt += 1
-                    eigvecs += [eigvec]
-                    eigvals += [eigval]
-                    if self._ret.aux_operators_evaluated is not None:
-                        aux_ops += [aux_op]
-                if cnt == k_orig:
+                    aux_op_val = None
+
+                if self._filter_criterion(eigvec, eigval, aux_op_val):
+                    count += 1
+                    filt_eigvecs.append(eigvec)
+                    filt_eigvals.append(eigval)
+                    if aux_op_vals is not None:
+                        filt_aux_op_vals.append(aux_op_val)
+
+                if count == k_orig:
                     break
 
-            self._ret.eigenstates = np.array(eigvecs)
-            self._ret.eigenvalues = np.array(eigvals)
-            # conversion to np.array breaks in case of aux_ops
-            self._ret.aux_operators_evaluated = aux_ops
+            eigvals = np.array(filt_eigvals)
+            eigvecs = np.array(filt_eigvecs)
+            aux_op_vals = filt_aux_op_vals
 
             self._k = k_orig
 
-        # evaluate ground state after filtering (in case a filter is set)
-        self._get_ground_state_energy(operator)
-        if self._ret.eigenstates is not None:
-            self._ret.eigenstates = [Statevector(vec) for vec in self._ret.eigenstates]
+        result = NumPyEigensolverResult()
+        result.eigenvalues = eigvals
+        result.eigenstates = [Statevector(vec) for vec in eigvecs]
+        result.aux_operators_evaluated = aux_op_vals
 
-        logger.debug("NumpyEigensolverResult:\n%s", self._ret)
-        return self._ret
+        logger.debug("NumpyEigensolverResult:\n%s", result)
+        return result
 
 
 class NumPyEigensolverResult(EigensolverResult):
diff --git a/qiskit/algorithms/minimum_eigensolvers/numpy_minimum_eigensolver.py b/qiskit/algorithms/minimum_eigensolvers/numpy_minimum_eigensolver.py
--- a/qiskit/algorithms/minimum_eigensolvers/numpy_minimum_eigensolver.py
+++ b/qiskit/algorithms/minimum_eigensolvers/numpy_minimum_eigensolver.py
@@ -43,7 +43,7 @@ def __init__(
     ) -> None:
         """
         Args:
-            filter_criterion: callable that allows to filter eigenvalues/eigenstates. The minimum
+            filter_criterion: Callable that allows to filter eigenvalues/eigenstates. The minimum
                 eigensolver is only searching over feasible states and returns an eigenstate that
                 has the smallest eigenvalue among feasible states. The callable has the signature
                 ``filter(eigenstate, eigenvalue, aux_values)`` and must return a boolean to indicate
diff --git a/qiskit/quantum_info/operators/operator.py b/qiskit/quantum_info/operators/operator.py
--- a/qiskit/quantum_info/operators/operator.py
+++ b/qiskit/quantum_info/operators/operator.py
@@ -470,6 +470,10 @@ def reverse_qargs(self):
         ret._op_shape = self._op_shape.reverse()
         return ret
 
+    def to_matrix(self):
+        """Convert operator to NumPy matrix."""
+        return self.data
+
     @classmethod
     def _einsum_matmul(cls, tensor, mat, indices, shift=0, right_mul=False):
         """Perform a contraction using Numpy.einsum


Test patch:
diff --git a/test/python/algorithms/eigensolvers/test_numpy_eigensolver.py b/test/python/algorithms/eigensolvers/test_numpy_eigensolver.py
--- a/test/python/algorithms/eigensolvers/test_numpy_eigensolver.py
+++ b/test/python/algorithms/eigensolvers/test_numpy_eigensolver.py
@@ -1,6 +1,6 @@
 # This code is part of Qiskit.
 #
-# (C) Copyright IBM 2018, 2021.
+# (C) Copyright IBM 2018, 2022.
 #
 # This code is licensed under the Apache License, Version 2.0. You may
 # obtain a copy of this license in the LICENSE.txt file in the root directory
@@ -10,7 +10,7 @@
 # copyright notice, and modified files need to carry a notice indicating
 # that they have been altered from the originals.
 
-""" Test NumPy Eigen solver """
+""" Test NumPyEigensolver """
 
 import unittest
 from test.python.algorithms import QiskitAlgorithmsTestCase
@@ -19,27 +19,31 @@
 from ddt import data, ddt
 
 from qiskit.algorithms.eigensolvers import NumPyEigensolver
+from qiskit.algorithms import AlgorithmError
 from qiskit.opflow import PauliSumOp
-from qiskit.quantum_info.operators import Operator
-
-H2_PAULI = PauliSumOp.from_list(
-    [
-        ("II", -1.052373245772859),
-        ("ZI", 0.39793742484318045),
-        ("IZ", -0.39793742484318045),
-        ("ZZ", -0.01128010425623538),
-        ("XX", 0.18093119978423156),
-    ]
+from qiskit.quantum_info import Operator, SparsePauliOp, Pauli, ScalarOp
+
+H2_SPARSE_PAULI = SparsePauliOp(
+    ["II", "ZI", "IZ", "ZZ", "XX"],
+    coeffs=[
+        -1.052373245772859,
+        0.39793742484318045,
+        -0.39793742484318045,
+        -0.01128010425623538,
+        0.18093119978423156,
+    ],
 )
 
-H2_OP = Operator(H2_PAULI.to_matrix())
+H2_OP = Operator(H2_SPARSE_PAULI.to_matrix())
+
+H2_PAULI = PauliSumOp(H2_SPARSE_PAULI)
 
 
 @ddt
 class TestNumPyEigensolver(QiskitAlgorithmsTestCase):
     """Test NumPy Eigen solver"""
 
-    @data(H2_PAULI, H2_OP)
+    @data(H2_SPARSE_PAULI, H2_PAULI, H2_OP)
     def test_ce(self, op):
         """Test basics"""
         algo = NumPyEigensolver()
@@ -49,7 +53,7 @@ def test_ce(self, op):
         self.assertEqual(result.eigenvalues.dtype, np.float64)
         self.assertAlmostEqual(result.eigenvalues[0], -1.85727503)
 
-    @data(H2_PAULI, H2_OP)
+    @data(H2_SPARSE_PAULI, H2_PAULI, H2_OP)
     def test_ce_k4(self, op):
         """Test for k=4 eigenvalues"""
         algo = NumPyEigensolver(k=4)
@@ -61,7 +65,7 @@ def test_ce_k4(self, op):
             result.eigenvalues, [-1.85727503, -1.24458455, -0.88272215, -0.22491125]
         )
 
-    @data(H2_PAULI, H2_OP)
+    @data(H2_SPARSE_PAULI, H2_PAULI, H2_OP)
     def test_ce_k4_filtered(self, op):
         """Test for k=4 eigenvalues with filter"""
 
@@ -77,7 +81,7 @@ def criterion(x, v, a_v):
         self.assertEqual(result.eigenvalues.dtype, np.float64)
         np.testing.assert_array_almost_equal(result.eigenvalues, [-0.88272215, -0.22491125])
 
-    @data(H2_PAULI, H2_OP)
+    @data(H2_SPARSE_PAULI, H2_PAULI, H2_OP)
     def test_ce_k4_filtered_empty(self, op):
         """Test for k=4 eigenvalues with filter always returning False"""
 
@@ -92,9 +96,9 @@ def criterion(x, v, a_v):
         self.assertEqual(len(result.eigenstates), 0)
 
     @data(
-        PauliSumOp.from_list([("X", 1)]),
-        PauliSumOp.from_list([("Y", 1)]),
-        PauliSumOp.from_list([("Z", 1)]),
+        SparsePauliOp(["X"], coeffs=[1.0]),
+        SparsePauliOp(["Y"], coeffs=[1.0]),
+        SparsePauliOp(["Z"], coeffs=[1.0]),
     )
     def test_ce_k1_1q(self, op):
         """Test for 1 qubit operator"""
@@ -103,9 +107,9 @@ def test_ce_k1_1q(self, op):
         np.testing.assert_array_almost_equal(result.eigenvalues, [-1])
 
     @data(
-        PauliSumOp.from_list([("X", 1)]),
-        PauliSumOp.from_list([("Y", 1)]),
-        PauliSumOp.from_list([("Z", 1)]),
+        SparsePauliOp(["X"], coeffs=[1.0]),
+        SparsePauliOp(["Y"], coeffs=[1.0]),
+        SparsePauliOp(["Z"], coeffs=[1.0]),
     )
     def test_ce_k2_1q(self, op):
         """Test for 1 qubit operator"""
@@ -113,11 +117,11 @@ def test_ce_k2_1q(self, op):
         result = algo.compute_eigenvalues(operator=op)
         np.testing.assert_array_almost_equal(result.eigenvalues, [-1, 1])
 
-    @data(H2_PAULI, H2_OP)
+    @data(H2_SPARSE_PAULI, H2_PAULI, H2_OP)
     def test_aux_operators_list(self, op):
         """Test list-based aux_operators."""
-        aux_op1 = Operator(PauliSumOp.from_list([("II", 2.0)]).to_matrix())
-        aux_op2 = PauliSumOp.from_list([("II", 0.5), ("ZZ", 0.5), ("YY", 0.5), ("XX", -0.5)])
+        aux_op1 = Operator(SparsePauliOp(["II"], coeffs=[2.0]).to_matrix())
+        aux_op2 = SparsePauliOp(["II", "ZZ", "YY", "XX"], coeffs=[0.5, 0.5, 0.5, -0.5])
         aux_ops = [aux_op1, aux_op2]
         algo = NumPyEigensolver()
         result = algo.compute_eigenvalues(operator=op, aux_operators=aux_ops)
@@ -153,11 +157,11 @@ def test_aux_operators_list(self, op):
         self.assertAlmostEqual(result.aux_operators_evaluated[0][1][1].pop("variance"), 0.0)
         self.assertEqual(result.aux_operators_evaluated[0][3][1].pop("variance"), 0.0)
 
-    @data(H2_PAULI, H2_OP)
+    @data(H2_SPARSE_PAULI, H2_PAULI, H2_OP)
     def test_aux_operators_dict(self, op):
         """Test dict-based aux_operators."""
-        aux_op1 = Operator(PauliSumOp.from_list([("II", 2.0)]).to_matrix())
-        aux_op2 = PauliSumOp.from_list([("II", 0.5), ("ZZ", 0.5), ("YY", 0.5), ("XX", -0.5)])
+        aux_op1 = Operator(SparsePauliOp(["II"], coeffs=[2.0]).to_matrix())
+        aux_op2 = SparsePauliOp(["II", "ZZ", "YY", "XX"], coeffs=[0.5, 0.5, 0.5, -0.5])
         aux_ops = {"aux_op1": aux_op1, "aux_op2": aux_op2}
         algo = NumPyEigensolver()
         result = algo.compute_eigenvalues(operator=op, aux_operators=aux_ops)
@@ -195,6 +199,18 @@ def test_aux_operators_dict(self, op):
             result.aux_operators_evaluated[0]["zero_operator"][1].pop("variance"), 0.0
         )
 
+    def test_pauli_op(self):
+        """Test simple pauli operator"""
+        algo = NumPyEigensolver(k=1)
+        result = algo.compute_eigenvalues(operator=Pauli("X"))
+        np.testing.assert_array_almost_equal(result.eigenvalues, [-1])
+
+    def test_scalar_op(self):
+        """Test scalar operator"""
+        algo = NumPyEigensolver(k=1)
+        with self.assertRaises(AlgorithmError):
+            algo.compute_eigenvalues(operator=ScalarOp(1))
+
 
 if __name__ == "__main__":
     unittest.main()
diff --git a/test/python/algorithms/minimum_eigensolvers/test_numpy_minimum_eigensolver.py b/test/python/algorithms/minimum_eigensolvers/test_numpy_minimum_eigensolver.py
--- a/test/python/algorithms/minimum_eigensolvers/test_numpy_minimum_eigensolver.py
+++ b/test/python/algorithms/minimum_eigensolvers/test_numpy_minimum_eigensolver.py
@@ -20,6 +20,22 @@
 
 from qiskit.algorithms.minimum_eigensolvers import NumPyMinimumEigensolver
 from qiskit.opflow import PauliSumOp
+from qiskit.quantum_info import Operator, SparsePauliOp
+
+H2_SPARSE_PAULI = SparsePauliOp(
+    ["II", "ZI", "IZ", "ZZ", "XX"],
+    coeffs=[
+        -1.052373245772859,
+        0.39793742484318045,
+        -0.39793742484318045,
+        -0.01128010425623538,
+        0.18093119978423156,
+    ],
+)
+
+H2_OP = Operator(H2_SPARSE_PAULI.to_matrix())
+
+H2_PAULI = PauliSumOp(H2_SPARSE_PAULI)
 
 
 @ddt
@@ -28,61 +44,47 @@ class TestNumPyMinimumEigensolver(QiskitAlgorithmsTestCase):
 
     def setUp(self):
         super().setUp()
-        self.qubit_op = PauliSumOp.from_list(
-            [
-                ("II", -1.052373245772859),
-                ("ZI", 0.39793742484318045),
-                ("IZ", -0.39793742484318045),
-                ("ZZ", -0.01128010425623538),
-                ("XX", 0.18093119978423156),
-            ]
-        )
-
-        aux_op1 = PauliSumOp.from_list([("II", 2.0)])
-        aux_op2 = PauliSumOp.from_list([("II", 0.5), ("ZZ", 0.5), ("YY", 0.5), ("XX", -0.5)])
+        aux_op1 = Operator(SparsePauliOp(["II"], coeffs=[2.0]).to_matrix())
+        aux_op2 = SparsePauliOp(["II", "ZZ", "YY", "XX"], coeffs=[0.5, 0.5, 0.5, -0.5])
         self.aux_ops_list = [aux_op1, aux_op2]
         self.aux_ops_dict = {"aux_op1": aux_op1, "aux_op2": aux_op2}
 
-    def test_cme(self):
+    @data(H2_SPARSE_PAULI, H2_PAULI, H2_OP)
+    def test_cme(self, op):
         """Basic test"""
         algo = NumPyMinimumEigensolver()
-        result = algo.compute_minimum_eigenvalue(
-            operator=self.qubit_op, aux_operators=self.aux_ops_list
-        )
+        result = algo.compute_minimum_eigenvalue(operator=op, aux_operators=self.aux_ops_list)
         self.assertAlmostEqual(result.eigenvalue, -1.85727503 + 0j)
         self.assertEqual(len(result.aux_operators_evaluated), 2)
         self.assertAlmostEqual(result.aux_operators_evaluated[0][0], 2)
         self.assertAlmostEqual(result.aux_operators_evaluated[1][0], 0)
 
-    def test_cme_reuse(self):
+    @data(H2_SPARSE_PAULI, H2_PAULI, H2_OP)
+    def test_cme_reuse(self, op):
         """Test reuse"""
         algo = NumPyMinimumEigensolver()
 
         with self.subTest("Test with no operator or aux_operators, give via compute method"):
-            result = algo.compute_minimum_eigenvalue(operator=self.qubit_op)
+            result = algo.compute_minimum_eigenvalue(operator=op)
             self.assertEqual(result.eigenvalue.dtype, np.float64)
             self.assertAlmostEqual(result.eigenvalue, -1.85727503)
             self.assertIsNone(result.aux_operators_evaluated)
 
         with self.subTest("Test with added aux_operators"):
-            result = algo.compute_minimum_eigenvalue(
-                operator=self.qubit_op, aux_operators=self.aux_ops_list
-            )
+            result = algo.compute_minimum_eigenvalue(operator=op, aux_operators=self.aux_ops_list)
             self.assertAlmostEqual(result.eigenvalue, -1.85727503 + 0j)
             self.assertEqual(len(result.aux_operators_evaluated), 2)
             self.assertAlmostEqual(result.aux_operators_evaluated[0][0], 2)
             self.assertAlmostEqual(result.aux_operators_evaluated[1][0], 0)
 
         with self.subTest("Test with aux_operators removed"):
-            result = algo.compute_minimum_eigenvalue(operator=self.qubit_op, aux_operators=[])
+            result = algo.compute_minimum_eigenvalue(operator=op, aux_operators=[])
             self.assertEqual(result.eigenvalue.dtype, np.float64)
             self.assertAlmostEqual(result.eigenvalue, -1.85727503)
             self.assertIsNone(result.aux_operators_evaluated)
 
         with self.subTest("Test with aux_operators set again"):
-            result = algo.compute_minimum_eigenvalue(
-                operator=self.qubit_op, aux_operators=self.aux_ops_list
-            )
+            result = algo.compute_minimum_eigenvalue(operator=op, aux_operators=self.aux_ops_list)
             self.assertAlmostEqual(result.eigenvalue, -1.85727503 + 0j)
             self.assertEqual(len(result.aux_operators_evaluated), 2)
             self.assertAlmostEqual(result.aux_operators_evaluated[0][0], 2)
@@ -95,7 +97,8 @@ def test_cme_reuse(self):
             self.assertAlmostEqual(result.eigenvalue, 2 + 0j)
             self.assertIsNone(result.aux_operators_evaluated)
 
-    def test_cme_filter(self):
+    @data(H2_SPARSE_PAULI, H2_PAULI, H2_OP)
+    def test_cme_filter(self, op):
         """Basic test"""
 
         # define filter criterion
@@ -104,15 +107,14 @@ def criterion(x, v, a_v):
             return v >= -0.5
 
         algo = NumPyMinimumEigensolver(filter_criterion=criterion)
-        result = algo.compute_minimum_eigenvalue(
-            operator=self.qubit_op, aux_operators=self.aux_ops_list
-        )
+        result = algo.compute_minimum_eigenvalue(operator=op, aux_operators=self.aux_ops_list)
         self.assertAlmostEqual(result.eigenvalue, -0.22491125 + 0j)
         self.assertEqual(len(result.aux_operators_evaluated), 2)
         self.assertAlmostEqual(result.aux_operators_evaluated[0][0], 2)
         self.assertAlmostEqual(result.aux_operators_evaluated[1][0], 0)
 
-    def test_cme_filter_empty(self):
+    @data(H2_SPARSE_PAULI, H2_PAULI, H2_OP)
+    def test_cme_filter_empty(self, op):
         """Test with filter always returning False"""
 
         # define filter criterion
@@ -121,9 +123,7 @@ def criterion(x, v, a_v):
             return False
 
         algo = NumPyMinimumEigensolver(filter_criterion=criterion)
-        result = algo.compute_minimum_eigenvalue(
-            operator=self.qubit_op, aux_operators=self.aux_ops_list
-        )
+        result = algo.compute_minimum_eigenvalue(operator=op, aux_operators=self.aux_ops_list)
         self.assertEqual(result.eigenvalue, None)
         self.assertEqual(result.eigenstate, None)
         self.assertEqual(result.aux_operators_evaluated, None)
@@ -132,24 +132,23 @@ def criterion(x, v, a_v):
     def test_cme_1q(self, op):
         """Test for 1 qubit operator"""
         algo = NumPyMinimumEigensolver()
-        operator = PauliSumOp.from_list([(op, 1.0)])
+        operator = SparsePauliOp([op], coeffs=1.0)
         result = algo.compute_minimum_eigenvalue(operator=operator)
         self.assertAlmostEqual(result.eigenvalue, -1)
 
-    def test_cme_aux_ops_dict(self):
+    @data(H2_SPARSE_PAULI, H2_PAULI, H2_OP)
+    def test_cme_aux_ops_dict(self, op):
         """Test dictionary compatibility of aux_operators"""
         # Start with an empty dictionary
         algo = NumPyMinimumEigensolver()
 
         with self.subTest("Test with an empty dictionary."):
-            result = algo.compute_minimum_eigenvalue(operator=self.qubit_op, aux_operators={})
+            result = algo.compute_minimum_eigenvalue(operator=op, aux_operators={})
             self.assertAlmostEqual(result.eigenvalue, -1.85727503 + 0j)
             self.assertIsNone(result.aux_operators_evaluated)
 
         with self.subTest("Test with two auxiliary operators."):
-            result = algo.compute_minimum_eigenvalue(
-                operator=self.qubit_op, aux_operators=self.aux_ops_dict
-            )
+            result = algo.compute_minimum_eigenvalue(operator=op, aux_operators=self.aux_ops_dict)
             self.assertAlmostEqual(result.eigenvalue, -1.85727503 + 0j)
             self.assertEqual(len(result.aux_operators_evaluated), 2)
             self.assertAlmostEqual(result.aux_operators_evaluated["aux_op1"][0], 2)
@@ -157,24 +156,20 @@ def test_cme_aux_ops_dict(self):
 
         with self.subTest("Test with additional zero and None operators."):
             extra_ops = {"None_op": None, "zero_op": 0, **self.aux_ops_dict}
-            result = algo.compute_minimum_eigenvalue(
-                operator=self.qubit_op, aux_operators=extra_ops
-            )
+            result = algo.compute_minimum_eigenvalue(operator=op, aux_operators=extra_ops)
             self.assertAlmostEqual(result.eigenvalue, -1.85727503 + 0j)
             self.assertEqual(len(result.aux_operators_evaluated), 3)
             self.assertAlmostEqual(result.aux_operators_evaluated["aux_op1"][0], 2)
             self.assertAlmostEqual(result.aux_operators_evaluated["aux_op2"][0], 0)
             self.assertEqual(result.aux_operators_evaluated["zero_op"], (0.0, {"variance": 0}))
 
-    def test_aux_operators_list(self):
+    @data(H2_SPARSE_PAULI, H2_PAULI, H2_OP)
+    def test_aux_operators_list(self, op):
         """Test list-based aux_operators."""
-        aux_op1 = PauliSumOp.from_list([("II", 2.0)])
-        aux_op2 = PauliSumOp.from_list([("II", 0.5), ("ZZ", 0.5), ("YY", 0.5), ("XX", -0.5)])
-        aux_ops = [aux_op1, aux_op2]
         algo = NumPyMinimumEigensolver()
 
         with self.subTest("Test with two auxiliary operators."):
-            result = algo.compute_minimum_eigenvalue(operator=self.qubit_op, aux_operators=aux_ops)
+            result = algo.compute_minimum_eigenvalue(operator=op, aux_operators=self.aux_ops_list)
             self.assertAlmostEqual(result.eigenvalue, -1.85727503 + 0j)
             self.assertEqual(len(result.aux_operators_evaluated), 2)
             # expectation values
@@ -185,10 +180,8 @@ def test_aux_operators_list(self):
             self.assertAlmostEqual(result.aux_operators_evaluated[1][1].pop("variance"), 0.0)
 
         with self.subTest("Test with additional zero and None operators."):
-            extra_ops = [*aux_ops, None, 0]
-            result = algo.compute_minimum_eigenvalue(
-                operator=self.qubit_op, aux_operators=extra_ops
-            )
+            extra_ops = [*self.aux_ops_list, None, 0]
+            result = algo.compute_minimum_eigenvalue(operator=op, aux_operators=extra_ops)
             self.assertAlmostEqual(result.eigenvalue, -1.85727503 + 0j)
             self.assertEqual(len(result.aux_operators_evaluated), 4)
             # expectation values
@@ -201,15 +194,13 @@ def test_aux_operators_list(self):
             self.assertAlmostEqual(result.aux_operators_evaluated[1][1].pop("variance"), 0.0)
             self.assertEqual(result.aux_operators_evaluated[3][1].pop("variance"), 0.0)
 
-    def test_aux_operators_dict(self):
+    @data(H2_SPARSE_PAULI, H2_PAULI, H2_OP)
+    def test_aux_operators_dict(self, op):
         """Test dict-based aux_operators."""
-        aux_op1 = PauliSumOp.from_list([("II", 2.0)])
-        aux_op2 = PauliSumOp.from_list([("II", 0.5), ("ZZ", 0.5), ("YY", 0.5), ("XX", -0.5)])
-        aux_ops = {"aux_op1": aux_op1, "aux_op2": aux_op2}
         algo = NumPyMinimumEigensolver()
 
         with self.subTest("Test with two auxiliary operators."):
-            result = algo.compute_minimum_eigenvalue(operator=self.qubit_op, aux_operators=aux_ops)
+            result = algo.compute_minimum_eigenvalue(operator=op, aux_operators=self.aux_ops_dict)
             self.assertAlmostEqual(result.eigenvalue, -1.85727503 + 0j)
             self.assertEqual(len(result.aux_operators_evaluated), 2)
             # expectation values
@@ -224,10 +215,8 @@ def test_aux_operators_dict(self):
             )
 
         with self.subTest("Test with additional zero and None operators."):
-            extra_ops = {**aux_ops, "None_operator": None, "zero_operator": 0}
-            result = algo.compute_minimum_eigenvalue(
-                operator=self.qubit_op, aux_operators=extra_ops
-            )
+            extra_ops = {**self.aux_ops_dict, "None_operator": None, "zero_operator": 0}
+            result = algo.compute_minimum_eigenvalue(operator=op, aux_operators=extra_ops)
             self.assertAlmostEqual(result.eigenvalue, -1.85727503 + 0j)
             self.assertEqual(len(result.aux_operators_evaluated), 3)
             # expectation values
diff --git a/test/python/quantum_info/operators/test_operator.py b/test/python/quantum_info/operators/test_operator.py
--- a/test/python/quantum_info/operators/test_operator.py
+++ b/test/python/quantum_info/operators/test_operator.py
@@ -206,6 +206,12 @@ def test_data(self):
         op = Operator(mat)
         assert_allclose(mat, op.data)
 
+    def test_to_matrix(self):
+        """Test Operator to_matrix method."""
+        mat = self.rand_matrix(2, 2)
+        op = Operator(mat)
+        assert_allclose(mat, op.to_matrix())
+
     def test_dim(self):
         """Test Operator dim property."""
         mat = self.rand_matrix(4, 4)