source: cpp/frams/genetics/fB/fB_oper.cpp @ 797

Last change on this file since 797 was 797, checked in by Maciej Komosinski, 6 years ago

A more complete implementation of fB, fH, fL

File size: 13.0 KB
Line 
1// This file is a part of Framsticks SDK.  http://www.framsticks.com/
2// Copyright (C) 1999-2018  Maciej Komosinski and Szymon Ulatowski.
3// See LICENSE.txt for details.
4
5#include <frams/util/sstring.h>
6#include <vector>
7#include <frams/param/param.h>
8#include "fB_conv.h"
9#include "fB_general.h"
10#include "fB_oper.h"
11#include "../fH/fH_oper.h"
12
13#define FIELDSTRUCT Geno_fB
14
15static ParamEntry GENOfBparam_tab[] =
16{
17        { "Genetics: fB", 3, FB_MUT_COUNT + FB_XOVER_COUNT, },
18        { "Genetics: fB: Mutation", },
19        { "Genetics: fB: Crossover", },
20        { "fB_mut_substitution", 1, 0, "Substitution", "f 0 1 0.6", FIELD(mutationprobs[FB_SUBSTITUTION]), "Probability of mutation by changing single random letter in genotype", },
21        { "fB_mut_insertion", 1, 0, "Insertion", "f 0 1 0.95", FIELD(mutationprobs[FB_INSERTION]), "Probability of mutation by inserting characters in random place of genotype", },
22        { "fB_mut_nclassins", 1, 0, "Insertion of neuron class definition", "f 0 1 0.05", FIELD(mutationprobs[FB_NCLASSINS]), "Probability of mutation by inserting neuron class definition in random place of genotype", },
23        { "fB_mut_deletion", 1, 0, "Deletion", "f 0 1 0.1", FIELD(mutationprobs[FB_DELETION]), "Probability of mutation by deleting random characters in genotype", },
24        { "fB_mut_duplication", 1, 0, "Duplication", "f 0 1 0.05", FIELD(mutationprobs[FB_DUPLICATION]), "Probability of mutation by copying single *gene* of genotype and appending it to the beginning of this genotype", },
25        { "fB_mut_translocation", 1, 0, "Translocation", "f 0 1 0.15", FIELD(mutationprobs[FB_TRANSLOCATION]), "Probability of mutation by replacing two substrings in genotype", },
26        { "fB_cross_gene_transfer", 2, 0, "Horizontal gene transfer", "f 0 1 0.8", FIELD(crossoverprobs[FB_GENE_TRANSFER]), "Probability of crossing over by transferring single genes from both parents to beginning of each other", },
27        { "fB_cross_crossover", 2, 0, "Crossing over", "f 0 1 0.2", FIELD(crossoverprobs[FB_CROSSING_OVER]), "Probability of crossing over by random distribution of genes from both parents to both children", },
28        { 0, },
29};
30
31#undef FIELDSTRUCT
32
33Geno_fB::Geno_fB()
34{
35        par.setParamTab(GENOfBparam_tab);
36        par.select(this);
37        par.setDefault();
38        supported_format = 'B';
39}
40
41bool Geno_fB::hasStick(SString genotype)
42{
43        for (int i = 0; i < fB_GenoHelpers::geneCount(genotype); i++)
44        {
45                int start, end;
46                SString gene = fB_GenoHelpers::getGene(i, genotype, start, end);
47                int endoffset = 0;
48                if (gene.indexOf("zz", 0) != -1) endoffset = 2;
49                if (gene.len() - endoffset < 3)
50                {
51                        return true; // genes with length < 3 are always sticks
52                }
53                else if (gene[2] >= 'a' && gene[2] <= 'i')
54                {
55                        return true; // gene within this range is stick
56                }
57        }
58        return false;
59}
60
61int Geno_fB::checkValidity(const char *geno, const char *genoname)
62{
63        // load genotype
64        SString genotype(geno);
65        SString line;
66        int pos = 0;
67        // if there is no genotype to load, then return error
68        if (!genotype.getNextToken(pos, line, '\n'))
69        {
70                return pos + 1;
71        }
72        // extract dimensions
73        int dims = 0;
74        if (!ExtValue::parseInt(line.c_str(), dims, true, false))
75        {
76                return 1;
77        }
78        // extract next token in order to check if next line starts with "aa"
79        int genstart = genotype.indexOf("aa", 0);
80        if (genstart != pos)
81        {
82                return pos + 1;
83        }
84        // check if rest of characters are lowercase
85        for (int i = genstart; i < genotype.len(); i++)
86        {
87                if (!islower(genotype[i]))
88                {
89                        if (genotype[i] == '"')
90                        {
91                                SString neuclassdef;
92                                int nextid = i + 1;
93                                if (!genotype.getNextToken(nextid, neuclassdef, '"'))
94                                {
95                                        return i + 1;
96                                }
97                                Neuro *neu = new Neuro();
98                                neu->setDetails(neuclassdef);
99
100                                bool isclass = neu->getClass() ? true : false;
101                                delete neu;
102                                if (!isclass)
103                                {
104                                        return i + 1;
105                                }
106                                i = nextid;
107                        }
108                        else
109                        {
110                                return i + 1;
111                        }
112                }
113        }
114        if (!hasStick(genotype))
115        {
116                return 1;
117        }
118        return GENOPER_OK;
119}
120
121int Geno_fB::validate(char *&geno, const char *genoname)
122{
123        // load genotype
124        SString genotype(geno);
125        SString strdims;
126        int pos = 0;
127        if (!genotype.getNextToken(pos, strdims, '\n'))
128        {
129                return GENOPER_OPFAIL;
130        }
131        // parse dimension
132        int dims = 0;
133        if (!ExtValue::parseInt(strdims.c_str(), dims, true, false))
134        {
135                return GENOPER_OPFAIL;
136        }
137        SString line;
138        bool fix = false;
139        int genstart = genotype.indexOf("aa", 0);
140        // if there is no "aa" codon in the beginning of a genotype, then add it
141        if (genstart != pos)
142        {
143                genotype = strdims + "\naa" + genotype.substr(pos);
144                fix = true;
145        }
146        for (int i = pos; i < genotype.len(); i++)
147        {
148                // if character is not alphabetic - error
149                if (!isalpha(genotype[i]))
150                {
151                        if (genotype[i] == '"')
152                        {
153                                SString neuclassdef;
154                                int nextid = i + 1;
155                                if (!genotype.getNextToken(nextid, neuclassdef, '"'))
156                                {
157                                        return i + 1;
158                                }
159                                Neuro *neu = new Neuro();
160                                neu->setDetails(neuclassdef);
161
162                                bool isclass = neu->getClass() ? true : false;
163                                delete neu;
164                                if (!isclass)
165                                {
166                                        return i + 1;
167                                }
168                                i = nextid;
169                        }
170                        else
171                        {
172                                return GENOPER_OPFAIL;
173                        }
174                }
175                // if character is uppercase, then convert it to lowercase
176                else if (isupper(genotype[i]))
177                {
178                        genotype.directWrite()[i] = tolower(genotype[i]);
179                        fix = true;
180                }
181        }
182        // if the genotype does not contain any stick - add it
183        if (!hasStick(genotype))
184        {
185                genotype = SString("aaazz") + genotype;
186        }
187        // if there were any changes - save them
188        if (fix)
189        {
190                free(geno);
191                geno = strdup(genotype.c_str());
192        }
193        return GENOPER_OK;
194}
195
196SString Geno_fB::detokenizeSequence(std::list<SString> tokenlist)
197{
198        SString res = "";
199        for (std::list<SString>::iterator it = tokenlist.begin(); it != tokenlist.end(); it++)
200        {
201                res += (*it);
202        }
203        return res;
204}
205
206std::list<SString> Geno_fB::tokenizeSequence(SString genotype)
207{
208        std::list<SString> res;
209        int i = 0;
210        while (i < genotype.len())
211        {
212                // if character is not alphabetic - error
213                if (isalpha(genotype[i]))
214                {
215                        SString el = "";
216                        el += genotype[i];
217                        res.push_back(el);
218                        i++;
219                }
220                else
221                {
222                        SString neuclassdef;
223                        i++;
224                        genotype.getNextToken(i, neuclassdef, '"');
225                        SString ndef = "\"";
226                        ndef += neuclassdef;
227                        ndef += "\"";
228                        res.push_back(ndef);
229                }
230        }
231        return res;
232}
233
234int Geno_fB::mutate(char *&geno, float &chg, int &method)
235{
236        SString genotype(geno);
237        SString strdims;
238        int pos = 0;
239        genotype.getNextToken(pos, strdims, '\n');
240        SString line;
241        genotype.getNextToken(pos, line, '\n');
242        method = roulette(mutationprobs, FB_MUT_COUNT);
243        switch (method)
244        {
245        case FB_SUBSTITUTION:
246        {
247                std::list<SString> tokenized = tokenizeSequence(line);
248                int rndid = randomN(tokenized.size()); // select random letter from genotype
249                // increment/decrement character - when overflow happens, this method
250                // uses reflect method
251                std::list<SString>::iterator it = tokenized.begin();
252                std::advance(it, rndid);
253                SString t = (*it);
254                if ((*it).len() == 1)
255                {
256                        if (randomN(2) == 0)
257                        {
258                                if ((*it)[0] == 'a') (*it).directWrite()[0] = 'b';
259                                else (*it).directWrite()[0] = (*it)[0] - 1;
260                        }
261                        else
262                        {
263                                if ((*it)[0] == 'z') (*it).directWrite()[0] = 'y';
264                                else (*it).directWrite()[0] = (*it)[0] + 1;
265                        }
266                        chg = 1.0 / line.len();
267                }
268                else
269                {
270                        // first method needs to extract quotes
271                        SString def = (*it);
272                        def = def.substr(1, def.len() - 2);
273                        Geno_fH::mutateNeuronProperties(def);
274                        SString res = "\"";
275                        res += def;
276                        res += "\"";
277                        (*it) = res;
278                        chg = (double)def.len() / line.len();
279                }
280                line = detokenizeSequence(tokenized);
281                break;
282        }
283        case FB_INSERTION:
284        {
285                chg = 1.0 / line.len();
286                std::list<SString> tokenized = tokenizeSequence(line);
287                int rndid = randomN(tokenized.size()); // select random insertion point
288                std::list<SString>::iterator it = tokenized.begin();
289                std::advance(it, rndid);
290                SString letter = "a";
291                letter.directWrite()[0] = 'a' + randomN(26);
292                tokenized.insert(it, letter);
293                line = detokenizeSequence(tokenized);
294                break;
295        }
296        case FB_NCLASSINS:
297        {
298                std::list<SString> tokenized = tokenizeSequence(line);
299                std::list<SString>::iterator it = tokenized.begin();
300                int rndid = randomN(tokenized.size()); // select random insertion point
301                std::advance(it, rndid);
302                NeuroClass *cls = getRandomNeuroClass();
303                SString classdef = cls->getName();
304                Geno_fH::mutateNeuronProperties(classdef);
305                SString res = "\"";
306                res += classdef;
307                res += "\"";
308                tokenized.insert(it, res);
309                chg = (double)classdef.len() / line.len();
310                line = detokenizeSequence(tokenized);
311                break;
312        }
313        case FB_DELETION:
314        {
315                chg = 1.0 / line.len();
316                std::list<SString> tokenized = tokenizeSequence(line);
317                std::list<SString>::iterator it = tokenized.begin();
318                int rndid = randomN(tokenized.size()); // select random deletion point
319                std::advance(it, rndid);
320                tokenized.erase(it);
321                line = detokenizeSequence(tokenized);
322                break;
323        }
324        case FB_DUPLICATION:
325        {
326                int rndgene = randomN(fB_GenoHelpers::geneCount(line));
327                int start, end;
328                SString gene = fB_GenoHelpers::getGene(rndgene, line, start, end);
329                if (gene.indexOf("zz", 0) == -1) gene += "zz";
330                chg = (float)gene.len() / line.len();
331                line = gene + line;
332                break;
333        }
334        case FB_TRANSLOCATION:
335        {
336                std::list<SString> tokenized = tokenizeSequence(line);
337                std::vector<unsigned int> cuts(4);
338                for (int i = 0; i < 4; i++)
339                {
340                        cuts[i] = randomN(tokenized.size());
341                }
342                std::sort(cuts.begin(), cuts.end());
343                std::vector<std::list<SString>::iterator> iters(4);
344                for (int i = 0; i < 4; i++)
345                {
346                        iters[i] = tokenized.begin();
347                        std::advance(iters[i], cuts[i]);
348                }
349
350                std::list<SString> res;
351                res.insert(res.end(), tokenized.begin(), iters[0]);
352                res.insert(res.end(), iters[2], iters[3]);
353                res.insert(res.end(), iters[1], iters[2]);
354                res.insert(res.end(), iters[0], iters[1]);
355                res.insert(res.end(), iters[3], tokenized.end());
356
357//              SString first = line.substr(cuts[0], cuts[1] - cuts[0]);
358//              SString second = line.substr(cuts[2], cuts[3] - cuts[2]);
359//              SString result = line.substr(0, cuts[0]) + second +
360//                      line.substr(cuts[1], cuts[2] - cuts[1]) + first + line.substr(cuts[3]);
361                line = detokenizeSequence(res);
362                chg = (float)(cuts[3] - cuts[2] + cuts[1] - cuts[0]) / line.len();
363                break;
364        }
365        }
366        SString result = strdims + "\n" + line;
367        free(geno);
368        geno = strdup(result.c_str());
369        return GENOPER_OK;
370}
371
372int Geno_fB::crossOver(char *&g1, char *&g2, float& chg1, float& chg2)
373{
374        SString p1(g1);
375        SString p2(g2);
376
377        int dims1 = 0, dims2 = 0;
378        int pos = 0;
379        SString strdims;
380        p1.getNextToken(pos, strdims, '\n');
381        ExtValue::parseInt(strdims.c_str(), dims1, true, false);
382        SString parent1;
383        p1.getNextToken(pos, parent1, '\n');
384
385        pos = 0;
386        p2.getNextToken(pos, strdims, '\n');
387        ExtValue::parseInt(strdims.c_str(), dims2, true, false);
388
389        if (dims1 != dims2)
390        {
391                return GENOPER_OPFAIL;
392        }
393
394        SString parent2;
395        p2.getNextToken(pos, parent2, '\n');
396
397        SString child1 = "";
398        SString child2 = "";
399
400        switch (roulette(crossoverprobs, FB_XOVER_COUNT))
401        {
402        case FB_GENE_TRANSFER:
403        {
404                // get random gene from first parent
405                int choice = randomN(fB_GenoHelpers::geneCount(parent1));
406                int start, end;
407                SString gene = fB_GenoHelpers::getGene(choice, parent1, start, end);
408                // add this gene to the beginning of the second parent genotype
409                child2 = gene + parent2;
410                chg2 = (float)parent2.len() / (float)child2.len();
411                // do the same for second parent
412                choice = randomN(fB_GenoHelpers::geneCount(parent2));
413                gene = fB_GenoHelpers::getGene(choice, parent2, start, end);
414                child1 = gene + parent1;
415                chg1 = (float)parent1.len() / (float)child1.len();
416                break;
417        }
418        case FB_CROSSING_OVER:
419        {
420                // iterate through all genes of the first parent and assign them
421                // randomly to children
422                for (int i = 0; i < fB_GenoHelpers::geneCount(parent1); i++)
423                {
424                        int start, end;
425                        SString gene = fB_GenoHelpers::getGene(i, parent1, start, end);
426                        if (randomN(2) == 0)
427                        {
428                                child1 += gene;
429                                chg1 += 1.0f;
430                        }
431                        else
432                        {
433                                child2 += gene;
434                        }
435                }
436                chg1 /= fB_GenoHelpers::geneCount(parent1);
437
438                // do the same with second parent
439                for (int i = 0; i < fB_GenoHelpers::geneCount(parent2); i++)
440                {
441                        int start, end;
442                        SString gene = fB_GenoHelpers::getGene(i, parent2, start, end);
443                        if (randomN(2) == 0)
444                        {
445                                child1 += gene;
446                        }
447                        else
448                        {
449                                child2 += gene;
450                                chg2 += 1.0f;
451                        }
452                }
453                chg2 /= fB_GenoHelpers::geneCount(parent2);
454                break;
455        }
456        }
457
458        free(g1);
459        free(g2);
460        if (child1.len() > 0 && child2.len() == 0)
461        {
462                child1 = strdims + "\n" + child1;
463                g1 = strdup(child1.c_str());
464                g2 = strdup("");
465        }
466        else if (child2.len() > 0 && child1.len() == 0)
467        {
468                child2 = strdims + "\n" + child2;
469                g1 = strdup(child2.c_str());
470                g2 = strdup("");
471        }
472        else
473        {
474                child1 = strdims + "\n" + child1;
475                child2 = strdims + "\n" + child2;
476                g1 = strdup(child1.c_str());
477                g2 = strdup(child2.c_str());
478        }
479        return GENOPER_OK;
480}
481
482uint32_t Geno_fB::style(const char *geno, int pos)
483{
484        char ch = geno[pos];
485        if (isdigit(ch))
486        {
487                while (pos > 0)
488                {
489                        pos--;
490                        if (isdigit(geno[pos]) == 0)
491                        {
492                                return GENSTYLE_CS(0, GENSTYLE_INVALID);
493                        }
494                }
495                return GENSTYLE_RGBS(0, 0, 200, GENSTYLE_BOLD);
496        }
497        if (islower(ch) == 0)
498        {
499                return GENSTYLE_CS(0, GENSTYLE_INVALID);
500        }
501        uint32_t style = GENSTYLE_CS(GENCOLOR_TEXT, GENSTYLE_NONE);
502        if (ch == 'a' && pos > 0 && (geno[pos - 1] == 'a' || geno[pos - 1] == '\n'))
503        {
504                style = GENSTYLE_RGBS(0, 200, 0, GENSTYLE_BOLD);
505        }
506        else if (ch == 'z' && pos > 0 && geno[pos - 1] == 'z')
507        {
508                style = GENSTYLE_RGBS(200, 0, 0, GENSTYLE_BOLD);
509        }
510        return style;
511}
Note: See TracBrowser for help on using the repository browser.