Source code for l2l.utils.trajectory

import time
from l2l.utils.groups import ParameterGroup, ResultGroup, ParameterDict
from l2l.utils.individual import Individual
import logging

logging = logging.getLogger("Trajectory")


[docs]class Trajectory: """ The trajectory is a class which holds the history of the parameter space exploration, defines the current parameters to be explored and holds the results from each execution. Based on the pypet trajectory concept: https://github.com/SmokinCaterpillar/pypet """ def __init__(self, **keyword_args): """ Initializes the trajectory. Some parameters are kept to match the interface with the pypet trajectory. TODO: remove all irrelevant attributes and simplify the class """ if 'name' in keyword_args: self._name = keyword_args['name'] self._timestamp = time.time() self._parameters = ParameterDict(self) # Contains all parameters self._results = {} # Contains all results self.individual = Individual() self.results = ResultGroup() self.results.f_add_result_group('all_results', "Contains all the results") self.current_results = {} self._parameters.parameter_group = {} self._parameters.parameter = {} self.individuals = {} self.v_idx = 0
[docs] def f_add_parameter_group(self, name, comment=""): """ Adds a new parameter group :param name: name of the new parameter group :param comment: ignored for the moment. Kept to match pypet interface. """ self._parameters[name] = ParameterGroup() logging.info("Added new parameter group: " + name)
[docs] def f_add_parameter_to_group(self, group_name, key, val): """ Adds a parameter to an already existing group. :param group_name: Name of the group where the parameter should be added :param key: Name of the parameter to be added :param val: Value of the parameter Throws an exception if the group does not exist """ if group_name in self._parameters.keys(): self._parameters[group_name].f_add_parameter(key, val) else: # LOG("Key not found when adding to result group") raise Exception("Group name not found when adding value to result group")
[docs] def f_add_result(self,key, val, comment=""): """ Adds a result to the trajectory :param key: it identifies either a generation params result group or another result :param val: The value to be added to the results TODO: verify where is the generation_params call performed """ if key == 'generation_params': self.results[key] = ResultGroup() else: self._results[key] = val
[docs] def f_add_parameter(self, key, val, comment=""): """ Adds a parameter to the trajectory :param key: Name of the parameter :param val: Value of the parameter :param comment """ self._parameters[key] = val
[docs] def f_add_derived_parameter(self, key, val, comment=""): """ Adds a derived parameter to the trajectory. Match the previous pypet interface. :param key: Name of the parameter :param val: Value of the parameter :param comment: """ self.f_add_parameter(key,val,comment)
[docs] def f_expand(self, build_dict, fail_safe=True): """ The expand function takes care of adding a new generation and individuals to the trajectory This is a critical function to allow the addition of a new generation, called by the optimizer from the postprocessing function :param build_dict: The dictionary containing the new generation id and its individuals :param fail_safe: Currently ignored """ params = {} gen = [] ind_idx = [] for key in build_dict.keys(): if key == 'generation': gen = build_dict['generation'] elif key == 'ind_idx': ind_idx = build_dict['ind_idx'] else: params[key] = build_dict[key] # TODO: Could/Should the build dictionary have more than one generation in it? generation = gen[0] self.individuals[generation] = [] for i in ind_idx: ind = Individual(generation,i,[]) for j in params: ind.f_add_parameter(j, params[j][i]) self.individuals[generation].append(ind) logging.info("Expanded trajectory for generation: " + str(generation))
def __str__(self): return str(self._parameters) def __getattr__(self, attr): """ Handle attribute access like a sdict :param attr: The attribute to be accessed :return: the value of this attributes """ if '.' in attr: # This is triggered exclusively in the case where __getattr__ is called from __getitem__ attrs = attr.split('.') ret = self._parameters.get(attrs[0]) for at in attrs[1:]: ret = ret[at] elif attr == 'par' or attr == 'parameters': ret = self._parameters else: ret = self._parameters.get(attr,default_value=None) return ret def __getitem__(self, key): return self.__getattr__(key) def __getstate__(self): print(self.__dict__) return self.__dict__ def __setstate__(self, d): self.__dict__.update(d)