[1007] | 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 | |
---|
| 13 | struct Individual |
---|
| 14 | { |
---|
| 15 | Geno geno; |
---|
| 16 | double fitness; |
---|
| 17 | }; |
---|
| 18 | |
---|
| 19 | double criterion(char symbol, double value) |
---|
| 20 | { |
---|
| 21 | return isupper(symbol) ? value : -value; |
---|
| 22 | } |
---|
| 23 | |
---|
| 24 | void 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 | |
---|
| 64 | int 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. */ |
---|
| 79 | int 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 | } |
---|