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

Last change on this file since 1157 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
RevLine 
[286]1// This file is a part of Framsticks SDK.  http://www.framsticks.com/
[1157]2// Copyright (C) 1999-2021  Maciej Komosinski and Szymon Ulatowski.
[286]3// See LICENSE.txt for details.
[120]4
[779]5#include "f9_oper.h"
6#include "f9_conv.h"
[899]7#include <common/nonstd.h> //rndUint, rndDouble
[1005]8#include <string.h>
[1157]9#include <assert.h>
[120]10
11
12#define FIELDSTRUCT GenoOper_f9
[974]13static ParamEntry geno_f9_paramtab[] =
[120]14{
[168]15        { "Genetics: f9", 1, 1, },
[1157]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)", },
[168]17        { 0, },
[120]18};
19#undef FIELDSTRUCT
20
21
22GenoOper_f9::GenoOper_f9()
23{
[974]24        par.setParamTab(geno_f9_paramtab);
[120]25        par.select(this);
26        par.setDefault();
[168]27        supported_format = '9';
[120]28}
29
[513]30int GenoOper_f9::checkValidity(const char* gene, const char *genoname)
[120]31{
32        if (!gene[0]) return 1; //empty is not valid
[168]33        bool ok = true;
[319]34        size_t i;
[168]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;
[120]37}
38
39///Remove all invalid letters from the genotype
[513]40int GenoOper_f9::validate(char *&gene, const char *genoname)
[120]41{
42        SString validated; //new genotype (everything except turtle_commands_f9 is skipped)
[319]43        for (size_t i = 0; i < strlen(gene); i++)
[168]44                if (strchr(turtle_commands_f9, gene[i])) validated += gene[i];  //validated contains only turtle_commands_f9
[120]45        free(gene);
[348]46        gene = strdup(validated.c_str()); //reallocate
[120]47        return GENOPER_OK;
48}
49
[1157]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
[168]84int GenoOper_f9::mutate(char *&gene, float &chg, int &method)
[120]85{
[168]86        method = 0;
87        int changes = 0, len = strlen(gene);
[120]88
[1157]89        if (mut_prob > 0)
90                for (int i = 0; i < len; i++)
[120]91                {
[1157]92                        if (rndDouble(1) < mut_prob) //normalize prob with the length of the genotype
93                        {
94                                mutate_replace(gene, i);
95                                changes++;
96                        }
[120]97                }
98
[896]99        if (rndDouble(1) < mut_prob) //add or delete a random char
[120]100        {
[1157]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++;
[120]105        }
106
[1157]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
[168]118        chg = (float)changes / len;
[1157]119        return changes > 0 ? GENOPER_OK : GENOPER_OPFAIL; //no changes? (should never happen) => OPFAIL so that GenMan will call mutate again
[120]120}
121
122///A simple one-point crossover
[168]123int GenoOper_f9::crossOver(char *&g1, char *&g2, float& chg1, float& chg2)
[120]124{
[168]125        int len1 = strlen(g1), len2 = strlen(g2);
[896]126        int p1 = rndUint(len1);  //random cut point for first genotype
127        int p2 = rndUint(len2);  //random cut point for second genotype
[168]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);
[120]136        return GENOPER_OK;
137}
138
139///Applying some colors and font styles...
[247]140uint32_t GenoOper_f9::style(const char *g, int pos)
[120]141{
[168]142        char ch = g[pos];
[247]143        uint32_t style = GENSTYLE_CS(0, GENSTYLE_INVALID); //default, should be changed below
[168]144        char *ptr = strchr((char*)turtle_commands_f9, ch);
[120]145        if (ptr)
146        {
[168]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);
[120]150        }
151        return style;
152}
Note: See TracBrowser for help on using the repository browser.