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

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

Invalid genotypes are now removed immediately from the population and new ones are generated to keep population size constant

File size: 5.8 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 10) times when the evolution ends instead of evaluating the last population as it is now in niching_novelty.py
10# TODO "debug" mode, displaying Step-based class names and 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    parser.add_argument('-genformat', required=False, default="1",
46                        help='Genetic format for the demo run, for example 4, 9, or B. If not given, f1 is assumed.')
47    parser.add_argument('-sim', required=False, default="eval-allcriteria.sim", help="Name of the .sim file with all parameter values")
48    parser.add_argument("-popsize", type=int, default=50, help="Population size, default 50.")
49    parser.add_argument('-generations', type=int, default=5, help="Number of generations, default 5.")
50    parser.add_argument('-tournament', type=int, default=5, help="Tournament size, default 5.")
51    return parser.parse_args()
52
53
54def extract_fitness(ind):
55    return ind.fitness
56
57
58def print_population_count(pop):
59    print("Current popsize:", len(pop))
60    return pop  # Each step must return a population
61
62
63def main():
64    parsed_args = parseArguments()
65    frams_lib = FramsticksLib(parsed_args.path, parsed_args.lib, parsed_args.sim)
66
67    hall_of_fame = HallOfFameStatistics(100, "fitness")
68    statistics_union = UnionStep([
69        hall_of_fame,
70        StatisticsDeap([
71            ("avg", np.mean),
72            ("stddev", np.std),
73            ("min", np.min),
74            ("max", np.max),
75            ("count", len)
76        ], extract_fitness)
77    ])
78
79    fitness_remove = UnionStep(
80        [
81        FitnessStep(frams_lib, fields={"velocity": "fitness", "data->recording": "recording"},
82                    fields_defaults={"velocity": None, "data->recording": None})  # custom definitions and handling
83        if EVAL_LIFESPAN_BEHAVIOR else
84        FitnessStep(frams_lib, fields={parsed_args.opt: "fitness", }, fields_defaults={parsed_args.opt: None})
85        ]
86        +
87        ([FieldRemove("recording", None)] if EVAL_LIFESPAN_BEHAVIOR else [FieldRemove("fitness", None)])
88        +
89        [print_population_count]  # Stages can also be any Callable
90    )
91
92    selection = TournamentSelection(parsed_args.tournament, copy=True, fit_attr="fitness")
93    new_generation_steps = [
94        FramsCrossAndMutate(frams_lib, cross_prob=0.2, mutate_prob=0.9),
95        fitness_remove
96    ]
97
98    generation_modifications = [
99        statistics_union  # Or niching, novelty
100    ]
101
102    init_stages = [FramsPopulation(frams_lib, parsed_args.genformat, parsed_args.popsize),
103                   fitness_remove,  # It is possible to create smaller population
104                   statistics_union]
105
106    end_steps = [PopulationSave("halloffame.gen", provider=hall_of_fame.halloffame,
107                                fields={"genotype": "genotype", "fitness": "fitness", "custom": "recording"}
108                                if EVAL_LIFESPAN_BEHAVIOR
109                                else {"genotype": "genotype", "fitness": "fitness"}
110                                )]
111
112    experiment = Experiment(init_population=init_stages,
113                            selection=selection,
114                            new_generation_steps=new_generation_steps,
115                            generation_modification=generation_modifications,
116                            end_steps=end_steps,
117                            population_size=parsed_args.popsize
118                            )
119    experiment.init()
120    experiment.run(parsed_args.generations)
121    for ind in hall_of_fame.halloffame:
122        print("%g\t%s" % (ind.fitness, ind.genotype))
123
124
125if __name__ == '__main__':
126    main()
Note: See TracBrowser for help on using the repository browser.