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

VQE construct circuit returns circuits #1121

Merged
merged 14 commits into from
Jul 31, 2020
43 changes: 38 additions & 5 deletions qiskit/aqua/algorithms/minimum_eigen_solvers/vqe.py
Original file line number Diff line number Diff line change
Expand Up @@ -299,9 +299,9 @@ def print_settings(self):
ret += "===============================================================\n"
return ret

def construct_circuit(self,
parameter: Union[List[float], List[Parameter], np.ndarray]
) -> OperatorBase:
def construct_expectation(self,
parameter: Union[List[float], List[Parameter], np.ndarray]
) -> OperatorBase:
r"""
Generate the ansatz circuit and expectation value measurement, and return their
runnable composition.
Expand Down Expand Up @@ -329,13 +329,46 @@ def construct_circuit(self,
wave_function = self.var_form.construct_circuit(parameter)

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

# If setting the expectation failed, raise an Error:
if self.expectation is None:
raise AquaError('No expectation set and could not automatically set one, please '
'try explicitly setting an expectation or specify a backend so it '
'can be chosen automatically.')

observable_meas = self.expectation.convert(StateFn(self.operator, is_measurement=True))
ansatz_circuit_op = CircuitStateFn(wave_function)
return observable_meas.compose(ansatz_circuit_op).reduce()

def construct_circuit(self,
parameter: Union[List[float], List[Parameter], np.ndarray]
) -> List[QuantumCircuit]:
"""Return the circuits used to compute the expectation value.

Args:
parameter: Parameters for the ansatz circuit.

Returns:
A list of the circuits used to compute the expectation value.
"""
expect_op = self.construct_expectation(parameter).to_circuit_op()

circuits = []

# recursively extract circuits
def extract_circuits(op):
if isinstance(op, CircuitStateFn):
circuits.append(op.primitive)
elif isinstance(op, ListOp):
for op_i in op.oplist:
extract_circuits(op_i)

extract_circuits(expect_op)

return circuits

def supports_aux_operators(self) -> bool:
return True

Expand Down Expand Up @@ -436,7 +469,7 @@ def _energy_evaluation(self, parameters: Union[List[float], np.ndarray]
RuntimeError: If the variational form has no parameters.
"""
if not self._expect_op:
self._expect_op = self.construct_circuit(self._var_form_params)
self._expect_op = self.construct_expectation(self._var_form_params)

num_parameters = self.var_form.num_parameters
if self._var_form.num_parameters == 0:
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
---
fixes:
- |
The ``construct_circuit`` method of ``VQE`` previously returned the
expectation value to be evaluated as type ``OperatorBase``.
This functionality has been moved into ``construct_expectation`` and
``construct_circuit`` returns a list of the circuits that are evaluated
to compute the expectation value.
20 changes: 19 additions & 1 deletion test/aqua/test_vqe.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,8 @@

from qiskit.aqua import QuantumInstance, aqua_globals, AquaError
from qiskit.aqua.operators import (WeightedPauliOperator, PrimitiveOp, X, Z, I,
AerPauliExpectation, PauliExpectation)
AerPauliExpectation, PauliExpectation,
MatrixExpectation)
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 @@ -97,6 +98,23 @@ def test_circuit_input(self):
result = vqe.run(self.statevector_simulator)
self.assertAlmostEqual(result.eigenvalue.real, self.h2_energy, places=5)

@data(
(MatrixExpectation(), 1),
(AerPauliExpectation(), 1),
(PauliExpectation(), 2),
)
@unpack
def test_construct_circuit(self, expectation, num_circuits):
"""Test construct circuits returns QuantumCircuits and the right number of them."""
wavefunction = EfficientSU2(2, reps=1)
vqe = VQE(self.h2_op, wavefunction, expectation=expectation)
params = [0] * wavefunction.num_parameters
circuits = vqe.construct_circuit(params)

self.assertEqual(len(circuits), num_circuits)
for circuit in circuits:
self.assertIsInstance(circuit, QuantumCircuit)

def test_legacy_operator(self):
"""Test the VQE accepts and converts the legacy WeightedPauliOperator."""
pauli_dict = {
Expand Down