source: cpp/frams/genetics/oper_fx.cpp @ 146

Last change on this file since 146 was 146, checked in by sz, 10 years ago

oops, forgot to include oper_fx.cpp in the previous Genetics update

  • Property svn:eol-style set to native
File size: 8.1 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 <ctype.h>  //isupper()
6#include "oper_fx.h"
7#include <common/framsg.h>
8#include <common/nonstd_math.h>
9#include <frams/util/rndutil.h>
10
11static double distrib_force[]=   // for '!'
12{
133,                 // distribution 0 -__/ +1
140.001, 0.2,        // "slow" neurons
150.001, 1,
16    1, 1,          // "fast" neurons
17};
18static double distrib_inertia[]=  // for '='
19{
202,                 // distribution 0 |..- +1
21  0, 0,            // "fast" neurons
220.7, 0.98,
23};
24static double distrib_sigmo[]=  // for '/'
25{
265,                 // distribution -999 -..-^-..- +999
27-999, -999,        //"perceptron"
28 999, 999,
29  -5, -1,          // nonlinear
30   1, 5,
31  -1, 1,           // ~linear
32};
33
34
35int GenoOperators::roulette(const double *probtab,const int count)
36{
37   double sum=0;
38   int i;
39   for (i=0;i<count;i++) sum+=probtab[i];
40   double sel=rnd01*sum;
41   for (sum=0,i=0;i<count;i++) {sum+=probtab[i]; if (sel<sum) return i;}
42   return -1;
43}
44
45bool GenoOperators::getMinMaxDef(ParamInterface *p,int i,double &mn,double &mx,double &def)
46{
47   mn=mx=def=0;
48   int defined=0;
49   if (p->type(i)[0]=='f')
50   {
51      double _mn=0,_mx=1,_def=0.5;
52      defined=p->getMinMax(i,_mn,_mx,_def);
53      if (defined==1) _mx=_mn+1.0;
54      if (_mx<_mn && defined==3) _mn=_mx=_def; //only default was defined, let's assume min=max=default
55      if (defined<3) _def=(_mn+_mx)/2.0;
56      mn=_mn; mx=_mx; def=_def;
57   }
58   if (p->type(i)[0]=='d')
59   {
60      long _mn=0,_mx=1,_def=0;
61      defined=p->getMinMax(i,_mn,_mx,_def);
62      if (defined==1) _mx=_mn+1;
63      if (_mx<_mn && defined==3) _mn=_mx=_def; //only default was defined, let's assume min=max=default
64      if (defined<3) _def=(_mn+_mx)/2;
65      mn=_mn; mx=_mx; def=_def;
66   }
67   return defined==3;
68}
69
70int GenoOperators::selectRandomProperty(Neuro* n)
71{
72   int neuext=n->extraProperties().getPropCount(),
73       neucls=n->getClass()==NULL?0:n->getClass()->getProperties().getPropCount();
74   if (neuext+neucls==0) return -1; //no properties in this neuron
75   int index=randomN(neuext+neucls);
76   if (index>=neuext) index=index-neuext+100;
77   return index;
78}
79
80double GenoOperators::mutateNeuProperty(double current,Neuro *n,int i)
81{
82   if (i==-1) return mutateCreepNoLimit('f',current,-10,10); //i==-1: mutating weight of neural connection
83   Param p;
84   if (i>=100) {i-=100; p=n->getClass()->getProperties();}
85      else p=n->extraProperties();
86   double newval=current;
87   /*bool ok=*/getMutatedProperty(p,i,current,newval);
88   return newval;
89}
90
91bool GenoOperators::mutatePropertyNaive(ParamInterface &p,int i)
92{
93   double mn,mx,df;
94   if (p.type(i)[0]!='f' && p.type(i)[0]!='d') return false; //don't know how to mutate
95   getMinMaxDef(&p,i,mn,mx,df);
96
97   ExtValue ev;
98   p.get(i,ev);
99   ev.setDouble(mutateCreep(p.type(i)[0],ev.getDouble(),mn,mx));
100   p.set(i,ev);
101   return true;
102}
103
104bool GenoOperators::mutateProperty(ParamInterface &p,int i)
105{
106   double newval;
107   ExtValue ev;
108   p.get(i,ev);
109   bool ok=getMutatedProperty(p,i,ev.getDouble(),newval);
110   if (ok) {ev.setDouble(newval); p.set(i,ev);}
111   return ok;
112}
113
114bool GenoOperators::getMutatedProperty(ParamInterface &p,int i,double oldval,double &newval)
115{
116   newval=0;
117   if (p.type(i)[0]!='f' && p.type(i)[0]!='d') return false; //don't know how to mutate
118   const char *n=p.id(i),*na=p.name(i);
119     if (strcmp(n,"si")==0 && strcmp(na,"Sigmoid")==0) newval=CustomRnd(distrib_sigmo); else
120     if (strcmp(n,"in")==0 && strcmp(na,"Inertia")==0) newval=CustomRnd(distrib_inertia); else
121     if (strcmp(n,"fo")==0 && strcmp(na,"Force")==0) newval=CustomRnd(distrib_force); else
122     {
123       double mn,mx,df;
124       getMinMaxDef(&p,i,mn,mx,df);
125       newval=mutateCreep(p.type(i)[0],oldval,mn,mx);
126     }
127   return true;
128}
129
130double GenoOperators::mutateCreepNoLimit(char type,double current,double mn,double mx)
131{
132   double result=RndGen.Gauss(current,(mx-mn)/2/5); // /halfinterval, 5 times narrower
133   if (type=='d') {result=int(result+0.5); if (result==current) result+=randomN(2)*2-1;}
134    else result=floor(result*1000+0.5)/1000.0; //round
135   return result;
136}
137
138double GenoOperators::mutateCreep(char type, double current, double mn, double mx)
139{
140        double result = mutateCreepNoLimit(type, current, mn, mx); //TODO consider that when boundary is touched (reflect/absorb below), the default precision (3 digits) may change. Is it good or bad?
141        //reflect:
142        if (result > mx) result = mx - (result - mx); else
143                if (result<mn) result = mn + (mn - result);
144        //absorb (just in case 'result' exceeded the allowed range so much):
145        if (result>mx) result = mx; else
146                if (result < mn) result = mn;
147        return result;
148}
149
150void GenoOperators::setIntFromDoubleWithProbabilisticDithering(ParamInterface &p, int index, double value) //TODO
151{
152        p.setInt(index, value); //TODO value=2.5 will result in 2 but we want it to be 2 or 3 with equal probability. value=2.1 would be mostly 2, rarely 3. Careful with negative values (test it!)
153}
154
155void GenoOperators::linearMix(ParamInterface &p1, int i1, ParamInterface &p2, int i2, double proportion)
156{
157        if (p1.type(i1)[0] == 'f' && p2.type(i2)[0] == 'f')
158        {
159                double v1 = p1.getDouble(i1);
160                double v2 = p2.getDouble(i2);
161                p1.setDouble(i1, v1*proportion + v2*(1 - proportion));
162                p2.setDouble(i2, v2*proportion + v1*(1 - proportion));
163        }
164        if (p1.type(i1)[0] == 'd' && p2.type(i2)[0] == 'd')
165        {
166                int v1 = p1.getInt(i1);
167                int v2 = p2.getInt(i2);
168                setIntFromDoubleWithProbabilisticDithering(p1, i1, v1*proportion + v2*(1 - proportion));
169                setIntFromDoubleWithProbabilisticDithering(p2, i2, v2*proportion + v1*(1 - proportion));
170        }
171}
172
173
174NeuroClass* GenoOperators::getRandomNeuroClass()
175{
176        SListTempl<NeuroClass*> active;
177   for(int i=0;i<Neuro::getClassCount();i++)
178      if (Neuro::getClass(i)->genactive) active+=Neuro::getClass(i);
179   if (!active==0) return NULL; else return active(randomN(!active));
180}
181
182NeuroClass* GenoOperators::parseNeuroClass(char*& s)
183{
184   int len=strlen(s);
185   int Len=0;
186   NeuroClass *I=NULL;
187   for(int i=0;i<Neuro::getClassCount();i++)
188   {
189      const char *n=Neuro::getClass(i)->name;
190      int l=strlen(n);
191      if (len>=l && l>Len && (strncmp(s,n,l)==0)) {I=Neuro::getClass(i); Len=l;}
192   }
193   s+=Len;
194   return I;
195}
196
197Neuro* GenoOperators::findNeuro(const Model *m,const NeuroClass *nc)
198{
199  if (!m) return NULL;
200  for(int i=0;i<m->getNeuroCount();i++)
201     if (m->getNeuro(i)->getClass()==nc) return m->getNeuro(i);
202  return NULL; //neuron of class 'nc' was not found
203}
204
205int GenoOperators::neuroClassProp(char*& s,NeuroClass *nc,bool also_v1_N_props)
206{
207   int len=strlen(s);
208   int Len=0,I=-1;
209   if (nc)
210   {
211      Param p=nc->getProperties();
212      for(int i=0;i<p.getPropCount();i++)
213      {
214         const char *n=p.id(i);
215         int l=strlen(n);
216         if (len>=l && l>Len && (strncmp(s,n,l)==0)) {I=100+i; Len=l;}
217         if (also_v1_N_props) //recognize old properties symbols /=!
218         {
219            if (strcmp(n,"si")==0) n="/"; else
220            if (strcmp(n,"in")==0) n="="; else
221            if (strcmp(n,"fo")==0) n="!";
222            l=strlen(n);
223            if (len>=l && l>Len && (strncmp(s,n,l)==0)) {I=100+i; Len=l;}
224         }
225      }
226   }
227   Neuro n;
228   Param p=n.extraProperties();
229   for(int i=0;i<p.getPropCount();i++)
230   {
231      const char *n=p.id(i);
232      int l=strlen(n);
233      if (len>=l && l>Len && (strncmp(s,n,l)==0)) {I=i; Len=l;}
234   }
235   s+=Len;
236   return I;
237}
238
239bool GenoOperators::isWS(const char c)
240{return c==' ' || c=='\n' || c=='\t' || c=='\r';}
241
242void GenoOperators::skipWS(char *&s)
243{ if (!s) FramMessage("GenoOperators","skipWS","NULL reference!",1); else
244     while (isWS(*s)) s++;
245}
246
247bool GenoOperators::areAlike(char *g1,char *g2)
248{
249        while (*g1 || *g2)
250        {
251                skipWS(g1);
252                skipWS(g2);
253                if (*g1 != *g2) return false; //when difference
254      if (!*g1 && !*g2) break; //both end
255      g1++;
256      g2++;
257        }
258        return true; //equal
259}
260
261char* GenoOperators::strchrn0(const char *str,char ch)
262{ return ch==0?NULL:strchr((char*)str,ch); }
263
264bool GenoOperators::isNeuroClassName(const char firstchar)
265{
266   return isupper(firstchar) || firstchar=='|' || firstchar=='@' || firstchar=='*';
267}
268
Note: See TracBrowser for help on using the repository browser.