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

Last change on this file since 183 was 183, checked in by Maciej Komosinski, 10 years ago

Improved handling of model properties

  • Property svn:eol-style set to native
File size: 27.0 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
405SString mod_props;
406modelparam.select(this);
407modelparam.save2(mod_props,handle_defaults ? &defaultmodel : NULL,true,!handle_defaults);
408if (mod_props.len()>0) //are there any non-default values?
409        {
410        gen+="m:";
411        gen+=mod_props;
412        }
413
414for (i=0;p=(Part*)parts(i);i++)
415        {
416        partparam.select(p);
417        len=gen.len();
418        gen+="p:";
419        partparam.save2(gen,handle_defaults ? &defaultpart : NULL,true,!handle_defaults);
420        if (map)
421                map->add(len,gen.len()-1,partToMap(i));
422        }
423for (i=0;j=(Joint*)joints(i);i++)
424        {
425        jointparam.select(j);
426        len=gen.len();
427        jointparam.setParamTab(j->usedelta?f0_joint_paramtab:f0_nodeltajoint_paramtab);
428        gen+="j:";
429        jointparam.save2(gen,handle_defaults ? &defaultjoint : NULL,true,!handle_defaults);
430        if (map)
431                map->add(len,gen.len()-1,jointToMap(i));
432        }
433for (i=0;n=(Neuro*)neurons(i);i++)
434        {
435        neuroparam.select(n);
436        len=gen.len();
437        gen+="n:";
438        neuroparam.save2(gen,handle_defaults ? &defaultneuro : NULL,true,!handle_defaults);
439        if (map)
440                map->add(len,gen.len()-1,neuroToMap(i));
441        }
442for (a=0;a<neurons.size();a++)
443        { // inputs
444        n=(Neuro*)neurons(a);
445//      if ((n->getInputCount()==1)&&(n->getInput(0).refno <= n->refno))
446//              continue; // already done with Neuro::conn_refno
447
448        for (b=0;b<n->getInputCount();b++)
449                {
450                double w;
451                NeuroConn nc;
452                Neuro* n2=n->getInput(b,w);
453//              if (((n2.parentcount==1)&&(n2.parent)&&(n2.parent->refno < n2.refno)) ^
454//                  (n2.neuro_refno>=0))
455//                      printf("!!!! bad Neuro::neuro_refno ?!\n");
456
457//              if ((n2.parentcount==1)&&(n2.parent)&&(n2.parent->refno < n2.refno))
458//              if (n2.neuro_refno>=0)
459//                      continue; // already done with Neuro::neuro_refno
460
461                nc.n1_refno=n->refno; nc.n2_refno=n2->refno;
462                nc.weight=w;
463                SString **s=n->inputInfo(b);
464                if ((s)&&(*s))
465                nc.info=**s;
466                connparam.select(&nc);
467                len=gen.len();
468                gen+="c:";
469                connparam.save2(gen,handle_defaults ? &defaultconn : NULL,true,!handle_defaults);
470                if (map)
471                        map->add(len,gen.len()-1,neuroToMap(n->refno));
472                }
473        }
474g=Geno(gen,'0');
475}
476
477//////////////
478
479void Model::open()
480{
481if (buildstatus==building) return;
482buildstatus=building;
483modelfromgenotype=0;
484partmappingchanged=0;
485f0genoknown=0;
486delMap();
487}
488
489void Model::checkpoint()
490{}
491
492void Model::setGeno(const Geno& newgeno)
493{
494geno=newgeno;
495}
496
497void Model::clearMap()
498{
499Part *p; Joint *j; Neuro *n;
500int i;
501delMap();
502delF0Map();
503for (i=0;p=(Part*)parts(i);i++)
504        p->clearMapping();
505for (i=0;j=(Joint*)joints(i);i++)
506        j->clearMapping();
507for (i=0;n=(Neuro*)neurons(i);i++)
508        n->clearMapping();
509}
510
511int Model::close()
512{
513if (buildstatus!=building)
514        FMprintf("Model","close",FMLV_WARN,"unexpected close() - no open()");
515if (internalcheck(1)>0)
516        {
517        buildstatus=valid;
518
519        if (partmappingchanged)
520                {
521                getMap();
522                Part *p; Joint *j; Neuro *n;
523                int i;
524                for (i=0;p=(Part*)parts(i);i++)
525                        if (p->getMapping())
526                                map->add(*p->getMapping(),partToMap(i));
527                for (i=0;j=(Joint*)joints(i);i++)
528                        if (j->getMapping())
529                                map->add(*j->getMapping(),jointToMap(i));
530                for (i=0;n=(Neuro*)neurons(i);i++)
531                        if (n->getMapping())
532                                map->add(*n->getMapping(),neuroToMap(i));
533                }
534        }
535else
536        buildstatus=invalid;
537
538return (buildstatus==valid);
539}
540
541int Model::validate()
542{
543return internalcheck(0);
544}
545
546Pt3D Model::whereDelta(const Part& start,const Pt3D& rot, const Pt3D& delta)
547{
548Orient roto;
549roto=rot;
550Orient o;
551roto.transform(o,start.o);
552//o.x=start.o/roto.x;
553//o.y=start.o/roto.y;
554//o.z=start.o/roto.z;
555return o.transform(delta)+start.p;
556}
557
558int Model::singleStepBuild(const SString &line,const MultiRange* srcrange)
559{
560int pos=0; const char*t=(const char*)line;
561for (;*t;t++,pos++)
562        if (!strchr(" \r\t",*t)) break;
563if (*t=='#') return 0;
564if (!*t) return 0;
565if (!strncmp(t,"p:",2))
566        {
567        Param partparam(f0_part_paramtab);
568        Part *p=new Part();
569        partparam.select(p);
570        pos+=2;
571        partparam.load2(line,pos);
572        p->o.rotate(p->rot);
573        parts+=p;
574        p->owner=this;
575        if (srcrange) p->setMapping(*srcrange);
576        return getPartCount()-1;
577        }
578if (!strncmp(t,"m:",2))
579        {
580        Param modelparam(f0_model_paramtab);
581        modelparam.select(this);
582        pos+=2;
583        modelparam.load2(line,pos);
584        return 0;
585        }
586else if (!strncmp(t,"j:",2))
587        {
588        Param jointparam(f0_joint_paramtab);
589        Joint *j=new Joint();
590        jointparam.select(j);
591        pos+=2;
592        j->owner=this;
593        jointparam.load2(line,pos);
594        if ((j->p1_refno>=0)&&(j->p1_refno<getPartCount())&&
595           (j->p2_refno>=0)&&(j->p2_refno<getPartCount()))
596                {
597                addJoint(j);
598                if ((j->d.x != JOINT_DELTA_MARKER) || (j->d.y != JOINT_DELTA_MARKER) || (j->d.z != JOINT_DELTA_MARKER))
599                        {
600                        j->useDelta(1);
601                        j->resetDeltaMarkers();
602                        }
603                j->attachToParts(j->p1_refno,j->p2_refno);
604                if (srcrange) j->setMapping(*srcrange);
605                return j->refno;
606                }
607        else
608                {
609                delete j;
610                FMprintf("Model","build",FMLV_ERROR,
611                         "invalid part reference for joint #%d",getJointCount()-1);
612                return -1;
613                }
614        }
615else if (!strncmp(t,"n:",2)) // neuro (or the old neuro object as the special case)
616        {
617        Param neuroparam(f0_neuro_paramtab);
618        Neuro *nu=new Neuro();
619        neuroparam.select(nu);
620        pos+=2;
621        neuroparam.load2(line,pos);
622#ifdef MODEL_V1_COMPATIBLE
623        if (nu->neuro_refno>=0) // parent specified...
624                {
625                if (nu->neuro_refno >= getNeuroCount()) // and it's illegal
626                        {
627                        delete nu;
628                        return -1;
629                        }
630                Neuro *parentNU=getNeuro(nu->neuro_refno);
631                parentNU->addInput(nu,nu->weight);
632                // default class for parented units: n-n link
633                //if (nu->moredata.len()==0) nu->moredata="-";
634                }
635        else
636#endif
637                {
638                // default class for unparented units: standard neuron
639                if (nu->getClassName().len()==0) nu->setClassName("N");
640                }
641/*
642        if (nu->conn_refno>=0) // input specified...
643                {
644                if (nu->conn_refno >= getNeuroCount()) // and it's illegal
645                        {
646                        delete nu;
647                        return -1;
648                        }
649                Neuro *inputNU=getNeuro(nu->conn_refno);
650                nu->addInput(inputNU,nu->weight);
651                }
652*/
653#ifdef MODEL_V1_COMPATIBLE
654        nu->weight=1.0;
655#endif
656        nu->owner=this;
657        // attach to part/joint
658        if (nu->part_refno>=0)
659                nu->attachToPart(nu->part_refno);
660        if (nu->joint_refno>=0)
661                nu->attachToJoint(nu->joint_refno);
662        if (srcrange) nu->setMapping(*srcrange);
663        // todo: check part/joint ref#
664#ifdef MODEL_V1_COMPATIBLE
665        if (hasOldNeuroLayout())
666                {
667                int count=old_getNeuroCount();
668                neurons.insert(count,nu);
669                oldneurocount=count+1;
670                return oldneurocount-1;
671                }
672        else
673#endif
674                {
675                neurons+=nu;
676                return neurons.size()-1;
677                }
678        }
679else if (!strncmp(t,"c:",2)) // add input
680        {
681        Param ncparam(f0_neuroconn_paramtab);
682        NeuroConn c;
683        ncparam.select(&c);
684        pos+=2;
685        ncparam.load2(line,pos);
686        if ((c.n1_refno>=0)&&(c.n1_refno<getNeuroCount())&&(c.n2_refno>=0)&&(c.n2_refno<getNeuroCount()))
687                {
688                Neuro *na=getNeuro(c.n1_refno);
689                Neuro *nb=getNeuro(c.n2_refno);
690                na->addInput(nb,c.weight,&c.info);
691                if (srcrange)
692                        na->addMapping(*srcrange);
693                return 0;
694                }
695        FMprintf("Model","build",FMLV_ERROR,
696                 "invalid neuron connection #%d <- #%d",c.n1_refno,c.n2_refno);
697        return -1;
698        }
699#ifdef MODEL_V1_COMPATIBLE
700else if (!strncmp(t,"ni:",3)) // old neuroitem
701        {
702        // we always use old layout for "ni:"
703        Param neuroitemparam(f0_neuroitem_paramtab);
704        Neuro *nu=new Neuro();
705        neuroitemparam.select(nu);
706        pos+=3;
707        neuroitemparam.load2(line,pos);
708        // illegal parent?
709        if ((nu->neuro_refno<0)||(nu->neuro_refno>=old_getNeuroCount()))
710                {
711                delete nu;
712                return -1;
713                }
714        Neuro *parentN=getNeuro(nu->neuro_refno);
715        // copy part/joint refno from parent, if possible
716        if ((nu->part_refno<0)&&(parentN->part_refno>=0))
717                nu->part_refno=parentN->part_refno;
718        if ((nu->joint_refno<0)&&(parentN->joint_refno>=0))
719                nu->joint_refno=parentN->joint_refno;
720        nu->owner=this;
721        // attach to part/joint
722        if (nu->part_refno>=0)
723                nu->attachToPart(nu->part_refno);
724        if (nu->joint_refno>=0)
725                nu->attachToJoint(nu->joint_refno);
726        if (srcrange)
727                nu->setMapping(*srcrange);
728        // special case: old muscles
729        // PARENT neuron will be set up to be the CHILD of the current one (!)
730        if (nu->isOldEffector())
731                {
732                nu->neuro_refno=parentN->refno;
733                neurons+=nu;
734                nu->owner=this;
735                nu->addInput(parentN,nu->weight); // (!)
736                nu->weight=1.0;
737                parentN->invalidateOldItems();
738                return 0; // !!! -> ...getItemCount()-1;
739                }
740        parentN->addInput(nu,nu->weight);
741        neurons+=nu;
742        parentN->invalidateOldItems();
743        if (nu->getClassName().len()==0)
744                {
745                nu->setClassName("-");
746                // for compatibility, "ni" can define a n-n connection
747                // referring to non-existent neuron (which will be hopefully defined later)
748                // internal check will add the proper input to this unit
749                // if conn_refno >=0 and input count==0
750                oldconnections=1;
751                if (srcrange)
752                        parentN->addMapping(*srcrange);
753                }
754        else
755                nu->weight=1.0;
756        return 0; // !!! -> ...getItemCount()-1;
757        }
758#endif
759else return -1;
760}
761
762#ifdef MODEL_V1_COMPATIBLE
763int Model::addOldConnectionsInputs()
764{
765if (!oldconnections) return 1;
766Neuro* n;
767for (int i=0;i<neurons.size();i++)
768        {
769        n=(Neuro*)neurons(i);
770        if (n->conn_refno>=0)
771                if (n->isNNConnection())
772                        if (n->conn_refno < old_getNeuroCount())
773                                { // good reference
774                                Neuro* parent=n->parent; // nn connection has exactly one parent
775                                int inp=parent->findInput(n);
776                                Neuro* target=getNeuro(n->conn_refno);
777                                parent->setInput(inp,target,n->weight);
778                                removeNeuro(i,0); // no need to remove references
779                                i--;
780                                }
781                        else
782                                {
783                                FMprintf("Model","internalCheck",FMLV_ERROR,
784                                         "illegal N-N connection #%d (reference to #%d) (%s)",
785                                         i,n->conn_refno,(const char*)geno.getName());
786                                return 0;
787                                }
788        }
789oldconnections=0;
790return 1;
791}
792#endif
793
794/////////////
795
796/** change the sequence of neuro units
797    and fix references in "-" objects (n-n connections)  */
798void Model::moveNeuro(int oldpos,int newpos)
799{
800if (oldpos==newpos) return; // nop!
801Neuro *n=getNeuro(oldpos);
802neurons-=oldpos;
803neurons.insert(newpos,n);
804 // conn_refno could be broken -> fix it
805#ifdef MODEL_V1_COMPATIBLE
806for (int i=0;i<neurons.size();i++)
807        {
808        Neuro *n2=getNeuro(i);
809        if (n2->isNNConnection())
810                if (n2->conn_refno == oldpos) n2->conn_refno=newpos;
811                else
812                { if (n2->conn_refno > oldpos) n2->conn_refno--;
813                  if (n2->conn_refno >= newpos) n2->conn_refno++; }
814        }
815invalidateOldNeuroCount();
816#endif
817}
818
819#ifdef MODEL_V1_COMPATIBLE
820/** move all old neurons (class "N") to the front of the neurons list.
821    @return number of old neurons
822  */
823int Model::reorderToOldLayout()
824{
825Neuro *n;
826int neurocount=0;
827for (int i=0;i<neurons.size();i++)
828        {
829        n=(Neuro*)neurons(i);
830        if (n->isOldNeuron())
831                {
832                moveNeuro(i,neurocount);
833                neurocount++;
834                i=neurocount-1;
835                }
836        }
837return neurocount;
838}
839#endif
840////////////
841
842void Model::updateNeuroRefno()
843{
844for (int i=0;i<neurons.size();i++)
845        {
846        Neuro* n=(Neuro*)neurons(i);
847        n->refno=i;
848        }
849}
850
851#define VALIDMINMAX(var,template,field) \
852if (var -> field < getMin ## template () . field) \
853        { var->field= getMin ## template () . field; \
854        FMprintf("Model","internalCheck",FMLV_WARN,# field " too small in " # template "#%d (adjusted)",i);} \
855else if (var -> field > getMax ## template () . field) \
856        { var->field= getMax ## template ()  . field; \
857        FMprintf("Model","internalCheck",FMLV_WARN,# field " too big in " # template "#%d (adjusted)",i);}
858
859#define LINKFLAG 0x8000000
860
861void Model::updateRefno()
862{
863int i;
864for (i=0;i<getPartCount();i++) getPart(i)->refno=i;
865for (i=0;i<getJointCount();i++) getJoint(i)->refno=i;
866for (i=0;i<getNeuroCount();i++) getNeuro(i)->refno=i;
867}
868
869int Model::internalcheck(int final)
870{
871Part *p;
872Joint *j;
873Neuro *n;
874int i,k;
875int ret=1;
876if ((parts.size()==0)&&(neurons.size()==0)) return 0;
877if (parts.size()==0)
878        size=Pt3D_0;
879else
880        {
881Pt3D bbmin=((Part*)parts(0))->p, bbmax=bbmin;
882for (i=0;i<parts.size();i++)
883        {
884        p=(Part*)parts(i);
885        p->owner=this;
886        p->refno=i;
887        if (p->shape==0)
888                {
889                if (checklevel>0)
890                        p->mass=0.0;
891                }
892//      VALIDMINMAX(p,part,mass);
893        VALIDMINMAX(p,Part,size);
894        VALIDMINMAX(p,Part,density);
895        VALIDMINMAX(p,Part,friction);
896        VALIDMINMAX(p,Part,ingest);
897        VALIDMINMAX(p,Part,assim);
898        p->flags&=~LINKFLAG; // for delta joint cycle detection
899        if (p->p.x-p->size < bbmin.x) bbmin.x=p->p.x-p->size;
900        if (p->p.y-p->size < bbmin.y) bbmin.y=p->p.y-p->size;
901        if (p->p.z-p->size < bbmin.z) bbmin.z=p->p.z-p->size;
902        if (p->p.x+p->size > bbmax.x) bbmax.x=p->p.x+p->size;
903        if (p->p.y+p->size > bbmax.y) bbmax.y=p->p.y+p->size;
904        if (p->p.z+p->size > bbmax.z) bbmax.z=p->p.z+p->size;
905        }
906size=bbmax-bbmin;
907for (i=0;i<joints.size();i++)
908        {
909        j=(Joint*)joints(i);
910        VALIDMINMAX(j,Joint,stamina);
911        VALIDMINMAX(j,Joint,stif);
912        VALIDMINMAX(j,Joint,rotstif);
913        j->refno=i;
914        j->owner=this;
915        if (j->part1 && j->part2 && (j->part1 != j->part2))
916                {
917                j->p1_refno=j->part1->refno;
918                j->p2_refno=j->part2->refno;
919                if (checklevel>0)
920                        {
921                        if (j->part1->shape==0)
922                                j->part1->mass+=1.0;
923                        if (j->part2->shape==0)
924                                j->part2->mass+=1.0;
925                        }
926                if ((j->usedelta)&&((j->d.x!=JOINT_DELTA_MARKER)||(j->d.y!=JOINT_DELTA_MARKER)||(j->d.z!=JOINT_DELTA_MARKER)))
927                        { // delta positioning -> calc. orient.
928                        if (j->part2->flags & LINKFLAG)
929                                {
930                                ret=0;
931                                FMprintf("Model","internalCheck",FMLV_ERROR,
932                                         "delta joint cycle detected at joint#%d (%s)",
933                                         i,(const char*)geno.getName());
934                                }
935                        j->resetDeltaMarkers();
936                        j->o=j->rot;
937                        j->part1->o.transform(j->part2->o,j->o);
938//                      j->part2->o.x=j->part1->o/j->o.x;
939//                      j->part2->o.y=j->part1->o/j->o.y;
940//                      j->part2->o.z=j->part1->o/j->o.z;
941                        j->part2->p=j->part2->o.transform(j->d)+j->part1->p;
942                        j->part2->flags|=LINKFLAG; j->part1->flags|=LINKFLAG; // for delta joint cycle detection
943                        }
944                else
945                        { // abs.positioning -> calc. delta
946                        if (final)
947                        {
948                        // calc orient delta
949//                      Orient tmpo(j->part2->o);
950//                      tmpo*=j->part1->o;
951                        Orient tmpo;
952                        j->part1->o.revTransform(tmpo,j->part2->o);
953                        tmpo.getAngles(j->rot);
954                        j->o=j->rot;
955                        // calc position delta
956                        Pt3D tmpp(j->part2->p);
957                        tmpp-=j->part1->p;
958                        j->d=j->part2->o.revTransform(tmpp);
959                        }
960                        }
961                if (final)
962                        {
963                        if (j->shape!=Joint::SHAPE_SOLID)
964                                {
965                        if (j->d()>getMaxJoint().d.x)
966                        {
967                        ret=0;
968                        FMprintf("Model","internalCheck",FMLV_ERROR,"delta too big in joint #%d (%s)",
969                                 i,(const char*)geno.getName());
970                        }
971                        else if (j->d()<getMinJoint().d.x)
972                        {
973                        ret=0;
974                        FMprintf("Model","internalCheck",FMLV_ERROR,"delta too small in joint #%d (%s)",
975                                 i,(const char*)geno.getName());
976                        }
977                                }
978                        }
979                }
980        else
981                {
982                FMprintf("Model","internalCheck",FMLV_ERROR,"illegal part references in joint #%d (%s)",
983                         i,(const char*)geno.getName());
984                ret=0;
985                }
986        }
987        }
988#ifdef MODEL_V1_COMPATIBLE
989if (!addOldConnectionsInputs())
990        return 0;
991#endif
992
993updateNeuroRefno(); // valid refno is important for n-n connections check (later)
994
995for (i=0;i<neurons.size();i++)
996        {
997        n=(Neuro*)neurons(i);
998        VALIDMINMAX(n,Neuro,state);
999#ifdef MODEL_V1_COMPATIBLE
1000        VALIDMINMAX(n,Neuro,inertia);
1001        VALIDMINMAX(n,Neuro,force);
1002        VALIDMINMAX(n,Neuro,sigmo);
1003        n->conn_refno=-1;
1004        n->weight=1.0;
1005        n->neuro_refno=-1;
1006#endif
1007        n->part_refno=(n->part)?n->part->refno:-1;
1008        n->joint_refno=(n->joint)?n->joint->refno:-1;
1009        }
1010
1011if (parts.size()&&(checklevel>0))
1012        {
1013        for (i=0;i<parts.size();i++)
1014                {
1015                p=(Part*)parts(i);
1016                if (p->shape==0)
1017                        if (p->mass<=0.001)
1018                                p->mass=1.0;
1019                p->flags&=~LINKFLAG;
1020                }
1021        getPart(0)->flags|=LINKFLAG;
1022        int change=1;
1023        while(change)
1024                {
1025                change=0;
1026                for (i=0;i<joints.size();i++)
1027                        {
1028                        j=(Joint*)joints(i);
1029                        if (j->part1->flags&LINKFLAG)
1030                                {
1031                                if (!(j->part2->flags&LINKFLAG))
1032                                        {
1033                                        change=1;
1034                                        j->part2->flags|=LINKFLAG;
1035                                        }
1036                                }
1037                        else
1038                        if (j->part2->flags&LINKFLAG)
1039                                {
1040                                if (!(j->part1->flags&LINKFLAG))
1041                                        {
1042                                        change=1;
1043                                        j->part1->flags|=LINKFLAG;
1044                                        }
1045                                }
1046                        }
1047                }
1048        for (i=0;i<parts.size();i++)
1049                {
1050                p=(Part*)parts(i);
1051                if (!(p->flags&LINKFLAG))
1052                        {
1053                        FMprintf("Model","internalCheck",FMLV_ERROR,"not all parts connected (eg.#0-#%d) (%s)",
1054                                 i,(const char*)geno.getName());
1055                        ret=0;
1056                        break;
1057                        }
1058                }
1059        }
1060
1061for (i=0;i<joints.size();i++)
1062        {
1063        j=(Joint*)joints(i);
1064        if (j->p1_refno==j->p2_refno)
1065                {
1066                FMprintf("Model","internalCheck",FMLV_ERROR,"illegal self connection, joint #%d (%s)",
1067                         i,(const char*)geno.getName());
1068                ret=0;
1069                break;
1070                }
1071        for (k=i+1;k<joints.size();k++)
1072                {
1073                Joint* j2=(Joint*)joints(k);
1074                if (((j->p1_refno==j2->p1_refno)&&(j->p2_refno==j2->p2_refno))
1075                    || ((j->p1_refno==j2->p2_refno)&&(j->p2_refno==j2->p1_refno)))
1076                        {
1077                        FMprintf("Model","internalCheck",FMLV_ERROR,"illegal duplicate joints #%d and #%d (%s)",
1078                                 i,k,(const char*)geno.getName());
1079                        ret=0;
1080                        break;
1081                        }
1082                }
1083        }
1084return ret;
1085}
1086
1087/////////////
1088
1089int Model::getErrorPosition(bool includingwarnings)
1090{
1091return includingwarnings?
1092        ((f0errorposition>=0) ? f0errorposition : f0warnposition)
1093        :
1094        f0errorposition;
1095}
1096
1097const Geno& Model::getGeno() const
1098{
1099return geno;
1100}
1101
1102const Geno Model::getF0Geno()
1103{
1104if (buildstatus==building)
1105        FMprintf("Model","getGeno",FMLV_WARN,"model was not completed - missing close()");
1106if (buildstatus!=valid)
1107        return Geno("",'0',"","invalid");
1108if (!f0genoknown)
1109        {
1110        if (autobuildmaps)
1111                {
1112                initF0Map();
1113                makeGeno(f0geno,f0map);
1114                }
1115        else
1116                {
1117                delF0Map();
1118                makeGeno(f0geno);
1119                }
1120        f0genoknown=1;
1121        }
1122return f0geno;
1123}
1124
1125int Model::getPartCount() const
1126{
1127return parts.size();
1128}
1129
1130Part* Model::getPart(int i) const
1131{
1132return ((Part*)parts(i));
1133}
1134
1135int Model::getJointCount() const
1136{
1137return joints.size();
1138}
1139
1140Joint* Model::getJoint(int i) const
1141{
1142return ((Joint*)joints(i));
1143}
1144
1145int Model::findJoints(SList& result,const Part* part)
1146{
1147Joint *j;
1148int n0=result.size();
1149if (part)
1150   for(int i=0;j=(Joint*)joints(i);i++)
1151     if ((j->part1 == part) || (j->part2 == part)) result+=(void*)j;
1152return result.size()-n0;
1153}
1154
1155int Model::findNeuro(Neuro* n)
1156{return neurons.find(n);}
1157
1158int Model::findPart(Part* p)
1159{return parts.find(p);}
1160
1161int Model::findJoint(Joint* j)
1162{return joints.find(j);}
1163
1164int Model::findJoint(Part *p1, Part *p2)
1165{
1166Joint* j;
1167for(int i=0;j=getJoint(i);i++)
1168        if ((j->part1==p1)&&(j->part2==p2)) return i;
1169return -1;
1170}
1171
1172
1173////////////////////
1174
1175#ifdef MODEL_V1_COMPATIBLE
1176void Model::calcOldNeuroCount()
1177{
1178if (oldneurocount>=0) return;
1179oldneurocount=reorderToOldLayout();
1180}
1181
1182int Model::old_getNeuroCount()
1183{ calcOldNeuroCount();
1184 return oldneurocount;}
1185
1186Neuro* Model::old_getNeuro(int i)
1187{calcOldNeuroCount();
1188return (i<oldneurocount)? (Neuro*)getNeuro(i) : (Neuro*)0;
1189}
1190
1191int Model::old_findNeuro(Neuro* n)
1192{calcOldNeuroCount();
1193return findNeuro(n);}
1194
1195Neuro *Model::old_addNewNeuro()
1196{
1197int count=old_getNeuroCount();
1198Neuro *nu=addNewNeuro();
1199nu->setClassName("N");
1200moveNeuro(nu->refno,oldneurocount);
1201oldneurocount=count+1;
1202return (Neuro*)nu;
1203}
1204#endif
1205
1206///////////////////////
1207
1208int Model::getNeuroCount() const
1209{return neurons.size();}
1210
1211Neuro* Model::getNeuro(int i) const
1212{return (Neuro*)neurons(i);}
1213
1214int Model::getConnectionCount() const
1215{
1216int n=0;
1217for(int i=0;i<getNeuroCount();i++)
1218        n+=getNeuro(i)->getInputCount();
1219return n;
1220}
1221
1222int Model::findNeuros(SList& result,
1223                          const char* classname,const Part* part,const Joint* joint)
1224{
1225Neuro *nu;
1226SString cn(classname);
1227int n0=result.size();
1228for(int i=0;nu=(Neuro*)neurons(i);i++)
1229        {
1230        if (part)
1231                if (nu->part != part) continue;
1232        if (joint)
1233                if (nu->joint != joint) continue;
1234        if (classname)
1235                if (nu->getClassName() != cn) continue;
1236        result+=(void*)nu;
1237        }
1238return result.size()-n0;
1239}
1240
1241///////////////////
1242
1243void Model::disturb(double amount)
1244{
1245int i;
1246if (amount<=0) return;
1247for(i=0;i<parts.size();i++)
1248        {
1249        Part *p=getPart(i);
1250        p->p.x+=(rnd01-0.5)*amount;
1251        p->p.y+=(rnd01-0.5)*amount;
1252        p->p.z+=(rnd01-0.5)*amount;
1253        }
1254for(i=0;i<joints.size();i++)
1255        {
1256        Joint *j=getJoint(i);
1257        Pt3D tmpp(j->part2->p);
1258        tmpp-=j->part1->p;
1259        j->d=j->part2->o.revTransform(tmpp);
1260        }
1261}
1262
1263//////////////////////
1264
1265class MinPart: public Part {public: MinPart() {Param par(f0_part_paramtab,this);par.setMin();}};
1266class MaxPart: public Part {public: MaxPart() {Param par(f0_part_paramtab,this);par.setMax();}};
1267class MinJoint: public Joint {public: MinJoint() {Param par(f0_joint_paramtab,this);par.setMin();}};
1268class MaxJoint: public Joint {public: MaxJoint() {Param par(f0_joint_paramtab,this);par.setMax();}};
1269class MinNeuro: public Neuro {public: MinNeuro() {Param par(f0_neuro_paramtab,this);par.setMin();}};
1270class MaxNeuro: public Neuro {public: MaxNeuro() {Param par(f0_neuro_paramtab,this);par.setMax();}};
1271
1272Part& Model::getMinPart() {static MinPart part; return part;}
1273Part& Model::getMaxPart() {static MaxPart part; return part;}
1274Part& Model::getDefPart() {static Part part; return part;}
1275Joint& Model::getMinJoint() {static MinJoint joint; return joint;}
1276Joint& Model::getMaxJoint() {static MaxJoint joint; return joint;}
1277Joint& Model::getDefJoint() {static Joint joint; return joint;}
1278Neuro& Model::getMinNeuro() {static MinNeuro neuro; return neuro;}
1279Neuro& Model::getMaxNeuro() {static MaxNeuro neuro; return neuro;}
1280Neuro& Model::getDefNeuro() {static Neuro neuro; return neuro;}
Note: See TracBrowser for help on using the repository browser.