Skip to content

Commit 362843b

Browse files
committed
Add MinimumEigensolver interface to VQEAdapt
1 parent 7f7d8b8 commit 362843b

File tree

1 file changed

+94
-31
lines changed
  • qiskit/chemistry/algorithms/minimum_eigen_solvers

1 file changed

+94
-31
lines changed

qiskit/chemistry/algorithms/minimum_eigen_solvers/vqe_adapt.py

Lines changed: 94 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -24,26 +24,28 @@
2424
from qiskit import ClassicalRegister
2525
from qiskit.aqua import QuantumInstance, AquaError
2626
from qiskit.aqua.algorithms import VQAlgorithm, VQE, VQEResult
27-
from qiskit.chemistry.components.variational_forms import UCCSD
28-
from qiskit.aqua.operators import WeightedPauliOperator
29-
from qiskit.aqua.operators import LegacyBaseOperator
27+
from qiskit.aqua.algorithms.minimum_eigen_solvers import (MinimumEigensolver,
28+
MinimumEigensolverResult)
3029
from qiskit.aqua.components.optimizers import Optimizer
3130
from qiskit.aqua.components.variational_forms import VariationalForm
31+
from qiskit.aqua.operators import OperatorBase, LegacyBaseOperator, WeightedPauliOperator
3232
from qiskit.aqua.utils.validation import validate_min
33+
from qiskit.chemistry.components.variational_forms import UCCSD
3334

3435
logger = logging.getLogger(__name__)
3536

3637

37-
class VQEAdapt(VQAlgorithm):
38+
class VQEAdapt(VQAlgorithm, MinimumEigensolver):
3839
"""
3940
The Adaptive VQE algorithm.
4041
4142
See https://arxiv.org/abs/1812.11173
4243
"""
4344

