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

Last change on this file since 1132 was 1131, checked in by Maciej Komosinski, 4 years ago

The "standard.py" example now incorporates features of invalid.py (handling invalid genotypes)

File size: 6.1 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 protect all examples against invalid genotypes (fill population until all genotypes are conrrectly evaluated). And maybe remove invalid.py if it overlaps with (is a subset of) other examples
11#TODO "debug" mode, displaying Step-based class names and their arguments so it is easy to see what happens during evolution
12
13from evolalg.base.lambda_step import LambdaStep
14from evolalg.experiment import Experiment
15from evolalg.fitness.fitness_step import FitnessStep
16from evolalg.mutation_cross.frams_cross_and_mutate import FramsCrossAndMutate
17from evolalg.population.frams_population import FramsPopulation
18from evolalg.repair.multistep import MultistepRepair
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.base.union_step import UnionStep
24from evolalg.utils.population_save import PopulationSave
25from evolalg.utils.stable_generation import StableGeneration
26from FramsticksLib import FramsticksLib
27
28
29
30EVAL_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)
31
32
33def ensureDir(string):
34    if os.path.isdir(string):
35        return string
36    else:
37        raise NotADirectoryError(string)
38
39
40def parseArguments():
41    parser = argparse.ArgumentParser(
42        description='Run this program with "python -u %s" if you want to disable buffering of its output.' % sys.argv[
43            0])
44    parser.add_argument('-path', type=ensureDir, required=True, help='Path to the Framsticks library without trailing slash.')
45    parser.add_argument('-opt', required=True,
46                        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.')
47    parser.add_argument('-lib', required=False, help="Filename of .so or .dll with the Framsticks library")
48    parser.add_argument('-genformat', required=False, default="1",
49                        help='Genetic format for the demo run, for example 4, 9, or B. If not given, f1 is assumed.')
50    parser.add_argument('-sim', required=False, default="eval-allcriteria.sim", help="Name of the .sim file with all parameter values")
51    parser.add_argument("-popsize", type=int, default=50, help="Population size, default 50.")
52    parser.add_argument('-generations', type=int, default=5, help="Number of generations, default 5.")
53    parser.add_argument('-tournament', type=int, default=5, help="Tournament size, default 5.")
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:", 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(100, "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(
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={})
88        ]
89        +
90        ([FieldRemove("recording", None)] if EVAL_LIFESPAN_BEHAVIOR else [])
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.