source: cpp/frams/genetics/f4/f4_conv.cpp @ 1233

Last change on this file since 1233 was 1231, checked in by Maciej Komosinski, 13 months ago
  • Thanks to r1230, it is possible to detect (and repair=remove) junk trailing genes that are left after successful parsing (after last '>')
  • The validate() function may attempt to repair a genotype where earlier it would give up
  • Stricter parsing of the '#' gene
  • Property svn:eol-style set to native
File size: 8.1 KB
RevLine 
[286]1// This file is a part of Framsticks SDK.  http://www.framsticks.com/
[1212]2// Copyright (C) 1999-2023  Maciej Komosinski and Szymon Ulatowski.
[286]3// See LICENSE.txt for details.
[193]4
[196]5// Copyright (C) 1999,2000  Adam Rotaru-Varga (adam_rotaru@yahoo.com), GNU LGPL
[760]6// Copyright (C) since 2001 Maciej Komosinski
7// 2018, Grzegorz Latosinski, added support for new API for neuron types and their properties
[196]8
[779]9#include "f4_conv.h"
[375]10#include <common/log.h>
[779]11#include "../genooperators.h" //for GENOPER_OK constant
[193]12
13#ifdef DMALLOC
14#include <dmalloc.h>
15#endif
16
17
[196]18GenoConv_f40::GenoConv_f40()
[193]19{
[196]20        name = "Developmental encoding";
21        in_format = '4';
22        out_format = '0';
23        mapsupport = 1;
[193]24}
25
26
[774]27SString GenoConv_f40::convert(SString &in, MultiMap *map, bool using_checkpoints)
[193]28{
[774]29        f4_Model *model = new f4_Model();
[1231]30        int res = model->buildFromF4(in, using_checkpoints);
31        if (res != GENOPER_OK)
[804]32        {
33                delete model;
34                return SString();  // oops
35        }
[196]36        if (NULL != map)
37                // generate to-f0 conversion map
38                model->getCurrentToF0Map(*map);
[534]39        SString out = model->getF0Geno().getGenes();
[196]40        delete model;
41        return out;
[193]42}
43
44
45GenoConv_F41_TestOnly::GenoConv_F41_TestOnly()
46{
[783]47        name = "Only for testing, approximate f4->f1 converter"; //Do not use in production! (adam)
[196]48        in_format = '4';
49        out_format = '1';
50        mapsupport = 0;
[193]51}
52
53
[774]54SString GenoConv_F41_TestOnly::convert(SString &in, MultiMap *map, bool using_checkpoints)
[193]55{
[774]56        f4_Model *model = new f4_Model();
[1231]57        int res = model->buildFromF4(in, using_checkpoints);
58        if (res != GENOPER_OK)
[804]59        {
60                delete model;
61                return SString();  // oops
62        }
[196]63        SString out;
64        model->toF1Geno(out);
65        delete model;
66        return out;
[193]67}
68
69
70f4_Model::f4_Model() : Model()
71{
[196]72        cells = NULL;
[193]73}
74
75f4_Model::~f4_Model()
76{
[196]77        if (cells) delete cells;
[193]78}
79
[760]80int f4_Model::buildFromF4(SString &geno, bool using_checkpoints)
[193]81{
[196]82        error = GENOPER_OK;
83        errorpos = -1;
[193]84
[1231]85        // transform geno from string to nodes
86        f4_Node f4rootnode;
87        int res = f4_process(geno.c_str(), &f4rootnode);
88        if (res || (f4rootnode.childCount() != 1)) //consider any error fatal, preventing building a model
89        {
90                error = GENOPER_OPFAIL;
91                errorpos = res;
92                return error;
93        }
94
[196]95        // build cells, and simulate
96        if (cells) delete cells;
[1231]97        cells = new f4_Cells(f4rootnode.child, false);
98        if (cells->getErrorCode() != GENOPER_OK)
[196]99        {
[1227]100                error = cells->getErrorCode();
101                errorpos = cells->getErrorPos();
[196]102                //delete cells;
103                return error;
104        }
[193]105
[196]106        cells->simulate();
[1231]107        if (cells->getErrorCode() != GENOPER_OK)
[196]108        {
[1227]109                error = cells->getErrorCode();
110                errorpos = cells->getErrorPos();
[196]111                return error;
112        }
[193]113
[196]114        // reset recursive traverse flags
[1231]115        for (int i = 0; i < cells->cell_count; i++)
[196]116                cells->C[i]->recProcessedFlag = 0;
[193]117
[760]118        open(using_checkpoints); // begin model build
[193]119
[196]120        // process every cell
[1231]121        for (int i = 0; i < cells->cell_count; i++)
[196]122        {
[1231]123                int res = buildModelRec(cells->C[i]);
[196]124                if (res)
125                {
[1231]126                        logPrintf("f4_Model", "buildFromF4", LOG_ERROR, "Error %d when building a Model", res);
[196]127                        error = res;
128                        break;
129                }
130        }
[193]131
[1231]132        int res_close = close();
133        if (res_close == 0) // invalid
134        {
135                logPrintf("f4_Model", "buildFromF4", LOG_ERROR, "Error %d when closing a Model", res_close);
[196]136                error = -10;
[1231]137        }
[193]138
[196]139        return error;
[193]140}
141
142
[774]143f4_Cell* f4_Model::getStick(f4_Cell *C)
[193]144{
[1227]145        if (C->type == CELL_STICK) return C;
[196]146        if (NULL != C->dadlink)
147                return getStick(C->dadlink);
148        // we have no more dadlinks, find any stick
[1227]149        for (int i = 0; i < cells->cell_count; i++)
150                if (cells->C[i]->type == CELL_STICK)
[196]151                        return cells->C[i];
152        // none!
[1227]153        logMessage("f4_Model", "getStick", LOG_ERROR, "Not a single stick");
[196]154        return NULL;
[193]155}
156
157
[774]158int f4_Model::buildModelRec(f4_Cell *C)
[193]159{
[196]160        int partidx;
161        int j, res;
162        MultiRange range;
[193]163
[196]164        if (C->recProcessedFlag)
165                // already processed
166                return 0;
[193]167
[196]168        // mark it processed
169        C->recProcessedFlag = 1;
[193]170
[196]171        // make sure parent is a stick
172        if (NULL != C->dadlink)
[1227]173                if (C->dadlink->type != CELL_STICK)
[196]174                {
[1227]175                        C->dadlink = getStick(C->dadlink);
[196]176                }
[193]177
[196]178        // make sure its parent is processed first
179        if (NULL != C->dadlink)
180        {
181                res = buildModelRec(C->dadlink);
182                if (res) return res;
183        }
[193]184
[196]185        char tmpLine[100];
[193]186
[196]187        range = C->genoRange;
[1227]188        if (C->type == CELL_STICK)
[196]189        {
190                int jj_p1_refno;  // save for later
191                // first end is connected to dad, or new
192                if (C->dadlink == NULL)
193                {
194                        // new part object for firstend
195                        // coordinates are left to be computed by Model
[726]196                        sprintf(tmpLine, "fr=%g,ing=%g,as=%g",
[671]197                                /*1.0/C->P.mass,*/ C->P.friction, C->P.ingestion, C->P.assimilation
[196]198                                //C->firstend.x, C->firstend.y, C->firstend.z
[1227]199                        );
[726]200                        partidx = addFromString(PartType, tmpLine, &range);
[196]201                        if (partidx < 0) return -1;
[760]202                        this->checkpoint();
[196]203                        jj_p1_refno = partidx;
204                }
205                else {
206                        // adjust mass/vol of first endpoint
207                        jj_p1_refno = C->dadlink->p2_refno;
[774]208                        Part *p1 = getPart(jj_p1_refno);
[196]209                        p1->mass += 1.0;
210                        //      p1->volume += 1.0/C->P.mass;
211                }
212                // new part object for lastend
[726]213                sprintf(tmpLine, "fr=%g,ing=%g,as=%g",
[196]214                        //C->lastend.x, C->lastend.y, C->lastend.z
[671]215                        /*"vol=" 1.0/C->P.mass,*/ C->P.friction, C->P.ingestion, C->P.assimilation
[1227]216                );
[726]217                partidx = addFromString(PartType, tmpLine, &range);
[196]218                if (partidx < 0) return -2;
219                C->p2_refno = partidx;
[193]220
[196]221                // new joint object
222                // check that the part references are valid
223                int jj_p2_refno = C->p2_refno;
224                if ((jj_p1_refno < 0) || (jj_p1_refno >= getPartCount())) return -11;
225                if ((jj_p2_refno < 0) || (jj_p2_refno >= getPartCount())) return -12;
[830]226                sprintf(tmpLine, "p1=%d,p2=%d,dx=%g,dy=0,dz=0,rx=%g,ry=0,rz=%g"\
[196]227                        ",stam=%g",
228                        jj_p1_refno, jj_p2_refno,
229                        // relative position -- always (len, 0, 0), along the stick
230                        // this is optional!
[671]231                        C->P.length,
[196]232                        // relative rotation
233                        C->xrot, C->zrot,
234                        //C->P.ruch,   // rotstif
[671]235                        C->P.stamina
[1227]236                );
[726]237                partidx = addFromString(JointType, tmpLine, &range);
[196]238                if (partidx < 0) return -13;
[760]239                this->checkpoint();
[196]240                C->joint_refno = partidx;
241        }
[193]242
[1227]243        if (C->type == CELL_NEURON)
[196]244        {
[774]245                const char* nclass = C->neuclass->name.c_str();
[760]246                int partno, jointno;
247                if (C->neuclass->getPreferredLocation() == 0)
248                {
249                        if (strcmp(nclass, "N") == 0)
250                        {
251                                partno = C->dadlink->p2_refno;
252                                if ((partno < 0) || (partno >= getPartCount())) return -21;
[830]253                                else sprintf(tmpLine, "p=%d,d=\"N:in=%g,fo=%g,si=%g\"", partno, C->inertia, C->force, C->sigmo);
[760]254                        }
255                        else
256                        {
257                                sprintf(tmpLine, "d=\"%s\"", nclass);
258                        }
259                        partidx = addFromString(NeuronType, tmpLine, &range);
260                        if (partidx < 0) return -22;
261                        this->checkpoint();
262                        C->neuro_refno = partidx;
263                }
264                else if (C->neuclass->getPreferredLocation() == 1) // attached to Part or have no required attachment - also part
265                {
266                        partno = C->dadlink->p2_refno;
267                        if ((partno < 0) || (partno >= getPartCount())) return -21;
[1227]268
[760]269                        if (strcmp(nclass, "N") == 0)
[831]270                                sprintf(tmpLine, "p=%d,d=\"N:in=%g,fo=%g,si=%g\"", partno, C->inertia, C->force, C->sigmo);
[760]271                        else
[830]272                                sprintf(tmpLine, "p=%d,d=\"%s\"", partno, nclass);
[1227]273
[760]274                        partidx = addFromString(NeuronType, tmpLine, &range);
275                        if (partidx < 0) return -22;
276                        this->checkpoint();
277                        C->neuro_refno = partidx;
278                }
[1212]279                else // attached to Joint, assume there are only three possibilities of getPreferredLocation()
[760]280                {
281                        jointno = C->dadlink->joint_refno;
[1227]282
283                        if (strcmp(nclass, "@") == 0)
284                                sprintf(tmpLine, "j=%d,d=\"@:p=%g\"", jointno, C->P.muscle_power);
285                        else if (strcmp(nclass, "|") == 0)
286                                sprintf(tmpLine, "j=%d,d=\"|:p=%g,r=%g\"", jointno, C->P.muscle_power, C->mz);
287                        else
288                                sprintf(tmpLine, "j=%d,d=\"%s\"", jointno, nclass);
289
[760]290                        partidx = addFromString(NeuronType, tmpLine, &range);
291                        if (partidx < 0) return -32;
292                        this->checkpoint();
293                }
[196]294                C->neuro_refno = partidx;
295                int n_refno = C->neuro_refno;
[193]296
[1227]297                for (j = 0; j < C->conns_count; j++)
[196]298                {
[1227]299                        if (C->conns[j]->from != NULL)
300                                buildModelRec(C->conns[j]->from);
[193]301
[196]302                        tmpLine[0] = 0;
[1227]303                        if (C->conns[j]->from == NULL)
[760]304                        {
[1227]305                                logMessage("f4_Model", "buildModelRec", LOG_ERROR, "Old code for sensors as inputs embedded in [connection]: C->conns[j]->from == NULL");
[760]306                        }
[196]307                        int from = -1;
[1227]308                        if (C->conns[j]->from != NULL) // input from another neuron
309                                from = C->conns[j]->from->neuro_refno;
[196]310                        if (from >= 0)
311                        {
[1227]312                                sprintf(tmpLine, "%d,%d,%g", n_refno, from, C->conns[j]->weight);
[726]313                                if (addFromString(NeuronConnectionType, tmpLine, &range) < 0) return -35;
[760]314                                this->checkpoint();
[196]315                        }
316                }
317        }
318        return 0;
[193]319}
320
321
322void f4_Model::toF1Geno(SString &out)
323{
[196]324        cells->toF1Geno(out);
[193]325}
Note: See TracBrowser for help on using the repository browser.