source: cpp/frams/genetics/f9/f9_oper.cpp @ 1158

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

Improved f9 mutation

  • Property svn:eol-style set to native
File size: 4.9 KB
Line 
1// This file is a part of Framsticks SDK.  http://www.framsticks.com/
2// Copyright (C) 1999-2021  Maciej Komosinski and Szymon Ulatowski.
3// See LICENSE.txt for details.
4
5#include "f9_oper.h"
6#include "f9_conv.h"
7#include <common/nonstd.h> //rndUint, rndDouble
8#include <string.h>
9#include <assert.h>
10
11
12#define FIELDSTRUCT GenoOper_f9
13static ParamEntry geno_f9_paramtab[] =
14{
15        { "Genetics: f9", 1, 1, },
16        { "f9_mut", 0, 0, "Mutation probability", "f 0 1 0", FIELD(mut_prob), "How many genes should be mutated during single mutation (1=all genes, 0.1=ten percent, 0=one gene)", },
17        { 0, },
18};
19#undef FIELDSTRUCT
20
21
22GenoOper_f9::GenoOper_f9()
23{
24        par.setParamTab(geno_f9_paramtab);
25        par.select(this);
26        par.setDefault();
27        supported_format = '9';
28}
29
30int GenoOper_f9::checkValidity(const char* gene, const char *genoname)
31{
32        if (!gene[0]) return 1; //empty is not valid
33        bool ok = true;
34        size_t i;
35        for (i = 0; i < strlen(gene); i++) if (!strchr(turtle_commands_f9, gene[i])) { ok = false; break; }
36        return ok ? GENOPER_OK : i + 1;
37}
38
39///Remove all invalid letters from the genotype
40int GenoOper_f9::validate(char *&gene, const char *genoname)
41{
42        SString validated; //new genotype (everything except turtle_commands_f9 is skipped)
43        for (size_t i = 0; i < strlen(gene); i++)
44                if (strchr(turtle_commands_f9, gene[i])) validated += gene[i];  //validated contains only turtle_commands_f9
45        free(gene);
46        gene = strdup(validated.c_str()); //reallocate
47        return GENOPER_OK;
48}
49
50void GenoOper_f9::mutate_replace(char *gene, int i)
51{
52        char oldgene = gene[i];
53        const char *pos = strchr(turtle_commands_f9, oldgene);
54        if (pos == NULL) //gene not in the set of allowed commands
55                gene[i] = turtle_commands_f9[rndUint(turtle_commands_f9_count)];
56        else
57                gene[i] = turtle_commands_f9[((pos - turtle_commands_f9) + 1 + rndUint(turtle_commands_f9_count - 1)) % turtle_commands_f9_count]; //always change to a different command
58        //printf("%c %c\n", oldgene, gene[i]);
59        assert(gene[i] != oldgene);
60}
61
62void GenoOper_f9::mutate_add_or_del(char *& gene, int len, int add_0_del_1)
63{
64        string newgeno(gene);
65        if (add_0_del_1 == 0) //add
66        {
67                int p = rndUint(len + 1);  //random location
68                //printf("before add: %s\n",(const char*)newgeno);
69                newgeno = newgeno.substr(0, p) + string(turtle_commands_f9 + rndUint(turtle_commands_f9_count), 1) + newgeno.substr(p);
70                //printf("after add: %s\n",(const char*)newgeno);
71        }
72        else //delete
73        {
74                int p = rndUint(len);  //random location
75                //printf("before delete: %s\n",(const char*)newgeno);
76                newgeno = newgeno.substr(0, p) + newgeno.substr(p + 1);
77                //printf("after delete: %s\n",(const char*)newgeno);
78        }
79        free(gene);
80        gene = strdup(newgeno.c_str()); //reallocate
81}
82
83///Simple mutation
84int GenoOper_f9::mutate(char *&gene, float &chg, int &method)
85{
86        method = 0;
87        int changes = 0, len = strlen(gene);
88
89        if (mut_prob > 0)
90                for (int i = 0; i < len; i++)
91                {
92                        if (rndDouble(1) < mut_prob) //normalize prob with the length of the genotype
93                        {
94                                mutate_replace(gene, i);
95                                changes++;
96                        }
97                }
98
99        if (rndDouble(1) < mut_prob) //add or delete a random char
100        {
101                int change_add_or_del = 1 + (len > 1); //either add a new symbol (1), or delete a random symbol (+(len>1))
102                int add_0_del_1 = rndUint(change_add_or_del);
103                mutate_add_or_del(gene, len, add_0_del_1);
104                changes++;
105        }
106
107        if (changes == 0) //if nothing changed so far, then fallback to minimal change: always changes one symbol
108        {
109                int change_what = len + 1 + (len > 1); //either replace an existing gene, or add a new symbol (+1), or delete a random symbol (+(len>1))
110                int change_selected = rndUint(change_what);
111                if (change_selected < len)
112                        mutate_replace(gene, change_selected);
113                else
114                        mutate_add_or_del(gene, len, change_selected - len);
115                changes++;
116        }
117
118        chg = (float)changes / len;
119        return changes > 0 ? GENOPER_OK : GENOPER_OPFAIL; //no changes? (should never happen) => OPFAIL so that GenMan will call mutate again
120}
121
122///A simple one-point crossover
123int GenoOper_f9::crossOver(char *&g1, char *&g2, float& chg1, float& chg2)
124{
125        int len1 = strlen(g1), len2 = strlen(g2);
126        int p1 = rndUint(len1);  //random cut point for first genotype
127        int p2 = rndUint(len2);  //random cut point for second genotype
128        char *child1 = (char*)malloc(p1 + len2 - p2 + 1);
129        char *child2 = (char*)malloc(p2 + len1 - p1 + 1);
130        strncpy(child1, g1, p1);   strcpy(child1 + p1, g2 + p2);
131        strncpy(child2, g2, p2);   strcpy(child2 + p2, g1 + p1);
132        free(g1); g1 = child1;
133        free(g2); g2 = child2;
134        chg1 = (float)p1 / strlen(child1);
135        chg2 = (float)p2 / strlen(child2);
136        return GENOPER_OK;
137}
138
139///Applying some colors and font styles...
140uint32_t GenoOper_f9::style(const char *g, int pos)
141{
142        char ch = g[pos];
143        uint32_t style = GENSTYLE_CS(0, GENSTYLE_INVALID); //default, should be changed below
144        char *ptr = strchr((char*)turtle_commands_f9, ch);
145        if (ptr)
146        {
147                int pos = ptr - turtle_commands_f9;
148                int axis = pos / 2;
149                style = GENSTYLE_RGBS(axis == 0 ? 200 : 0, axis == 1 ? 200 : 0, axis == 2 ? 200 : 0, GENSTYLE_NONE);
150        }
151        return style;
152}
Note: See TracBrowser for help on using the repository browser.