Esempio n. 1
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,
                }
Esempio n. 2
0
    def _set_section_property_without_checking_defaults(
            self, section_name, property_name, value):
        """
        Args:
            section_name (str): the name of the section, case insensitive
            property_name (str): the name of the property
            value (obj): the value of the property
        Returns:
            Bool: True if value changed
        Raises:
            AquaError: validation error
        """
        section_name = JSONSchema.format_section_name(section_name).lower()
        property_name = JSONSchema.format_property_name(property_name)
        value = self._json_schema.check_property_value(section_name,
                                                       property_name, value)
        types = self.get_property_types(section_name, property_name)
        sections_temp = copy.deepcopy(self._sections)
        BaseParser._set_section_property(sections_temp, section_name,
                                         property_name, value, types)
        msg = self._json_schema.validate_property(sections_temp, section_name,
                                                  property_name)
        if msg is not None:
            raise AquaError("{}.{}: Value '{}': '{}'".format(
                section_name, property_name, value, msg))

        value_changed = False
        old_value = None
        if section_name not in self._sections:
            value_changed = True
        elif property_name not in self._sections[section_name]:
            value_changed = True
        else:
            old_value = self.get_section_property(section_name, property_name)
            value_changed = (old_value != value)

        if not value_changed:
            # nothing changed
            return False

        # check if the provider/backend is loadable and valid
        # set values from self.backend if exists
        if JSONSchema.BACKEND == section_name and \
                property_name in [JSONSchema.PROVIDER, JSONSchema.NAME]:
            if self.backend is not None:
                value = self.backend.name() \
                    if property_name == JSONSchema.NAME else get_provider_from_backend(self.backend)
            elif property_name == JSONSchema.NAME:
                provider_name = self.get_section_property(
                    section_name, JSONSchema.PROVIDER)
                backend_names = get_backends_from_provider(provider_name)
                if value not in backend_names:
                    raise AquaError(
                        "Backend '{}' not valid for provider: '{}' backends: '{}'"
                        .format(value, provider_name, backend_names))

        # update value internally
        BaseParser._set_section_property(self._sections, section_name,
                                         property_name, value, types)

        if JSONSchema.BACKEND == section_name and property_name == JSONSchema.PROVIDER:
            if self.backend is not None:
                # set value from self.backend if exists
                BaseParser._set_section_property(self._sections, section_name,
                                                 JSONSchema.NAME,
                                                 self.backend.name(),
                                                 ['string'])
            else:
                backend_name = self.get_section_property(
                    section_name, JSONSchema.NAME)
                backend_names = get_backends_from_provider(value)
                if backend_name not in backend_names:
                    # use first backend available in provider
                    backend_name = backend_names[0] if backend_names else ''
                    BaseParser._set_section_property(self._sections,
                                                     section_name,
                                                     JSONSchema.NAME,
                                                     backend_name, ['string'])

        # update backend schema
        if JSONSchema.BACKEND == section_name and \
                property_name in [JSONSchema.PROVIDER, JSONSchema.NAME]:
            # update backend schema
            self._json_schema.update_backend_schema(self)
            return True

        if property_name == JSONSchema.NAME:
            if BaseParser.is_pluggable_section(section_name):
                self._json_schema.update_pluggable_schemas(self)
                self._update_dependency_sections(section_name)
                # remove any previous pluggable sections not in new dependency list
                old_dependencies = \
                    self._get_dependency_sections(section_name, old_value) \
                    if old_value is not None else set()
                new_dependencies = \
                    self._get_dependency_sections(section_name, value) \
                    if value is not None else set()
                for pluggable_name in old_dependencies.difference(
                        new_dependencies):
                    if pluggable_name in self._sections:
                        del self._sections[pluggable_name]

                # reorder sections
                self._sections = self._order_sections(self._sections)
                return True

            if JSONSchema.PROBLEM == section_name:
                self._update_algorithm_problem()

            self.post_set_section_property(section_name, property_name)

        return True