source: cpp/frams/_demos/evol_test.cpp @ 1007

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

Added a simple evolutionary algorithm test

File size: 4.3 KB
Line 
1// This file is a part of Framsticks SDK.  http://www.framsticks.com/
2// Copyright (C) 2019-2020  Maciej Komosinski and Szymon Ulatowski.
3// See LICENSE.txt for details.
4
5
6#include <vector>
7#include "common/loggers/loggertostdout.h"
8#include "frams/genetics/preconfigured.h"
9#include "frams/genetics/genman.h"
10#include "frams/model/model.h"
11
12
13struct Individual
14{
15        Geno geno;
16        double fitness;
17};
18
19double criterion(char symbol, double value)
20{
21        return isupper(symbol) ? value : -value;
22}
23
24void evaluate_fitness(Individual &ind, const char *fitness_def)
25{
26        SString genotype = ind.geno.getGenes();
27        Model model = Model(ind.geno, Model::SHAPETYPE_UNKNOWN);
28        double fitness = 0;
29        const char *p = fitness_def;
30        while (*p)
31        {
32                switch (*p)
33                {
34                case 'l':
35                case 'L':
36                        fitness += criterion(*p, genotype.length());
37                        break;
38                case 'p':
39                case 'P':
40                        fitness += criterion(*p, model.getPartCount());
41                        break;
42                case 'j':
43                case 'J':
44                        fitness += criterion(*p, model.getJointCount());
45                        break;
46                case 'n':
47                case 'N':
48                        fitness += criterion(*p, model.getNeuroCount());
49                        break;
50                case 'c':
51                case 'C':
52                        fitness += criterion(*p, model.getConnectionCount());
53                        break;
54                        // TODO add more criteria as described in main() below
55                default:
56                        printf("Unknown fitness criterion symbol: '%c'\n", *p);
57                        exit(3);
58                }
59                p++;
60        }
61        ind.fitness = fitness;
62}
63
64int tournament(const vector<Individual> &population, int tournament_size)
65{
66        int best = -1;
67        for (int i = 0; i < tournament_size; i++)
68        {
69                int rnd = rndUint(population.size());
70                if (best == -1) best = rnd;
71                else if (population[rnd].fitness > population[best].fitness) //assume maximization
72                        best = rnd;
73        }
74        return best;
75}
76
77
78/** A minimalistic steady-state evolutionary algorithm. */
79int main(int argc, char *argv[])
80{
81        PreconfiguredGenetics genetics;
82        LoggerToStdout messages_to_stdout(LoggerBase::Enable);
83        GenMan genman;
84
85        bool deterministic;
86        int pop_size, nr_evals;
87        double prob_mut, prob_xover;
88        const char* format;
89        const char* fitness_def;
90
91        if (argc < 8)
92        {
93                printf("Too few parameters!\n");
94                printf("Command line: <deterministic?_0_or_1> <population_size> <nr_evaluations> <prob_mut> <prob_xover> <genetic_format> <fitness_definition>\n");
95                printf("Example: 1 10 50 0.5 0.5 4 NC\n\n\n");
96                printf("Fitness definition is a sequence of capital (+1 weight) and small (-1 weight) letters.\n");
97                printf("Each letter corresponds to one fitness criterion, and they are all weighted and added together.\n");
98                printf("  l or L - genotype length in characters.\n");
99                printf("  p or P - the number of Parts.\n");
100                printf("  j or J - the number of Joints.\n");
101                printf("  n or N - the number of Neurons.\n");
102                printf("  c or C - the number of neural Connections.\n");
103                //TODO add b - bounding box volume (from Model), s - surface area (from geometry), v - volume (from geometry), h,w,d - three consecutive dimensions (from geometry)
104
105                return 1;
106        }
107
108        deterministic = atoi(argv[1]) == 1;
109        pop_size = atoi(argv[2]);
110        nr_evals = atoi(argv[3]);
111        prob_mut = atof(argv[4]);
112        prob_xover = atof(argv[5]);
113        format = argv[6];
114        fitness_def = argv[7];
115
116        if (!deterministic)
117                rndGetInstance().randomize();
118
119        vector<Individual> population(pop_size);
120        for (Individual& ind : population)
121        {
122                ind.geno = genman.getSimplest(format);
123                if (ind.geno.getGenes() == "")
124                {
125                        printf("Could not get the simplest genotype for format '%s'\n", format);
126                        return 2;
127                }
128                evaluate_fitness(ind, fitness_def);
129        }
130        for (int i = 0; i < nr_evals; i++)
131        {
132                int selected_positive = tournament(population, max(2, int(sqrt(population.size()) / 2))); //moderate positive selection pressure
133                int selected_negative = rndUint(population.size()); //random negative selection
134
135                double rnd = rndDouble(prob_mut + prob_xover);
136                if (rnd < prob_mut)
137                {
138                        population[selected_negative].geno = genman.mutate(population[selected_positive].geno);
139                        //TODO handle failed mutation
140                        evaluate_fitness(population[selected_negative], fitness_def);
141                }
142                else
143                {
144                        //TODO crossover
145                }
146
147                if (i % population.size() == 0 || i == nr_evals - 1)
148                        printf("Evaluation %d\t...\n", i); //TODO print min,avg,max fitness \t min,avg,max genotype length \t min,avg,max parts \t min,avg,max neurons
149        }
150        for (const Individual& ind : population)
151        {
152                printf("%.1f\t", ind.fitness);
153                printf("%s\n", ind.geno.getGenes().c_str());
154        }
155
156        return 0;
157}
Note: See TracBrowser for help on using the repository browser.