source: cpp/frams/genetics/fn/fn_oper.cpp @ 1186

Last change on this file since 1186 was 1186, checked in by Maciej Komosinski, 17 months ago

For consistency with other numerical types, unlimited string length is now indicated by "-1" as the second value of the definition of the "s" property

File size: 5.6 KB
Line 
1// This file is a part of Framsticks SDK.  http://www.framsticks.com/
2// Copyright (C) 1999-2020  Maciej Komosinski and Szymon Ulatowski.
3// See LICENSE.txt for details.
4
5#include "fn_oper.h"
6#include "fn_conv.h"
7#include <common/nonstd.h> //rndUint, rndDouble
8
9
10/**
11\class GenoOper_fn
12
13This genetic representation only stores a vector of real numbers. A fitness function must be provided
14for the gene pool, for example the "Booth function" would be:
15
16var X = String.deserialize(this.geno.rawgenotype); //a vector of real values
17var result = Math.pow(X[0]+2*X[1]-7,2) + Math.pow(2*X[0]+X[1]-5,2);
18return -result; //negation because Framsticks assumes maximization, and the original function needs to be minimized
19*/
20
21
22
23#define FIELDSTRUCT GenoOper_fn
24static ParamEntry genooper_fn_paramtab[] =
25{
26        { "Genetics: fn", 1, 6, },
27        { "fn_xover", 0, 0, "Fraction inherited in linear mix crossover", "f 0.5 1.0 0.9", FIELD(xover_proportion), "0.5 => children are averaged parents.\n0.8 => children are only 20% different from parents.\n1.0 => each child is identical to one parent (no crossover).", },
28        { "fn_xover_random", 0, 0, "Random fraction inherited in crossover", "d 0 1 1", FIELD(xover_proportion_random), "If active, the amount of linear mix is random in each crossover operation, so the \"Fraction inherited in linear mix crossover\" parameter is ignored.", },
29        { "fn_mut_bound_low", 1, 0, "Lower bounds for mutation", "s 0 -1 [-10.0, -10.0]", FIELD(mut_bound_low), "A vector of lower bounds (one real value for each variable)", },
30        { "fn_mut_bound_high", 1, 0, "Higher bounds for mutation", "s 0 -1 [10.0, 10.0]", FIELD(mut_bound_high), "A vector of higher bounds (one real value for each variable)", },
31        { "fn_mut_stddev", 1, 0, "Standard deviations for mutation", "s 0 -1 [0.1, 0.1]", FIELD(mut_stddev), "A vector of standard deviations (one real value for each variable)", },
32        { "fn_mut_single_var", 0, 0, "Mutate only a single variable", "d 0 1 0", FIELD(mut_single_var), "If active, only a single randomly selected variable will be mutated in each mutation operation. Otherwise all variables will be mutated.", },
33        { 0, },
34};
35#undef FIELDSTRUCT
36
37
38
39GenoOper_fn::GenoOper_fn()
40{
41        par.setParamTab(genooper_fn_paramtab);
42        par.select(this);
43        par.setDefault();
44        supported_format = 'n';
45}
46
47int GenoOper_fn::checkValidity(const char* gene, const char *genoname)
48{
49        vector<double> values = GenoConv_fn0::stringToVector(gene);
50        return values.size() > 0 ? GENOPER_OK : 1;
51}
52
53int GenoOper_fn::validate(char *&gene, const char *genoname)
54{
55        vector<double> values = GenoConv_fn0::stringToVector(gene);
56        if (values.size() == 0)
57                values.push_back(0.0);
58        string validated = GenoConv_fn0::vectorToString(values);
59        free(gene);
60        gene = strdup(validated.c_str()); //reallocate
61        return GENOPER_OK;
62}
63
64//Creep-mutate variable(s)
65int GenoOper_fn::mutate(char *&gene, float &chg, int &method)
66{
67        method = 0;
68        vector<double> values = GenoConv_fn0::stringToVector(gene);
69        if (values.size() == 0)
70                return GENOPER_OPFAIL;
71        vector<double> bound_low = GenoConv_fn0::stringToVector(mut_bound_low.c_str());
72        vector<double> bound_high = GenoConv_fn0::stringToVector(mut_bound_high.c_str());
73        vector<double> stddev = GenoConv_fn0::stringToVector(mut_stddev.c_str());
74        if (bound_low.size() != bound_high.size() || bound_high.size() != stddev.size() || stddev.size() != values.size())
75        {
76                logPrintf("GenoOper_fn", "mutate", LOG_ERROR, "The solution vector, bound vectors, and standard deviation vectors must all have the same number of values");
77                return GENOPER_OPFAIL;
78        }
79
80        if (mut_single_var) //mutate only one, randomly selected variable
81        {
82                int which = rndUint(values.size());
83                values[which] = GenoOperators::mutateCreep('f', values[which], bound_low[which], bound_high[which], stddev[which], false);
84                chg = 1.0f / values.size();
85        }
86        else //mutate all variables
87        {
88                for (int which = 0; which < (int)values.size(); which++)
89                        values[which] = GenoOperators::mutateCreep('f', values[which], bound_low[which], bound_high[which], stddev[which], false);
90                chg = 1.0f;
91        }
92        string saved = GenoConv_fn0::vectorToString(values);
93        free(gene);
94        gene = strdup(saved.c_str()); //reallocate
95        return GENOPER_OK;
96}
97
98//Averaging crossover
99int GenoOper_fn::crossOver(char *&g1, char *&g2, float& chg1, float& chg2)
100{
101        //g1 = strdup("[1,0.5,0.5,0.5,0.5,1,1]"); //testing...
102        //g2 = strdup("[4,1,  1,  1,  1,  2,2]"); //testing...
103        //xover_proportion = 0.1; //testing...
104
105        double proportion = xover_proportion_random ? 0.5 + rndDouble(0.5) : xover_proportion;
106
107        chg1 = proportion;
108        chg2 = 1 - proportion;
109
110        vector<double> v1 = GenoConv_fn0::stringToVector(g1);
111        vector<double> v2 = GenoConv_fn0::stringToVector(g2);
112
113        if (v1.size() != v2.size())
114        {
115                logPrintf("GenoOper_fn", "crossOver", LOG_ERROR, "Tried to cross over solutions with a differing number of variables (%d and %d)", v1.size(), v2.size());
116                return GENOPER_OPFAIL;
117        }
118
119        GenoOperators::linearMix(v1, v2, proportion);
120
121        string saved = GenoConv_fn0::vectorToString(v1);
122        free(g1);
123        g1 = strdup(saved.c_str()); //reallocate
124        saved = GenoConv_fn0::vectorToString(v2);
125        free(g2);
126        g2 = strdup(saved.c_str()); //reallocate
127        return GENOPER_OK;
128}
129
130//Applying some colors and font styles...
131uint32_t GenoOper_fn::style(const char *g, int pos)
132{
133        char ch = g[pos];
134        uint32_t style = GENSTYLE_CS(0, GENSTYLE_INVALID); //default, should be changed below
135        if (strchr("-.e 0123456789", ch) != NULL)
136                style = GENSTYLE_CS(GENCOLOR_NUMBER, GENSTYLE_NONE);
137        else if (strchr("[,]", ch) != NULL)
138                style = GENSTYLE_RGBS(0, 0, 0, GENSTYLE_BOLD);
139        return style;
140}
Note: See TracBrowser for help on using the repository browser.