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

Last change on this file since 955 was 955, checked in by Maciej Komosinski, 4 years ago

Genetic format ID becomes a string (no longer limited to a single character)

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