source: cpp/frams/genetics/fL/fL_general.cpp @ 780

Last change on this file since 780 was 780, checked in by Maciej Komosinski, 2 years ago

Added sources for genetic encodings fB, fH, fL

File size: 25.4 KB
Line 
1#include <algorithm>
2#include <stack>
3#include "fL_general.h"
4
5const char *fL_part_names[PART_PROPS_COUNT] = { "dn", "fr", "ing", "as" };
6const char *fL_part_fullnames[PART_PROPS_COUNT] = { "details", "friction", "ingestion", "assimilation" };
7
8const char *fL_joint_names[JOINT_PROPS_COUNT] = { "stif", "rotstif", "stam" };
9const char *fL_joint_fullnames[JOINT_PROPS_COUNT] = { "stiffness", "rotation stiffness", "stamina" };
10
11#define FIELDSTRUCT fL_Word
12ParamEntry fL_word_paramtab[] =
13{
14        { "Word", 1, 2, "w" },
15        { "name", 0, PARAM_CANOMITNAME, "word name", "s", FIELD(name), },
16        { "npar", 0, PARAM_CANOMITNAME, "number of parameters", "d 0 3 0", FIELD(npar), },
17        { 0, 0, 0, }
18};
19#undef FIELDSTRUCT
20
21#define FIELDSTRUCT fL_Rule
22ParamEntry fL_rule_paramtab[] =
23{
24        { "Rule", 1, 3, "r" },
25        { "pred", 0, PARAM_CANOMITNAME, "predecessor", "s", FIELD(predecessor), },
26        { "cond", 0, PARAM_CANOMITNAME, "parameter condition", "s", FIELD(condition), },
27        { "succ", 0, PARAM_CANOMITNAME, "successor", "s", FIELD(successor), },
28        { 0, 0, 0, }
29};
30#undef FIELDSTRUCT
31
32#define FIELDSTRUCT fL_Builder
33ParamEntry fL_builder_paramtab[] =
34{
35        { "LSystemInfo", 1, 3, "i" },
36        { "axiom", 0, PARAM_CANOMITNAME, "starting sequence of L-System", "s", FIELD(axiom), },
37        { "time", 0, PARAM_CANOMITNAME, "development time", "f 1.0 100.0 1.0", FIELD(time), },
38        { "numckp", 0, PARAM_CANOMITNAME, "number of checkpoints", "d 1 50 1", FIELD(numckp), },
39        { 0, 0, 0, }
40};
41#undef FIELDSTRUCT
42
43fL_Builder::~fL_Builder()
44{
45        // first remove words from builder
46        for (fL_Word *word : genotype)
47        {
48                delete word;
49        }
50        genotype.clear();
51        // remove rules from builder
52        for (fL_Rule *rule : rules)
53        {
54                delete rule;
55        }
56        rules.clear();
57
58        // remove words definitions with their ParamTabs
59        std::unordered_map<std::string, fL_Word *>::iterator it;
60        for (it = words.begin(); it != words.end(); it++)
61        {
62                ParamObject::freeParamTab(it->second->tab);
63                delete it->second;
64        }
65        words.clear();
66}
67
68bool fL_Builder::getNextObject(int &pos, SString src, SString &token)
69{
70        // if position exceeds length then return false
71        if (pos >= src.len()) return false;
72        int opencount = -1;
73        int i = pos;
74        for (; i < src.len(); i++)
75        {
76                // token cannot contain branching parenthesis
77                if (src[i] == '[' || src[i] == ']')
78                {
79                        // if token started - return parenthesis mismatch
80                        if (opencount != -1)
81                        {
82                                pos = -1;
83                                return false;
84                        }
85                        // otherwise [ and ] are interpreted as tokens and they do not have parenthesis
86                        token = src.substr(pos, i + 1 - pos);
87                        pos = i + 1;
88                        return true;
89                }
90                // every word, except [ and ], has () parenthesis
91                // every open parenthesis increment opencount counter;
92                if (src[i] == '(')
93                {
94                        if (opencount == -1) opencount = 1;
95                        else opencount++;
96                }
97                // every close parenthesis decrement opencount counter
98                else if (src[i] == ')')
99                {
100                        // if there were no open parenthesis, return parenthesis mismatch
101                        if (opencount == -1)
102                        {
103                                pos = -1;
104                                return false;
105                        }
106                        else opencount--;
107                }
108                // if counter reaches 0, the token extraction is finished
109                if (opencount == 0)
110                {
111                        break;
112                }
113        }
114        if (opencount == 0)
115        {
116                token = src.substr(pos, i + 1 - pos);
117                pos = i + 1;
118                return true;
119        }
120        // if there was no closing parenthesis, then return parenthesis mismatch
121        pos = -1;
122        return false;
123}
124
125std::string fL_Builder::trimSpaces(std::string data)
126{
127        size_t first = data.find_first_not_of(' ');
128        if (std::string::npos == first)
129        {
130                return data;
131        }
132        size_t last = data.find_last_not_of(' ');
133        return data.substr(first, (last - first + 1));
134}
135
136int fL_Builder::tokenize(SString sequence, std::list<fL_Word *> &result, int numparams)
137{
138        int pos = 0;
139        SString token;
140        int branchcount = 0;
141        if (result.size() > 0)
142        {
143                for (fL_Word *word : result)
144                {
145                        delete word;
146                }
147                result.clear();
148        }
149        // iterate through available tokens
150        while (getNextObject(pos, sequence, token))
151        {
152                // if token is of open branch type, then add start of branch
153                if (token.indexOf("[", 0) != -1)
154                {
155                        fL_Branch *word = new fL_Branch(fL_Branch::BranchType::OPEN);
156                        result.push_back(word);
157                        branchcount++;
158                        continue;
159                }
160                // if token is of closed branch type, then add end of branch
161                if (token.indexOf("]", 0) != -1)
162                {
163                        if (branchcount == 0)
164                        {
165                                SString message = "Branch parenthesis mismatch at:  ";
166                                message += sequence;
167                                logMessage("fL_Builder", "tokenize", LOG_ERROR, message.c_str());
168                                return 1;
169                        }
170                        fL_Branch *word = new fL_Branch(fL_Branch::BranchType::CLOSE);
171                        result.push_back(word);
172                        branchcount--;
173                        continue;
174                }
175                SString wordn;
176                int tokpos = 0;
177                // if word name cannot be extracted, then return error
178                if (!token.getNextToken(tokpos, wordn, '('))
179                {
180                        SString message = "Error during parsing words sequence:  ";
181                        message += sequence;
182                        logMessage("fL_Builder", "tokenize", LOG_ERROR, message.c_str());
183                        return 1;
184                }
185                std::string wordname = fL_Builder::trimSpaces(wordn.c_str());
186                // if word cannot be found in available words, then return error
187                if (words.find(wordname) == words.end())
188                {
189                        SString message = "Word '";
190                        message += wordname.c_str();
191                        message += "' in sequence does not exist";
192                        logMessage("fL_Builder", "tokenize", LOG_ERROR, message.c_str());
193                        return 1;
194                }
195
196                // create new word and assign parameters
197                fL_Word *word = new fL_Word();
198
199                *word = *words[wordname];
200
201                // if word has parameters
202                if (word->npar > 0)
203                {
204                        // create ParamObject that will hold parameter data
205                        word->data = ParamObject::makeObject(word->tab);
206                        Param par(word->tab);
207                        par.select(word->data);
208                        par.setDefault();
209                        ParamInterface::LoadOptions opts;
210
211                        SString temp;
212                        temp = token.substr(tokpos);
213                        temp = temp.substr(0, temp.len() - 1);
214                        // load parameters from string
215                        par.load(ParamInterface::FormatSingleLine, temp, &opts);
216                        for (int i = 0; i < par.getPropCount(); i++)
217                        {
218                                // create MathEvaluation object to check if string contained by
219                                // parameter is valid
220                                double tmp;
221                                MathEvaluation *eval = new MathEvaluation(numparams);
222                                SString seq = par.getString(i);
223                                // if string is empty, then evaluate this with 0
224                                if (seq.len() == 0)
225                                {
226                                        eval->evaluate("0", tmp);
227                                }
228                                // if sequence could not be evaluated, then return error
229                                else if (eval->evaluate(seq.c_str(), tmp) != 0)
230                                {
231                                        SString message = "Word in sequence has invalid parameter:  ";
232                                        message += temp;
233                                        logMessage("fL_Builder", "tokenize", LOG_ERROR, message.c_str());
234                                        delete eval;
235                                        delete word;
236                                        return 1;
237                                }
238                                word->parevals.push_back(eval);
239                        }
240                }
241                result.push_back(word);
242        }
243
244        // check if there were no parenthesis errors in genotype
245        if (pos == -1)
246        {
247                SString message = "Parenthesis mismatch at:  ";
248                message += sequence;
249                logMessage("fL_Builder", "tokenize", LOG_ERROR, message.c_str());
250                return 1;
251        }
252        if (branchcount != 0)
253        {
254                SString message = "Branching mismatch at:  ";
255                message += sequence;
256                logMessage("fL_Builder", "tokenize", LOG_ERROR, message.c_str());
257                return 1;
258        }
259        return 0;
260}
261
262void fL_Word::operator=(const fL_Word& src)
263{
264        if (&src != this)
265        {
266                name = src.name;
267                npar = src.npar;
268
269                //mut = src.mut;
270                tab = src.tab;
271
272                parevals = src.parevals;
273
274                data = NULL; // properties cannot be copied
275        }
276}
277
278int fL_Word::processDefinition(fL_Builder *builder)
279{
280        // if word already exist, then return error
281        if (this->name.len() == 0)
282        {
283                logMessage("fL_Word", "processDefinition", LOG_ERROR, "Axiom name is empty");
284                return 1;
285        }
286        if (builder->words.find(this->name.c_str()) != builder->words.end())
287        {
288                std::string message = "Word redefinition:  ";
289                message += this->name.c_str();
290                logMessage("fL_Word", "processDefinition", LOG_ERROR, message.c_str());
291                return 1;
292        }
293
294        // create ParamTab for word
295        for (int i = 0; i < npar; i++)
296        {
297                std::string n = "n";
298                n += std::to_string(i);
299                mut.addProperty(NULL, n.c_str(), LSYSTEM_PARAM_TYPE, n.c_str(), "", PARAM_CANOMITNAME, 0, -1);
300        }
301
302        tab = ParamObject::makeParamTab((ParamInterface *)&mut, 0, 0, mut.firstMutableIndex());
303
304        builder->words[this->name.c_str()] = this;
305        return 0;
306}
307
308int fL_Rule::processDefinition(fL_Builder *builder)
309{
310        // if there is no word among words that matches predecessor, then return error
311        if (builder->words.find(predecessor.c_str()) == builder->words.end())
312        {
313                logMessage("fL_Rule", "processDefinition", LOG_ERROR, "Word in Rule condition does not exist");
314                return 1;
315        }
316
317        objpred = new fL_Word();
318        *objpred = *builder->words[predecessor.c_str()];
319
320        // parse condition
321        if (condition != "")
322        {
323                std::string cond = condition.c_str();
324                condeval = new MathEvaluation(objpred->npar);
325                double tmp;
326                if (condeval->evaluate(condition.c_str(), tmp) != 0)
327                {
328                        SString message = "Parametric condition of rule invalid:  ";
329                        message += condition;
330                        logMessage("fL_Rule", "processDefinition", LOG_ERROR, message.c_str());
331                        return 1;
332                }
333        }
334
335        // parse successor
336        if (successor == "")
337        {
338                logMessage("fL_Rule", "processDefinition", LOG_ERROR, "Successor cannot be empty");
339                return 1;
340        }
341
342        if (builder->tokenize(successor, objsucc, objpred->npar) != 0)
343        {
344                logMessage("fL_Rule", "processDefinition", LOG_ERROR, "Unable to process successor sequence");
345                return 1;
346        }
347
348        builder->rules.push_back(this);
349        return 0;
350}
351
352int fL_Builder::processDefinition(fL_Builder *builder)
353{
354        // tokenize axiom
355        if (tokenize(axiom, genotype, 0) != 0)
356        {
357                logMessage("fL_Builder", "processDefinition", LOG_ERROR, "Unable to process axiom sequence");
358                return 1;
359        }
360        else if (genotype.size() == 0)
361        {
362                logMessage("fL_Builder", "processDefinition", LOG_ERROR, "Axiom sequence is empty");
363                return 1;
364        }
365        return 0;
366}
367
368int fL_Builder::processLine(fLElementType type, SString line, fL_Element *&obj, int linenumber, int begin, int end)
369{
370        ParamEntry *tab;
371        // choose proper ParamTab and construct proper object
372        switch (type)
373        {
374        case fLElementType::TERM:
375        {
376                tab = fL_word_paramtab;
377                obj = new fL_Word();
378                break;
379        }
380        case fLElementType::INFO:
381        {
382                tab = fL_builder_paramtab;
383                obj = this;
384                break;
385        }
386        case fLElementType::RULE:
387        {
388                tab = fL_rule_paramtab;
389                obj = new fL_Rule(begin, end);
390                break;
391        }
392        default:
393                break;
394        }
395        Param par(tab);
396        par.select(obj);
397        par.setDefault();
398        ParamInterface::LoadOptions opts;
399
400        par.load(ParamInterface::FormatSingleLine, line, &opts);
401
402        if (opts.parse_failed)
403        {
404                std::string message = "Error in parsing parameters at line:  " + std::to_string(linenumber);
405                logMessage("fL_Builder", "processLine", LOG_ERROR, message.c_str());
406                delete obj;
407                return begin + 1;
408        }
409
410        return 0;
411}
412
413void fL_Builder::addModelWords()
414{
415        // stick S
416        fL_Word *stick = new fL_Word(true);
417        stick->name = "S";
418        stick->npar = 8;
419        for (int i = 0; i < PART_PROPS_COUNT; i++)
420        {
421                stick->mut.addProperty(NULL, fL_part_names[i], "s", fL_part_fullnames[i], fL_part_fullnames[i], PARAM_CANOMITNAME, 0, -1);
422        }
423
424        for (int i = 0; i < JOINT_PROPS_COUNT; i++)
425        {
426                stick->mut.addProperty(NULL, fL_joint_names[i], "s", fL_joint_fullnames[i], fL_joint_fullnames[i], PARAM_CANOMITNAME, 0, -1);
427        }
428
429        stick->mut.addProperty(NULL, "l", "s", "length", "length", PARAM_CANOMITNAME, 0, -1);
430        stick->tab = ParamObject::makeParamTab((ParamInterface *)&stick->mut, 0, 0, stick->mut.firstMutableIndex());
431        words["S"] = stick;
432
433        // neuron N
434        fL_Word *neuron = new fL_Word(true);
435        neuron->name = "N";
436        neuron->npar = 1;
437        neuron->mut.addProperty(NULL, "d", "s", "details", "details", PARAM_CANOMITNAME, 0, -1);
438        neuron->tab = ParamObject::makeParamTab((ParamInterface *)&neuron->mut, 0, 0, neuron->mut.firstMutableIndex());
439        words["N"] = neuron;
440
441        // connection C
442        fL_Word *connection = new fL_Word(true);
443        connection->name = "C";
444        connection->npar = 2;
445        connection->mut.addProperty(NULL, "w", "s", "weight", "weight", PARAM_CANOMITNAME, 0, -1);
446        connection->mut.addProperty(NULL, "attr", "s", "attractor", "connection attractor", PARAM_CANOMITNAME, 0, -1);
447        connection->tab = ParamObject::makeParamTab((ParamInterface *)&connection->mut, 0, 0, connection->mut.firstMutableIndex());
448        words["C"] = connection;
449
450        // rotation objects
451        fL_Word *rotx = new fL_Word(true);
452        rotx->name = "rotX";
453        rotx->npar = 1;
454        rotx->processDefinition(this);
455
456        fL_Word *roty = new fL_Word(true);
457        roty->name = "rotY";
458        roty->npar = 1;
459        roty->processDefinition(this);
460
461        fL_Word *rotz = new fL_Word(true);
462        rotz->name = "rotZ";
463        rotz->npar = 1;
464        rotz->processDefinition(this);
465}
466
467int fL_Builder::parseGenotype(SString genotype)
468{
469        int pos = 0;
470        int lastpos = 0;
471        SString line;
472        int linenumber = 0;
473
474        fLElementType type = fLElementType::TERM;
475
476        // add default words first to prevent redefinitions
477        addModelWords();
478
479        while (genotype.getNextToken(pos, line, '\n'))
480        {
481                if (line.len() > 0)
482                {
483                        // words can be defined in the beginning of genotype
484                        if (line.startsWith("w:") && type != fLElementType::TERM)
485                        {
486                                logMessage("fL_Builder", "parseGenotype", LOG_ERROR, "All words should be defined in the beginning of genotype");
487                                return lastpos + 1;
488                        }
489                        else if (line.startsWith("i:"))
490                        {
491                                // after all words are defined, next definition should be information
492                                if (type == fLElementType::TERM)
493                                {
494                                        type = fLElementType::INFO;
495                                }
496                                else
497                                {
498                                        logMessage("fL_Builder", "parseGenotype", LOG_ERROR, "Axioms and iteration number should be defined after word definitions");
499                                        return lastpos + 1;
500                                }
501                        }
502                        else if (line.startsWith("r:"))
503                        {
504                                // after information definition, the last thing is rule definitions
505                                if (type == fLElementType::TERM)
506                                {
507                                        logMessage("fL_Builder", "parseGenotype", LOG_ERROR, "Axiom is not defined - define it after words definition");
508                                        return lastpos + 1;
509                                }
510                                else if (type == fLElementType::INFO)
511                                {
512                                        type = fLElementType::RULE;
513                                }
514                        }
515                        // create object
516                        fL_Element *obj = NULL;
517                        int res = processLine(type, line.substr(2), obj, linenumber, lastpos, pos - 1);
518                        if (res != 0)
519                        {
520                                if (obj && obj != this) delete obj;
521                                return res;
522                        }
523                        res = obj->processDefinition(this);
524                        if (res != 0)
525                        {
526                                if (obj && obj != this) delete obj;
527                                return res;
528                        }
529                }
530                lastpos = pos;
531        }
532        if (type == fLElementType::TERM)
533        {
534                logMessage("fL_Builder", "parseGenotype", LOG_ERROR, "Info line was not declared");
535                return 1;
536        }
537        return 0;
538}
539
540int fL_Word::saveEvals(bool keepformulas)
541{
542        if (npar > 0)
543        {
544                Param par(tab);
545                par.select(data);
546                for (int i = 0; i < npar; i++)
547                {
548                        if (parevals[i] != NULL)
549                        {
550                                double val;
551                                if (parevals[i]->evaluateRPN(val) != 0)
552                                {
553                                        logMessage("fL_Word", "saveEvals", LOG_ERROR, "Could not stringify mathematical expression in Word");
554                                        return 1;
555                                }
556                                if (val == 0)
557                                {
558                                        par.setString(i, "");
559                                }
560                                else
561                                {
562                                        if (keepformulas)
563                                        {
564                                                std::string res;
565                                                if (parevals[i]->RPNToInfix(res) != 0)
566                                                {
567                                                        logMessage("fL_Word", "saveEvals", LOG_ERROR, "Could not stringify mathematical expression in Word");
568                                                        return 1;
569                                                }
570                                                par.setString(i, res.c_str());
571                                        }
572                                        else
573                                        {
574                                                SString r = SString::valueOf(val);
575                                                par.setString(i, r);
576                                        }
577                                }
578                        }
579                }
580        }
581        return 0;
582}
583
584// Methods for converting L-System objects to string
585
586SString fL_Word::toString()
587{
588        Param par(fL_word_paramtab);
589        fL_Word *obj = new fL_Word();
590        par.select(this);
591        SString res;
592        par.saveSingleLine(res, obj, true, false);
593        res = SString("w:") + res;
594        delete obj;
595        return res;
596}
597
598SString fL_Word::stringify(bool keepformulas)
599{
600        SString res = name;
601        SString params = "";
602        if (npar > 0)
603        {
604                saveEvals(keepformulas);
605                Param par(tab);
606                void *obj = ParamObject::makeObject(tab);
607                par.select(obj);
608                par.setDefault();
609                par.select(data);
610                par.saveSingleLine(params, obj, false, false);
611                ParamObject::freeObject(obj);
612        }
613        res += "(";
614        res += params + ")";
615        return res;
616}
617
618SString fL_Rule::toString()
619{
620        predecessor = objpred->name;
621        std::string tmp;
622        if (condeval)
623        {
624                condeval->RPNToInfix(tmp);
625                condition = tmp.c_str();
626        }
627        else
628        {
629                condition = "";
630        }
631        successor = "";
632        std::list<fL_Word *>::iterator i;
633        for (i = objsucc.begin(); i != objsucc.end(); i++)
634        {
635                successor += (*i)->stringify();
636        }
637        Param par(fL_rule_paramtab);
638        fL_Rule *obj = new fL_Rule(0, 0);
639        par.select(this);
640        SString res;
641        par.saveSingleLine(res, obj, true, false);
642        res = SString("r:") + res;
643        delete obj;
644        return res;
645}
646
647SString fL_Builder::getStringifiedProducts()
648{
649        axiom = "";
650        std::list<fL_Word *>::iterator i;
651        for (i = genotype.begin(); i != genotype.end(); i++)
652        {
653                axiom += (*i)->stringify(false);
654        }
655        return axiom;
656}
657
658SString fL_Builder::toString()
659{
660        SString res;
661        for (std::unordered_map<std::string, fL_Word *>::iterator it = words.begin(); it != words.end(); it++)
662        {
663                if (!it->second->builtin)
664                {
665                        res += it->second->toString();
666                }
667        }
668        getStringifiedProducts();
669        Param par(fL_builder_paramtab);
670        fL_Builder *obj = new fL_Builder();
671        par.select(this);
672        SString tmp;
673        par.saveSingleLine(tmp, obj, true, false);
674        res += SString("i:") + tmp;
675        delete obj;
676        for (fL_Rule * rule : rules)
677        {
678                res += rule->toString();
679        }
680        return res;
681}
682
683int fL_Rule::deploy(fL_Word *in, std::list<fL_Word *>::iterator &it, std::list<fL_Word *> &genotype, double currtime)
684{
685        // if predecessor and given word differ, then rule is not applicable
686        if (in->name != objpred->name || in->npar != objpred->npar)
687        {
688                return 1;
689        }
690        // store predecessor values in separate array
691        double *inwordvalues = new double[in->npar];
692        for (int i = 0; i < in->npar; i++)
693        {
694                if (in->parevals[i] != NULL)
695                {
696                        in->parevals[i]->modifyVariable(-1, currtime == in->creationiter + 1.0 ? 1.0 : currtime - floor(currtime));
697                        in->parevals[i]->evaluateRPN(inwordvalues[i]);
698                }
699                else
700                {
701                        inwordvalues[i] = 0;
702                }
703        }
704        // if condition exists
705        if (condeval)
706        {
707                // check if condition is satisfied. If not, rule is not applicable
708                for (int i = 0; i < in->npar; i++)
709                {
710                        condeval->modifyVariable(i, inwordvalues[i]);
711                }
712                double condvalue;
713                condeval->evaluateRPN(condvalue);
714                if (condvalue == 0)
715                {
716                        delete[] inwordvalues;
717                        return 1;
718                }
719        }
720
721        // remove predecessor word from genotype and replace it with successor
722        it = genotype.erase(it);
723        for (std::list<fL_Word *>::iterator word = objsucc.begin(); word != objsucc.end(); word++)
724        {
725                // create new word and copy properties from word definition
726                fL_Word *nword = new fL_Word();
727                *nword = **word;
728                // store information about when word has been created
729                nword->creationiter = currtime;
730                nword->parevals.clear();
731                if (nword->npar > 0)
732                {
733                        nword->data = ParamObject::makeObject(nword->tab);
734                }
735                // calculate word parameters and store MathEvaluation objects for further
736                // time manipulations.
737                for (int q = 0; q < nword->npar; q++)
738                {
739                        if ((*word)->parevals[q] == NULL)
740                        {
741                                MathEvaluation *ev = new MathEvaluation(0);
742                                ev->convertString("0");
743                                nword->parevals.push_back(ev);
744                        }
745                        else
746                        {
747                                std::string tmp;
748                                (*word)->parevals[q]->RPNToInfix(tmp);
749                                MathEvaluation *ev = new MathEvaluation(in->npar);
750                                for (int i = 0; i < in->npar; i++)
751                                {
752                                        ev->modifyVariable(i, inwordvalues[i]);
753                                }
754                                ev->modifyVariable(-1, currtime == (*word)->creationiter + 1.0 ? 1.0 : currtime - floor(currtime));
755                                ev->convertString(tmp);
756                                nword->parevals.push_back(ev);
757                        }
758                }
759                genotype.insert(it, nword);
760        }
761        delete[] inwordvalues;
762        delete in;
763        return 0;
764}
765
766int fL_Builder::iterate(double currtime)
767{
768        // deploy proper rules for all words in current genotype
769        std::list<fL_Word *>::iterator word = genotype.begin();
770        while (word != genotype.end())
771        {
772                bool deployed = false;
773                for (fL_Rule * rule : rules)
774                {
775                        if (rule->deploy((*word), word, genotype, currtime) == 0)
776                        {
777                                deployed = true;
778                                break;
779                        }
780                }
781                if (!deployed) word++;
782        }
783        return 0;
784}
785
786int fL_Builder::alterTimedProperties(double currtime)
787{
788        // alter parameters of all words, if they are time-dependent
789        std::list<fL_Word *>::iterator word = genotype.begin();
790        while (word != genotype.end())
791        {
792                if (currtime - (*word)->creationiter <= 1.0)
793                {
794                        for (MathEvaluation *ev : (*word)->parevals)
795                        {
796                                if (ev) ev->modifyVariable(-1, currtime == (*word)->creationiter + 1.0 ? 1.0 : currtime - floor(currtime));
797                        }
798                }
799                word++;
800        }
801        return 0;
802}
803
804int fL_Builder::alterPartProperties(Part *part, fL_Word *stickword, double &alterationcount)
805{
806        Param par(stickword->tab, stickword->data);
807        Param ppar = part->properties();
808        for (int i = 0; i < PART_PROPS_COUNT; i++)
809        {
810                double partprop;
811                double currval;
812                if (!ExtValue::parseDouble(par.getStringById(fL_part_names[i]).c_str(), currval, false))
813                {
814                        logMessage("fL_Builder", "alterPartProperties", LOG_ERROR,
815                                "Error parsing word parameter");
816                        return 1;
817                }
818                partprop = (ppar.getDoubleById(fL_part_names[i]) * alterationcount +
819                        currval) / (alterationcount + 1.0);
820                ppar.setDoubleById(fL_part_names[i], partprop);
821        }
822        return 0;
823}
824
825bool fL_Word::operator==(const fL_Word& other) const
826{
827        if (name == other.name) return false;
828        if (npar == other.npar) return false;
829        for (int i = 0; i < npar; i++)
830        {
831                if (parevals[i] && other.parevals[i])
832                {
833                        double first;
834                        double second;
835                        parevals[i]->evaluateRPN(first);
836                        other.parevals[i]->evaluateRPN(second);
837                        if (first != second)
838                        {
839                                return false;
840                        }
841                }
842                else
843                {
844                        return false;
845                }
846        }
847        return true;
848}
849
850void fL_Builder::findNext(fL_Word *word, std::list<fL_Word *> genotype, std::list<fL_Word *>::iterator &it)
851{
852        int rightdist = 0;
853        std::list<fL_Word *>::iterator iter(it);
854        for (; iter != genotype.end(); iter++)
855        {
856                if (*word == **iter)
857                {
858                        break;
859                }
860                rightdist++;
861        }
862        int leftdist = 0;
863        std::list<fL_Word *>::reverse_iterator riter(it);
864        for (; riter != genotype.rend(); riter++)
865        {
866                if (*word == **riter)
867                {
868                        break;
869                }
870                leftdist++;
871        }
872        if (iter == genotype.end())
873        {
874                it = riter.base();
875        }
876        else if (riter == genotype.rend())
877        {
878                it = iter;
879        }
880        else if (leftdist < rightdist)
881        {
882                it = riter.base();
883        }
884        else
885        {
886                it = iter;
887        }
888}
889
890Neuro *fL_Builder::findInputNeuron(std::list<fL_Word *> genotype, std::list<fL_Word *>::iterator it, fL_Word *attractor)
891{
892        if (!attractor)
893        {
894                attractor = new fL_Word();
895                *attractor = *(*it);
896                attractor->data = NULL;
897                // TODO implement
898        }
899        return NULL;
900}
901
902int fL_Builder::developModel(Model &model)
903{
904        // TODO implement
905        fL_State currstate;
906        std::unordered_map<Part *, double> counters;
907        std::stack<fL_State> statestack;
908        std::vector<std::pair<std::list<fL_Word *>::iterator, Neuro *>> connsbuffer;
909        Part *firstpart = NULL;
910
911        for (std::list<fL_Word *>::iterator w = genotype.begin(); w != genotype.end(); w++)
912        {
913                fL_Word *word = (*w);
914                if (word->builtin)
915                {
916                        if (word->name == "S")
917                        {
918                                if (!currstate.currpart)
919                                {
920                                        if (!firstpart)
921                                        {
922                                                firstpart = new Part();
923                                                firstpart->p = Pt3D_0;
924                                                counters[firstpart] = 0;
925                                                model.addPart(firstpart);
926                                        }
927                                        currstate.currpart = firstpart;
928                                }
929                                if (alterPartProperties(currstate.currpart, word, counters[currstate.currpart]) != 0)
930                                {
931                                        return 1;
932                                }
933                                counters[currstate.currpart] += 1;
934                                Part *newpart = new Part();
935                                counters[newpart] = 0;
936                                if (alterPartProperties(newpart, word, counters[newpart]) != 0)
937                                {
938                                        delete newpart;
939                                        return 1;
940                                }
941                                Param par(word->tab, word->data);
942                                double length;
943                                if (!ExtValue::parseDouble(par.getStringById("l").c_str(), length, false))
944                                {
945                                        delete newpart;
946                                        logMessage("fL_Builder", "alterPartProperties", LOG_ERROR,
947                                                "Error parsing word parameter");
948                                        return 1;
949                                }
950                                newpart->p = currstate.currpart->p + currstate.direction * length;
951                                counters[newpart] += 1;
952                                model.addPart(newpart);
953
954                                Joint *newjoint = new Joint();
955                                newjoint->attachToParts(currstate.currpart, newpart);
956
957                                Param jpar = newjoint->properties();
958                                for (int i = 0; i < JOINT_PROPS_COUNT; i++)
959                                {
960                                        double jointprop;
961                                        if (!ExtValue::parseDouble(par.getStringById(fL_joint_names[i]).c_str(), jointprop, false))
962                                        {
963                                                logMessage("fL_Builder", "developModel", LOG_ERROR,
964                                                        "Error parsing word parameter");
965                                                delete newjoint;
966                                                return 1;
967                                        }
968                                        jpar.setDoubleById(fL_joint_names[i], jointprop);
969                                }
970                                model.addJoint(newjoint);
971                                currstate.currpart = newpart;
972                        }
973                        else if (word->name == "N")
974                        {
975                                Param npar(word->tab, word->data);
976                                Neuro *neu = new Neuro();
977                                neu->setDetails(npar.getStringById("d"));
978                                if (!neu->getClass())
979                                {
980                                        logMessage("fL_Builder", "developModel", LOG_ERROR, "Error parsing neuron class");
981                                        delete neu;
982                                        return 1;
983                                }
984                                model.addNeuro(neu);
985                                currstate.currneuron = neu;
986                        }
987                        else if (word->name == "C")
988                        {
989                                connsbuffer.push_back({ w, currstate.currneuron });
990                        }
991                        else if (word->name.startsWith("rot"))
992                        {
993                                Orient rotmatrix;
994                                double rot;
995                                if (word->parevals[0]->evaluateRPN(rot) != 0)
996                                {
997                                        logMessage("fL_Builder", "developModel", LOG_ERROR, "Error parsing neuron class");
998                                        return 1;
999                                }
1000                                if (word->name == "rotX")
1001                                {
1002                                        rotmatrix.rotate(Pt3D(rot, 0.0, 0.0));
1003                                }
1004                                else if (word->name == "rotY")
1005                                {
1006                                        rotmatrix.rotate(Pt3D(0.0, rot, 0.0));
1007                                }
1008                                else if (word->name == "rotZ")
1009                                {
1010                                        rotmatrix.rotate(Pt3D(0.0, 0.0, rot));
1011                                }
1012                                currstate.direction = rotmatrix.transform(currstate.direction);
1013                        }
1014                        else if (word->name == "[")
1015                        {
1016                                statestack.push(currstate);
1017                        }
1018                        else if (word->name == "]")
1019                        {
1020                                currstate = statestack.top();
1021                                statestack.pop();
1022                        }
1023                }
1024        }
1025
1026        // connections need
1027        //      for (std::pair<std::list<fL_Word *>::iterator, Neuro *> conndata : connsbuffer)
1028        //      {
1029        //
1030        //      }
1031        return 0;
1032}
1033
1034int fL_Builder::develop()
1035{
1036        Model m;
1037        double curriter = 0;
1038        double timestamp = 1.0 / numckp;
1039        double t = 0;
1040        for (; t <= time; t += timestamp)
1041        {
1042                alterTimedProperties(t); // always alter timed properties in the beginning
1043                // if iteration exceeds integer value, then deploy rules
1044                if (floor(t) > curriter)
1045                {
1046                        iterate(t);
1047                        curriter += 1.0;
1048                }
1049        }
1050        // if exact time of development was not reached due to floating point errors,
1051        // then alter timed properties
1052        if (time < t)
1053        {
1054                alterTimedProperties(time);
1055        }
1056        return 0;
1057}
Note: See TracBrowser for help on using the repository browser.