source: cpp/gdk/model.cpp @ 66

Last change on this file since 66 was 66, checked in by Maciej Komosinski, 13 years ago

set 'eol-style' to 'native'

  • Property svn:eol-style set to native
File size: 26.7 KB
Line 
1// This file is a part of the Framsticks GDK library.
2// Copyright (C) 2002-2011  Szymon Ulatowski.  See LICENSE.txt for details.
3// Refer to http://www.framsticks.com/ for further information.
4
5#include "nonstd.h"
6#include "model.h"
7#include "framsg.h"
8#include "multimap.h"
9#include "errmanager.h"
10
11#include <math.h>
12
13#define FIELDSTRUCT Model
14ParamEntry f0_model_paramtab[]=
15{
16{"Model",1,2,"m",},
17{"se",2,0,"startenergy","f",FIELD(startenergy),},
18{"Vstyle",2,0,"vis_style","s",FIELD(vis_style),},
19{0,0,0,},
20};
21#undef FIELDSTRUCT
22
23Model::Model()
24{
25autobuildmaps=0;
26init();
27}
28
29void Model::init()
30{
31partmappingchanged=0;
32buildstatus=empty;
33modelfromgenotype=0;
34startenergy=1.0;
35checklevel=1;
36#ifdef MODEL_V1_COMPATIBLE
37oldneurocount=-1; // == unknown
38oldconnections=0;
39#endif
40map=0;
41f0map=0;
42f0genoknown=1;
43}
44
45void Model::moveElementsFrom(Model &source)
46{
47int i;
48open();
49for (i=0;i<source.getPartCount();i++)
50        addPart(source.getPart(i));
51for (i=0;i<source.getJointCount();i++)
52        addJoint(source.getJoint(i));
53for (i=0;i<source.getNeuroCount();i++)
54        addNeuro(source.getNeuro(i));
55source.parts.clear(); source.joints.clear(); source.neurons.clear();
56source.clear();
57}
58
59void Model::internalCopy(const Model &mod)
60{
61geno=mod.geno;
62f0genoknown=0;
63startenergy=mod.startenergy;
64if (mod.getStatus()==valid)
65        {
66        modelfromgenotype=mod.modelfromgenotype;
67        {for (int i=0;i<mod.getPartCount();i++)
68                addPart(new Part(*mod.getPart(i)));}
69        {for (int i=0;i<mod.getJointCount();i++)
70                {
71                Joint *oldj=mod.getJoint(i);
72                Joint *j=new Joint(*oldj);
73                addJoint(j);
74                j->attachToParts(oldj->part1->refno,oldj->part2->refno);
75                }}
76        {for (int i=0;i<mod.getNeuroCount();i++)
77                {
78                Neuro *oldn=mod.getNeuro(i);
79                Neuro *n=new Neuro(*oldn);
80                addNeuro(n);
81                if (oldn->part_refno>=0) n->attachToPart(oldn->part_refno);
82                else n->attachToJoint(oldn->joint_refno);
83                }}
84        for (int i=0;i<mod.getNeuroCount();i++)
85                {
86                Neuro *oldn=mod.getNeuro(i);
87                Neuro *n=getNeuro(i);
88                for (int ni=0;ni < oldn->getInputCount();ni++)
89                        {
90                        float w;
91                        Neuro *oldinput=oldn->getInput(ni,w);
92                        SString info=n->getInputInfo(ni);
93                        n->addInput(getNeuro(oldinput->refno),w,&info);
94                        }
95                }
96        }
97}
98
99
100Model::Model(const Geno &src,int buildmaps)
101        :autobuildmaps(buildmaps)
102{init(src);}
103
104void Model::operator=(const Model &mod)
105{
106clear();
107open();
108internalCopy(mod);
109buildstatus=mod.buildstatus;
110}
111
112Model::Model(const Model &mod,int buildmaps)
113        :autobuildmaps(buildmaps)
114{
115init();
116open();
117internalCopy(mod);
118buildstatus=mod.buildstatus;
119}
120
121void Model::init(const Geno &src)
122{
123init();
124modelfromgenotype=1;
125geno=src;
126build();
127}
128
129void Model::resetAllDelta()
130{
131for (int i=0;i<getJointCount();i++)
132        getJoint(i)->resetDelta();
133}
134
135void Model::useAllDelta(bool yesno)
136{
137for (int i=0;i<getJointCount();i++)
138        getJoint(i)->useDelta(yesno);
139}
140
141Model::~Model()
142{
143delmodel_list.action((long)this);
144clear();
145}
146
147void Model::clear()
148{
149Part *p;
150for (parts.start();p=(Part*)parts();) delete p;
151Joint* j;
152for (joints.start();j=(Joint*)joints();) delete j;
153Neuro *n;
154for (neurons.start();n=(Neuro*)neurons();) delete n;
155parts.clear(); joints.clear(); neurons.clear();
156delMap();
157delF0Map();
158init();
159geno=Geno();
160f0geno=Geno();
161}
162
163Part *Model::addPart(Part *p)
164{
165p->owner=this;
166p->refno=parts.size();
167parts+=p;
168return p;
169}
170
171Joint *Model::addJoint(Joint *j)
172{
173j->owner=this;
174j->refno=joints.size();
175joints+=j;
176return j;
177}
178
179Neuro *Model::addNeuro(Neuro *n)
180{
181n->owner=this;
182n->refno=neurons.size();
183neurons+=n;
184return n;
185}
186
187void Model::removeNeuros(SList &nlist)
188{
189FOREACH(Neuro*,nu,nlist)
190        {
191        int i=findNeuro(nu);
192        if (i>=0) removeNeuro(i);
193        }
194}
195
196void Model::removePart(int partindex,int removeattachedjoints,int removeattachedneurons)
197{
198Part *p=getPart(partindex);
199if (removeattachedjoints)
200        {
201        SList jlist;
202        findJoints(jlist,p);
203        FOREACH(Joint*,j,jlist)
204                {
205                int i=findJoint(j);
206                if (i>=0) removeJoint(i,removeattachedneurons);
207                }
208        }
209if (removeattachedneurons)
210        {
211        SList nlist;
212        findNeuros(nlist,0,p);
213        removeNeuros(nlist);
214        }
215parts-=partindex;
216delete p;
217}
218
219void Model::removeJoint(int jointindex,int removeattachedneurons)
220{
221Joint *j=getJoint(jointindex);
222if (removeattachedneurons)
223        {
224        SList nlist;
225        findNeuros(nlist,0,0,j);
226        removeNeuros(nlist);
227        }
228joints-=jointindex;
229delete j;
230}
231
232void Model::removeNeuro(int neuroindex,bool removereferences)
233{
234Neuro* thisN=getNeuro(neuroindex);
235
236if (removereferences)
237        {
238        Neuro* n;
239// remove all references to thisN
240        for (int i=0;n=(Neuro*)neurons(i);i++)
241                {
242                Neuro *inp;
243                for (int j=0;inp=n->getInput(j);j++)
244                        if (inp==thisN)
245                                {
246                                n->removeInput(j);
247                                j--;
248                                }
249                }
250        }
251
252neurons-=neuroindex;
253delete thisN;
254}
255
256MultiMap& Model::getMap()
257{
258if (!map) map=new MultiMap();
259return *map;
260}
261
262void Model::delMap()
263{
264if (map) {delete map; map=0;}
265}
266void Model::delF0Map()
267{
268if (f0map) {delete f0map; f0map=0;}
269}
270
271void Model::makeGenToGenMap(MultiMap& result,const MultiMap& gen1tomodel,const MultiMap& gen2tomodel)
272{
273result.clear();
274MultiMap m;
275m.addReversed(gen2tomodel);
276result.addCombined(gen1tomodel,m);
277}
278
279void Model::getCurrentToF0Map(MultiMap& result)
280{
281result.clear();
282if (!map) return;
283const MultiMap& f0m=getF0Map();
284makeGenToGenMap(result,*map,f0m);
285}
286
287void Model::rebuild(int buildm)
288{
289autobuildmaps=buildm;
290clear();
291build();
292}
293
294void Model::initMap()
295{
296if (!map) map=new MultiMap();
297else map->clear();
298}
299
300void Model::initF0Map()
301{
302if (!f0map) f0map=new MultiMap();
303else f0map->clear();
304}
305
306void Model::build()
307{
308f0errorposition=-1;
309f0warnposition=-1;
310MultiMap *convmap=autobuildmaps?new MultiMap():0;
311f0geno=(geno.getFormat()=='0')? geno : geno.getConverted('0',convmap);
312f0genoknown=1;
313if (f0geno.isInvalid())
314        {
315        buildstatus=invalid;
316        if (convmap) delete convmap;
317        return;
318        }
319SString f0txt=f0geno.getGene();
320buildstatus=building; // was: open();
321if (autobuildmaps)
322        {
323        partmappingchanged=0;
324        initMap();
325        initF0Map();
326        }
327int pos=0,lnum=1,lastpos=0;
328SString line;
329MultiRange frommap;
330ErrorHandler err(ErrorHandler::DontBlock);
331for (;f0txt.getNextToken(pos,line,'\n');lnum++)
332        {
333        if (autobuildmaps)
334                {
335                frommap.clear();
336                frommap.add(lastpos,pos-1);
337                }
338        err.reset();
339        if (singleStepBuild(line,autobuildmaps?(&frommap):0)==-1)
340                {
341                buildstatus=invalid;
342                FMprintf("Model","build",FMLV_ERROR,
343                         geno.getName().len()?"illegal f0 code at line %d (%s)":"illegal f0 code at line %d",
344                         lnum,(const char*)geno.getName());
345                f0errorposition=lastpos;
346                if (convmap) delete convmap;
347                return;
348                }
349        if (err.getWarningCount())
350                {if (f0warnposition<0) f0warnposition=lastpos;}
351        lastpos=pos;
352        }
353err.disable();
354close();
355if (convmap)
356        {
357        *f0map=*map;
358        if (geno.getFormat()!='0')
359                {
360                MultiMap tmp;
361                tmp.addCombined(*convmap,getMap());
362                *map=tmp;
363                }
364        delete convmap;
365        }
366}
367
368const MultiMap& Model::getF0Map()
369{
370if (!f0map)
371        {
372        f0map=new MultiMap();
373        makeGeno(f0geno,f0map);
374        f0genoknown=1;
375        }
376return *f0map;
377}
378
379Geno Model::rawGeno()
380{
381Geno tmpgen;
382makeGeno(tmpgen);
383return tmpgen;
384}
385
386void Model::makeGeno(Geno &g,MultiMap *map)
387{
388if ((buildstatus!=valid)&&(buildstatus!=building))
389        {
390        g=Geno(0,0,0,"invalid model");
391        return;
392        }
393
394SString gen;
395
396static Param modelparam(f0_model_paramtab);
397static Param partparam(f0_part_paramtab);
398static Param jointparam(f0_joint_paramtab);
399static Param neuroparam(f0_neuro_paramtab);
400static Param connparam(f0_neuroconn_paramtab);
401
402static Part defaultpart;
403static Joint defaultjoint;
404static Neuro defaultneuro;
405static Model defaultmodel;
406static NeuroConn defaultconn;
407//static NeuroItem defaultneuroitem;
408
409Part *p;
410Joint *j;
411Neuro *n;
412int i;
413int len;
414int a,b;
415//NeuroItem *ni;
416
417if (startenergy!=defaultmodel.startenergy)
418        {
419        modelparam.select(this);
420        gen+="m:";
421        modelparam.save2(gen,&defaultmodel);
422        }
423
424for (i=0;p=(Part*)parts(i);i++)
425        {
426        partparam.select(p);
427        len=gen.len();
428        gen+="p:";
429        partparam.save2(gen,&defaultpart);
430        if (map)
431                map->add(len,gen.len()-1,partToMap(i));
432        }
433for (i=0;j=(Joint*)joints(i);i++)
434        {
435        jointparam.select(j);
436        len=gen.len();
437        jointparam.setParamTab(j->usedelta?f0_joint_paramtab:f0_nodeltajoint_paramtab);
438        gen+="j:";
439        jointparam.save2(gen,&defaultjoint);
440        if (map)
441                map->add(len,gen.len()-1,jointToMap(i));
442        }
443for (i=0;n=(Neuro*)neurons(i);i++)
444        {
445        neuroparam.select(n);
446        len=gen.len();
447        gen+="n:";
448        neuroparam.save2(gen,&defaultneuro);
449        if (map)
450                map->add(len,gen.len()-1,neuroToMap(i));
451        }
452for (a=0;a<neurons.size();a++)
453        { // inputs
454        n=(Neuro*)neurons(a);
455//      if ((n->getInputCount()==1)&&(n->getInput(0).refno <= n->refno))
456//              continue; // already done with Neuro::conn_refno
457
458        for (b=0;b<n->getInputCount();b++)
459                {
460                float w;
461                NeuroConn nc;
462                Neuro* n2=n->getInput(b,w);
463//              if (((n2.parentcount==1)&&(n2.parent)&&(n2.parent->refno < n2.refno)) ^
464//                  (n2.neuro_refno>=0))
465//                      printf("!!!! bad Neuro::neuro_refno ?!\n");
466
467//              if ((n2.parentcount==1)&&(n2.parent)&&(n2.parent->refno < n2.refno))
468//              if (n2.neuro_refno>=0)
469//                      continue; // already done with Neuro::neuro_refno
470
471                nc.n1_refno=n->refno; nc.n2_refno=n2->refno;
472                nc.weight=w;
473                SString **s=n->inputInfo(b);
474                if ((s)&&(*s))
475                nc.info=**s;
476                connparam.select(&nc);
477                len=gen.len();
478                gen+="c:";
479                connparam.save2(gen,&defaultconn);
480                if (map)
481                        map->add(len,gen.len()-1,neuroToMap(n->refno));
482                }
483        }
484g=Geno(gen,'0');
485}
486
487//////////////
488
489void Model::open()
490{
491if (buildstatus==building) return;
492buildstatus=building;
493modelfromgenotype=0;
494partmappingchanged=0;
495f0genoknown=0;
496delMap();
497}
498
499void Model::checkpoint()
500{}
501
502void Model::setGeno(const Geno& newgeno)
503{
504geno=newgeno;
505}
506
507void Model::clearMap()
508{
509Part *p; Joint *j; Neuro *n;
510int i;
511delMap();
512delF0Map();
513for (i=0;p=(Part*)parts(i);i++)
514        p->clearMapping();
515for (i=0;j=(Joint*)joints(i);i++)
516        j->clearMapping();
517for (i=0;n=(Neuro*)neurons(i);i++)
518        n->clearMapping();
519}
520
521int Model::close()
522{
523if (buildstatus!=building)
524        FMprintf("Model","close",FMLV_WARN,"unexpected close() - no open()");
525if (internalcheck(1)>0)
526        {
527        buildstatus=valid;
528
529        if (partmappingchanged)
530                {
531                getMap();
532                Part *p; Joint *j; Neuro *n;
533                int i;
534                for (i=0;p=(Part*)parts(i);i++)
535                        if (p->getMapping())
536                                map->add(*p->getMapping(),partToMap(i));
537                for (i=0;j=(Joint*)joints(i);i++)
538                        if (j->getMapping())
539                                map->add(*j->getMapping(),jointToMap(i));
540                for (i=0;n=(Neuro*)neurons(i);i++)
541                        if (n->getMapping())
542                                map->add(*n->getMapping(),neuroToMap(i));
543                }
544        }
545else
546        buildstatus=invalid;
547
548return (buildstatus==valid);
549}
550
551int Model::validate()
552{
553return internalcheck(0);
554}
555
556Pt3D Model::whereDelta(const Part& start,const Pt3D& rot, const Pt3D& delta)
557{
558Orient roto;
559roto=rot;
560Orient o;
561roto.transform(o,start.o);
562//o.x=start.o/roto.x;
563//o.y=start.o/roto.y;
564//o.z=start.o/roto.z;
565return o.transform(delta)+start.p;
566}
567
568int Model::singleStepBuild(const SString &line,const MultiRange* srcrange)
569{
570int pos=0; const char*t=(const char*)line;
571for (;*t;t++,pos++)
572        if (!strchr(" \r\t",*t)) break;
573if (*t=='#') return 0;
574if (!*t) return 0;
575if (!strncmp(t,"p:",2))
576        {
577        static Param partparam(f0_part_paramtab);
578        Part *p=new Part();
579        partparam.select(p);
580        pos+=2;
581        partparam.load2(line,pos);
582        p->o.rotate(p->rot);
583        parts+=p;
584        p->owner=this;
585        if (srcrange) p->setMapping(*srcrange);
586        return getPartCount()-1;
587        }
588if (!strncmp(t,"m:",2))
589        {
590        static Param modelparam(f0_model_paramtab);
591        modelparam.select(this);
592        pos+=2;
593        modelparam.load2(line,pos);
594        return 0;
595        }
596else if (!strncmp(t,"j:",2))
597        {
598        static Param jointparam(f0_joint_paramtab);
599        Joint *j=new Joint();
600        jointparam.select(j);
601        pos+=2;
602        j->owner=this;
603        jointparam.load2(line,pos);
604        if ((j->p1_refno>=0)&&(j->p1_refno<getPartCount())&&
605           (j->p2_refno>=0)&&(j->p2_refno<getPartCount()))
606                {
607                addJoint(j);
608                if (j->d.x < (JOINT_DELTA_MARKER-1.0))
609                        j->useDelta(1);
610                j->attachToParts(j->p1_refno,j->p2_refno);
611                if (srcrange) j->setMapping(*srcrange);
612                return j->refno;
613                }
614        else
615                {
616                delete j;
617                FMprintf("Model","build",FMLV_ERROR,
618                         "invalid part reference for joint #%d",getJointCount()-1);
619                return -1;
620                }
621        }
622else if (!strncmp(t,"n:",2)) // neuro (or the old neuro object as the special case)
623        {
624        static Param neuroparam(f0_neuro_paramtab);
625        Neuro *nu=new Neuro();
626        neuroparam.select(nu);
627        pos+=2;
628        neuroparam.load2(line,pos);
629#ifdef MODEL_V1_COMPATIBLE
630        if (nu->neuro_refno>=0) // parent specified...
631                {
632                if (nu->neuro_refno >= getNeuroCount()) // and it's illegal
633                        {
634                        delete nu;
635                        return -1;
636                        }
637                Neuro *parentNU=getNeuro(nu->neuro_refno);
638                parentNU->addInput(nu,nu->weight);
639                // default class for parented units: n-n link
640                //if (nu->moredata.len()==0) nu->moredata="-";
641                }
642        else
643#endif
644                {
645                // default class for unparented units: standard neuron
646                if (nu->getClassName().len()==0) nu->setClassName("N");
647                }
648/*
649        if (nu->conn_refno>=0) // input specified...
650                {
651                if (nu->conn_refno >= getNeuroCount()) // and it's illegal
652                        {
653                        delete nu;
654                        return -1;
655                        }
656                Neuro *inputNU=getNeuro(nu->conn_refno);
657                nu->addInput(inputNU,nu->weight);
658                }
659*/
660#ifdef MODEL_V1_COMPATIBLE
661        nu->weight=1.0;
662#endif
663        nu->owner=this;
664        // attach to part/joint
665        if (nu->part_refno>=0)
666                nu->attachToPart(nu->part_refno);
667        if (nu->joint_refno>=0)
668                nu->attachToJoint(nu->joint_refno);
669        if (srcrange) nu->setMapping(*srcrange);
670        // todo: check part/joint ref#
671#ifdef MODEL_V1_COMPATIBLE
672        if (hasOldNeuroLayout())
673                {
674                int count=old_getNeuroCount();
675                neurons.insert(count,nu);
676                oldneurocount=count+1;
677                return oldneurocount-1;
678                }
679        else
680#endif
681                {
682                neurons+=nu;
683                return neurons.size()-1;
684                }
685        }
686else if (!strncmp(t,"c:",2)) // add input
687        {
688        static Param ncparam(f0_neuroconn_paramtab);
689        NeuroConn c;
690        ncparam.select(&c);
691        pos+=2;
692        ncparam.load2(line,pos);
693        if ((c.n1_refno>=0)&&(c.n1_refno<getNeuroCount())&&(c.n2_refno>=0)&&(c.n2_refno<getNeuroCount()))
694                {
695                Neuro *na=getNeuro(c.n1_refno);
696                Neuro *nb=getNeuro(c.n2_refno);
697                na->addInput(nb,c.weight,&c.info);
698                if (srcrange)
699                        na->addMapping(*srcrange);
700                return 0;
701                }
702        FMprintf("Model","build",FMLV_ERROR,
703                 "invalid neuron connection #%d <- #%d",c.n1_refno,c.n2_refno);
704        return -1;
705        }
706#ifdef MODEL_V1_COMPATIBLE
707else if (!strncmp(t,"ni:",3)) // old neuroitem
708        {
709        // we always use old layout for "ni:"
710        static Param neuroitemparam(f0_neuroitem_paramtab);
711        Neuro *nu=new Neuro();
712        neuroitemparam.select(nu);
713        pos+=3;
714        neuroitemparam.load2(line,pos);
715        // illegal parent?
716        if ((nu->neuro_refno<0)||(nu->neuro_refno>=old_getNeuroCount()))
717                {
718                delete nu;
719                return -1;
720                }
721        Neuro *parentN=getNeuro(nu->neuro_refno);
722        // copy part/joint refno from parent, if possible
723        if ((nu->part_refno<0)&&(parentN->part_refno>=0))
724                nu->part_refno=parentN->part_refno;
725        if ((nu->joint_refno<0)&&(parentN->joint_refno>=0))
726                nu->joint_refno=parentN->joint_refno;
727        nu->owner=this;
728        // attach to part/joint
729        if (nu->part_refno>=0)
730                nu->attachToPart(nu->part_refno);
731        if (nu->joint_refno>=0)
732                nu->attachToJoint(nu->joint_refno);
733        if (srcrange)
734                nu->setMapping(*srcrange);
735        // special case: old muscles
736        // PARENT neuron will be set up to be the CHILD of the current one (!)
737        if (nu->isOldEffector())
738                {
739                nu->neuro_refno=parentN->refno;
740                neurons+=nu;
741                nu->owner=this;
742                nu->addInput(parentN,nu->weight); // (!)
743                nu->weight=1.0;
744                parentN->invalidateOldItems();
745                return 0; // !!! -> ...getItemCount()-1;
746                }
747        parentN->addInput(nu,nu->weight);
748        neurons+=nu;
749        parentN->invalidateOldItems();
750        if (nu->getClassName().len()==0)
751                {
752                nu->setClassName("-");
753                // for compatibility, "ni" can define a n-n connection
754                // referring to non-existent neuron (which will be hopefully defined later)
755                // internal check will add the proper input to this unit
756                // if conn_refno >=0 and input count==0
757                oldconnections=1;
758                if (srcrange)
759                        parentN->addMapping(*srcrange);
760                }
761        else
762                nu->weight=1.0;
763        return 0; // !!! -> ...getItemCount()-1;
764        }
765#endif
766else return -1;
767}
768
769#ifdef MODEL_V1_COMPATIBLE
770int Model::addOldConnectionsInputs()
771{
772if (!oldconnections) return 1;
773Neuro* n;
774for (int i=0;i<neurons.size();i++)
775        {
776        n=(Neuro*)neurons(i);
777        if (n->conn_refno>=0)
778                if (n->isNNConnection())
779                        if (n->conn_refno < old_getNeuroCount())
780                                { // good reference
781                                Neuro* parent=n->parent; // nn connection has exactly one parent
782                                int inp=parent->findInput(n);
783                                Neuro* target=getNeuro(n->conn_refno);
784                                parent->setInput(inp,target,n->weight);
785                                removeNeuro(i,0); // no need to remove references
786                                i--;
787                                }
788                        else
789                                {
790                                FMprintf("Model","internalCheck",FMLV_ERROR,
791                                         "illegal N-N connection #%d (reference to #%d) (%s)",
792                                         i,n->conn_refno,(const char*)geno.getName());
793                                return 0;
794                                }
795        }
796oldconnections=0;
797return 1;
798}
799#endif
800
801/////////////
802
803/** change the sequence of neuro units
804    and fix references in "-" objects (n-n connections)  */
805void Model::moveNeuro(int oldpos,int newpos)
806{
807if (oldpos==newpos) return; // nop!
808Neuro *n=getNeuro(oldpos);
809neurons-=oldpos;
810neurons.insert(newpos,n);
811 // conn_refno could be broken -> fix it
812#ifdef MODEL_V1_COMPATIBLE
813for (int i=0;i<neurons.size();i++)
814        {
815        Neuro *n2=getNeuro(i);
816        if (n2->isNNConnection())
817                if (n2->conn_refno == oldpos) n2->conn_refno=newpos;
818                else
819                { if (n2->conn_refno > oldpos) n2->conn_refno--;
820                  if (n2->conn_refno >= newpos) n2->conn_refno++; }
821        }
822invalidateOldNeuroCount();
823#endif
824}
825
826#ifdef MODEL_V1_COMPATIBLE
827/** move all old neurons (class "N") to the front of the neurons list.
828    @return number of old neurons
829  */
830int Model::reorderToOldLayout()
831{
832Neuro *n;
833int neurocount=0;
834for (int i=0;i<neurons.size();i++)
835        {
836        n=(Neuro*)neurons(i);
837        if (n->isOldNeuron())
838                {
839                moveNeuro(i,neurocount);
840                neurocount++;
841                i=neurocount-1;
842                }
843        }
844return neurocount;
845}
846#endif
847////////////
848
849void Model::updateNeuroRefno()
850{
851for (int i=0;i<neurons.size();i++)
852        {
853        Neuro* n=(Neuro*)neurons(i);
854        n->refno=i;
855        }
856}
857
858#define VALIDMINMAX(var,template,field) \
859if (var -> field < getMin ## template () . field) \
860        { var->field= getMin ## template () . field; \
861        FMprintf("Model","internalCheck",FMLV_WARN,# field " too small in " # template "#%d (adjusted)",i);} \
862else if (var -> field > getMax ## template () . field) \
863        { var->field= getMax ## template ()  . field; \
864        FMprintf("Model","internalCheck",FMLV_WARN,# field " too big in " # template "#%d (adjusted)",i);}
865
866#define LINKFLAG 0x8000000
867
868void Model::updateRefno()
869{
870int i;
871for (i=0;i<getPartCount();i++) getPart(i)->refno=i;
872for (i=0;i<getJointCount();i++) getJoint(i)->refno=i;
873for (i=0;i<getNeuroCount();i++) getNeuro(i)->refno=i;
874}
875
876int Model::internalcheck(int final)
877{
878Part *p;
879Joint *j;
880Neuro *n;
881int i,k;
882int ret=1;
883if ((parts.size()==0)&&(neurons.size()==0)) return 0;
884if (parts.size()==0)
885        size=Pt3D_0;
886else
887        {
888Pt3D bbmin=((Part*)parts(0))->p, bbmax=bbmin;
889for (i=0;i<parts.size();i++)
890        {
891        p=(Part*)parts(i);
892        p->owner=this;
893        p->refno=i;
894        if (checklevel>0)
895                p->mass=0.0;
896//      VALIDMINMAX(p,part,mass);
897        VALIDMINMAX(p,Part,size);
898        VALIDMINMAX(p,Part,density);
899        VALIDMINMAX(p,Part,friction);
900        VALIDMINMAX(p,Part,ingest);
901        VALIDMINMAX(p,Part,assim);
902        p->flags&=~LINKFLAG; // for delta joint cycle detection
903        if (p->p.x-p->size < bbmin.x) bbmin.x=p->p.x-p->size;
904        if (p->p.y-p->size < bbmin.y) bbmin.y=p->p.y-p->size;
905        if (p->p.z-p->size < bbmin.z) bbmin.z=p->p.z-p->size;
906        if (p->p.x+p->size > bbmax.x) bbmax.x=p->p.x+p->size;
907        if (p->p.y+p->size > bbmax.y) bbmax.y=p->p.y+p->size;
908        if (p->p.z+p->size > bbmax.z) bbmax.z=p->p.z+p->size;
909        }
910size=bbmax-bbmin;
911for (i=0;i<joints.size();i++)
912        {
913        j=(Joint*)joints(i);
914        VALIDMINMAX(j,Joint,stamina);
915        VALIDMINMAX(j,Joint,stif);
916        VALIDMINMAX(j,Joint,rotstif);
917        j->refno=i;
918        j->owner=this;
919        if (j->part1 && j->part2 && (j->part1 != j->part2))
920                {
921                j->p1_refno=j->part1->refno;
922                j->p2_refno=j->part2->refno;
923                if (checklevel>0)
924                        {
925                        j->part1->mass+=1.0;
926                        j->part2->mass+=1.0;
927                        }
928                if ((j->usedelta)&&(j->d.x < (JOINT_DELTA_MARKER-1.0)))
929                        { // delta positioning -> calc. orient.
930                        if (j->part2->flags & LINKFLAG)
931                                {
932                                ret=0;
933                                FMprintf("Model","internalCheck",FMLV_ERROR,
934                                         "delta joint cycle detected at joint#%d (%s)",
935                                         i,(const char*)geno.getName());
936                                }
937                        j->o=j->rot;
938                        j->part1->o.transform(j->part2->o,j->o);
939//                      j->part2->o.x=j->part1->o/j->o.x;
940//                      j->part2->o.y=j->part1->o/j->o.y;
941//                      j->part2->o.z=j->part1->o/j->o.z;
942                        j->part2->p=j->part2->o.transform(j->d)+j->part1->p;
943                        j->part2->flags|=LINKFLAG; j->part1->flags|=LINKFLAG; // for delta joint cycle detection
944                        }
945                else
946                        { // abs.positioning -> calc. delta
947                        if (final)
948                        {
949                        // calc orient delta
950//                      Orient tmpo(j->part2->o);
951//                      tmpo*=j->part1->o;
952                        Orient tmpo;
953                        j->part1->o.revTransform(tmpo,j->part2->o);
954                        tmpo.getAngles(j->rot);
955                        j->o=j->rot;
956                        // calc position delta
957                        Pt3D tmpp(j->part2->p);
958                        tmpp-=j->part1->p;
959                        j->d=j->part2->o.revTransform(tmpp);
960                        }
961                        }
962                if (final)
963                        {
964                        if (j->d()>getMaxJoint().d.x)
965                        {
966                        ret=0;
967                        FMprintf("Model","internalCheck",FMLV_ERROR,"delta too big in joint #%d (%s)",
968                                 i,(const char*)geno.getName());
969                        }
970                        else if (j->d()<getMinJoint().d.x)
971                        {
972                        ret=0;
973                        FMprintf("Model","internalCheck",FMLV_ERROR,"delta too small in joint #%d (%s)",
974                                 i,(const char*)geno.getName());
975                        }
976                        }
977                }
978        else
979                {
980                FMprintf("Model","internalCheck",FMLV_ERROR,"illegal part references in joint #%d (%s)",
981                         i,(const char*)geno.getName());
982                ret=0;
983                }
984        }
985        }
986#ifdef MODEL_V1_COMPATIBLE
987if (!addOldConnectionsInputs())
988        return 0;
989#endif
990
991updateNeuroRefno(); // valid refno is important for n-n connections check (later)
992
993for (i=0;i<neurons.size();i++)
994        {
995        n=(Neuro*)neurons(i);
996        VALIDMINMAX(n,Neuro,state);
997#ifdef MODEL_V1_COMPATIBLE
998        VALIDMINMAX(n,Neuro,inertia);
999        VALIDMINMAX(n,Neuro,force);
1000        VALIDMINMAX(n,Neuro,sigmo);
1001        n->conn_refno=-1;
1002        n->weight=1.0;
1003        n->neuro_refno=-1;
1004#endif
1005        n->part_refno=(n->part)?n->part->refno:-1;
1006        n->joint_refno=(n->joint)?n->joint->refno:-1;
1007        }
1008
1009if (parts.size()&&(checklevel>0))
1010        {
1011        for (i=0;i<parts.size();i++)
1012                {
1013                p=(Part*)parts(i);
1014                if (p->mass<=0.001)
1015                        p->mass=1.0;
1016                p->flags&=~LINKFLAG;
1017                }
1018        getPart(0)->flags|=LINKFLAG;
1019        int change=1;
1020        while(change)
1021                {
1022                change=0;
1023                for (i=0;i<joints.size();i++)
1024                        {
1025                        j=(Joint*)joints(i);
1026                        if (j->part1->flags&LINKFLAG)
1027                                {
1028                                if (!(j->part2->flags&LINKFLAG))
1029                                        {
1030                                        change=1;
1031                                        j->part2->flags|=LINKFLAG;
1032                                        }
1033                                }
1034                        else
1035                        if (j->part2->flags&LINKFLAG)
1036                                {
1037                                if (!(j->part1->flags&LINKFLAG))
1038                                        {
1039                                        change=1;
1040                                        j->part1->flags|=LINKFLAG;
1041                                        }
1042                                }
1043                        }
1044                }
1045        for (i=0;i<parts.size();i++)
1046                {
1047                p=(Part*)parts(i);
1048                if (!(p->flags&LINKFLAG))
1049                        {
1050                        FMprintf("Model","internalCheck",FMLV_ERROR,"not all parts connected (eg.#0-#%d) (%s)",
1051                                 i,(const char*)geno.getName());
1052                        ret=0;
1053                        break;
1054                        }
1055                }
1056        }
1057
1058for (i=0;i<joints.size();i++)
1059        {
1060        j=(Joint*)joints(i);
1061        if (j->p1_refno==j->p2_refno)
1062                {
1063                FMprintf("Model","internalCheck",FMLV_ERROR,"illegal self connection, joint #%d (%s)",
1064                         i,(const char*)geno.getName());
1065                ret=0;
1066                break;
1067                }
1068        for (k=i+1;k<joints.size();k++)
1069                {
1070                Joint* j2=(Joint*)joints(k);
1071                if (((j->p1_refno==j2->p1_refno)&&(j->p2_refno==j2->p2_refno))
1072                    || ((j->p1_refno==j2->p2_refno)&&(j->p2_refno==j2->p1_refno)))
1073                        {
1074                        FMprintf("Model","internalCheck",FMLV_ERROR,"illegal duplicate joints #%d and #%d (%s)",
1075                                 i,k,(const char*)geno.getName());
1076                        ret=0;
1077                        break;
1078                        }
1079                }
1080        }
1081return ret;
1082}
1083
1084/////////////
1085
1086int Model::getErrorPosition(bool includingwarnings)
1087{
1088return includingwarnings?
1089        ((f0errorposition>=0) ? f0errorposition : f0warnposition)
1090        :
1091        f0errorposition;
1092}
1093
1094const Geno& Model::getGeno() const
1095{
1096return geno;
1097}
1098
1099const Geno& Model::getF0Geno()
1100{
1101static Geno invalidgeno("",'0',"","invalid");
1102if (buildstatus==building)
1103        FMprintf("Model","getGeno",FMLV_WARN,"model was not completed - missing close()");
1104if (buildstatus!=valid)
1105        return invalidgeno;
1106if (!f0genoknown)
1107        {
1108        if (autobuildmaps)
1109                {
1110                initF0Map();
1111                makeGeno(f0geno,f0map);
1112                }
1113        else
1114                {
1115                delF0Map();
1116                makeGeno(f0geno);
1117                }
1118        f0genoknown=1;
1119        }
1120return f0geno;
1121}
1122
1123int Model::getPartCount() const
1124{
1125return parts.size();
1126}
1127
1128Part* Model::getPart(int i) const
1129{
1130return ((Part*)parts(i));
1131}
1132
1133int Model::getJointCount() const
1134{
1135return joints.size();
1136}
1137
1138Joint* Model::getJoint(int i) const
1139{
1140return ((Joint*)joints(i));
1141}
1142
1143int Model::findJoints(SList& result,const Part* part)
1144{
1145Joint *j;
1146int n0=result.size();
1147if (part)
1148   for(int i=0;j=(Joint*)joints(i);i++)
1149     if ((j->part1 == part) || (j->part2 == part)) result+=(void*)j;
1150return result.size()-n0;
1151}
1152
1153int Model::findNeuro(Neuro* n)
1154{return neurons.find(n);}
1155
1156int Model::findPart(Part* p)
1157{return parts.find(p);}
1158
1159int Model::findJoint(Joint* j)
1160{return joints.find(j);}
1161
1162int Model::findJoint(Part *p1, Part *p2)
1163{
1164Joint* j;
1165for(int i=0;j=getJoint(i);i++)
1166        if ((j->part1==p1)&&(j->part2==p2)) return i;
1167return -1;
1168}
1169
1170
1171////////////////////
1172
1173#ifdef MODEL_V1_COMPATIBLE
1174void Model::calcOldNeuroCount()
1175{
1176if (oldneurocount>=0) return;
1177oldneurocount=reorderToOldLayout();
1178}
1179
1180int Model::old_getNeuroCount()
1181{ calcOldNeuroCount();
1182 return oldneurocount;}
1183
1184Neuro* Model::old_getNeuro(int i)
1185{calcOldNeuroCount();
1186return (i<oldneurocount)? (Neuro*)getNeuro(i) : (Neuro*)0;
1187}
1188
1189int Model::old_findNeuro(Neuro* n)
1190{calcOldNeuroCount();
1191return findNeuro(n);}
1192
1193Neuro *Model::old_addNewNeuro()
1194{
1195int count=old_getNeuroCount();
1196Neuro *nu=addNewNeuro();
1197nu->setClassName("N");
1198moveNeuro(nu->refno,oldneurocount);
1199oldneurocount=count+1;
1200return (Neuro*)nu;
1201}
1202#endif
1203
1204///////////////////////
1205
1206int Model::getNeuroCount() const
1207{return neurons.size();}
1208
1209Neuro* Model::getNeuro(int i) const
1210{return (Neuro*)neurons(i);}
1211
1212int Model::getConnectionCount() const
1213{
1214int n=0;
1215for(int i=0;i<getNeuroCount();i++)
1216        n+=getNeuro(i)->getInputCount();
1217return n;
1218}
1219
1220int Model::findNeuros(SList& result,
1221                          const char* classname,const Part* part,const Joint* joint)
1222{
1223Neuro *nu;
1224SString cn(classname);
1225int n0=result.size();
1226for(int i=0;nu=(Neuro*)neurons(i);i++)
1227        {
1228        if (part)
1229                if (nu->part != part) continue;
1230        if (joint)
1231                if (nu->joint != joint) continue;
1232        if (classname)
1233                if (nu->getClassName() != cn) continue;
1234        result+=(void*)nu;
1235        }
1236return result.size()-n0;
1237}
1238
1239///////////////////
1240
1241void Model::disturb(double amount)
1242{
1243int i;
1244if (amount<=0) return;
1245for(i=0;i<parts.size();i++)
1246        {
1247        Part *p=getPart(i);
1248        p->p.x+=(rnd01-0.5)*amount;
1249        p->p.y+=(rnd01-0.5)*amount;
1250        p->p.z+=(rnd01-0.5)*amount;
1251        }
1252for(i=0;i<joints.size();i++)
1253        {
1254        Joint *j=getJoint(i);
1255        Pt3D tmpp(j->part2->p);
1256        tmpp-=j->part1->p;
1257        j->d=j->part2->o.revTransform(tmpp);
1258        }
1259}
1260
1261//////////////////////
1262
1263class MinPart: public Part {public: MinPart() {Param par(f0_part_paramtab,this);par.setMin();}};
1264class MaxPart: public Part {public: MaxPart() {Param par(f0_part_paramtab,this);par.setMax();}};
1265class MinJoint: public Joint {public: MinJoint() {Param par(f0_joint_paramtab,this);par.setMin();}};
1266class MaxJoint: public Joint {public: MaxJoint() {Param par(f0_joint_paramtab,this);par.setMax();}};
1267class MinNeuro: public Neuro {public: MinNeuro() {Param par(f0_neuro_paramtab,this);par.setMin();}};
1268class MaxNeuro: public Neuro {public: MaxNeuro() {Param par(f0_neuro_paramtab,this);par.setMax();}};
1269
1270Part& Model::getMinPart() {static MinPart part; return part;}
1271Part& Model::getMaxPart() {static MaxPart part; return part;}
1272Part& Model::getDefPart() {static Part part; return part;}
1273Joint& Model::getMinJoint() {static MinJoint joint; return joint;}
1274Joint& Model::getMaxJoint() {static MaxJoint joint; return joint;}
1275Joint& Model::getDefJoint() {static Joint joint; return joint;}
1276Neuro& Model::getMinNeuro() {static MinNeuro neuro; return neuro;}
1277Neuro& Model::getMaxNeuro() {static MaxNeuro neuro; return neuro;}
1278Neuro& Model::getDefNeuro() {static Neuro neuro; return neuro;}
Note: See TracBrowser for help on using the repository browser.