24
24
from qiskit import ClassicalRegister
25
25
from qiskit .aqua import QuantumInstance , AquaError
26
26
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 )
30
29
from qiskit .aqua .components .optimizers import Optimizer
31
30
from qiskit .aqua .components .variational_forms import VariationalForm
31
+ from qiskit .aqua .operators import OperatorBase , LegacyBaseOperator , WeightedPauliOperator
32
32
from qiskit .aqua .utils .validation import validate_min
33
+ from qiskit .chemistry .components .variational_forms import UCCSD
33
34
34
35
logger = logging .getLogger (__name__ )
35
36
36
37
37
- class VQEAdapt (VQAlgorithm ):
38
+ class VQEAdapt (VQAlgorithm , MinimumEigensolver ):
38
39
"""
39
40
The Adaptive VQE algorithm.
40
41
41
42
See https://arxiv.org/abs/1812.11173
42
43
"""
43
44
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 ,
47
49
initial_point : Optional [np .ndarray ] = None ,
48
50
excitation_pool : Optional [List [WeightedPauliOperator ]] = None ,
49
51
threshold : float = 1e-5 ,
@@ -69,24 +71,27 @@ def __init__(self, operator: LegacyBaseOperator,
69
71
70
72
Raises:
71
73
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
73
75
"""
74
76
validate_min ('threshold' , threshold , 1e-15 )
75
77
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
76
83
super ().__init__ (var_form = var_form_base ,
77
84
optimizer = optimizer ,
78
85
initial_point = initial_point ,
79
86
quantum_instance = quantum_instance )
87
+
80
88
self ._ret = None # type: Dict
81
89
self ._optimizer .set_max_evals_grouped (max_evals_grouped )
82
90
if initial_point is None :
83
91
self ._initial_point = var_form_base .preferred_init_points
84
92
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 \
90
95
if excitation_pool is None else excitation_pool
91
96
self ._threshold = threshold
92
97
self ._delta = delta
@@ -98,21 +103,78 @@ def __init__(self, operator: LegacyBaseOperator,
98
103
for aux_op in aux_operators :
99
104
self ._aux_operators .append (aux_op )
100
105
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 :
103
165
"""
104
166
Computes the gradients for all available excitation operators.
105
167
106
168
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
113
175
114
176
Returns:
115
- list: List of pairs consisting of gradient and excitation operator.
177
+ List of pairs consisting of gradient and excitation operator.
116
178
"""
117
179
res = []
118
180
# compute gradients for all excitation in operator pool
@@ -143,9 +205,10 @@ def _run(self) -> 'VQEAdaptResult':
143
205
Raises:
144
206
AquaError: wrong setting of operator and backend.
145
207
"""
208
+ if self .operator is None :
209
+ raise AquaError ("The operator was never provided." )
210
+
146
211
self ._ret = {} # TODO should be eliminated
147
- # self._operator = VQE._config_the_best_mode(self, self._operator,
148
- # self._quantum_instance.backend)
149
212
self ._quantum_instance .circuit_summary = True
150
213
151
214
threshold_satisfied = False
@@ -160,7 +223,7 @@ def _run(self) -> 'VQEAdaptResult':
160
223
logger .info ('--- Iteration #%s ---' , str (iteration ))
161
224
# compute gradients
162
225
cur_grads = self ._compute_gradients (self ._excitation_pool , theta , self ._delta ,
163
- self ._var_form_base , self ._operator ,
226
+ self ._var_form , self ._operator ,
164
227
self ._optimizer )
165
228
# pick maximum gradient
166
229
max_grad_index , max_grad = max (enumerate (cur_grads ),
@@ -186,11 +249,11 @@ def _run(self) -> 'VQEAdaptResult':
186
249
logger .info ("Final maximum gradient: %s" , str (np .abs (max_grad [0 ])))
187
250
alternating_sequence = True
188
251
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 ])
191
254
theta .append (0.0 )
192
255
# 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 ,
194
257
initial_point = theta )
195
258
vqe_result = algorithm .run (self ._quantum_instance )
196
259
self ._ret ['opt_params' ] = vqe_result .optimal_point
@@ -203,7 +266,7 @@ def _run(self) -> 'VQEAdaptResult':
203
266
204
267
# once finished evaluate auxiliary operators if any
205
268
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 ,
207
270
initial_point = theta , aux_operators = self ._aux_operators )
208
271
vqe_result = algorithm .run (self ._quantum_instance )
209
272
self ._ret ['opt_params' ] = vqe_result .optimal_point
@@ -233,7 +296,7 @@ def _check_cyclicity(indices: List) -> bool:
233
296
Auxiliary function to check for cycles in the indices of the selected excitations.
234
297
235
298
Returns:
236
- bool: Whether repeating sequences of indices have been detected.
299
+ Whether repeating sequences of indices have been detected.
237
300
"""
238
301
cycle_regex = re .compile (r"(\b.+ .+\b)( \b\1\b)+" )
239
302
# reg-ex explanation:
@@ -261,7 +324,7 @@ def get_optimal_circuit(self):
261
324
if 'opt_params' not in self ._ret :
262
325
raise AquaError ("Cannot find optimal circuit before running the "
263
326
"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' ])
265
328
266
329
def get_optimal_vector (self ):
267
330
# pylint: disable=import-outside-toplevel
0 commit comments