Пример #1
0
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')
Пример #3
0
 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])
Пример #4
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
Пример #5
0
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
Пример #6
0
 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')