source: cpp/frams/model/model.cpp @ 153

Last change on this file since 153 was 153, checked in by sz, 6 years ago

SList container iteration: FOREACH() macro now creates local variable for maintaining the loop, removed the obsolete SList iteration implementation, replaced some unnecessarily complex for() with FOREACH()

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