Skip to content
This repository has been archived by the owner on Dec 7, 2021. It is now read-only.

Commit

Permalink
VQE change backends
Browse files Browse the repository at this point in the history
  • Loading branch information
manoelmarques committed Jul 31, 2020
1 parent 7ac0fbd commit 21cab81
Show file tree
Hide file tree
Showing 4 changed files with 71 additions and 20 deletions.
34 changes: 19 additions & 15 deletions qiskit/aqua/algorithms/minimum_eigen_solvers/vqe.py
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,7 @@ def __init__(self,
self._max_evals_grouped = max_evals_grouped
self._circuit_sampler = None # type: Optional[CircuitSampler]
self._expectation = expectation
self._user_passed_expectation = self._expectation is not None
self._include_custom = include_custom
self._expect_op = None
self._operator = None
Expand Down Expand Up @@ -184,26 +185,29 @@ def operator(self, operator: Union[OperatorBase, LegacyBaseOperator]) -> None:
self._operator = operator
self._expect_op = None
self._check_operator_varform()
# Expectation is None, try to create one
if self._expectation is None:
self._try_set_expectation_value_from_factory()

def _try_set_expectation_value_from_factory(self):
if self.operator and self.quantum_instance:
self.expectation = ExpectationFactory.build(operator=self.operator,
backend=self.quantum_instance,
include_custom=self._include_custom)
def _try_set_expectation_value_from_factory(self) -> None:
if self.operator is not None and self.quantum_instance is not None:
self._set_expectation(ExpectationFactory.build(operator=self.operator,
backend=self.quantum_instance,
include_custom=self._include_custom))

def _set_expectation(self, exp: ExpectationBase) -> None:
self._expectation = exp
self._user_passed_expectation = False
self._expect_op = None

@QuantumAlgorithm.quantum_instance.setter
def quantum_instance(self, quantum_instance: Union[QuantumInstance, BaseBackend]) -> None:
""" set quantum_instance """
super(VQE, self.__class__).quantum_instance.__set__(self, quantum_instance)

if self._circuit_sampler is None:
self._circuit_sampler = CircuitSampler(self._quantum_instance)
else:
self._circuit_sampler.quantum_instance = self._quantum_instance

if self._expectation is None:
self._circuit_sampler = CircuitSampler(self._quantum_instance)
# Expectation is None or was not passed by user, try to create one
if self._expectation is None or not self._user_passed_expectation:
self._try_set_expectation_value_from_factory()

@property
Expand All @@ -214,8 +218,8 @@ def expectation(self) -> ExpectationBase:

@expectation.setter
def expectation(self, exp: ExpectationBase) -> None:
self._expectation = exp
self._expect_op = None
self._set_expectation(exp)
self._user_passed_expectation = True

@property
def aux_operators(self) -> Optional[List[Optional[OperatorBase]]]:
Expand Down Expand Up @@ -328,8 +332,8 @@ def construct_expectation(self,
else:
wave_function = self.var_form.construct_circuit(parameter)

# If ExpectationValue was never created, create one now.
if self.expectation is None:
# Expectation is None, try to create one
if self._expectation is None:
self._try_set_expectation_value_from_factory()

# If setting the expectation failed, raise an Error:
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
---
fixes:
- |
Changing backends in VQE from statevector to qasm_simulator or real device
was causing an error due to CircuitSampler incompatible reuse. VQE was changed
to always create a new CircuitSampler and create a new expectation in case not
entered by user.
Refer to
`#1153 <https://github.com/Qiskit/qiskit-aqua/issues/1153>` for more details.
34 changes: 33 additions & 1 deletion test/aqua/test_vqe.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
from qiskit.aqua import QuantumInstance, aqua_globals, AquaError
from qiskit.aqua.operators import (WeightedPauliOperator, PrimitiveOp, X, Z, I,
AerPauliExpectation, PauliExpectation,
MatrixExpectation)
MatrixExpectation, ExpectationBase)
from qiskit.aqua.components.variational_forms import RYRZ
from qiskit.aqua.components.optimizers import L_BFGS_B, COBYLA, SPSA, SLSQP
from qiskit.aqua.algorithms import VQE
Expand Down Expand Up @@ -315,6 +315,38 @@ def test_ibmq(self):
self.assertIsNotNone(result.cost_function_evals)
self.assertIsNotNone(result.optimizer_time)

@data(MatrixExpectation(), None)
def test_backend_change(self, user_expectation):
"""Test that VQE works when backend changes."""
vqe = VQE(operator=self.h2_op,
var_form=TwoLocal(rotation_blocks=['ry', 'rz'], entanglement_blocks='cz'),
optimizer=SLSQP(maxiter=2),
expectation=user_expectation,
quantum_instance=BasicAer.get_backend('statevector_simulator'))
result0 = vqe.run()
if user_expectation is not None:
with self.subTest('User expectation kept.'):
self.assertEqual(vqe.expectation, user_expectation)
else:
with self.subTest('Expectation created.'):
self.assertIsInstance(vqe.expectation, ExpectationBase)
try:
vqe.set_backend(BasicAer.get_backend('qasm_simulator'))
except Exception as ex: # pylint: disable=broad-except
self.fail("Failed to change backend. Error: '{}'".format(str(ex)))
return

result1 = vqe.run()
if user_expectation is not None:
with self.subTest('Change backend with user expectation, it is kept.'):
self.assertEqual(vqe.expectation, user_expectation)
else:
with self.subTest('Change backend without user expectation, one created.'):
self.assertIsInstance(vqe.expectation, ExpectationBase)

with self.subTest('Check results.'):
self.assertEqual(len(result0.optimal_point), len(result1.optimal_point))


if __name__ == '__main__':
unittest.main()
14 changes: 10 additions & 4 deletions test/optimization/test_qaoa.py
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ def test_qaoa(self, w, prob, m, solutions, convert_to_matrix_op):
self.assertIn(''.join([str(int(i)) for i in graph_solution]), solutions)

def test_change_operator_size(self):
""" QAOA test """
""" QAOA change operator size test """
backend = BasicAer.get_backend('statevector_simulator')
optimizer = COBYLA(maxiter=2)
qubit_op, _ = max_cut.get_operator(W1)
Expand All @@ -97,9 +97,15 @@ def test_change_operator_size(self):
aqua_globals.random_seed = seed
qaoa = QAOA(qubit_op, optimizer, P1)
quantum_instance = QuantumInstance(backend, seed_simulator=seed, seed_transpiler=seed)
qaoa.run(quantum_instance)
qaoa.operator = (X ^ qubit_op ^ Z)
qaoa.run()
result0 = qaoa.run(quantum_instance)
try:
qaoa.operator = (X ^ qubit_op ^ Z)
except Exception as ex: # pylint: disable=broad-except
self.fail("Failed to change operator. Error: '{}'".format(str(ex)))
return

result1 = qaoa.run()
self.assertEqual(len(result0.optimal_point), len(result1.optimal_point))

@idata([
[W2, S2, None],
Expand Down

0 comments on commit 21cab81

Please sign in to comment.