Ejemplo n.º 1
0
    def _run(self):
        """
        Run the algorithm to compute the minimum eigenvalue.

        Returns:
            Dictionary of results
        """
        if not self._quantum_instance.is_statevector and self._operator_mode == 'matrix':
            logger.warning(
                'Qasm simulation does not work on {} mode, changing '
                'the operator_mode to "paulis"'.format(self._operator_mode))
            self._operator_mode = 'paulis'

        self._use_simulator_operator_mode = \
            is_aer_statevector_backend(self._quantum_instance.backend) \
            and self._operator_mode != 'matrix'

        self._quantum_instance.circuit_summary = True
        self._eval_count = 0
        self._solve()
        self._get_ground_state_energy()
        self._eval_aux_ops()
        self._ret['eval_count'] = self._eval_count
        self._ret['eval_time'] = self._eval_time
        return self._ret
Ejemplo n.º 2
0
    def _config_the_best_mode(self, operator, backend):

        if not isinstance(operator, (WeightedPauliOperator, MatrixOperator,
                                     TPBGroupedWeightedPauliOperator)):
            logger.debug("Unrecognized operator type, skip auto conversion.")
            return operator

        ret_op = operator
        if not is_statevector_backend(
                backend):  # assume qasm, should use grouped paulis.
            if isinstance(operator, (WeightedPauliOperator, MatrixOperator)):
                logger.debug(
                    "When running with Qasm simulator, grouped pauli can "
                    "save number of measurements. "
                    "We convert the operator into grouped ones.")
                ret_op = op_converter.to_tpb_grouped_weighted_pauli_operator(
                    operator, TPBGroupedWeightedPauliOperator.sorted_grouping)
        else:
            if not is_aer_statevector_backend(backend):
                if not isinstance(operator, MatrixOperator):
                    logger.info(
                        "When running with non-Aer statevector simulator, "
                        "represent operator as a matrix could "
                        "achieve the better performance. We convert "
                        "the operator to matrix.")
                    ret_op = op_converter.to_matrix_operator(operator)
            else:
                if not isinstance(operator, WeightedPauliOperator):
                    logger.info("When running with Aer statevector simulator, "
                                "represent operator as weighted paulis could "
                                "achieve the better performance. We convert "
                                "the operator to weighted paulis.")
                    ret_op = op_converter.to_weighted_pauli_operator(operator)
        return ret_op
