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

Last change on this file since 1227 was 1227, checked in by Maciej Komosinski, 12 months ago

Improvements in f4:

  • fixed a bug where newly created cells in a given development step were not counted as in-active-development (overlooked), and if they were the only in-active-development cells, the development of an organism would stop
  • added one extra development step (#ifdef EXTRA_STEP_CELL_DEVELOPMENT) so that cells that became not in-active-development ("halted" or yielding, usually due to waiting for neurons to develop in other cells) would get a chance to continue development (important when we don't want to ignore invalid neuron connections, #ifdef TREAT_BAD_CONNECTIONS_AS_INVALID_GENO)
  • ensured that all connections in a cell are processed (earlier they could be skipped if the development of the cell was "halted" and all cells became not in-active-development)
  • got rid of neuron connection syntax [sensor:weight], now all neuron classes are handled in a uniform way and their [connections] too; the only allowed syntax is [input_index:weight]
  • unified handling of all neuroclasses during parsing, conversion and mutation
  • more correct syntax coloring
  • got rid of general-purpose fields (i1, i2, f1, s1) in class f4_node - now separate fields serve their individual purpose
  • rewritten creating and modifying neuron connections - it is more deliberate to satisfy neuron input/output preferences
  • some invalid neuron connections make a genotype invalid (previously invalid neuron connections were ignored and the genotype was considered valid)
  • added (surprisingly missing) simple debug printout functions to see the f4_Node tree structure and the developing f4_Cells
  • more informative variable and constant names
  • improved performance
  • Property svn:eol-style set to native
File size: 7.7 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 support for new API for neuron types and their properties
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        int res;
30        f4_Model *model = new f4_Model();
31        res = model->buildFromF4(in, using_checkpoints);
32        if (GENOPER_OK != res)
33        {
34                delete model;
35                return SString();  // oops
36        }
37        if (NULL != map)
38                // generate to-f0 conversion map
39                model->getCurrentToF0Map(*map);
40        SString out = model->getF0Geno().getGenes();
41        delete model;
42        return out;
43}
44
45
46GenoConv_F41_TestOnly::GenoConv_F41_TestOnly()
47{
48        name = "Only for testing, approximate f4->f1 converter"; //Do not use in production! (adam)
49        in_format = '4';
50        out_format = '1';
51        mapsupport = 0;
52}
53
54
55SString GenoConv_F41_TestOnly::convert(SString &in, MultiMap *map, bool using_checkpoints)
56{
57        int res;
58        f4_Model *model = new f4_Model();
59        res = model->buildFromF4(in, using_checkpoints);
60        if (GENOPER_OK != res)
61        {
62                delete model;
63                return SString();  // oops
64        }
65        SString out;
66        model->toF1Geno(out);
67        delete model;
68        return out;
69}
70
71
72f4_Model::f4_Model() : Model()
73{
74        cells = NULL;
75}
76
77f4_Model::~f4_Model()
78{
79        if (cells) delete cells;
80}
81
82int f4_Model::buildFromF4(SString &geno, bool using_checkpoints)
83{
84        int i;
85
86        error = GENOPER_OK;
87        errorpos = -1;
88
89        // build cells, and simulate
90        if (cells) delete cells;
91        cells = new f4_Cells(geno, 0);
92        if (GENOPER_OK != cells->getErrorCode())
93        {
94                error = cells->getErrorCode();
95                errorpos = cells->getErrorPos();
96                //delete cells;
97                return error;
98        }
99
100        cells->simulate();
101        if (GENOPER_OK != cells->getErrorCode())
102        {
103                error = cells->getErrorCode();
104                errorpos = cells->getErrorPos();
105                return error;
106        }
107
108        // reset recursive traverse flags
109        for (i = 0; i < cells->cell_count; i++)
110                cells->C[i]->recProcessedFlag = 0;
111
112        open(using_checkpoints); // begin model build
113
114        // process every cell
115        int res;
116        for (i = 0; i < cells->cell_count; i++)
117        {
118                res = buildModelRec(cells->C[i]);
119                if (res)
120                {
121                        logMessage("f4_Model", "buildFromF4", LOG_ERROR, "Error in building a Model");
122                        error = res;
123                        break;
124                }
125        }
126
127        res = close();
128        if (0 == res) // invalid
129                error = -10;
130
131        return error;
132}
133
134
135f4_Cell* f4_Model::getStick(f4_Cell *C)
136{
137        if (C->type == CELL_STICK) return C;
138        if (NULL != C->dadlink)
139                return getStick(C->dadlink);
140        // we have no more dadlinks, find any stick
141        for (int i = 0; i < cells->cell_count; i++)
142                if (cells->C[i]->type == CELL_STICK)
143                        return cells->C[i];
144        // none!
145        logMessage("f4_Model", "getStick", LOG_ERROR, "Not a single stick");
146        return NULL;
147}
148
149
150int f4_Model::buildModelRec(f4_Cell *C)
151{
152        int partidx;
153        int j, res;
154        MultiRange range;
155
156        if (C->recProcessedFlag)
157                // already processed
158                return 0;
159
160        // mark it processed
161        C->recProcessedFlag = 1;
162
163        // make sure parent is a stick
164        if (NULL != C->dadlink)
165                if (C->dadlink->type != CELL_STICK)
166                {
167                        C->dadlink = getStick(C->dadlink);
168                }
169
170        // make sure its parent is processed first
171        if (NULL != C->dadlink)
172        {
173                res = buildModelRec(C->dadlink);
174                if (res) return res;
175        }
176
177        char tmpLine[100];
178
179        range = C->genoRange;
180        if (C->type == CELL_STICK)
181        {
182                int jj_p1_refno;  // save for later
183                // first end is connected to dad, or new
184                if (C->dadlink == NULL)
185                {
186                        // new part object for firstend
187                        // coordinates are left to be computed by Model
188                        sprintf(tmpLine, "fr=%g,ing=%g,as=%g",
189                                /*1.0/C->P.mass,*/ C->P.friction, C->P.ingestion, C->P.assimilation
190                                //C->firstend.x, C->firstend.y, C->firstend.z
191                        );
192                        partidx = addFromString(PartType, tmpLine, &range);
193                        if (partidx < 0) return -1;
194                        this->checkpoint();
195                        jj_p1_refno = partidx;
196                }
197                else {
198                        // adjust mass/vol of first endpoint
199                        jj_p1_refno = C->dadlink->p2_refno;
200                        Part *p1 = getPart(jj_p1_refno);
201                        p1->mass += 1.0;
202                        //      p1->volume += 1.0/C->P.mass;
203                }
204                // new part object for lastend
205                sprintf(tmpLine, "fr=%g,ing=%g,as=%g",
206                        //C->lastend.x, C->lastend.y, C->lastend.z
207                        /*"vol=" 1.0/C->P.mass,*/ C->P.friction, C->P.ingestion, C->P.assimilation
208                );
209                partidx = addFromString(PartType, tmpLine, &range);
210                if (partidx < 0) return -2;
211                C->p2_refno = partidx;
212
213                // new joint object
214                // check that the part references are valid
215                int jj_p2_refno = C->p2_refno;
216                if ((jj_p1_refno < 0) || (jj_p1_refno >= getPartCount())) return -11;
217                if ((jj_p2_refno < 0) || (jj_p2_refno >= getPartCount())) return -12;
218                sprintf(tmpLine, "p1=%d,p2=%d,dx=%g,dy=0,dz=0,rx=%g,ry=0,rz=%g"\
219                        ",stam=%g",
220                        jj_p1_refno, jj_p2_refno,
221                        // relative position -- always (len, 0, 0), along the stick
222                        // this is optional!
223                        C->P.length,
224                        // relative rotation
225                        C->xrot, C->zrot,
226                        //C->P.ruch,   // rotstif
227                        C->P.stamina
228                );
229                partidx = addFromString(JointType, tmpLine, &range);
230                if (partidx < 0) return -13;
231                this->checkpoint();
232                C->joint_refno = partidx;
233        }
234
235        if (C->type == CELL_NEURON)
236        {
237                const char* nclass = C->neuclass->name.c_str();
238                int partno, jointno;
239                if (C->neuclass->getPreferredLocation() == 0)
240                {
241                        if (strcmp(nclass, "N") == 0)
242                        {
243                                partno = C->dadlink->p2_refno;
244                                if ((partno < 0) || (partno >= getPartCount())) return -21;
245                                else sprintf(tmpLine, "p=%d,d=\"N:in=%g,fo=%g,si=%g\"", partno, C->inertia, C->force, C->sigmo);
246                        }
247                        else
248                        {
249                                sprintf(tmpLine, "d=\"%s\"", nclass);
250                        }
251                        partidx = addFromString(NeuronType, tmpLine, &range);
252                        if (partidx < 0) return -22;
253                        this->checkpoint();
254                        C->neuro_refno = partidx;
255                }
256                else if (C->neuclass->getPreferredLocation() == 1) // attached to Part or have no required attachment - also part
257                {
258                        partno = C->dadlink->p2_refno;
259                        if ((partno < 0) || (partno >= getPartCount())) return -21;
260
261                        if (strcmp(nclass, "N") == 0)
262                                sprintf(tmpLine, "p=%d,d=\"N:in=%g,fo=%g,si=%g\"", partno, C->inertia, C->force, C->sigmo);
263                        else
264                                sprintf(tmpLine, "p=%d,d=\"%s\"", partno, nclass);
265
266                        partidx = addFromString(NeuronType, tmpLine, &range);
267                        if (partidx < 0) return -22;
268                        this->checkpoint();
269                        C->neuro_refno = partidx;
270                }
271                else // attached to Joint, assume there are only three possibilities of getPreferredLocation()
272                {
273                        jointno = C->dadlink->joint_refno;
274
275                        if (strcmp(nclass, "@") == 0)
276                                sprintf(tmpLine, "j=%d,d=\"@:p=%g\"", jointno, C->P.muscle_power);
277                        else if (strcmp(nclass, "|") == 0)
278                                sprintf(tmpLine, "j=%d,d=\"|:p=%g,r=%g\"", jointno, C->P.muscle_power, C->mz);
279                        else
280                                sprintf(tmpLine, "j=%d,d=\"%s\"", jointno, nclass);
281
282                        partidx = addFromString(NeuronType, tmpLine, &range);
283                        if (partidx < 0) return -32;
284                        this->checkpoint();
285                }
286                C->neuro_refno = partidx;
287                int n_refno = C->neuro_refno;
288
289                for (j = 0; j < C->conns_count; j++)
290                {
291                        if (C->conns[j]->from != NULL)
292                                buildModelRec(C->conns[j]->from);
293
294                        tmpLine[0] = 0;
295                        if (C->conns[j]->from == NULL)
296                        {
297                                logMessage("f4_Model", "buildModelRec", LOG_ERROR, "Old code for sensors as inputs embedded in [connection]: C->conns[j]->from == NULL");
298                        }
299                        int from = -1;
300                        if (C->conns[j]->from != NULL) // input from another neuron
301                                from = C->conns[j]->from->neuro_refno;
302                        if (from >= 0)
303                        {
304                                sprintf(tmpLine, "%d,%d,%g", n_refno, from, C->conns[j]->weight);
305                                if (addFromString(NeuronConnectionType, tmpLine, &range) < 0) return -35;
306                                this->checkpoint();
307                        }
308                }
309        }
310        return 0;
311}
312
313
314void f4_Model::toF1Geno(SString &out)
315{
316        cells->toF1Geno(out);
317}
Note: See TracBrowser for help on using the repository browser.