Skip to content

Commit

Permalink
Add tests for NumpyMES and import in module.
Browse files Browse the repository at this point in the history
  • Loading branch information
declanmillar committed Sep 12, 2022
1 parent 6ff00e8 commit a79aaea
Show file tree
Hide file tree
Showing 4 changed files with 233 additions and 1 deletion.
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,14 @@
"""The minimum eigensolvers package."""

from .minimum_eigensolver import MinimumEigensolver, MinimumEigensolverResult
from .numpy_minimum_eigensolver import NumPyMinimumEigensolver, NumPyMinimumEigensolverResult
from .vqe import VQE, VQEResult

__all__ = [
"MinimumEigensolver",
"MinimumEigensolverResult",
"NumPyMinimumEigensolver",
"NumPyMinimumEigensolverResult",
"VQE",
"VQEResult",
]
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,10 @@ def compute_minimum_eigenvalue(
class NumPyMinimumEigensolverResult(MinimumEigensolverResult):
"""NumPy minimum eigensolver result."""

def __init__(self) -> None:
super().__init__()
self._eigenstate = None

@property
def eigenstate(self) -> np.ndarray | None:
"""Return eigenstate."""
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,225 @@
# This code is part of Qiskit.
#
# (C) Copyright IBM 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
# of this source tree or at http://www.apache.org/licenses/LICENSE-2.0.
#
# Any modifications or derivative works of this code must retain this
# copyright notice, and modified files need to carry a notice indicating
# that they have been altered from the originals.

""" Test NumPy minimum eigensolver """

import unittest
from test.python.algorithms import QiskitAlgorithmsTestCase

import numpy as np
from ddt import ddt, data

from qiskit.algorithms.minimum_eigensolvers import NumPyMinimumEigensolver
from qiskit.opflow import PauliSumOp, X, Y, Z


@ddt
class TestNumPyMinimumEigensolver(QiskitAlgorithmsTestCase):
"""Test NumPy minimum eigensolver"""

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)])
self.aux_ops_list = [aux_op1, aux_op2]
self.aux_ops_dict = {"aux_op1": aux_op1, "aux_op2": aux_op2}

def test_cme(self):
"""Basic test"""
algo = NumPyMinimumEigensolver()
result = algo.compute_minimum_eigenvalue(
operator=self.qubit_op, aux_operators=self.aux_ops_list
)
self.assertAlmostEqual(result.eigenvalue, -1.85727503 + 0j)
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])

def test_cme_reuse(self):
"""Test reuse"""
# Start with no operator or aux_operators, give via compute method
algo = NumPyMinimumEigensolver()
result = algo.compute_minimum_eigenvalue(operator=self.qubit_op)
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_list
)
self.assertAlmostEqual(result.eigenvalue, -1.85727503 + 0j)
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.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_list
)
self.assertAlmostEqual(result.eigenvalue, -1.85727503 + 0j)
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])

# Finally just set one of aux_operators and main operator, remove aux_operators
result = algo.compute_minimum_eigenvalue(operator=self.aux_ops_list[0], aux_operators=[])
self.assertAlmostEqual(result.eigenvalue, 2 + 0j)
self.assertIsNone(result.aux_operator_eigenvalues)

def test_cme_filter(self):
"""Basic test"""

# define filter criterion
# pylint: disable=unused-argument
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
)
self.assertAlmostEqual(result.eigenvalue, -0.22491125 + 0j)
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])

def test_cme_filter_empty(self):
"""Test with filter always returning False"""

# define filter criterion
# pylint: disable=unused-argument
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
)
self.assertEqual(result.eigenvalue, None)
self.assertEqual(result.eigenstate, None)
self.assertEqual(result.aux_operator_eigenvalues, None)

@data(X, Y, Z)
def test_cme_1q(self, op):
"""Test for 1 qubit operator"""
algo = NumPyMinimumEigensolver()
result = algo.compute_minimum_eigenvalue(operator=op)
self.assertAlmostEqual(result.eigenvalue, -1)

def test_cme_aux_ops_dict(self):
"""Test dictionary compatibility of aux_operators"""
# Start with an empty dictionary
algo = NumPyMinimumEigensolver()
result = algo.compute_minimum_eigenvalue(operator=self.qubit_op, aux_operators={})
self.assertAlmostEqual(result.eigenvalue, -1.85727503 + 0j)
self.assertIsNone(result.aux_operator_eigenvalues)

# Add aux_operators dictionary and go again
result = algo.compute_minimum_eigenvalue(
operator=self.qubit_op, aux_operators=self.aux_ops_dict
)
self.assertAlmostEqual(result.eigenvalue, -1.85727503 + 0j)
self.assertEqual(len(result.aux_operator_eigenvalues), 2)
np.testing.assert_array_almost_equal(result.aux_operator_eigenvalues["aux_op1"], [2, 0])
np.testing.assert_array_almost_equal(result.aux_operator_eigenvalues["aux_op2"], [0, 0])

