source: framspy/evolalg_steps/examples/standard.py @ 1316

Last change on this file since 1316 was 1205, checked in by Maciej Komosinski, 22 months ago

Splitting (potentially) multiple .sim files is already done by FramsticksLib?.py

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_steps.base.union_step import UnionStep
15from evolalg_steps.experiment import Experiment
16from evolalg_steps.fitness.fitness_step import FitnessStep
17from evolalg_steps.mutation_cross.frams_cross_and_mutate import FramsCrossAndMutate
18from evolalg_steps.population.frams_population import FramsPopulation
19from evolalg_steps.repair.remove.field import FieldRemove
20from evolalg_steps.selection.tournament import TournamentSelection
21from evolalg_steps.statistics.halloffame_stats import HallOfFameStatistics
22from evolalg_steps.statistics.statistics_deap import StatisticsDeap
23from evolalg_steps.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)
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.