Ejemplo n.º 3
0
    def _run(self):
        """
        Run the algorithm to compute the minimum eigenvalue.

        Returns:
            dict: Dictionary of results

        Raises:
            AquaError: wrong setting of operator and backend.
        """
        if self._auto_conversion:
            self._operator = \
                self._config_the_best_mode(self._operator, self._quantum_instance.backend)
            for i in range(len(self._aux_operators)):
                if not self._aux_operators[i].is_empty():
                    self._aux_operators[i] = \
                        self._config_the_best_mode(self._aux_operators[i],
                                                   self._quantum_instance.backend)

        # sanity check
        if isinstance(
                self._operator,
                MatrixOperator) and not self._quantum_instance.is_statevector:
            raise AquaError("Non-statevector simulator can not work "
                            "with `MatrixOperator`, either turn ON "
                            "auto_conversion or use the proper "
                            "combination between operator and 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

        self._eval_count = 0
        self._ret = self.find_minimum(initial_point=self.initial_point,
                                      var_form=self.var_form,
                                      cost_fn=self._energy_evaluation,
                                      optimizer=self.optimizer)
        if self._ret['num_optimizer_evals'] is not None and \
                self._eval_count >= self._ret['num_optimizer_evals']:
            self._eval_count = self._ret['num_optimizer_evals']
        self._eval_time = self._ret['eval_time']
        logger.info(
            'Optimization complete in %s seconds.\nFound opt_params %s in %s evals',
            self._eval_time, self._ret['opt_params'], self._eval_count)
        self._ret['eval_count'] = self._eval_count

        self._ret['energy'] = self.get_optimal_cost()
        self._ret['eigvals'] = np.asarray([self.get_optimal_cost()])
        self._ret['eigvecs'] = np.asarray([self.get_optimal_vector()])
        self._eval_aux_ops()

        self.cleanup_parameterized_circuits()
        return self._ret
Ejemplo n.º 4
0
    def _run(self):
        """
        Run the algorithm to compute the minimum eigenvalue.

        Returns:
            Dictionary of results
        """
        if not self._quantum_instance.is_statevector and self._operator_mode == 'matrix':
            logger.warning(
                'Qasm simulation does not work on {} mode, changing '
                'the operator_mode to "paulis"'.format(self._operator_mode))
            self._operator_mode = 'paulis'

        self._use_simulator_operator_mode = \
            is_aer_statevector_backend(self._quantum_instance.backend) \
            and self._operator_mode != 'matrix'

        self._quantum_instance.circuit_summary = True

        self._eval_count = 0
        self._ret = self.find_minimum(initial_point=self.initial_point,
                                      var_form=self.var_form,
                                      cost_fn=self._energy_evaluation,
                                      optimizer=self.optimizer)

        if self._ret[
                'num_optimizer_evals'] is not None and self._eval_count >= self._ret[
                    'num_optimizer_evals']:
            self._eval_count = self._ret['num_optimizer_evals']
        self._eval_time = self._ret['eval_time']
        logger.info(
            'Optimization complete in {} seconds.\nFound opt_params {} in {} evals'
            .format(self._eval_time, self._ret['opt_params'],
                    self._eval_count))
        self._ret['eval_count'] = self._eval_count

        self._ret['energy'] = self.get_optimal_cost()
        self._ret['eigvals'] = np.asarray([self.get_optimal_cost()])
        self._ret['eigvecs'] = np.asarray([self.get_optimal_vector()])
        self._eval_aux_ops()
        return self._ret
Ejemplo n.º 5
0
    def update_backend_schema(self, input_parser):
        """
        Updates backend schema
        """
        if JSONSchema.BACKEND not in self._schema['properties']:
            return

        # Updates defaults provider/backend
        default_provider_name = None
        default_backend_name = None
        orig_backend_properties = self._original_schema.get(
            'properties', {}).get(JSONSchema.BACKEND, {}).get('properties')
        if orig_backend_properties is not None:
            default_provider_name = orig_backend_properties.get(
                JSONSchema.PROVIDER, {}).get('default')
            default_backend_name = orig_backend_properties.get(
                JSONSchema.NAME, {}).get('default')

        providers = get_local_providers()
        if default_provider_name is None or default_provider_name not in providers:
            # use first provider available
            providers_items = providers.items()
            provider_tuple = next(
                iter(providers_items)) if len(providers_items) > 0 else ('',
                                                                         [])
            default_provider_name = provider_tuple[0]

        if default_backend_name is None or default_backend_name not in providers.get(
                default_provider_name, []):
            # use first backend available in provider
            default_backend_name = providers.get(
                default_provider_name)[0] if len(
                    providers.get(default_provider_name, [])) > 0 else ''

        self._schema['properties'][JSONSchema.BACKEND] = {
            'type': 'object',
            'properties': {
                JSONSchema.PROVIDER: {
                    'type': 'string',
                    'default': default_provider_name
                },
                JSONSchema.NAME: {
                    'type': 'string',
                    'default': default_backend_name
                },
            },
            'required': [JSONSchema.PROVIDER, JSONSchema.NAME],
            'additionalProperties': False,
        }
        provider_name = input_parser.get_section_property(
            JSONSchema.BACKEND, JSONSchema.PROVIDER, default_provider_name)
        backend_names = get_backends_from_provider(provider_name)
        backend_name = input_parser.get_section_property(
            JSONSchema.BACKEND, JSONSchema.NAME, default_backend_name)
        if backend_name not in backend_names:
            # use first backend available in provider
            backend_name = backend_names[0] if len(backend_names) > 0 else ''

        backend = get_backend_from_provider(provider_name, backend_name)
        config = backend.configuration()

        # Include shots in schema only if not a statevector backend.
        # For statevector, shots will be set to 1, in QiskitAqua
        if not is_statevector_backend(backend):
            self._schema['properties'][
                JSONSchema.BACKEND]['properties']['shots'] = {
                    'type': 'integer',
                    'minimum': 1,
                }
            default_shots = 1024
            # ensure default_shots <= max_shots
            if config.max_shots:
                default_shots = min(default_shots, config.max_shots)
                self._schema['properties'][JSONSchema.BACKEND]['properties'][
                    'shots']['maximum'] = config.max_shots

            self._schema['properties'][JSONSchema.BACKEND]['properties'][
                'shots']['default'] = default_shots

        self._schema['properties'][
            JSONSchema.BACKEND]['properties']['skip_transpiler'] = {
                'type': 'boolean',
                'default': False,
            }

        coupling_map_devices = []
        noise_model_devices = []
        check_coupling_map = is_simulator_backend(backend)
        check_noise_model = is_aer_provider(
            backend) and not is_aer_statevector_backend(backend)
        try:
            if (check_coupling_map or check_noise_model) and has_ibmq():
                backend_names = get_backends_from_provider('qiskit.IBMQ')
                for backend_name in backend_names:
                    ibmq_backend = get_backend_from_provider(
                        'qiskit.IBMQ', backend_name)
                    if is_simulator_backend(ibmq_backend):
                        continue
                    if check_noise_model:
                        noise_model_devices.append('qiskit.IBMQ:' +
                                                   backend_name)
                    if check_coupling_map and ibmq_backend.configuration(
                    ).coupling_map:
                        coupling_map_devices.append('qiskit.IBMQ:' +
                                                    backend_name)
        except Exception as e:
            logger.debug("Failed to load IBMQ backends. Error {}".format(
                str(e)))

        # Includes 'coupling map' and 'coupling_map_from_device' in schema only if a simulator backend.
        # Actual devices have a coupling map based on the physical configuration of the device.
        # The user can configure the coupling map so its the same as the coupling map
        # of a given device in order to better simulate running on the device.
        # Property 'coupling_map_from_device' is a list of provider:name backends that are
        # real devices e.g qiskit.IBMQ:ibmqx5.
        # If property 'coupling_map', an array, is provided, it overrides coupling_map_from_device,
        # the latter defaults to 'None'. So in total no coupling map is a default, i.e. all to all coupling is possible.
        if is_simulator_backend(backend):
            self._schema['properties'][
                JSONSchema.BACKEND]['properties']['coupling_map'] = {
                    'type': ['array', 'null'],
                    'default': None,
                }
            if len(coupling_map_devices) > 0:
                coupling_map_devices.append(None)
                self._schema['properties'][JSONSchema.BACKEND]['properties'][
                    'coupling_map_from_device'] = {
                        'type': ['string', 'null'],
                        'default': None,
                        'oneOf': [{
                            'enum': coupling_map_devices
                        }],
                    }

        # noise model that can be setup for Aer simulator so as to model noise of an actual device.
        if len(noise_model_devices) > 0:
            noise_model_devices.append(None)
            self._schema['properties'][
                JSONSchema.BACKEND]['properties']['noise_model'] = {
                    'type': ['string', 'null'],
                    'default': None,
                    'oneOf': [{
                        'enum': noise_model_devices
                    }],
                }

        # If a noise model is supplied then the basis gates is set as per the noise model
        # unless basis gates is not None in which case it overrides noise model and a warning msg is logged.
        # as it is an advanced use case.
        self._schema['properties'][
            JSONSchema.BACKEND]['properties']['basis_gates'] = {
                'type': ['array', 'null'],
                'default': None,
            }

        # TODO: Not sure if we want to continue with initial_layout in declarative form.
        # It requires knowledge of circuit registers etc. Perhaps its best to leave this detail to programming API.
        self._schema['properties'][
            JSONSchema.BACKEND]['properties']['initial_layout'] = {
                'type': ['object', 'null'],
                'default': None,
            }

        # The same default and minimum as current RunConfig values
        self._schema['properties'][
            JSONSchema.BACKEND]['properties']['max_credits'] = {
                'type': 'integer',
                'default': 10,
                'minimum': 3,
                'maximum': 10,
            }

        # Timeout and wait are for remote backends where we have to connect over network
        if not is_local_backend(backend):
            self._schema['properties'][
                JSONSchema.BACKEND]['properties']['timeout'] = {
                    "type": ["number", "null"],
                    'default': None,
                }
            self._schema['properties'][
                JSONSchema.BACKEND]['properties']['wait'] = {
                    'type': 'number',
                    'default': 5.0,
                    'minimum': 0.0,
                }
Ejemplo n.º 6
0
    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