44-
# TODO make re-usable, implement MinimumEignesolver interface
45-
def __init__(self, operator: LegacyBaseOperator,
46-
var_form_base: VariationalForm, optimizer: Optimizer,
45+
def __init__(self,
46+
operator: LegacyBaseOperator = None,
47+
var_form_base: VariationalForm = None,
48+
optimizer: Optimizer = None,
4749
initial_point: Optional[np.ndarray] = None,
4850
excitation_pool: Optional[List[WeightedPauliOperator]] = None,
4951
threshold: float = 1e-5,
@@ -69,24 +71,27 @@ def __init__(self, operator: LegacyBaseOperator,
6971
7072
Raises:
7173
ValueError: if var_form_base is not an instance of UCCSD.
72-
See also: qiskit/chemistry/components/variational_forms/uccsd_adapt.py
74+
See also: qiskit/chemistry/components/variational_forms/uccsd.py
7375
"""
7476
validate_min('threshold', threshold, 1e-15)
7577
validate_min('delta', delta, 1e-5)
78+
79+
if var_form_base is None or not isinstance(var_form_base, UCCSD):
80+
raise ValueError("var_form_base has to be an instance of UCCSD.")
81+
82+
self._quantum_instance = None
7683
super().__init__(var_form=var_form_base,
7784
optimizer=optimizer,
7885
initial_point=initial_point,
7986
quantum_instance=quantum_instance)
87+
8088
self._ret = None # type: Dict
8189
self._optimizer.set_max_evals_grouped(max_evals_grouped)
8290
if initial_point is None:
8391
self._initial_point = var_form_base.preferred_init_points
8492
self._operator = operator
85-
if not isinstance(var_form_base, UCCSD):
86-
raise ValueError("var_form_base has to be an instance of UCCSD.")
87-
self._var_form_base = var_form_base
88-
self._var_form_base.manage_hopping_operators()
89-
self._excitation_pool = self._var_form_base.excitation_pool \
93+
self._var_form.manage_hopping_operators()
94+
self._excitation_pool = self._var_form.excitation_pool \
9095
if excitation_pool is None else excitation_pool
9196
self._threshold = threshold
9297
self._delta = delta
@@ -98,21 +103,78 @@ def __init__(self, operator: LegacyBaseOperator,
98103
for aux_op in aux_operators:
99104
self._aux_operators.append(aux_op)
100105

101-
def _compute_gradients(self, excitation_pool, theta, delta,
102-
var_form, operator, optimizer):
106+
@property
107+
def operator(self) -> Optional[OperatorBase]:
108+
""" Returns operator """
109+
return self._operator
110+
111+
@operator.setter
112+
def operator(self, operator: Union[OperatorBase, LegacyBaseOperator]) -> None:
113+
""" set operator """
114+
self._operator = operator
115+
116+
@property
117+
def aux_operators(self) -> Optional[List[Optional[OperatorBase]]]:
118+
""" Returns aux operators """
119+
return self._aux_operators
120+
121+
@aux_operators.setter
122+
def aux_operators(self,
123+
aux_operators: Optional[
124+
Union[OperatorBase,
125+
LegacyBaseOperator,
126+
List[Optional[Union[OperatorBase,
127+
LegacyBaseOperator]]]]]) -> None:
128+
""" Set aux operators """
129+
if aux_operators is None:
130+
aux_operators = []
131+
elif not isinstance(aux_operators, list):
132+
aux_operators = [aux_operators]
133+
134+
self._aux_operators = aux_operators # type: List
135+
136+
@property
137+
def quantum_instance(self) -> Optional[QuantumInstance]:
138+
""" Returns quantum instance """
139+
return self._quantum_instance
140+
141+
@quantum_instance.setter
142+
def quantum_instance(self, quantum_instance) -> None:
143+
""" set quantum instance """
144+
self._quantum_instance = quantum_instance
145+
146+
def supports_aux_operators(self) -> bool:
147+
return True
148+
149+
def compute_minimum_eigenvalue(
150+
self,
151+
operator: Optional[Union[OperatorBase, LegacyBaseOperator]] = None,
152+
aux_operators: Optional[List[Optional[Union[OperatorBase,
153+
LegacyBaseOperator]]]] = None
154+
) -> MinimumEigensolverResult:
155+
super().compute_minimum_eigenvalue(operator, aux_operators)
156+
return self._run()
157+
158+
def _compute_gradients(self,
159+
excitation_pool: List,
160+
theta: float,
161+
delta: float,
162+
var_form: VariationalForm,
163+
operator: LegacyBaseOperator,
164+
optimizer: Optimizer) -> List:
103165
"""
104166
Computes the gradients for all available excitation operators.
105167
106168
Args:
107-
excitation_pool (list): pool of excitation operators
108-
theta (list): list of (up to now) optimal parameters
109-
delta (float): finite difference step size (for gradient computation)
110-
var_form (VariationalForm): current variational form
111-
operator (LegacyBaseOperator): system Hamiltonian
112-
optimizer (Optimizer): classical optimizer algorithm
169+
excitation_pool: pool of excitation operators
170+
theta: list of (up to now) optimal parameters
171+
delta: finite difference step size (for gradient computation)
172+
var_form: current variational form
173+
operator: system Hamiltonian
174+
optimizer: classical optimizer algorithm
113175
114176
Returns:
115-
list: List of pairs consisting of gradient and excitation operator.
177+
List of pairs consisting of gradient and excitation operator.
116178
"""
117179
res = []
118180
# compute gradients for all excitation in operator pool
@@ -143,9 +205,10 @@ def _run(self) -> 'VQEAdaptResult':
143205
Raises:
144206
AquaError: wrong setting of operator and backend.
145207
"""
208+
if self.operator is None:
209+
raise AquaError("The operator was never provided.")
210+
146211
self._ret = {} # TODO should be eliminated
147-
# self._operator = VQE._config_the_best_mode(self, self._operator,
148-
# self._quantum_instance.backend)
149212
self._quantum_instance.circuit_summary = True
150213

151214
threshold_satisfied = False
@@ -160,7 +223,7 @@ def _run(self) -> 'VQEAdaptResult':
160223
logger.info('--- Iteration #%s ---', str(iteration))
161224
# compute gradients
162225
cur_grads = self._compute_gradients(self._excitation_pool, theta, self._delta,
163-
self._var_form_base, self._operator,
226+
self._var_form, self._operator,
164227
self._optimizer)
165228
# pick maximum gradient
166229
max_grad_index, max_grad = max(enumerate(cur_grads),
@@ -186,11 +249,11 @@ def _run(self) -> 'VQEAdaptResult':
186249
logger.info("Final maximum gradient: %s", str(np.abs(max_grad[0])))
187250
alternating_sequence = True
188251
break
189-
# add new excitation to self._var_form_base
190-
self._var_form_base.push_hopping_operator(max_grad[1])
252+
# add new excitation to self._var_form
253+
self._var_form.push_hopping_operator(max_grad[1])
191254
theta.append(0.0)
192255
# run VQE on current Ansatz
193-
algorithm = VQE(self._operator, self._var_form_base, self._optimizer,
256+
algorithm = VQE(self._operator, self._var_form, self._optimizer,
194257
initial_point=theta)
195258
vqe_result = algorithm.run(self._quantum_instance)
196259
self._ret['opt_params'] = vqe_result.optimal_point
@@ -203,7 +266,7 @@ def _run(self) -> 'VQEAdaptResult':
203266

204267
# once finished evaluate auxiliary operators if any
205268
if self._aux_operators is not None and self._aux_operators:
206-
algorithm = VQE(self._operator, self._var_form_base, self._optimizer,
269+
algorithm = VQE(self._operator, self._var_form, self._optimizer,
207270
initial_point=theta, aux_operators=self._aux_operators)
208271
vqe_result = algorithm.run(self._quantum_instance)
209272
self._ret['opt_params'] = vqe_result.optimal_point
@@ -233,7 +296,7 @@ def _check_cyclicity(indices: List) -> bool:
233296
Auxiliary function to check for cycles in the indices of the selected excitations.
234297
235298
Returns:
236-
bool: Whether repeating sequences of indices have been detected.
299+
Whether repeating sequences of indices have been detected.
237300
"""
238301
cycle_regex = re.compile(r"(\b.+ .+\b)( \b\1\b)+")
239302
# reg-ex explanation:
@@ -261,7 +324,7 @@ def get_optimal_circuit(self):
261324
if 'opt_params' not in self._ret:
262325
raise AquaError("Cannot find optimal circuit before running the "
263326
"algorithm to find optimal params.")
264-
return self._var_form_base.construct_circuit(self._ret['opt_params'])
327+
return self._var_form.construct_circuit(self._ret['opt_params'])
265328

266329
def get_optimal_vector(self):
267330
# pylint: disable=import-outside-toplevel

0 commit comments

Comments
 (0)