class TestInitialStateZero(QiskitAquaTestCase): def test_qubits_2_vector(self): self.zero = Zero(2) cct = self.zero.construct_circuit('vector') np.testing.assert_array_equal(cct, [1.0, 0.0, 0.0, 0.0]) def test_qubits_5_vector(self): self.zero = Zero(5) cct = self.zero.construct_circuit('vector') np.testing.assert_array_equal(cct, [ 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 ]) def test_qubits_2_circuit(self): self.zero = Zero(2) cct = self.zero.construct_circuit('circuit') self.assertEqual(cct.qasm(), 'OPENQASM 2.0;\ninclude "qelib1.inc";\nqreg q[2];\n') def test_qubits_5_circuit(self): self.zero = Zero(5) cct = self.zero.construct_circuit('circuit') self.assertEqual(cct.qasm(), 'OPENQASM 2.0;\ninclude "qelib1.inc";\nqreg q[5];\n')
def test_qubits_5_circuit(self): """ Qubits 5 circuit test """ zero = Zero(5) cct = zero.construct_circuit('circuit') # pylint: disable=no-member self.assertEqual(cct.qasm(), 'OPENQASM 2.0;\ninclude "qelib1.inc";\nqreg q[5];\n')
def test_qubits_5_vector(self): """ Qubits 5 vector test """ zero = Zero(5) cct = zero.construct_circuit('vector') np.testing.assert_array_equal(cct, [1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0])
class ADAPTVQE(QuantumAlgorithm): CONFIGURATION = { 'name': 'ADAPTVQE', 'description': 'ADAPT-VQE Algorithm', } def __init__( self, operator_pool: OperatorPool, initial_state: Union[InitialState, None], vqe_optimizer: Optimizer, hamiltonian: BaseOperator, max_iters: int = 10, grad_tol: float = 1e-3, max_evals_grouped=1, aux_operators=None, auto_conversion=True, use_zero_initial_parameters=False ): super().__init__() self.operator_pool = copy.deepcopy(operator_pool) if initial_state is None: self.initial_state = Zero(num_qubits=operator_pool.num_qubits) else: self.initial_state = initial_state self.vqe_optimizer = vqe_optimizer self.hamiltonian = hamiltonian self.max_iters = max_iters self.grad_tol = grad_tol self.max_evals_grouped = max_evals_grouped self.aux_operators = aux_operators self.auto_conversion = auto_conversion self.use_zero_initial_parameters = use_zero_initial_parameters self.parameters_per_step = 1 self._coms = None self.first_step = False self._current_max_grad = None self._optimal_circuit = None self._ret = {} self.adapt_step_history = { 'gradient_list': [], # updated in _compute_gradients 'max_gradient': [], # updated in _ansatz_operator_list 'optimal_parameters': [], # updated in _run 'circuit': [], # updated in _run 'operators': [], # updated in _ansatz_operator_list 'vqe_ret': [], # updated in _run 'energy_history': [], # updated in _run 'Total Eval Time': 0, #added by WillB 'Total num evals': 0 #added by WillB } @property def _new_param(self): if self.use_zero_initial_parameters: if self.first_step: return [0.0] return [0.0 for i in range(self.parameters_per_step)] else: if self.first_step: return [np.random.uniform(-np.pi, +np.pi)] return [np.random.uniform(-np.pi, +np.pi) for i in range(self.parameters_per_step)] def _run(self) -> dict: start_time = time.time() #Added by WillB logger.info('Starting ADAPT step {} of maximum {}'.format(1, self.max_iters)) circuit = self.initial_state.construct_circuit(mode='circuit') params = self._new_param op_list = self._ansatz_operator_list(current_circuit=circuit, current_ops=[]) vqe = self._vqe_run(operator_list=op_list, initial_parameters=params) self.adapt_step_history['optimal_parameters'].append(vqe['optimal_params']) self.adapt_step_history['circuit'].append(vqe['optimal_circuit']) self.adapt_step_history['vqe_ret'].append(vqe['_ret']) self.adapt_step_history['Total num evals'] += vqe['_ret']['num_optimizer_evals'] #added by WillB self.adapt_step_history['energy_history'].append(vqe['_ret']['energy']) logger.info('Finished ADAPT step {} of maximum {} with energy {}'.format(1, self.max_iters, vqe['_ret']['energy'])) iters = 1 print(iters) while iters <= self.max_iters: #and self._current_max_grad > self.grad_tol: #removed by WillB logger.info('Starting ADAPT step {} of maximum {}'.format(iters, self.max_iters)) circuit = vqe['optimal_circuit'] params = np.concatenate((vqe['optimal_params'], self._new_param)) op_list = self._ansatz_operator_list(current_circuit=circuit, current_ops=op_list) #if self._current_max_grad < self.grad_tol: #removed by willB # break vqe = self._vqe_run(operator_list=op_list, initial_parameters=params) self.adapt_step_history['optimal_parameters'].append(vqe['optimal_params']) self.adapt_step_history['circuit'].append(vqe['optimal_circuit']) self.adapt_step_history['vqe_ret'].append(vqe['_ret']) self.adapt_step_history['Total num evals'] += vqe['_ret']['num_optimizer_evals'] #added by WillB self.adapt_step_history['energy_history'].append(vqe['_ret']['energy']) logger.info( 'Finished ADAPT step {} of maximum {} with energy {}'.format(iters, self.max_iters, vqe['_ret']['energy'])) iters += 1 print(iters) logger.info('Finished final ADAPT step {} of maximum {}, with final energy {}'.format( iters, self.max_iters, vqe['_ret']['energy'] )) logger.info('Final gradient is {} where tolerance is {}'.format( self._current_max_grad, self.grad_tol )) self._optimal_circuit = circuit self._ret = vqe['_ret'] del self.adapt_step_history['vqe_ret'] #added by WillB stop_time = time.time() - start_time #added by WillB self.adapt_step_history['Total Eval Time'] = stop_time #added by WillB return self.adapt_step_history def _compute_gradients(self, circuit: QuantumCircuit) -> List[Tuple[complex, complex]]: kwargs = {'statevector_mode': self.quantum_instance.is_statevector} logger.info('Constructing evaluation circuits...') total_evaluation_circuits = list(parallel_map( _circ_eval, self.commutators, task_kwargs={**kwargs, 'wave_function': circuit}, num_processes=aqua_globals.num_processes )) total_evaluation_circuits = [item for sublist in total_evaluation_circuits for item in sublist] logger.info('Removing duplicate circuits') final_circs = [] for circ in total_evaluation_circuits: if not fast_circuit_inclusion(circ, final_circs): final_circs.append(circ) logger.info('Finished removing duplicate circuits') logger.debug('Executing {} circuits for gradient evaluation...'.format(len(final_circs))) result = self.quantum_instance.execute(final_circs) logger.debug('Computing {} gradients...'.format(len(self.commutators))) grads = list(parallel_map( _compute_grad, self.commutators, task_kwargs={**kwargs, 'result': result}, num_processes=aqua_globals.num_processes )) self.adapt_step_history['Total num evals'] += len(final_circs) logger.debug('Computed gradients: {}'.format(grads)) return [abs(tup[0]) for tup in grads] @property def commutators(self) -> List[BaseOperator]: if self._coms is not None: return self._coms logger.info('Computing commutators...') self._coms = list(parallel_map( _commutator, self.operator_pool.pool, task_kwargs={'hamiltonian': self.hamiltonian, 'gradient_tolerance': self.grad_tol}, num_processes=aqua_globals.num_processes )) # type: List[BaseOperator] logger.info('Computed {} commutators'.format(len(self._coms))) if all(isinstance(op, WeightedPauliOperator) for op in self._coms): new_coms = [] new_pool = [] for com, op in zip(self._coms, self.operator_pool.pool): if len(com.paulis) > 0: new_coms.append(com) new_pool.append(op) self._coms = new_coms self.operator_pool._pool = new_pool logger.info('Dropped commuting terms, new pool has size {}'.format(len(self._coms))) else: logger.info( 'Dropping commuting terms currently only supported for WeightedPauliOperator class') if len(self._coms) == 0: raise ValueError('List of commutators is empty.') return self._coms def _ansatz_operator_list(self, current_circuit: QuantumCircuit, current_ops: List[BaseOperator]) -> List[BaseOperator]: grads = self._compute_gradients(circuit=current_circuit) self._current_max_grad = np.max(grads) self.adapt_step_history['max_gradient'].append(self._current_max_grad) new_op = self.operator_pool.pool[np.argmax(grads)] # type: BaseOperator logger.info('New operator with gradient {} added to ansatz: {}'.format( self._current_max_grad, str(new_op) )) self.adapt_step_history['operators'].append(new_op.print_details()) return current_ops + [new_op] def _vqe_run(self, operator_list: List[BaseOperator], initial_parameters: np.ndarray, **kwargs) -> dict: self._current_operator_list = operator_list self._current_initial_parameters = initial_parameters var_form = self.variational_form() vqe = VQE( operator=self.hamiltonian, var_form=var_form, optimizer=self.vqe_optimizer, initial_point=initial_parameters, max_evals_grouped=self.max_evals_grouped, aux_operators=self.aux_operators, callback=None, auto_conversion=self.auto_conversion ) vqe_result = vqe.run(self.quantum_instance, **kwargs) # == vqe._ret return { 'optimal_circuit': vqe.get_optimal_circuit(), 'optimal_params': vqe.optimal_params, '_ret': vqe_result } def variational_form(self): return ADAPTVariationalForm( operator_pool=self._current_operator_list, bounds=[(-np.pi, +np.pi)] * len(self._current_operator_list), initial_state=self.initial_state ) def get_optimal_circuit(self): if self._optimal_circuit is None: raise AquaError( "Cannot find optimal circuit before running the algorithm to find optimal params.") return self._optimal_circuit
class ADAPTVQEROTO(ADAPTVQE): def __init__( self, operator_pool, initial_state, vqe_optimizer, hamiltonian, max_iters, energy_step_tol= 1e-8, auto_conversion=True, use_zero_initial_parameters=False, postprocessing = False, include_parameter = True ): #most of these params no longer matter, should edit to remove necessity self._quantum_instance = None super().__init__(operator_pool, initial_state, vqe_optimizer, hamiltonian, max_iters, #mximum number of iterations grad_tol = 1e-3, #stopping criteria if we were using gradient tolerance (we're not) max_evals_grouped=1,#unsure what this means aux_operators=None, #additional operators in pool auto_conversion=True, #when using VQE algorithm auto converts operators to best representaiton for backend use_zero_initial_parameters=False #Make your parameters start at zero before gradient based optimization ) #initialization from ADAPTVQE self.energy_step_tol = energy_step_tol #the stopping criteria for energy step self.hamiltonian = hamiltonian self.postprocessing = postprocessing self.include_parameter = include_parameter if initial_state is None: #creates new initial state if none passed self.initial_state = Zero(num_qubits=operator_pool.num_qubits) #Custom(hamiltonian.num_qubits, state='uniform') else: self.initial_state = initial_state #clean up old dictionary del self.adapt_step_history['gradient_list'] del self.adapt_step_history['max_gradient'] #del self.adapt_step_history['vqe_ret'] #self.adapt_step_history.update({'Total Eval Time': 0}) #self.adapt_step_history.update({'Total num Evals': 0}) self.adapt_step_history.update({'Total number energy iterations': 0}) self.adapt_step_history.update({'Max Energy Step': 0}) def find_optim_param_energy(self, preferred_op = None, preferred_op_mode = False, previous_circuit = None) -> dict: """method: find_optim_param_energy finds the optimum operator+parameter pair for the next iteration of the ansatz args: preferred_op - an operator (weightedpaulioperator) predetermined to be the next operator in the ansatz (essentially converts this method to rotosolve instead of rotoselect) preferred_op_mode - a flag (boolean) to choose whether or not preferred op should be used returns: dictionary with: optimal operator, name of optimal operator (for output purposes), optimal parameter, optimal energy, A, B, and C for Asin(theta + B) + C """ A = np.empty(0) C = np.empty(0) final_circs = [] E_list = [] #measure energies (theta = 0, theta = pi/4, theta = -pi/4) if(self.adapt_step_history['Total number energy iterations'] == 0): wavefunc = self.initial_state.construct_circuit() Energy_0_circ = self.hamiltonian.construct_evaluation_circuit(wavefunc, True) result = self.quantum_instance.execute(Energy_0_circ) Energy_0 = np.real(self.hamiltonian.evaluate_with_result(result, True)[0]) self.adapt_step_history['Total num evals'] += 1 else: op_list = self._current_operator_list bounds=[(-np.pi, +np.pi)]*len(op_list) vf = ADAPTVariationalForm(op_list, bounds, self.initial_state) wavefunc = vf.construct_circuit(self.adapt_step_history['optimal_parameters'][-1]) Energy_0 = self.adapt_step_history['energy_history'][-1] if preferred_op_mode: pool = preferred_op else: pool = self.operator_pool.pool args = [] kwargs = {'ham': self.hamiltonian, 'energy_step_tol': self.energy_step_tol, 'parameter': np.pi/4} op_list_pi4 = list(parallel_map( Generate_op, pool, args, kwargs )) kwargs['parameter'] = -np.pi/4 op_list_negpi4 = list(parallel_map( Generate_op, self.operator_pool.pool, args, kwargs )) op_list = op_list_pi4 + op_list_negpi4 kwargs = {'statevector_mode': self.quantum_instance.is_statevector} total_evaluation_circuits = list(parallel_map( _circ_eval, op_list, task_kwargs={**kwargs, 'wave_function': wavefunc}, num_processes=aqua_globals.num_processes )) total_evaluation_circuits = [item for sublist in total_evaluation_circuits for item in sublist] logger.info('Removing duplicate circuits') for circ in total_evaluation_circuits: if not fast_circuit_inclusion(circ, final_circs): final_circs.append(circ) result = self.quantum_instance.execute(final_circs) Energies = list(parallel_map( _compute_energy, op_list, task_kwargs={**kwargs, 'result': result}, num_processes=aqua_globals.num_processes )) for entry in Energies: E_list.append(np.real(entry[0])) cutoff = int(len(E_list)/2) Energy_pi4 = np.array(E_list[0:cutoff]) Energy_negpi4 = np.array(E_list[cutoff:]) #calculate minimum energy + A,B, and C from measured energies B = np.arctan2(( -Energy_negpi4 - Energy_pi4 + 2*Energy_0),(Energy_pi4 - Energy_negpi4)) Optim_param_array = (-B - np.pi/2)/2 X = np.sin(B) Y = np.sin(B + np.pi/2) Z = np.sin(B - np.pi/2) for i in range(0,(len(Energy_negpi4)-1)): if Y[i] != 0: C = np.append(C, (Energy_0-Energy_pi4[i]*(X[i]/Y[i]))/(1-X[i]/Y[i])) A = np.append(A, (Energy_pi4[i] - C[-1])/Y[i]) else: C = np.append(C, Energy_pi4[i]) A = np.append(A, (Energy_0 - C[-1])/X[i]) Optim_energy_array = C - A #find minimum energy index Optim_param_pos = np.argmin(Optim_energy_array) min_energy = Optim_energy_array[Optim_param_pos] Optim_param = Optim_param_array[Optim_param_pos] #CPU has limit on smallest number to be calculated - looks like its somewhere around 1e-16 #manually set this to zero as it should be zero. if min_energy > Energy_0 and abs(Optim_param) < 2e-16: Optim_param = 0 min_energy = Energy_0 #find optimum operator Optim_operator = self.operator_pool.pool[Optim_param_pos] Optim_operator_name = self.operator_pool.pool[Optim_param_pos].print_details() #keep track of number of quantum evaluations self.adapt_step_history['Total num evals'] += len(final_circs) return {'Newly Minimized Energy': min_energy, 'Next Parameter value': Optim_param, 'Next Operator identity': Optim_operator, 'Next Operator Name': Optim_operator_name, 'A': A[Optim_param_pos], 'B': B[Optim_param_pos], 'C': C[Optim_param_pos]} def recent_energy_step(self): return abs(self.adapt_step_history['energy_history'][-1] - self.adapt_step_history['energy_history'][-2]) #Our new run function, this will take time to edit def run(self, quantum_instance) -> dict: #we'll keep this structure of returning a dictionary, though maybe I'll return the full changelog, start = time.time() self._current_operator_list = [] self._quantum_instance = quantum_instance while self.adapt_step_history['Total number energy iterations'] <= 1: logger.info('Starting ADAPTROTO step {} of maximum {}'.format(self.adapt_step_history['Total number energy iterations'], self.max_iters)) New_minimizing_data = self.find_optim_param_energy() if self.adapt_step_history['Total number energy iterations'] > 1: #and New_minimizing_data['Newly Minimized Energy'] > self.adapt_step_history['energy_history'][-1]: break self._current_operator_list.append(New_minimizing_data['Next Operator identity']) if self.include_parameter == True: new_parameter = float(New_minimizing_data['Next Parameter value']) else: new_parameter = 0 if self.adapt_step_history['Total number energy iterations'] == 0: self.adapt_step_history['optimal_parameters'].append([new_parameter]) else: new_list = self.adapt_step_history['optimal_parameters'][-1] + [new_parameter] self.adapt_step_history['optimal_parameters'].append(new_list) self.adapt_step_history['operators'].append(New_minimizing_data['Next Operator Name']) if self.postprocessing: vqe_rotosolve_result = self._vqe_run(self._current_operator_list,np.array(self.adapt_step_history['optimal_parameters'][-1])) self.adapt_step_history['optimal_parameters'].append(list(vqe_rotosolve_result['optimal_params'])) self.adapt_step_history['energy_history'].append(vqe_rotosolve_result['_ret']['energy']) self.adapt_step_history['Total num evals'] += vqe_rotosolve_result['_ret']['num_optimizer_evals'] else: self.adapt_step_history['energy_history'].append(New_minimizing_data['Newly Minimized Energy']) logger.info('Finished ADAPTROTO step {} of maximum {} with energy {}'.format(self.adapt_step_history['Total number energy iterations'], self.max_iters, self.adapt_step_history['energy_history'][-1])) self.adapt_step_history['Total number energy iterations'] += 1 print(self.adapt_step_history['Total number energy iterations']) if self.recent_energy_step() > self.adapt_step_history['Max Energy Step']: self.adapt_step_history['Max Energy Step'] = self.recent_energy_step() while self.adapt_step_history['Total number energy iterations'] <= self.max_iters: #and self.recent_energy_step() >= self.energy_step_tol: logger.info('Starting ADAPTROTO step {} of maximum {}'.format(self.adapt_step_history['Total number energy iterations'], self.max_iters)) New_minimizing_data = self.find_optim_param_energy() #if New_minimizing_data['Newly Minimized Energy'] > self.adapt_step_history['energy_history'][-1]: # break self._current_operator_list.append(New_minimizing_data['Next Operator identity']) if self.include_parameter == True: new_parameter = float(New_minimizing_data['Next Parameter value']) else: new_parameter = 0 self.adapt_step_history['optimal_parameters'].append(self.adapt_step_history['optimal_parameters'][-1] + [new_parameter]) self.adapt_step_history['operators'].append(New_minimizing_data['Next Operator Name']) if self.postprocessing: vqe_rotosolve_result = self._vqe_run(self._current_operator_list, np.array(self.adapt_step_history['optimal_parameters'][-1])) self.adapt_step_history['optimal_parameters'].append(list(vqe_rotosolve_result['optimal_params'])) self.adapt_step_history['energy_history'].append(vqe_rotosolve_result['_ret']['energy']) self.adapt_step_history['Total num evals'] += vqe_rotosolve_result['_ret']['num_optimizer_evals'] else: self.adapt_step_history['energy_history'].append(New_minimizing_data['Newly Minimized Energy']) logger.info('Finished ADAPTROTO step {} of maximum {} with energy {}'.format(self.adapt_step_history['Total number energy iterations'], self.max_iters, self.adapt_step_history['energy_history'][-1])) self.adapt_step_history['Total number energy iterations'] += 1 print(self.adapt_step_history['Total number energy iterations']) if self.recent_energy_step() > self.adapt_step_history['Max Energy Step']: self.adapt_step_history['Max Energy Step'] = self.recent_energy_step() logger.info('Final energy step is {} where tolerance is {}'.format( self.recent_energy_step(), self.energy_step_tol )) eval_time = time.time() - start self.adapt_step_history['Total Eval Time'] = eval_time return self.adapt_step_history #return final minimized energy list
def test_qubits_2_circuit(self): """ Qubits 2 Circuit test """ zero = Zero(2) cct = zero.construct_circuit('circuit') self.assertEqual(cct.qasm(), 'OPENQASM 2.0;\ninclude "qelib1.inc";\nqreg q[2];\n')