def _compute_gradients(self, excitation_pool, theta, delta, var_form, operator, optimizer): """ Computes the gradients for all available excitation operators. Args: excitation_pool (list): pool of excitation operators theta (list): list of (up to now) optimal parameters delta (float): finite difference step size (for gradient computation) var_form (VariationalForm): current variational form operator (BaseOperator): system Hamiltonian optimizer (Optimizer): classical optimizer algorithm Returns: list: List of pairs consisting of gradient and excitation operator. """ res = [] # compute gradients for all excitation in operator pool for exc in excitation_pool: # push next excitation to variational form var_form.push_hopping_operator(exc) # construct auxiliary VQE instance vqe = VQE(operator, var_form, optimizer) vqe._quantum_instance = self._quantum_instance vqe._use_simulator_operator_mode = self._use_simulator_operator_mode # evaluate energies parameter_sets = theta + [-delta] + theta + [delta] energy_results = vqe._energy_evaluation(np.asarray(parameter_sets)) # compute gradient gradient = (energy_results[0] - energy_results[1]) / (2 * delta) res.append((np.abs(gradient), exc)) # pop excitation from variational form var_form.pop_hopping_operator() return res
def _run(self): """ Run the algorithm to compute the minimum eigenvalue. Returns: dict: Dictionary of results Raises: AquaError: wrong setting of operator and backend. """ self._operator = VQE._config_the_best_mode( self, self._operator, self._quantum_instance.backend) self._use_simulator_operator_mode = \ is_aer_statevector_backend(self._quantum_instance.backend) \ and isinstance(self._operator, (WeightedPauliOperator, TPBGroupedWeightedPauliOperator)) self._quantum_instance.circuit_summary = True cycle_regex = re.compile(r'(.+)( \1)+') # reg-ex explanation: # 1. (.+) will match at least one number and try to match as many as possible # 2. the match of this part is placed into capture group 1 # 3. ( \1)+ will match a space followed by the contents of capture group 1 # -> this results in any number of repeating numbers being detected threshold_satisfied = False alternating_sequence = False prev_op_indices = [] theta = [] max_grad = () iteration = 0 while not threshold_satisfied and not alternating_sequence: iteration += 1 logger.info('--- Iteration #%s ---', str(iteration)) # compute gradients cur_grads = self._compute_gradients(self._excitation_pool, theta, self._delta, self._var_form_base, self._operator, self._optimizer) # pick maximum gradient max_grad_index, max_grad = max(enumerate(cur_grads), key=lambda item: np.abs(item[1][0])) # store maximum gradient's index for cycle detection prev_op_indices.append(max_grad_index) # log gradients gradlog = "\nGradients in iteration #{}".format(str(iteration)) gradlog += "\nID: Excitation Operator: Gradient <(*) maximum>" for i, grad in enumerate(cur_grads): gradlog += '\n{}: {}: {}'.format(str(i), str(grad[1]), str(grad[0])) if grad[1] == max_grad[1]: gradlog += '\t(*)' logger.info(gradlog) if np.abs(max_grad[0]) < self._threshold: logger.info( "Adaptive VQE terminated succesfully with a final maximum gradient: %s", str(np.abs(max_grad[0]))) threshold_satisfied = True break # check indices of picked gradients for cycles if cycle_regex.search(' '.join(map(str, prev_op_indices))) is not None: logger.info("Alternating sequence found. Finishing.") logger.info("Final maximum gradient: %s", str(np.abs(max_grad[0]))) alternating_sequence = True break # add new excitation to self._var_form_base self._var_form_base.push_hopping_operator(max_grad[1]) theta.append(0.0) # run VQE on current Ansatz algorithm = VQE(self._operator, self._var_form_base, self._optimizer, initial_point=theta) self._ret = algorithm.run(self._quantum_instance) theta = self._ret['opt_params'].tolist() # once finished evaluate auxiliary operators if any if self._aux_operators is not None and self._aux_operators: algorithm = VQE(self._operator, self._var_form_base, self._optimizer, initial_point=theta, aux_operators=self._aux_operators) self._ret = algorithm.run(self._quantum_instance) # extend VQE returned information with additional outputs logger.info('The final energy is: %s', str(self._ret['energy'])) self._ret['num_iterations'] = iteration self._ret['final_max_grad'] = max_grad[0] if threshold_satisfied: self._ret['finishing_criterion'] = 'threshold_converged' elif alternating_sequence: self._ret['finishing_criterion'] = 'aborted_due_to_cyclicity' else: raise AquaError( 'The algorithm finished due to an unforeseen reason!') return self._ret
num_particles, qubit_mapping=qubit_mapping, two_qubit_reduction=two_qubit_reduction) depth = 1 var_form = UCCSD(hamiltonian.num_qubits, depth, num_orbitals, num_particles, initial_state=init_state, qubit_mapping=qubit_mapping, two_qubit_reduction=two_qubit_reduction) optimizer = COBYLA(maxiter=5000) algo = VQE(hamiltonian, var_form, optimizer) results = algo.run(sv_simulator) print(results) energy = results['energy'] opt_params = results['opt_params'] ground_state = results['min_vector'] eom = QEquationOfMotion(hamiltonian, num_orbitals, num_particles, qubit_mapping=qubit_mapping, two_qubit_reduction=two_qubit_reduction) excitation_energies, eom_matrices = eom.calculate_excited_states(ground_state)