def set_section_property(self, section_name, property_name, value): section_name = InputParser._format_section_name(section_name) property_name = InputParser._format_property_name(property_name) types = self.get_property_types(section_name, property_name) value = InputParser._get_value(value, types) if len(types) > 0: validator = jsonschema.Draft4Validator(self._schema) valid = False for type in types: valid = validator.is_type(value, type) if valid: break if not valid: raise AlgorithmError( "{}.{}: Value '{}' is not of types: '{}'".format( section_name, property_name, value, types)) sections_temp = copy.deepcopy(self._sections) InputParser._set_section_property(sections_temp, section_name, property_name, value, types) msg = self._validate(sections_temp, section_name, property_name) if msg is not None: raise AlgorithmError("{}.{}: Value '{}': '{}'".format( section_name, property_name, value, msg)) InputParser._set_section_property(self._sections, section_name, property_name, value, types) if property_name == InputParser.NAME: if InputParser.INPUT == section_name: self._update_algorithm_input_schema() # remove properties that are not valid for this section default_properties = self.get_section_default_properties( section_name) if isinstance(default_properties, dict): properties = self.get_section_properties(section_name) for property_name in list(properties.keys()): if property_name != InputParser.NAME and property_name not in default_properties: self.delete_section_property( section_name, property_name) elif InputParser.PROBLEM == section_name: self._update_algorithm_problem() self._update_input_problem() elif InputParser.is_pluggable_section(section_name): self._update_pluggable_input_schemas() # remove properties that are not valid for this section default_properties = self.get_section_default_properties( section_name) if isinstance(default_properties, dict): properties = self.get_section_properties(section_name) for property_name in list(properties.keys()): if property_name != InputParser.NAME and property_name not in default_properties: self.delete_section_property( section_name, property_name) if section_name == InputParser.ALGORITHM: self._update_dependency_sections() self._sections = self._order_sections(self._sections)
def save_to_file(self, file_name): if file_name is None: raise AlgorithmError('Missing file path') file_name = file_name.strip() if len(file_name) == 0: raise AlgorithmError('Missing file path') with open(file_name, 'w') as f: print(json.dumps(self.get_sections(), sort_keys=True, indent=4), file=f)
def get_algorithm_ck(params, algo_input=None, json_output=False): """ Retrieve algorithm as named in params, using params and algo_input as input data and returning a result dictionary Args: params (dict): Dictionary of params for algo and dependent objects algo_input(algorithminput): Main input data for algorithm. Optional, an algo may run entirely from params json_output(bool): False for regular python dictionary return, True for json conversion Returns: Result dictionary containing result of algorithm computation """ _discover_on_demand() inputparser = InputParser(params) inputparser.parse() inputparser.validate_merge_defaults() logger.debug('Algorithm Input: {}'.format(json.dumps(inputparser.get_sections(), sort_keys=True, indent=4))) algo_name = inputparser.get_section_property(InputParser.ALGORITHM, InputParser.NAME) if algo_name is None: raise AlgorithmError('Missing algorithm name') if algo_name not in local_algorithms(): raise AlgorithmError('Algorithm "{0}" missing in local algorithms'.format(algo_name)) backend_cfg = None backend = inputparser.get_section_property(InputParser.BACKEND, InputParser.NAME) if backend is not None: backend_cfg = {k: v for k, v in inputparser.get_section(InputParser.BACKEND).items() if k != 'name'} backend_cfg['backend'] = backend algorithm = get_algorithm_instance(algo_name) algorithm.random_seed = inputparser.get_section_property(InputParser.PROBLEM, 'random_seed') if backend_cfg is not None: algorithm.setup_quantum_backend(**backend_cfg) algo_params = copy.deepcopy(inputparser.get_sections()) if algo_input is None: input_name = inputparser.get_section_property('input', InputParser.NAME) if input_name is not None: algo_input = get_input_instance(input_name) input_params = copy.deepcopy(inputparser.get_section_properties('input')) del input_params[InputParser.NAME] convert_json_to_dict(input_params) algo_input.from_params(input_params) algorithm.init_params(algo_params, algo_input) return algorithm
def _update_input_problem(self): problem_name = self.get_section_property(InputParser.PROBLEM, InputParser.NAME) if problem_name is None: problem_name = self.get_property_default_value( InputParser.PROBLEM, InputParser.NAME) if problem_name is None: raise AlgorithmError( "No algorithm 'problem' section found on input.") input_name = self.get_section_property(InputParser.INPUT, InputParser.NAME) if input_name is not None and problem_name in InputParser.get_input_problems( input_name): return for input_name in local_inputs(): if problem_name in self.get_input_problems(input_name): # set to the first input to solve the problem self.set_section_property(InputParser.INPUT, InputParser.NAME, input_name) return # no input solve this problem, remove section self.delete_section(InputParser.INPUT)
def _update_algorithm_problem(self): problem_name = self.get_section_property(InputParser.PROBLEM, InputParser.NAME) if problem_name is None: problem_name = self.get_property_default_value( InputParser.PROBLEM, InputParser.NAME) if problem_name is None: raise AlgorithmError( "No algorithm 'problem' section found on input.") algo_name = self.get_section_property(InputParser.ALGORITHM, InputParser.NAME) if algo_name is not None and problem_name in InputParser.get_algorithm_problems( algo_name): return for algo_name in local_algorithms(): if problem_name in self.get_algorithm_problems(algo_name): # set to the first algorithm to solve the problem self.set_section_property(InputParser.ALGORITHM, InputParser.NAME, algo_name) return # no algorithm solve this problem, remove section self.delete_section(InputParser.ALGORITHM)
def __init__(self, input=None): """Create InputParser object.""" self._original_sections = None self._filename = None self._sections = None if input is not None: if isinstance(input, dict): self._sections = input elif isinstance(input, str): self._filename = input else: raise AlgorithmError("Invalid parser input type.") self._section_order = [ InputParser.PROBLEM, InputParser.INPUT, InputParser.ALGORITHM ] for pluggable_type in local_pluggables_types(): if pluggable_type != InputParser.ALGORITHM: self._section_order.append(pluggable_type) self._section_order.extend([InputParser.BACKEND, InputParser._UNKNOWN]) problems_dict = OrderedDict() for algo_name in local_algorithms(): problems = InputParser.get_algorithm_problems(algo_name) for problem in problems: problems_dict[problem] = None problems_enum = {'enum': list(problems_dict.keys())} jsonfile = os.path.join(os.path.dirname(__file__), 'input_schema.json') with open(jsonfile) as json_file: self._schema = json.load(json_file) self._schema['definitions'][InputParser.PROBLEM]['properties'][ InputParser.NAME]['oneOf'] = [problems_enum] self._original_schema = copy.deepcopy(self._schema)
def _format_property_name(property_name): if property_name is None: property_name = '' property_name = property_name.strip() if len(property_name) == 0: raise AlgorithmError("Empty property name.") return property_name
def _format_section_name(section_name): if section_name is None: section_name = '' section_name = section_name.strip() if len(section_name) == 0: raise AlgorithmError("Empty section name.") return section_name
def _validate_input_problem(self): input_name = self.get_section_property(InputParser.INPUT, InputParser.NAME) if input_name is None: return problem_name = self.get_section_property(InputParser.PROBLEM, InputParser.NAME) if problem_name is None: problem_name = self.get_property_default_value( InputParser.PROBLEM, InputParser.NAME) if problem_name is None: raise AlgorithmError( "No algorithm 'problem' section found on input.") problems = InputParser.get_input_problems(input_name) if problem_name not in problems: raise AlgorithmError( "Problem: {} not in the list of problems: {} for input: {}.". format(problem_name, problems, input_name))
def parse(self): """Parse the data.""" if self._sections is None: if self._filename is None: raise AlgorithmError("Missing input file") with open(self._filename) as json_file: self._sections = json.load(json_file) self._update_pluggable_input_schemas() self._update_algorithm_input_schema() self._sections = self._order_sections(self._sections) self._original_sections = copy.deepcopy(self._sections)
def get_section(self, section_name): """Return a Section by name. Args: section_name (str): the name of the section, case insensitive Returns: Section: The section with this name Raises: AlgorithmError: if the section does not exist. """ section_name = InputParser._format_section_name(section_name) try: return self._sections[section_name] except KeyError: raise AlgorithmError('No section "{0}"'.format(section_name))
def validate_merge_defaults(self): try: self._merge_default_values() json_dict = self.get_sections() logger.debug('Algorithm Input: {}'.format( json.dumps(json_dict, sort_keys=True, indent=4))) logger.debug('Algorithm Input Schema: {}'.format( json.dumps(self._schema, sort_keys=True, indent=4))) jsonschema.validate(json_dict, self._schema) except jsonschema.exceptions.ValidationError as ve: logger.info('JSON Validation error: {}'.format(str(ve))) raise AlgorithmError(ve.message) self._validate_algorithm_problem() self._validate_input_problem()
def set_section_data(self, section_name, value): """ Sets a section data. Args: section_name (str): the name of the section, case insensitive value : value to set """ section_name = InputParser._format_section_name(section_name) types = self.get_section_types(section_name) value = InputParser._get_value(value, types) if len(types) > 0: validator = jsonschema.Draft4Validator(self._schema) valid = False for type in types: valid = validator.is_type(value, type) if valid: break if not valid: raise AlgorithmError( "{}: Value '{}' is not of types: '{}'".format( section_name, value, types)) self._sections[section_name] = value
def _update_algorithm_input_schema(self): # find alogorithm input default_name = self.get_property_default_value(InputParser.INPUT, InputParser.NAME) input_name = self.get_section_property(InputParser.INPUT, InputParser.NAME, default_name) if input_name is None: # find the first valid input for the problem problem_name = self.get_section_property(InputParser.PROBLEM, InputParser.NAME) if problem_name is None: problem_name = self.get_property_default_value( InputParser.PROBLEM, InputParser.NAME) if problem_name is None: raise AlgorithmError( "No algorithm 'problem' section found on input.") for name in local_inputs(): if problem_name in self.get_input_problems(name): # set to the first input to solve the problem input_name = name break if input_name is None: # just remove fromm schema if none solves the problem if InputParser.INPUT in self._schema['definitions']: del self._schema['definitions'][InputParser.INPUT] if InputParser.INPUT in self._schema['properties']: del self._schema['properties'][InputParser.INPUT] return if default_name is None: default_name = input_name config = {} try: config = get_input_configuration(input_name) except: pass input_schema = config[ 'input_schema'] if 'input_schema' in config else {} properties = input_schema[ 'properties'] if 'properties' in input_schema else {} properties[InputParser.NAME] = {'type': 'string'} required = input_schema[ 'required'] if 'required' in input_schema else [] additionalProperties = input_schema[ 'additionalProperties'] if 'additionalProperties' in input_schema else True if default_name is not None: properties[InputParser.NAME]['default'] = default_name required.append(InputParser.NAME) if InputParser.INPUT not in self._schema['definitions']: self._schema['definitions'][InputParser.INPUT] = {'type': 'object'} if InputParser.INPUT not in self._schema['properties']: self._schema['properties'][InputParser.INPUT] = { '$ref': "#/definitions/{}".format(InputParser.INPUT) } self._schema['definitions'][ InputParser.INPUT]['properties'] = properties self._schema['definitions'][InputParser.INPUT]['required'] = required self._schema['definitions'][ InputParser.INPUT]['additionalProperties'] = additionalProperties