# Add None and zero operators and go again
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)
self.assertAlmostEqual(result.eigenvalue, -1.85727503 + 0j)
self.assertEqual(len(result.aux_operator_eigenvalues), 3)
np.testing.assert_array_almost_equal(result.aux_operator_eigenvalues["aux_op1"], [2, 0])
np.testing.assert_array_almost_equal(result.aux_operator_eigenvalues["aux_op2"], [0, 0])
self.assertEqual(result.aux_operator_eigenvalues["zero_op"], (0.0, 0))

def test_aux_operators_list(self):
"""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()
result = algo.compute_minimum_eigenvalue(operator=self.qubit_op, aux_operators=aux_ops)
self.assertAlmostEqual(result.eigenvalue, -1.85727503 + 0j)
self.assertEqual(len(result.aux_operator_eigenvalues), 2)
# expectation values
self.assertAlmostEqual(result.aux_operator_eigenvalues[0][0], 2, places=6)
self.assertAlmostEqual(result.aux_operator_eigenvalues[1][0], 0, places=6)
# standard deviations
self.assertAlmostEqual(result.aux_operator_eigenvalues[0][1], 0.0)
self.assertAlmostEqual(result.aux_operator_eigenvalues[1][1], 0.0)

# Go again with additional None and zero operators
extra_ops = [*aux_ops, None, 0]
result = algo.compute_minimum_eigenvalue(operator=self.qubit_op, aux_operators=extra_ops)
self.assertAlmostEqual(result.eigenvalue, -1.85727503 + 0j)
self.assertEqual(len(result.aux_operator_eigenvalues), 4)
# expectation values
self.assertAlmostEqual(result.aux_operator_eigenvalues[0][0], 2, places=6)
self.assertAlmostEqual(result.aux_operator_eigenvalues[1][0], 0, places=6)
self.assertIsNone(result.aux_operator_eigenvalues[2], None)
self.assertEqual(result.aux_operator_eigenvalues[3][0], 0.0)
# standard deviations
self.assertAlmostEqual(result.aux_operator_eigenvalues[0][1], 0.0)
self.assertAlmostEqual(result.aux_operator_eigenvalues[1][1], 0.0)
self.assertEqual(result.aux_operator_eigenvalues[3][1], 0.0)

def test_aux_operators_dict(self):
"""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()
result = algo.compute_minimum_eigenvalue(operator=self.qubit_op, aux_operators=aux_ops)
self.assertAlmostEqual(result.eigenvalue, -1.85727503 + 0j)
self.assertEqual(len(result.aux_operator_eigenvalues), 2)
# expectation values
self.assertAlmostEqual(result.aux_operator_eigenvalues["aux_op1"][0], 2, places=6)
self.assertAlmostEqual(result.aux_operator_eigenvalues["aux_op2"][0], 0, places=6)
# standard deviations
self.assertAlmostEqual(result.aux_operator_eigenvalues["aux_op1"][1], 0.0)
self.assertAlmostEqual(result.aux_operator_eigenvalues["aux_op2"][1], 0.0)

# Go again with additional None and zero operators
extra_ops = {**aux_ops, "None_operator": None, "zero_operator": 0}
result = algo.compute_minimum_eigenvalue(operator=self.qubit_op, aux_operators=extra_ops)
self.assertAlmostEqual(result.eigenvalue, -1.85727503 + 0j)
self.assertEqual(len(result.aux_operator_eigenvalues), 3)
# expectation values
self.assertAlmostEqual(result.aux_operator_eigenvalues["aux_op1"][0], 2, places=6)
self.assertAlmostEqual(result.aux_operator_eigenvalues["aux_op2"][0], 0, places=6)
self.assertEqual(result.aux_operator_eigenvalues["zero_operator"][0], 0.0)
self.assertTrue("None_operator" not in result.aux_operator_eigenvalues.keys())
# standard deviations
self.assertAlmostEqual(result.aux_operator_eigenvalues["aux_op1"][1], 0.0)
self.assertAlmostEqual(result.aux_operator_eigenvalues["aux_op2"][1], 0.0)
self.assertAlmostEqual(result.aux_operator_eigenvalues["zero_operator"][1], 0.0)


if __name__ == "__main__":
unittest.main()
2 changes: 1 addition & 1 deletion test/python/algorithms/minimum_eigensolvers/test_vqe.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
from qiskit import QuantumCircuit
from qiskit.algorithms import AlgorithmError
from qiskit.algorithms.gradients import ParamShiftEstimatorGradient
from qiskit.algorithms.minimum_eigensolvers.vqe import VQE
from qiskit.algorithms.minimum_eigensolvers import VQE
from qiskit.algorithms.optimizers import (
CG,
COBYLA,
Expand Down

0 comments on commit a79aaea

Please sign in to comment.