def __getattr__(self, method): try: object.__getattr__(self, method) except AttributeError: if method.startswith("get"): # Deprecated method names # -- this will be deprecated in favour of the error below new_names = {"get_cl": "get_Cl"} if method in new_names: msg = create_banner( "Method '%s' has been re-capitalized to '%s'.\n" "Overriding for now, but please change it: " "this will produce an error in the future." % (method, new_names[method])) for line in msg.split("\n"): self.log.warning(line) return getattr(self, new_names[method]) # End of deprecation block ------------------------------ raise LoggedError( self.log, "Getter method for cosmology product %r is not known. " "Maybe you meant any of %r?", method, fuzzy_match(method, dir(self), n=3))
def update_info(info): """ Creates an updated info starting from the defaults for each module and updating it with the input info. """ # Don't modify the original input! input_info = deepcopy_where_possible(info) # Creates an equivalent info using only the defaults updated_info = odict() default_params_info = odict() default_prior_info = odict() modules = get_used_modules(input_info) for block in modules: updated_info[block] = odict() for module in modules[block]: # Preprocess "no options" and "external function" in input try: input_info[block][module] = input_info[block][module] or {} except TypeError: raise LoggedError( log, "Your input info is not well formatted at the '%s' block. " "It must be a dictionary {'%s':{options}, ...}. ", block, block) if not hasattr(input_info[block][module], "get"): input_info[block][module] = { _external: input_info[block][module] } # Get default class options updated_info[block][module] = deepcopy( getattr( import_module(_package + "." + block, package=_package), "class_options", {})) default_module_info = get_default_info(module, block) # TODO: check - get_default_info was ignoring this extra arg: input_info[block][module]) updated_info[block][module].update( default_module_info[block][module] or {}) # Update default options with input info # Consistency is checked only up to first level! (i.e. subkeys may not match) ignore = set( [_external, _p_renames, _input_params, _output_params]) options_not_recognized = (set( input_info[block][module]).difference(ignore).difference( set(updated_info[block][module]))) if options_not_recognized: alternatives = odict() available = (set([_external, _p_renames ]).union(updated_info[block][module])) while options_not_recognized: option = options_not_recognized.pop() alternatives[option] = fuzzy_match(option, available, n=3) did_you_mean = ", ".join([ ("'%s' (did you mean %s?)" % (o, "|".join(["'%s'" % _ for _ in a])) if a else "'%s'" % o) for o, a in alternatives.items() ]) if default_module_info[block][module]: # Internal module raise LoggedError( log, "'%s' does not recognize some options: %s. " "To see the allowed options, check out the documentation of" " this module.", module, did_you_mean) else: # External module raise LoggedError( log, "External %s '%s' does not recognize some options: %s. " "Check the documentation for 'external %s'.", block, module, did_you_mean, block) updated_info[block][module].update(input_info[block][module]) # Store default parameters and priors of class, and save to combine later if block == _likelihood: params_info = default_module_info.get(_params, {}) updated_info[block][module].update( {_params: list(params_info or [])}) default_params_info[module] = params_info default_prior_info[module] = default_module_info.get( _prior, {}) # Add priors info, after the necessary checks if _prior in input_info or any(default_prior_info.values()): updated_info[_prior] = input_info.get(_prior, odict()) for prior_info in default_prior_info.values(): for name, prior in prior_info.items(): if updated_info[_prior].get(name, prior) != prior: raise LoggedError( log, "Two different priors cannot have the same name: '%s'.", name) updated_info[_prior][name] = prior # Add parameters info, after the necessary updates and checks defaults_merged = merge_default_params_info(default_params_info) updated_info[_params] = merge_params_info(defaults_merged, input_info.get(_params, {})) # Add aliases for theory params (after merging!) if _theory in updated_info: renames = list(updated_info[_theory].values())[0].get(_p_renames) str_to_list = lambda x: ([x] if isinstance(x, string_types) else x) renames_flat = [ set([k] + str_to_list(v)) for k, v in (renames or {}).items() ] for p in updated_info.get(_params, {}): # Probably could be made faster by inverting the renames dicts *just once* renames_pairs = [a for a in renames_flat if p in a] if renames_pairs: this_renames = reduce(lambda x, y: x.union(y), [a for a in renames_flat if p in a]) updated_info[_params][p][_p_renames] = list( set(this_renames).union( set( str_to_list(updated_info[_params][p].get( _p_renames, [])))).difference(set([p]))) # Rest of the options for k, v in input_info.items(): if k not in updated_info: updated_info[k] = v return updated_info
def update_info(info): """ Creates an updated info starting from the defaults for each component and updating it with the input info. """ component_base_classes = get_base_classes() # Don't modify the original input, and convert all Mapping to consistent dict input_info = deepcopy_where_possible(info) # Creates an equivalent info using only the defaults updated_info = {} default_params_info = {} default_prior_info = {} components = get_used_components(input_info) from cobaya.component import CobayaComponent for block in components: updated = {} updated_info[block] = updated input_block = input_info[block] for component in components[block]: # Preprocess "no options" and "external function" in input try: input_block[component] = input_block[component] or {} except TypeError: raise LoggedError( log, "Your input info is not well formatted at the '%s' block. " "It must be a dictionary {'%s_i':{options}, ...}. ", block, block) if isinstance(component, CobayaComponent) or \ isinstance(input_block[component], CobayaComponent): raise LoggedError( log, "Input for %s:%s should specify a class not " "an instance", block, component) # TODO: allow instance passing? # could allow this, but would have to sort out deepcopy # if input_block[component]: # raise LoggedError(log, "Instances should be passed a dictionary " # "entry of the form 'instance: None'") # change_key(input_block, component, component.get_name(), # {_external: component}) # updated[component.get_name()] = input_block[component.get_name()].copy() # continue if inspect.isclass(input_block[component]) or \ not isinstance(input_block[component], dict): input_block[component] = {_external: input_block[component]} ext = input_block[component].get(_external) if ext: if inspect.isclass(ext): default_class_info = get_default_info( ext, block, input_options=input_block[component]) else: default_class_info = deepcopy_where_possible( component_base_classes[block].get_defaults()) else: component_path = input_block[component].get( _component_path, None) default_class_info = get_default_info( component, block, class_name=input_block[component].get(_class_name), component_path=component_path, input_options=input_block[component]) updated[component] = default_class_info or {} # Update default options with input info # Consistency is checked only up to first level! (i.e. subkeys may not match) # Reserved attributes not necessarily already in default info: reserved = { _external, _class_name, _provides, _requires, partag.renames, _input_params, _output_params, _component_path, _aliases } options_not_recognized = (set( input_block[component]).difference(reserved).difference( set(updated[component]))) if options_not_recognized: alternatives = {} available = ({ _external, _class_name, _requires, partag.renames }.union(updated_info[block][component])) while options_not_recognized: option = options_not_recognized.pop() alternatives[option] = fuzzy_match(option, available, n=3) did_you_mean = ", ".join([ ("'%s' (did you mean %s?)" % (o, "|".join(["'%s'" % _ for _ in a])) if a else "'%s'" % o) for o, a in alternatives.items() ]) raise LoggedError( log, "%s '%s' does not recognize some options: %s. " "Check the documentation for '%s'.", block, component, did_you_mean, block) updated[component].update(input_block[component]) # save params and priors of class to combine later default_params_info[component] = default_class_info.get( _params, {}) default_prior_info[component] = default_class_info.get(_prior, {}) # Add priors info, after the necessary checks if _prior in input_info or any(default_prior_info.values()): updated_info[_prior] = input_info.get(_prior, {}) for prior_info in default_prior_info.values(): for name, prior in prior_info.items(): if updated_info[_prior].get(name, prior) != prior: raise LoggedError( log, "Two different priors cannot have the same name: '%s'.", name) updated_info[_prior][name] = prior # Add parameters info, after the necessary updates and checks defaults_merged = merge_default_params_info(default_params_info) updated_info[_params] = merge_params_info( [defaults_merged, input_info.get(_params, {})], default_derived=False) # Add aggregated chi2 params if kinds.likelihood in info: all_types = set( chain(*[ str_to_list(like_info.get("type", []) or []) for like_info in updated_info[kinds.likelihood].values() ])) for t in all_types: updated_info[_params][_get_chi2_name(t)] = { partag.latex: _get_chi2_label(t), partag.derived: True } # Add automatically-defined parameters if _auto_params in updated_info: make_auto_params(updated_info.pop(_auto_params), updated_info[_params]) # Add aliases for theory params (after merging!) for kind in [ k for k in [kinds.theory, kinds.likelihood] if k in updated_info ]: for item in updated_info[kind].values(): renames = item.get(partag.renames) if renames: if not isinstance(renames, Mapping): raise LoggedError( log, "'renames' should be a dictionary of name mappings " "(or you meant to use 'aliases')") renames_flat = [ set([k] + str_to_list(v)) for k, v in renames.items() ] for p in updated_info[_params]: # Probably could be made faster by inverting the renames dicts *once* renames_pairs = [a for a in renames_flat if p in a] if renames_pairs: this_renames = reduce( lambda x, y: x.union(y), [a for a in renames_flat if p in a]) updated_info[_params][p][partag.renames] = \ list(set(this_renames).union(set(str_to_list( updated_info[_params][p].get(partag.renames, [])))) .difference({p})) # Rest of the options for k, v in input_info.items(): if k not in updated_info: updated_info[k] = v return updated_info
def update_info(info: _Dict, add_aggr_chi2=True) -> _Dict: """ Creates an updated info starting from the defaults for each component and updating it with the input info. """ component_base_classes = get_base_classes() # Don't modify the original input, and convert all Mapping to consistent dict input_info = deepcopy_where_possible(info) # Creates an equivalent info using only the defaults updated_info: _Dict = {} default_params_info = {} default_prior_info = {} used_kind_members = get_used_components(input_info) from cobaya.component import CobayaComponent for block in used_kind_members: updated: InfoDict = {} updated_info[block] = updated input_block = input_info[block] name: str for name in used_kind_members[block]: # Preprocess "no options" and "external function" in input try: input_block[name] = input_block[name] or {} except TypeError: raise LoggedError( log, "Your input info is not well formatted at the '%s' block. " "It must be a dictionary {'%s_i':{options}, ...}. ", block, block) if isinstance(name, CobayaComponent) or isinstance(name, type): raise LoggedError( log, "Instances and classes should be passed a " "dictionary entry of the form 'name: instance'") if isinstance(input_block[name], CobayaComponent): log.warning("Support for input instances is experimental") if isinstance(input_block[name], type) or \ not isinstance(input_block[name], dict): input_block[name] = {"external": input_block[name]} ext = input_block[name].get("external") annotations = {} if ext: if isinstance(ext, type): default_class_info, annotations = \ get_default_info(ext, block, input_options=input_block[name], return_undefined_annotations=True) else: default_class_info = deepcopy_where_possible( component_base_classes[block].get_defaults()) else: component_path = input_block[name].get("python_path") default_class_info, annotations = get_default_info( name, block, class_name=input_block[name].get("class"), component_path=component_path, input_options=input_block[name], return_undefined_annotations=True) updated[name] = default_class_info or {} # Update default options with input info # Consistency is checked only up to first level! (i.e. subkeys may not match) # Reserved attributes not necessarily already in default info: reserved = { "external", "class", "provides", "requires", "renames", "input_params", "output_params", "python_path", "aliases" } options_not_recognized = set(input_block[name]).difference( chain(reserved, updated[name], annotations)) if options_not_recognized: alternatives = {} available = {"external", "class", "requires", "renames"}.union(updated_info[block][name]) while options_not_recognized: option = options_not_recognized.pop() alternatives[option] = fuzzy_match(option, available, n=3) did_you_mean = ", ".join([ ("'%s' (did you mean %s?)" % (o, "|".join(["'%s'" % _ for _ in a])) if a else "'%s'" % o) for o, a in alternatives.items() ]) raise LoggedError( log, "%s '%s' does not recognize some options: %s. " "Check the documentation for '%s'.", block, name, did_you_mean, block) updated[name].update(input_block[name]) # save params and priors of class to combine later default_params_info[name] = default_class_info.get("params", {}) default_prior_info[name] = default_class_info.get("prior", {}) # Add priors info, after the necessary checks if "prior" in input_info or any(default_prior_info.values()): updated_info["prior"] = input_info.get("prior", {}) for prior_info in default_prior_info.values(): for name, prior in prior_info.items(): if updated_info["prior"].get(name, prior) != prior: raise LoggedError( log, "Two different priors cannot have the same name: '%s'.", name) updated_info["prior"][name] = prior # Add parameters info, after the necessary updates and checks defaults_merged = merge_default_params_info(default_params_info) param_info: ExpandedParamsDict = merge_params_info( [defaults_merged, input_info.get("params", {})], default_derived=False) updated_info["params"] = param_info # type: ignore # Add aggregated chi2 params if info.get("likelihood") and add_aggr_chi2: all_types = set( chain(*[ str_to_list(like_info.get("type", []) or []) for like_info in updated_info["likelihood"].values() if like_info is not None ])) add_aggregated_chi2_params(param_info, all_types) # Add automatically-defined parameters if "auto_params" in updated_info: make_auto_params(updated_info.pop("auto_params"), param_info) # Add aliases for theory params (after merging!) for name in ("theory", "likelihood"): if isinstance(updated_info.get(name), dict): for item in updated_info[name].values(): renames = item.get("renames") if renames: if not isinstance(renames, Mapping): raise LoggedError( log, "'renames' should be a dictionary of " "name mappings " "(or you meant to use 'aliases')") renames_flat = [ set([k] + str_to_list(v)) for k, v in renames.items() ] for p in param_info: # Probably could be made faster by inverting # the renames dicts *once* renames_pairs = [a for a in renames_flat if p in a] if renames_pairs: this_renames = reduce( lambda x, y: x.union(y), [a for a in renames_flat if p in a]) param_info[p]["renames"] = \ list(set(chain(this_renames, str_to_list( param_info[p].get("renames", [])))) .difference({p})) # Rest of the options for k, v in input_info.items(): if k not in updated_info: updated_info[k] = v return updated_info