timor.configuration_search.GA ============================= .. py:module:: timor.configuration_search.GA Classes ------- .. autoapisummary:: timor.configuration_search.GA.GA timor.configuration_search.GA.ProgressUnit Functions --------- .. autoapisummary:: timor.configuration_search.GA.get_ga_progress Module Contents --------------- .. py:class:: GA(db, custom_hp = None, mutation_weights = None, rng = None) This class provides an interface to optimize assemblies with genetic algorithms using a custom fitness function. The idea of a genetic algorithm is to mimic the process of natural selection and evolution to solve optimization problems. It involves creating a population of potential solutions (chromosomes), applying genetic operators like crossover and mutation to generate offsprings, evaluating their fitness, and selecting the fittest individuals for the next generation. Here, our target is to select candidate modules from a module base and assemble them in a sequence aiming to minimize a user-specified fitness function.The iterative process ends after a pre-defined number of iterations. Currently, this class is limited to modules that have exactly two connectors, so it can only be used for the assembly of serial kinematic chains. Initialize the GA optimizer by performing necessary pre-computations once a DB is provided. The initialization itself does not perform any optimization and is computationally cheap. To start the actual optimization, call the optimize() method. :param db: Either the name of a ModulesDB or a ModulesDB instance that will be used for the GA. The operators for the genetic optimization expect each module to have exactly two connectors -- if the DB contains any modules with more or less connectors, this method will raise an error. :param custom_hp: A dictionary of custom hyperparameters that will be used instead of the default ones. For more hyperparameters see reference: https://pygad.readthedocs.io/en/latest/pygad.html#pygad-ga-class. :param mutation_weights: Maps a module ID or the `EMPTY` ID to a weight that determines how likely it is to be chosen as a replacement during mutation. If None, all modules have the same weight. :param rng: A numpy random number generator. If None, a new one will be created. .. py:attribute:: G :type: networkx.MultiDiGraph .. py:attribute:: __assembly_cache_size :type: int :value: 1000 .. py:attribute:: __empty_slot :value: 'EMPTY' .. py:attribute:: __fitness_cache_size :type: int :value: 1000000 .. py:method:: _chain_callbacks(original_callback = None, optional_callbacks = ()) :staticmethod: This is a helper function to create a single callback function from a sequence of callable objects. The order of the callbacks is preserved, with the original callback being called first. If any of the optional callbacks returns False, the callback chain is terminated and "stop" is returned which will stop the GA. :param original_callback: The original callback function - this function can return any value, but any value other than "stop" will be ignored by pygad. :param optional_callbacks: A sequence of optional callbacks. Each callback should return True to continue the callback chain, or either False or 'stop' to stop the callback chain. .. py:method:: _get_candidate_assembly(module_ids) Perform pre-computation for the fitness function. It converts the solution from integer encodings to IDs and assembles the modules in a chain. :param module_ids: The solution to be evaluated, encoded as module ids. .. py:method:: _get_initial_population(population_size, module_weights = None) Generates the initial population for the genetic algorithm. It returns a list of chromosomes, where each chromosome represents a potential solution. It extends the shortest paths to a desired length by successively adding detours of length 1. Each chromosome is a list of genes, where each gene represents a module. The first gene is the base, the last gene is the end effector, and the genes in between are links and joints. The length of the chromosome equals to the gene_len. :param population_size: The size of the initial population as a tuple of (num_offsprings, num_genes). :param module_weights: A dictionary, mapping each module ID in the database to be optimized to a weight that determines how likely it is to be chosen as a replacement during mutation. .. py:attribute:: _last_ga_instance :type: Optional[pygad.GA] :value: None .. py:method:: _map_genes_to_id(genome) Maps a list of gene encodings to the corresponding tuple of module IDs. :param genome: A genome, encoding genes as integers. .. py:attribute:: all_modules :type: Tuple[str, Ellipsis] .. py:attribute:: assembly_cache :type: timor.utilities.dtypes.LimitedSizeMap[Tuple[str], timor.ModuleAssembly] .. py:attribute:: base_ids :type: Tuple[str, Ellipsis] .. py:method:: check_individual(individual) Checks whether an integer-encoded individual (i.e. a module sequence) can be assembled. :param individual: The individual/offspring to be checked. Notice it consists of integers, not IDs. :return: True of the offspring is valid, False otherwise. .. py:method:: create_gene_space(run_hp) Create gene space and type for pygad. .. py:attribute:: eef_ids :type: Tuple[str, Ellipsis] .. py:attribute:: fitness_cache :type: timor.utilities.dtypes.LimitedSizeMap[Tuple[str], float] .. py:attribute:: hp :type: Dict[str, any] .. py:attribute:: hp_default :type: Dict[str, any] .. py:attribute:: id2num :type: Dict[str, int] .. py:attribute:: joint_ids :type: Tuple[str, Ellipsis] .. py:attribute:: link_ids :type: Tuple[str, Ellipsis] .. py:method:: make_visualization_callback(viz = None, task = None, save_at = None, file_format = 'html', every_n_generations = 10, checkmark_successful = False) Creates a callback function that can be passed to the GA optimizer to visualize solution candidates. The callback function will be called every n generations and will visualize the best solution candidate of that generation. If multiple candidates achieve the best fitness, one will be selected at random. :param viz: A meshcat visualizer instance. If None, a new visualizer will be created. :param task: If given, a candidate assembly will be visualized in the context of the given task. :param save_at: Per default, the visualization is only shown in the browser. If a path to a directory is given, all visualizations will be saved in there as static HTML or PNG. :param file_format: If save_at is given, this parameter determines the format of the saved visualizations. Can be either 'html' or 'png'. While html works "headless" without opening a browser, png enforces opening a viewer and cannot be used on a remote server. However, html files are much larger than png files. :param every_n_generations: Every nth generation, a visualization will be created. :param checkmark_successful: If True, a checkmark will be added to every goal that was achieved in the task. .. py:method:: mutation(population, ga_instance) Performs mutation on each chromosome of the offspring by randomly selecting genes and replacing them. The replacement is based on finding modules with the same connectors as the initial module, and the replacement candidate is chosen randomly. Notice offspring contains integers not IDs. :param population: The offspring to be mutated. :param ga_instance: The instance of pygad.GA class. .. py:attribute:: mutation_weights :type: Dict[str, float] :value: None .. py:method:: optimize(fitness_function, hp = None, progress_bar = True, debug_logging_frequency = 10, sane_keyboard_interrupt = True, timeout = None, wandb_run=None, progress_unit = ProgressUnit.GENERATIONS, steps_at_start = 0, selection_type = 'sss', **ga_kwargs) Perform optimization utilizing a GA by trying to optimize the fitness function over module assemblies. Users can specify the hyperparameters for the GA. If not specified, the default hyperparameters will be used. :ref: https://pygad.readthedocs.io/en/latest/pygad.html?highlight=steady%20state%20parent#supported-parent-selection-operations # noqa: E501 :param fitness_function: the fitness function for the GA. It should take three arguments: a ModuleAssembly which is to be evaluated as well as the GA instance and the index of the solution in the population. It is up to the user which of these arguments are used in the fitness function. :param hp: Optional hyperparameters overriding the user and default hyperparameters. :param progress_bar: If True, a tqdm progress bar over the numbers of generations completed will be shown. :param debug_logging_frequency: If specified, internal debug metrics will be logged every full n progress units. :param sane_keyboard_interrupt: If True, the GA will be stopped when a keyboard interrupt is received, but the exception will not be raised. :param timeout: If specified, the GA will be stopped after the specified number of seconds. :param wandb_run: You can optionally pass a Weights and Biases run instance to log the results. A run instance can be obtained by calling wandb.init() before calling this function. :param progress_unit: The metric to be used for tracking performance metrics, e.g. for logging or wandb. :param steps_at_start: The value of the progress unit at the first generation. This is useful if you want to continue a run that was interrupted or if multiple runs should be tracked "as one". :param selection_type: The type of parent selection to be used. The options defined in pyGAD include 'sss', 'rws', 'sus', 'rank', 'tournament', 'random'. Notice that use a customized rank-based selection function can be beneficial for diversity in the population and avoiding premature convergence to suboptimal solutions. :param ga_kwargs: Additional keyword arguments to be passed to the pygad.GA class that do not qualify as hyperparameters (so anything that should not be logged as a hyperparameter, e.g., callbacks). .. py:method:: rank_based_selection(fitness, num_parents, ga_instance) Selects the parents using a rank-based selection process. :source: https://en.wikipedia.org/wiki/Selection_(genetic_algorithm). The original paper for linear ranking: - Baker, James E. (1985), Grefenstette, John J. (ed.), "Adaptive Selection Methods for Genetic Algorithms", Conf. Proc. of the 1st Int. Conf. on Genetic Algorithms and Their Applications (ICGA), Hillsdale, New. Jersey: L. Erlbaum Associates, pp. 101–111, ISBN 0-8058-0426-9 - Baker, James E. (1987), Grefenstette, John J. (ed.), "Reducing Bias and Inefficiency in the Selection Algorithm", Conf. Proc. of the 2nd Int. Conf. on Genetic Algorithms and Their Applications (ICGA), Hillsdale, New. Jersey: L. Erlbaum Associates, pp. 14–21, ISBN 0-8058-0158-8 :param fitness: A list of fitness values of the current population. Its shape is 1D array with length equal to the number of individuals, while each element is a 'Lexicographic' object encompassing multiple values. :param num_parents: The number of parents to select. :param ga_instance: An instance of the pygad.GA class. :return: 1. The selected parents as a numpy array. Its shape is (the number of selected parents, num_genes). Note that the number of selected parents is equal to num_parents. 2. The indices of the selected parents inside the population. It is a 1D list with length equal to the number of selected parents. .. py:attribute:: rng :type: numpy.random.Generator :value: None .. py:attribute:: same_connector_cache :type: Dict[str, List[str]] .. py:method:: single_valid_crossover(parents, offspring_size, ga_instance) Performs single-point crossover between parents to create new offspring. Generally speaking, the genetic section after the split point in 'parent1' is replaced with the genetic section after the same split point in 'parent2'. Notice parents consists of integers not IDs. :params parents: Indicates the whole parental generation of genetic sections. :params offspring_size: Indicates the size of the offspring, which is a tuple of (num_offsprings, num_genes). :params ga_instance: The instance of pygad.GA class. .. py:attribute:: sp .. py:class:: ProgressUnit(*args, **kwds) .. autoapi-inheritance-diagram:: timor.configuration_search.GA.ProgressUnit :parts: 1 :private-bases: Classifies the different methods to count the progress in a GA optimization. .. py:attribute:: GENERATIONS :value: 0 .. py:attribute:: INDIVIDUALS :value: 1 .. py:attribute:: SECONDS :value: 2 .. py:function:: get_ga_progress(unit, ga_inst = None, t0 = 0, generation_bias = 0) Returns the progress of a genetic algorithm in [ProgressUnit] units. :param unit: The unit to count the progress in. :param ga_inst: The pygad.GA instance to get the progress from. Necessary for GENERATIONS and INDIVIDUALS. :param t0: The start time of the optimization. Necessary for SECONDS. :param generation_bias: The "generation" to start counting from