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

Last change on this file since 1240 was 1240, checked in by Maciej Komosinski, 11 months ago

Updated f4->f1 approximate converter

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