source: cpp/frams/genetics/geno.cpp @ 751

Last change on this file since 751 was 732, checked in by Maciej Komosinski, 7 years ago

Added support for "checkpoints" (intermediate phases of development of the Model when converting between genetic encodings). See Model.checkpoint() and conv_f1.cpp for an example.

  • Property svn:eol-style set to native
File size: 7.7 KB
RevLine 
[286]1// This file is a part of Framsticks SDK.  http://www.framsticks.com/
[732]2// Copyright (C) 1999-2018  Maciej Komosinski and Szymon Ulatowski.
[286]3// See LICENSE.txt for details.
[109]4
5#include "geno.h"
[145]6#include "genoconv.h"
[452]7#include <common/loggers/loggers.h>
8#include <common/stl-util.h>
[109]9#include <frams/model/model.h>
10
[348]11THREAD_LOCAL_DEF_PTR(Geno::Validators, geno_validators);
12THREAD_LOCAL_DEF_PTR(GenoConvManager, geno_converters);
[109]13
[522]14Geno::Validators* Geno::getValidators() { return tlsGetPtr(geno_validators); }
15GenoConvManager* Geno::getConverters() { return tlsGetPtr(geno_converters); }
[346]16
[348]17Geno::Validators* Geno::useValidators(Validators* val)
[522]18{
19        return tlsSetPtr(geno_validators, val);
20}
[348]21GenoConvManager* Geno::useConverters(GenoConvManager* gcm)
[522]22{
23        return tlsSetPtr(geno_converters, gcm);
24}
[346]25
[150]26void Geno::init(const SString& genstring, char genformat, const SString& genname, const SString& comment)
[109]27{
[150]28        refcount = 1;
29        owner = 0;
30        f0gen = 0;
[530]31        isvalid = -1;
32        name = genname;
33        txt = comment;
[732]34        setGenesAndFormat(genstring, genformat);
[530]35}
36
[534]37void Geno::setGenesAndFormat(const SString& genstring, char genformat)
[530]38{
[150]39        mapinshift = 0;
40        mapoutshift = 0;
41        SString gencopy(genstring);
42        if (genformat == -1)
[109]43        { // unknown format
[150]44                genformat = '1';
45                if (genstring.charAt(0) == '/')
[109]46                {
[522]47                        int end, error_end = -1;
[150]48                        switch (genstring.charAt(1))
[109]49                        {
50                        case '/':
[150]51                                genformat = genstring.charAt(2);
52                                if ((end = genstring.indexOf('\n')) >= 0)
53                                {
[530]54                                        mapinshift = end + 1;
55                                        gencopy = genstring.substr(end + 1);
[732]56                                        if ((end > 0) && (genstring[end - 1] == '\r')) end--;
[522]57                                        error_end = end;
58                                        if (end != 3) genformat = INVALID_FORMAT;
[150]59                                }
[109]60                                else
[150]61                                {
[522]62                                        if (genstring.len() != 3) genformat = INVALID_FORMAT;
[150]63                                        gencopy = 0;
64                                        mapinshift = genstring.len();
65                                }
[109]66                                break;
67                        case '*':
[150]68                                genformat = genstring.charAt(2);
69                                if ((end = genstring.indexOf("*/")) >= 0)
70                                {
[522]71                                        error_end = end + 2;
72                                        if (end != 3) genformat = INVALID_FORMAT;
[150]73                                        gencopy = genstring.substr(end + 2);
74                                        mapinshift = end + 2;
75                                }
[109]76                                else
[150]77                                {
[522]78                                        if (genstring.len() != 5) genformat = INVALID_FORMAT;
[150]79                                        gencopy = 0;
80                                        mapinshift = genstring.len();
81                                }
[109]82                                break;
83                        }
[732]84                        if (!isalnum(genformat)) genformat = INVALID_FORMAT;
[522]85                        if (genformat == INVALID_FORMAT)
[521]86                        {
[522]87                                SString cut;
88                                if (error_end<0) error_end = genstring.len();
89                                static const int MAX_ERROR = 20;
90                                if (error_end>MAX_ERROR)
91                                        cut = genstring.substr(0, MAX_ERROR) + "...";
92                                else
93                                        cut = genstring.substr(0, error_end);
94                                int lf = cut.indexOf('\n');
[732]95                                if (lf >= 0) { if ((lf > 0) && (cut[lf - 1] == '\r')) lf--; cut = cut.substr(0, lf); }
[530]96                                sstringQuote(cut);
97                                logPrintf("Geno", "init", LOG_ERROR, "Invalid genotype format declaration: '%s'%s", cut.c_str(), name.len() ? SString::sprintf(" in '%s'", name.c_str()).c_str() : "");
[521]98                        }
99
[109]100                }
101        }
[150]102        gen = gencopy;
[530]103        multiline = (strchr(gen.c_str(), '\n') != 0);
[150]104        format = genformat;
[530]105        freeF0();
106        isvalid = -1;
[150]107        // mapoutshift...?
[109]108}
109
110void Geno::freeF0()
111{
[150]112        if (f0gen) { delete f0gen; f0gen = 0; }
[109]113}
114
[150]115Geno::Geno(const char *genstring, char genformat, const char *genname, const char *comment)
[109]116{
[150]117        init(SString(genstring), genformat, SString(genname), SString(comment));
[109]118}
119
[150]120Geno::Geno(const SString& genstring, char genformat, const SString& genname, const SString& comment)
[109]121{
[150]122        init(genstring, genformat, genname, comment);
[109]123}
124
125Geno::Geno(const Geno& src)
[522]126        :gen(src.gen), name(src.name), format(src.format), txt(src.txt), isvalid(src.isvalid),
127        f0gen(0), mapinshift(src.mapinshift), mapoutshift(src.mapinshift),
128        multiline(src.multiline), owner(0)
[150]129{
130        f0gen = src.f0gen ? new Geno(*src.f0gen) : 0; refcount = 1;
131}
[109]132
133void Geno::operator=(const Geno& src)
134{
[150]135        freeF0();
136        gen = src.gen;
137        name = src.name;
138        format = src.format;
139        txt = src.txt;
140        isvalid = src.isvalid;
141        mapinshift = src.mapinshift;
142        mapoutshift = src.mapinshift;
143        multiline = src.multiline;
144        f0gen = src.f0gen ? new Geno(*src.f0gen) : 0;
145        owner = 0;
[109]146}
147
148Geno::Geno(const SString& src)
149{
[150]150        init(src, -1, SString::empty(), SString::empty());
[109]151}
152
[534]153void Geno::setGenesAssumingSameFormat(const SString& g)
[109]154{
[150]155        gen = g;
156        isvalid = -1;
157        freeF0();
[109]158}
159
160void Geno::setString(const SString& g)
161{
[150]162        freeF0();
163        init(g, -1, SString::empty(), SString::empty());
[109]164}
165
166void Geno::setName(const SString& n)
167{
[150]168        name = n;
[109]169}
170
171void Geno::setComment(const SString& c)
172{
[150]173        txt = c;
[109]174}
175
[534]176SString Geno::getGenesAndFormat(void) const
[109]177{
[150]178        SString out;
179        if (format != '1')
[109]180        {
[150]181                if (multiline)
182                        out += "//";
183                else
184                        out += "/*";
185                if (format == 0)
186                        out += "invalid";
187                else
188                        out += format;
189                if (multiline)
190                        out += "\n";
191                else
192                        out += "*/";
[109]193        }
[150]194        out += gen;
195        return out;
[109]196}
197
198int Geno::mapGenToString(int genpos) const
199{
[150]200        if (genpos > gen.len()) return -2;
[522]201        if (genpos < 0) return -1;
[150]202        return mapinshift + genpos;
[109]203}
204
205int Geno::mapStringToGen(int stringpos) const
206{
[150]207        stringpos -= mapinshift;
[522]208        if (stringpos > gen.len()) return -2;
[150]209        if (stringpos < 0) return -1;
210        return stringpos;
[109]211}
212
[534]213SString Geno::getGenes(void) const { return gen; }
[150]214SString Geno::getName(void) const { return name; }
215char Geno::getFormat(void) const { return format; }
216SString Geno::getComment(void) const { return txt; }
[109]217
218int ModelGenoValidator::testGenoValidity(Geno& g)
219{
[150]220        if (g.getFormat() == '0')
[109]221        {
[150]222                Model mod(g);
223                return mod.isValid();
[109]224        }
[150]225        else
[109]226        {
[150]227                bool converter_missing;
[732]228                Geno f0geno = g.getConverted('0', NULL, false, &converter_missing);
[150]229                if (converter_missing)
230                        return -1;//no result
231                return f0geno.isValid();
[109]232        }
233}
234
235void Geno::validate()
236{
[150]237        if (isvalid >= 0) return;
238        if (gen.len() == 0) { isvalid = 0; return; }
[518]239        if (format == INVALID_FORMAT) { isvalid = 0; return; }
[522]240        Validators* vals = getValidators();
241        if (vals != NULL)
242        {
[508]243#ifdef WARN_VALIDATION_INCONSISTENCY
244                vector<int> results;
245                int first_result=-1;
246                FOREACH(GenoValidator*, v, (*vals))
[522]247                {
[508]248                        int r=v->testGenoValidity(*this);
249                        if (first_result<0) first_result=r;
250                        results.push_back(r);
[522]251                }
[508]252                int N=vals->size();
253                for(int i=1;i<N;i++)
254                        if (results[i]!=results[0])
[522]255                        {
256                        SString txt="Inconsistent validation results";
257                        for(int i=0;i<N;i++)
258                                txt+=SString::sprintf(" %d",results[i]);
259                        txt+=" for genotype '";
260                        txt+=getGene();
261                        txt+="'";
262                        logPrintf("Geno","validate",LOG_WARN,txt.c_str());
263                        break;
264                        }
[508]265                isvalid=first_result;
266                if (isvalid>=0)
267                        return;
268#else
[522]269                FOREACH(GenoValidator*, v, (*vals))
270                        if ((isvalid = v->testGenoValidity(*this)) >= 0)
271                                return;
[508]272#endif
[522]273        }
[150]274        isvalid = 0;
[521]275        logPrintf("Geno", "validate", LOG_WARN, "Wrong configuration? No genotype validators defined for genetic format 'f%c'.", format);
[109]276}
277
278bool Geno::isValid(void)
279{
[522]280        if (isvalid < 0)
281        {
282                LoggerToMemory err(LoggerBase::Enable | LoggerToMemory::StoreAllMessages, LOG_INFO);
[452]283                validate();
284                err.disable();
[522]285                string msg = err.getCountSummary();
286                if (msg.size() > 0)
287                {
288                        msg += ssprintf(" while checking validity of '%s'", getName().c_str());
289                        msg += "\n";
290                        msg += err.getMessages();
291                        logMessage("Geno", "isValid", err.getErrorLevel(), msg.c_str());
[452]292                }
[522]293        }
294        return isvalid > 0;
[109]295}
296
[732]297Geno Geno::getConverted(char otherformat, MultiMap *m, bool using_checkpoints, bool *converter_missing)
[109]298{
[150]299        if (otherformat == getFormat()) { if (converter_missing) *converter_missing = false; return *this; }
[109]300#ifndef NO_GENOCONVMANAGER
[522]301        GenoConvManager *converters = getConverters();
[150]302        if (converters)
[109]303        {
[732]304                if ((otherformat == '0') && (!m) && (!using_checkpoints))
[145]305                {
[150]306                        if (!f0gen)
[732]307                                f0gen = new Geno(converters->convert(*this, otherformat, NULL, using_checkpoints, converter_missing));
[500]308                        else
[522]309                        {
310                                if (converter_missing) *converter_missing = false;
311                        }
[150]312                        return *f0gen;
313                }
314                else
[732]315                        return converters->convert(*this, otherformat, m, using_checkpoints, converter_missing);
[109]316        }
[145]317#endif
[150]318        if (converter_missing) *converter_missing = true;
319        return (otherformat == getFormat()) ? *this : Geno(0, 0, 0, "GenConvManager not available");
[109]320}
321
322Geno::~Geno()
323{
[150]324        if (f0gen) delete f0gen;
[109]325}
Note: See TracBrowser for help on using the repository browser.