source: framspy/evolalg/examples/standard.py @ 1170

Last change on this file since 1170 was 1149, checked in by Maciej Komosinski, 3 years ago

Added support for loading multiple .sim files where each can overwrite selected settings

File size: 6.2 KB
Line 
1import argparse
2import os
3import sys
4import numpy as np
5
6# TODO add new example: steadystate.py (analogous to standard.py) OR include steadysteate as a mode in this example or in niching_novelty.py
7# TODO extend both standard.py and steadystate.py to support >1 criteria (using DEAP's selNSGA2() and selSPEA2())
8# TODO add comments to all examples in this directory
9# TODO add to standard.py and steadystate.py evaluating each genotype in HOF N (configurable, default 20) times when the evolution ends, as it is in niching_novelty.py
10# TODO "-debug" mode, indent nested steps (pre++, post-- of a static counter?) and print their arguments so it is easy to see what happens during evolution
11
12
13from FramsticksLib import FramsticksLib
14from evolalg.base.union_step import UnionStep
15from evolalg.experiment import Experiment
16from evolalg.fitness.fitness_step import FitnessStep
17from evolalg.mutation_cross.frams_cross_and_mutate import FramsCrossAndMutate
18from evolalg.population.frams_population import FramsPopulation
19from evolalg.repair.remove.field import FieldRemove
20from evolalg.selection.tournament import TournamentSelection
21from evolalg.statistics.halloffame_stats import HallOfFameStatistics
22from evolalg.statistics.statistics_deap import StatisticsDeap
23from evolalg.utils.population_save import PopulationSave
24
25
26
27EVAL_LIFESPAN_BEHAVIOR = False  # if False, standard evaluation criteria can be used as fitness as defined by the -opt parameter. If True, it is assumed that the expdef provides custom dictionary fields in evaluation, and they need to be handled specifically in python source code below (this could be parametrized in command-line too, but the syntax would be complex).
28
29
30def ensureDir(string):
31    if os.path.isdir(string):
32        return string
33    else:
34        raise NotADirectoryError(string)
35
36
37def parseArguments():
38    parser = argparse.ArgumentParser(
39        description='Run this program with "python -u %s" if you want to disable buffering of its output.' % sys.argv[
40            0])
41    parser.add_argument('-path', type=ensureDir, required=True, help='Path to the Framsticks library without trailing slash.')
42    parser.add_argument('-opt', required=True,
43                        help='optimization criteria : vertpos, velocity, distance, vertvel, lifespan, numjoints, numparts, numneurons, numconnections (or other as long as it is provided by the .sim file and its .expdef). Single or multiple criteria.')
44    parser.add_argument('-lib', required=False, help="Filename of .so or .dll with the Framsticks library")
45
46    parser.add_argument('-genformat', required=False, default="1",
47                        help='Genetic format for the demo run, for example 4, 9, or B. If not given, f1 is assumed.')
48    parser.add_argument('-sim', required=False, default="eval-allcriteria.sim", help="Name of the .sim file with all parameter values. If you want to provide more files, separate them with a semicolon ';'.")
49    parser.add_argument("-popsize", type=int, default=50, help="Population size, default 50.")
50    parser.add_argument('-generations', type=int, default=5, help="Number of generations, default 5.")
51    parser.add_argument('-tournament', type=int, default=5, help="Tournament size, default 5.")
52
53    parser.add_argument('-hof_size', type=int, default=10, help="Number of genotypes in Hall of Fame. Default: 10.")
54    return parser.parse_args()
55
56
57def extract_fitness(ind):
58    return ind.fitness
59
60
61def print_population_count(pop):
62    print("Current popsize:", len(pop))
63    return pop  # Each step must return a population
64
65
66def main():
67    parsed_args = parseArguments()
68    frams_lib = FramsticksLib(parsed_args.path, parsed_args.lib, parsed_args.sim.split(";"))
69
70    hall_of_fame = HallOfFameStatistics(parsed_args.hof_size, "fitness")
71    statistics_union = UnionStep([
72        hall_of_fame,
73        StatisticsDeap([
74            ("avg", np.mean),
75            ("stddev", np.std),
76            ("min", np.min),
77            ("max", np.max),
78            ("count", len)
79        ], extract_fitness)
80    ])
81
82    fitness_remove = UnionStep(  # evaluate performance and fitness, rename some of the fields, and remove some performance fields that we get from Framsticks, but we don't need them here
83        [
84        FitnessStep(frams_lib, fields={"velocity": "fitness", "data->recording": "recording"},
85                    fields_defaults={"velocity": None, "data->recording": None})  # custom definitions and handling
86        if EVAL_LIFESPAN_BEHAVIOR else
87        FitnessStep(frams_lib, fields={parsed_args.opt: "fitness"}, fields_defaults={parsed_args.opt: None})
88        ]
89        +
90        ([FieldRemove("recording", None)] if EVAL_LIFESPAN_BEHAVIOR else [FieldRemove("fitness", None)])
91        +
92        [print_population_count]  # Stages can also be any Callable
93    )
94
95    selection = TournamentSelection(parsed_args.tournament, copy=True, fit_attr="fitness")
96    new_generation_steps = [
97        FramsCrossAndMutate(frams_lib, cross_prob=0.2, mutate_prob=0.9),
98        fitness_remove
99    ]
100
101    generation_modifications = [
102        statistics_union  # Or niching, novelty
103    ]
104
105    init_stages = [FramsPopulation(frams_lib, parsed_args.genformat, parsed_args.popsize),
106                   fitness_remove,  # It is possible to create smaller population
107                   statistics_union]
108
109    end_steps = [PopulationSave("halloffame.gen", provider=hall_of_fame.halloffame,
110                                fields={"genotype": "genotype", "fitness": "fitness", "custom": "recording"}
111                                if EVAL_LIFESPAN_BEHAVIOR
112                                else {"genotype": "genotype", "fitness": "fitness"}
113                                )]
114
115    experiment = Experiment(init_population=init_stages,
116                            selection=selection,
117                            new_generation_steps=new_generation_steps,
118                            generation_modification=generation_modifications,
119                            end_steps=end_steps,
120                            population_size=parsed_args.popsize
121                            )
122    experiment.init()
123    experiment.run(parsed_args.generations)
124    for ind in hall_of_fame.halloffame:
125        print("%g\t%s" % (ind.fitness, ind.genotype))
126
127
128if __name__ == '__main__':
129    main()
Note: See TracBrowser for help on using the repository browser.