source: cpp/frams/_demos/genomanipulation.cpp @ 1288

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

Make genomanipulation.cpp results consistent across platforms by using our random number generator instead of stdlib's

  • Property svn:eol-style set to native
File size: 13.9 KB
RevLine 
[286]1// This file is a part of Framsticks SDK.  http://www.framsticks.com/
[972]2// Copyright (C) 1999-2020  Maciej Komosinski and Szymon Ulatowski.
[286]3// See LICENSE.txt for details.
[109]4
5#include <stdlib.h>
6#include <stdio.h>
7#include <time.h>
[382]8#include <common/virtfile/stdiofile.h>
[109]9
10#include <frams/model/model.h>
[145]11#include <frams/genetics/preconfigured.h>
[391]12#include <common/loggers/loggertostdout.h>
[109]13
14/**
15 @file
16 Sample code: Accessing model elements
[742]17 */
[109]18
19void printNiceBanner(const char* title)
20{
[742]21        printf("    #############################################\n"
22                "   ##                                           ##\n"
23                "  ##    %-37s    ##\n"
24                "   ##                                           ##\n"
25                "    #############################################\n", title);
[109]26}
27void printProperties(Param &pi)
28{
[742]29        printf(" #        id                      type  name        group (%d properties)\n", pi.getPropCount());
30        for (int i = 0; i < pi.getPropCount(); i++)
[109]31        {
[742]32                const char* type = pi.type(i);
33                if (*type == 'p') continue;
34                printf("%2d. %8s = %-20s %-3s %-10s  %-10s\n", i, pi.id(i), pi.get(i).c_str(), pi.type(i), pi.name(i), pi.grname(pi.group(i)));
[109]35        }
36}
37
38#define PRINT_PROPERTIES(p) {Param tmp_param(p); printProperties(tmp_param);}
39
40void changeOneProperty(Param &pi)
41{
[742]42        if (pi.getPropCount() <= 0) return;
[1018]43        int i = rndUint(pi.getPropCount());
[742]44        double maxprop = 1, minprop = 0, def;
45        pi.getMinMaxDouble(i, minprop, maxprop, def);
46        printf("      Change property #%d to random value from range [%g..%g]\n", i, minprop, maxprop);
47        printf("      Current value of '%s' (%s) is '%s'\n", pi.id(i), pi.name(i), pi.get(i).c_str());
48        char t[100];
[896]49        sprintf(t, "%g", minprop + rndDouble(maxprop - minprop));
[742]50        printf("      Setting new value... [ using ParamInterface::set() ]\n");
51        pi.setFromString(i, t);
52        printf("      The value is now '%s'\n", pi.get(i).c_str());
[109]53}
54
55#define CHANGE_ONE_PROPERTY(p) {Param tmp_param(p); changeOneProperty(tmp_param);}
56
57void moreAboutPart(Part* p)
58{
[742]59        printf("Here is the full listing of properties as they are printed in f0\n"
60                " (please compare with f0 genotype).\n"
61                "Some properties have special meaning (eg. geometry and connections groups)\n"
62                "and should be handled with care, because they influence other elements of the model.\n\n"
63                " [this data is provided by Part::properties() ]\n");
64        PRINT_PROPERTIES(p->properties());
65        printf("\nHowever, there is a subset of properties which may be modified more freely.\n"
66                "Properties on this list are related only to this part and can be changed\n"
67                "without much consideration. They are guaranteed to be always valid; any inconsistencies\n"
68                "will be silently repaired.\n"
69                "\n [this data is provided by Part::extraProperties() ]\n");
70        PRINT_PROPERTIES(p->extraProperties());
71        printf("\nThis set of properties can vary from release to release,\n"
72                "but can be safely accessed by using extraProperties() call.\n"
73                "This method accesses the full set of properies (even those\n"
74                "which appear in future releases).\n"
75                "Now we will try to change some of properties:\n\n");
76        p->getModel().open();
77        CHANGE_ONE_PROPERTY(p->extraProperties());
78        p->getModel().close();
79        printf("\nLet's see f0... (check out part #%d !)\n\n%s\n", p->refno, p->getModel().getF0Geno().getGenes().c_str());
[109]80}
81
82void playWithAbsolute(Joint *j)
83{
[742]84        printf("\nAbsolute Joints adapt to its Parts' positions.\n"
85                "We can move a Part, and it does not influence the second part, nor the Joint.\n"
86                "Let's move the first Part along y axis by -0.1...\n");
87        j->getModel().open();
88        j->part1->p.y -= 0.1;
89        j->getModel().close();
90        printf("The Part's position is changed, but everything else stays intact:\n\n%s\n",
91                j->getModel().getF0Geno().getGenes().c_str());
[109]92}
93
94void playWithDelta(Joint *j)
95{
[742]96        printf("\nDelta fields (dx,dy,dz) describe relative location of the second part.\n"
97                "This joint will change the second Part's positions to preserve delta distance.\n"
98                "Let's move the first Part (#%d) along y axis (+0.1) and change delta.z (dz) by 0.1.\n", j->part1->refno);
99        j->getModel().open();
100        j->part1->p.y += 0.1;
101        j->d.z += 0.1;
102        j->getModel().close();
103        printf("Position of the second Part referenced by this joint (part #%d) is now changed:\n\n%s\n",
104                j->part2->refno, j->getModel().getF0Geno().getGenes().c_str());
105        printf("If no delta fields are defined, they will be computed automatically.\n"
106                "You can always delete existing delta values by using Joint::resetDelta().\n"
107                "Now we will change the second Part's z position by -0.2 and call resetDelta()...\n");
108        j->getModel().open();
109        j->part2->p.z -= 0.2;
110        j->resetDelta();
111        j->getModel().close();
112        printf("As you can see, Joint's delta fields have altered:\n\n%s\n", j->getModel().getF0Geno().getGenes().c_str());
[109]113}
114
115void switchDelta(Joint *j)
116{
[742]117        int option = !j->isDelta();
118        printf("How would this joint look like with delta option %s?\n[ by calling Joint::useDelta(%d) ]\n", option ? "enabled" : "disabled", option);
119        j->getModel().open();
120        j->useDelta(!j->isDelta());
121        j->getModel().close();
122        printf("f0 is now:\n\n%s\n...so this is %s joint.\n",
123                j->getModel().getF0Geno().getGenes().c_str(), option ? "a delta" : "an absolute");
[109]124
125}
126
127void moreAboutJoint(Joint* j)
128{
[742]129        printf("Similarly as with Part, the full list of properties comes first:\n\n");
130        PRINT_PROPERTIES(j->properties());
131        printf("\nActually, there are two kinds of Joints: delta and absolute.\n"
132                "For this object, Joint::isDelta() returns %d, so this is the %s Joint.\n",
133                j->isDelta(), j->isDelta() ? "delta" : "absolute");
134        if (j->isDelta())
[109]135        {
[742]136                playWithDelta(j);
137                switchDelta(j);
138                playWithAbsolute(j);
[109]139        }
[742]140        else
[109]141        {
[742]142                playWithAbsolute(j);
143                switchDelta(j);
144                playWithDelta(j);
[109]145        }
146
[742]147        printf("Part references and delta fields are the 'core' properties of the Joint.\n"
148                "The other properties are available from Joint::extraProperties()\n"
149                "and at the moment are defined as follows:\n\n");
150        PRINT_PROPERTIES(j->extraProperties());
151        printf("\nThey can be changed just like Part's extra properties:\n");
152        j->getModel().open();
153        CHANGE_ONE_PROPERTY(j->extraProperties());
154        j->getModel().close();
155        printf("And after that we have this genotype:\n\n%s\n", j->getModel().getF0Geno().getGenes().c_str());
[109]156}
157
158
159
160void moreAboutNeuro(Neuro* n)
161{
[742]162        printf("Basic features of Neuro object are similar to those of Part and Joint.\n"
163                "We can request a property list:\n\n");
164        PRINT_PROPERTIES(n->properties());
165        printf("\n...and extra properties (which are designed to be always valid and easy to change):\n\n");
166        PRINT_PROPERTIES(n->extraProperties());
167        printf("\nAs usual, we will change something:\n");
168        n->getModel().open();
169        CHANGE_ONE_PROPERTY(n->extraProperties());
170        n->getModel().close();
171        printf("Each neuron can have any number of inputs = weighted connections\n with other neurons.\n"
172                "According to Neuro::getInputCount(), this one has %d inputs.\n", n->getInputCount());
173        printf("Standard API is provided for accessing those inputs (getInput(int)),\n"
174                "adding inputs (addInput(Neuro*)) and removing them (removeInput(int)).\n\n");
[109]175
[742]176        printf("\nThe most unusual thing is 'details' field (d).\n"
177                "It is something like separate object with its own set of properties.\n"
178                "Currently the value of 'd' is '%s'.\n", n->getDetails().c_str());
[109]179
[742]180        {
181                NeuroClass* cl = n->getClass();
182                if (!cl)
183                        printf("It should contain the class name but the meaning of '%s' is unknown\n", n->getDetails().c_str());
184                else
185                {
[109]186
[742]187                        printf("'%s' is the class name (Neuro::getClassName() == '%s') and means '%s'.\n",
188                                cl->getName().c_str(), cl->getName().c_str(), cl->getLongName().c_str());
189                        printf("Neuro::getClass() gives you information about basic characteristic\n"
190                                "of the class, that can be analyzed automatically.\n");
191                        printf("For the current object we can learn that it supports ");
192                        if (cl->getPreferredInputs() < 0) printf("any number of inputs");
193                        else if (cl->getPreferredInputs() == 0) printf("no inputs");
194                        else printf("%d inputs", cl->getPreferredInputs());
195                        printf(" (getPreferredInputs()) ");
196                        printf(cl->getPreferredOutput() ? "and provides meaningful output signal (getPreferredOutput()==1).\n" : "and doesn't provide useful output signal (getPreferredOutput()==0).\n");
[977]197                        printf("Instances of '%s' can be used in models having ", cl->getName().c_str());
[999]198                        if (cl->getSupportedShapeTypes() == NeuroClass::SUPPORTED_SHAPETYPE_ALL)
[977]199                                printf("any shape types.\n");
200                        else
[990]201                        {
[977]202                                printf("shape types:");
[999]203                                for (int i = Model::SHAPETYPE_FIRST; i <= Model::SHAPETYPE_LAST; i++)
[977]204                                        if (cl->isShapeTypeSupported((Model::ShapeType)i))
[990]205                                                printf(" '%s'", Model::getShapeTypeName((Model::ShapeType)i));
[977]206                                printf(".\n");
[990]207                        }
[977]208                        if (cl->preflocation == NeuroClass::PREFER_JOINT)
[990]209                        {
[977]210                                printf("Instances of '%s' can be attached to Joints having ", cl->getName().c_str());
[999]211                                if (cl->getSupportedJointShapes() == NeuroClass::SUPPORTED_JOINTSHAPE_ALL)
[977]212                                        printf("any shapes");
213                                else
[990]214                                {
[977]215                                        printf("shapes:");
[990]216                                        for (int i = Joint::SHAPE_FIRST; i <= Joint::SHAPE_LAST; i++)
[977]217                                                if (cl->isJointShapeSupported((Joint::Shape)i))
[990]218                                                        printf(" '%s'", Joint::getShapeName((Joint::Shape)i));
219                                }
[977]220                                printf(".\n");
[990]221                        }
[977]222                        else if (cl->preflocation == NeuroClass::PREFER_PART)
223                                printf("Instances of '%s' can be attached to Parts.\n", cl->getName().c_str());
[109]224
[742]225                        SyntParam p = n->classProperties();
226                        if (p.getPropCount() > 0)
227                        {
228                                printf("The class defines its own properties:\n\n [ data provided by Neuro::classProperties() ]\n");
229                                printProperties(p);
230                                printf("and they can be changed:\n");
231                                n->getModel().open();
232                                changeOneProperty(p);
233                                p.update();
234                                n->getModel().close();
235                                printf("After that, 'details' contains the new object: '%s'.\n", n->getDetails().c_str());
236                        }
237                        else
238                                printf("(This class does not have its own properties\n"
[972]239                                        " - Neuro::classProperties().getPropCount()==0)\n");
[742]240                }
[109]241        }
242
[742]243        printf("The class of this object can be changed using Neuro::setClassName()\n"
244                "The following classes are available:\n"
245                " [ data provided by Neuro::getClassInfo()->getProperties() ]\n\n");
246        printf(" #  class  description       properties\n");
247        for (int i = 0; i < n->getClassCount(); i++)
[109]248        {
[742]249                NeuroClass* cl = n->getClass(i);
250                Param p = cl->getProperties();
251                printf("%2d.%6s  %-20s  %2d\n", i, cl->getName().c_str(), cl->getLongName().c_str(), p.getPropCount());
[109]252        }
[1018]253        int cl = rndUint(n->getClassCount());
[742]254        printf("\nLet's change the Neuro's class to '%s'...\n", n->getClassName(cl).c_str());
255        n->getModel().open();
256        n->setClass(n->getClass(cl));
[109]257        {
[742]258                SyntParam p = n->classProperties();
[972]259                if (p.getPropCount() > 0)
[742]260                {
261                        printProperties(p);
262                        changeOneProperty(p);
263                        p.update();
264                }
[109]265        }
266
[742]267        if (n->getInputCount() > 0)
268        {
269                printf("Info for input #0 = \"%s\"\n", n->getInputInfo(0).c_str());
270                printf("Info for input #0, field \"%s\" = \"%s\"\n", "abc", n->getInputInfo(0, "abc").c_str());
271                n->setInputInfo(0, "test", 44);
272                n->setInputInfo(0, "abc", "yeah");
273        }
[109]274
[742]275        n->getModel().close();
276        printf("The final object description will be then: '%s'\nAnd the full f0 genotype:\n\n%s\n",
277                n->getDetails().c_str(), n->getModel().getF0Geno().getGenes().c_str());
[109]278
279
280}
281
282void findingConverters()
283{
[742]284        GenoConverter *gc = Geno::getConverters()->findConverters(0, '1');
[990]285        if (gc) printf("Found converter accepting f1: \"%s\"\n", gc->name);
[742]286        SListTempl<GenoConverter*> found;
[989]287        Geno::getConverters()->findConverters(&found, Geno::FORMAT_UNKNOWN, '0');
[990]288        printf("Found %d converter(s) producing f0\n", found.size());
[109]289}
290
[742]291int main(int argc, char*argv[])
[109]292{
[742]293        LoggerToStdout messages_to_stdout(LoggerBase::Enable); //redirect model-related errors to stdout
294        PreconfiguredGenetics genetics;
[291]295
[1018]296        //rndRandomizeSeed(); //uncomment to see the demonstration of different behaviors and results on each run
[990]297        printNiceBanner("Welcome to Genotype Manipulation Demo!");
[109]298
[742]299        findingConverters();
[109]300
[742]301        SString gen(argc > 1 ? argv[1] : "X[|G:1.23]");
302        if (!strcmp(gen.c_str(), "-"))
[109]303        {
[742]304                gen = 0;
305                StdioFILEDontClose in(stdin);
306                loadSString(&in, gen);
[109]307        }
[742]308        Geno g(gen);
309        printf("\nSource genotype: '%s'\n", g.getGenes().c_str());
[955]310        printf("                  ( format %s %s)\n",
311                g.getFormat().c_str(), g.getComment().c_str());
[109]312
[999]313        Model m(g, Model::SHAPETYPE_UNKNOWN);//.getConverted('0'));
[109]314
[742]315        if (!m.isValid())
[109]316        {
[742]317                printf("Cannot build Model from this genotype!\n");
318                return 2;
[109]319        }
[742]320        printf("Converted to f0:\n%s\n", m.getF0Geno().getGenes().c_str());
[109]321
[742]322        printf("Model contains: %d part(s)\n"
323                "                %d joint(s)\n"
324                "                %d neuron(s)\n", m.getPartCount(), m.getJointCount(), m.getNeuroCount());
[109]325
[742]326        printf("\nInvestigating details...\n");
[109]327
[742]328        if (m.getPartCount() > 0)
[109]329        {
[1018]330                int p = rndUint(m.getPartCount());
[742]331                printNiceBanner("P A R T    O B J E C T");
332                printf("            (part # %d)\n", p);
333                moreAboutPart(m.getPart(p));
[109]334        }
335
[742]336        if (m.getJointCount() > 0)
[109]337        {
[1018]338                int j = rndUint(m.getJointCount());
[742]339                printNiceBanner("J O I N T    O B J E C T");
340                printf("            (joint # %d)\n", j);
341                moreAboutJoint(m.getJoint(j));
[109]342        }
343
[742]344        if (m.getNeuroCount() > 0)
[109]345        {
[1018]346                int n = rndUint(m.getNeuroCount());
[742]347                printNiceBanner("N E U R O    O B J E C T");
348                printf("            (neuro # %d)\n", n);
349                moreAboutNeuro(m.getNeuro(n));
[109]350        }
351
352#ifdef MODEL_V1_COMPATIBLE
[742]353        printNiceBanner("Old Neuro/NeuroItem view");
354        int nc = m.old_getNeuroCount();
355        printf("Model::old_getNeuroCount() = %d\n", nc);
356        for (int i = 0; i < nc; i++)
[109]357        {
[742]358                Neuro *n = m.old_getNeuro(i);
359                printf("neuron #%d: p=%d, j=%d, force=%g, inertia=%g, sigmoid=%g\n",
360                        i, n->part_refno, n->joint_refno,
361                        n->force, n->inertia, n->sigmo);
362                int nicount = n->getItemCount();
363                printf("    %d items\n", nicount);
364                for (int j = 0; j < nicount; j++)
[109]365                {
[742]366                        NeuroItem *ni = n->getNeuroItem(j);
367                        printf("        item #%d - '%s', conn=%d, weight=%g\n",
368                                j, ni->getDetails().c_str(), ni->conn_refno, ni->weight);
[109]369                }
370        }
[742]371        printf("end.\n");
[109]372#endif
373
[742]374        printf("\n######### THE END ###########\n\n"
375                "Hints:\n"
376                "  1. You can redirect output: genomanipulation >filename.txt\n"
[990]377                "  2. Each run can yield different results and new behaviors, but you\n"
[1018]378                "     need to uncomment rndRandomizeSeed() in genomanipulation.cpp.\n"
[742]379                "  3. This application will use custom genotype passed as\n"
[1009]380                "     a commandline parameter: genomanipulation \"/*9*/FULU\"\n"
[742]381                "\n");
382        return 0;
[109]383}
Note: See TracBrowser for help on using the repository browser.