source: cpp/f0-fuzzy/geno_f0Fuzzy.cpp @ 97

Last change on this file since 97 was 2, checked in by Maciej Komosinski, 16 years ago

added f0-fuzzy (the Fuzzy neuron and its f0-based mutation and crossover)

File size: 56.6 KB
Line 
1#include <math.h> //HUGE_VAL
2#include "geno_f0Fuzzy.h"
3#include "neuroimpl-fuzzy.h"
4#include "neuroimpl-fuzzy-f0.h"
5#include "rndutil.h"
6#include "model.h"
7
8#define FIELDSTRUCT Geno_f0Fuzzy
9static ParamEntry GENO7param_tab[]=   //external access to f0Fuzzy genetic parameters
10{
11{"Genetics: f0-fuzzy",1,8,},
12{"f0Fuzzy_maxSets",0,0,"Max. sets","d 0 999",FIELD(maximumSetsNr),"Maximum number of fuzzy sets",},
13{"f0Fuzzy_maxRules",0,0,"Max. rules","d 0 999",FIELD(maximumRulesNr),"Maximum number of fuzzy rules",},
14{"f0Fuzzy_prob0",0,0,"Add new fuzzy set (with simple rule)","f 0 1",FIELD(probtab[F0Fuzzy_ADDSET]),"Probability of adding new fuzzy set with simple rule, which uses this set (1=proceed on all genes, 0.1=proceed on ten percent)",},
15{"f0Fuzzy_prob1",0,0,"Remove fuzzy set","f 0 1",FIELD(probtab[F0Fuzzy_REMSET]),"Probability of removing fuzzy set (1=proceed on all genes, 0.1=proceed on ten percent)",},
16{"f0Fuzzy_prob2",0,0,"Add new rule","f 0 1",FIELD(probtab[F0Fuzzy_ADDRULE]),"Probability of adding new rule (1=proceed on all genes, 0.1=proceed on ten percent)",},
17{"f0Fuzzy_prob3",0,0,"Remove rule","f 0 1",FIELD(probtab[F0Fuzzy_REMRULE]),"Probability of removing rule (1=proceed on all genes, 0.1=proceed on ten percent)",},
18{"f0Fuzzy_prob4",0,0,"Add new input/output to existing rule","f 0 1",FIELD(probtab[F0Fuzzy_MODRULE]),"Probability of adding new input or output to exisitng rule (1=proceed on all genes, 0.1=proceed on ten percent)",},
19{"f0Fuzzy_prob5",0,0,"Remove input/output from existing rule","f 0 1",FIELD(probtab[F0Fuzzy_MOD2RULE]),"Probability of removing input or output from exisitng rule (1=proceed on all genes, 0.1=proceed on ten percent)",},
20{0,},
21};
22#undef FIELDSTRUCT
23
24Geno_f0Fuzzy::Geno_f0Fuzzy()
25{
26  par.setParamTab(GENO7param_tab);
27  par.select(this);
28  supported_format='0';
29  name="Fuzzy control system";
30  maximumSetsNr=50;
31  maximumRulesNr=100;
32  probtab[F0Fuzzy_ADDSET] = 0.01;
33  probtab[F0Fuzzy_REMSET] = 0.0112;
34  probtab[F0Fuzzy_ADDRULE]= 0.01;
35  probtab[F0Fuzzy_REMRULE]= 0.0222; //when new set is created, new rule (using this new set) is also created but when rule is removed, unused set are removed too
36  probtab[F0Fuzzy_MODRULE] = 0.005;
37  probtab[F0Fuzzy_MOD2RULE] = 0.005;
38}
39
40char *Geno_f0Fuzzy::getSimplest()
41{
42  return "p:\np:1\nj:0,1\nn:d=\"G\",j=0\nn:d=\"|\",j=0\nn:d=\"Fuzzy: ns=1, nr=1, fs=-1;0;0;1;, fr=0;0:0;0/\"\nn:d=\"ChSel:ch=0\"\nc:2, 0\nc:3, 2\nc:1, 3\n";
43};
44
45int Geno_f0Fuzzy::markDuplicatedSets(const double fuzzySets1[], const int setsNr1, const double fuzzySets2[], const int setsNr2, int transTable[], const int setsNr3)
46{
47  if(setsNr1+setsNr2!=setsNr3) return -1;
48  int i, j;
49  for(i=0;i<setsNr1;i++)
50    for(j=0;j<setsNr2;j++)
51      if((fuzzySets1[4*i]==fuzzySets2[4*j])&&(fuzzySets1[4*i+1]==fuzzySets2[4*j+1])&&
52         (fuzzySets1[4*i+2]==fuzzySets2[4*j+2])&&(fuzzySets1[4*i+3]==fuzzySets2[4*j+3]))
53           transTable[setsNr1+j]=i; //mark equal sets
54  return 0;
55}
56
57
58int Geno_f0Fuzzy::nearestSet(double set[4], double sets[], int setsNr)
59{
60  int i, nearest=0;
61  double disCur, disNear;
62
63  disCur=disNear=10; //the largest distance i between -1;-1;-1;-1 and 1;1;1;1, and equals 8.
64  for(i=0;i<setsNr;i++)
65  {
66    disCur=fabs(sets[4*i]-set[0])+fabs(sets[4*i+1]-set[1])+
67           fabs(sets[4*i+2]-set[2])+fabs(sets[4*i+3]-set[3]);
68    if(disCur<disNear){ nearest=i; disNear=disCur; }
69  }
70
71  return nearest;
72}
73
74int Geno_f0Fuzzy::changeSetsNumeration(SString &rules, int transTable[], int nrItems)
75{
76  //for each rule (from rules string), change number of fuzzy set into new one
77  int pos=0;
78  SString oneRule, newRules;
79  while(rules.getNextToken(pos, oneRule, '/'))
80  {
81    SString cond, dec, nrStr;
82    int p=0, setNr;
83    char temp[10];
84    oneRule.getNextToken(p, cond, ':');
85    oneRule.getNextToken(p, dec, '/');
86    p=0;
87    while(cond.getNextToken(p, nrStr, ';')) //first: input number
88    {
89      newRules += nrStr; newRules += ";";
90      cond.getNextToken(p, nrStr, ';'); //then fuzzy set nr
91      if((setNr=atoi(nrStr))>=nrItems)
92        sprintf(temp, "%i", setNr); //might occur when new fuzzy set and new fuzzy rule added - does not need to be transformated
93      else
94        sprintf(temp, "%i", transTable[setNr]); //transformate set number
95      newRules += temp;
96      if(p<cond.len())
97        newRules += ";";
98    }
99    p=0; newRules += ":";
100    while(dec.getNextToken(p, nrStr, ';')) //first: output number
101    {
102      newRules += nrStr; newRules += ";";
103      dec.getNextToken(p, nrStr, ';'); //then fuzzy set nr
104      if((setNr=atoi(nrStr))>=nrItems)
105        sprintf(temp, "%i", setNr); //might occur when new fuzzy set and new fuzzy rule added - does not need to be transformated
106      else
107        sprintf(temp, "%i", transTable[setNr]); //transformate set number
108      newRules += temp;
109      if(p<dec.len())
110        newRules += ";";
111    }
112    newRules += "/";
113  }
114
115  rules=newRules;
116  return 0;
117}
118
119int Geno_f0Fuzzy::removeUnusedSets(SString &sets, SString rules, int &setsNr, int transTable[])
120{
121  //for each rule (from rules string), change number of fuzzy set into new one
122  int pos=0, i, nrUsedSets, *transTableOryginal = new int[setsNr];
123  bool *setUsed = new bool[setsNr], unusedPresent;
124  SString oneRule, newSets, nrStr;
125  for(i=0;i<setsNr;i++) { setUsed[i]=false; transTableOryginal[i]=transTable[i];} //copy oryginal values of trans table
126
127  //mark used sets
128  while(rules.getNextToken(pos, oneRule, '/'))
129  {
130    SString cond, dec;
131    int p=0, setNr;
132    oneRule.getNextToken(p, cond, ':');
133    oneRule.getNextToken(p, dec, '/');
134    p=0;
135    while(cond.getNextToken(p, nrStr, ';')) //first: input number
136    {
137      cond.getNextToken(p, nrStr, ';'); //then fuzzy set nr
138      setNr=atoi(nrStr);
139      if((setNr>=setsNr)||(setNr<0)) setNr=randomN(setsNr); //if everything ok, impossible to happen
140      setUsed[setNr]=true;
141    }
142    p=0;
143    while(dec.getNextToken(p, nrStr, ';')) //first: output number
144    {
145      dec.getNextToken(p, nrStr, ';'); //then fuzzy set nr
146      setNr=atoi(nrStr);
147      if((setNr>=setsNr)||(setNr<0)) setNr=randomN(setsNr); //if everything ok,impossible to happen
148      setUsed[setNr]=true;
149    }
150  }
151
152  for(i=0, nrUsedSets=0, unusedPresent=false;i<setsNr;i++)
153    if(setUsed[i]==false)
154    {
155      unusedPresent=true;
156      //change numbers in transTable - some set will be removed, so further renumeration is needed
157      for(int j=0;j<setsNr;j++) if(transTableOryginal[j]>i) transTable[j]--;
158    }
159    else
160      nrUsedSets++;
161
162  SAFEDELETEARRAY(transTableOryginal)
163
164  if(!unusedPresent)
165  {
166    SAFEDELETEARRAY(setUsed)
167    return 0; //all sets are necessery
168  }
169
170  //remove from new fuzzy sets unused sets
171  pos=0;
172  newSets="";
173  int semicol=0, nrOfSet=0;
174  SString tempSet="";
175  while(sets.getNextToken(pos, nrStr, ';'))
176  {
177    tempSet += nrStr; tempSet += ';';
178    if(++semicol==4)
179    {
180      if(setUsed[nrOfSet])
181        newSets += tempSet;
182      tempSet="";
183      semicol=0;
184      nrOfSet++;
185    }
186  }
187
188  setsNr=nrUsedSets;
189  sets=newSets;
190
191  SAFEDELETEARRAY(setUsed)
192
193  return 1;
194}
195
196int Geno_f0Fuzzy::removeExcessiveInOut(SString &rules, int inputsNr, int outputsNr)
197{
198  SString newRules, oneRule;
199  int pos, i;
200  char tempChar50[50];
201
202  pos=0;
203  while(rules.getNextToken(pos, oneRule, '/'))
204  {
205    SString cond, dec, nrStr, newInput, newOutput;
206    int p=0;
207    bool *usedInOut, first;
208
209    oneRule.getNextToken(p, cond, ':');
210    oneRule.getNextToken(p, dec, '/');
211
212    //create input table
213    usedInOut = new bool[inputsNr]; for(i=0;i<inputsNr;i++) usedInOut[i]=false;
214    //create new rule, which omits double inputs
215    p=0; newInput=""; first=true;
216    while(cond.getNextToken(p, nrStr, ';')) //first: input number
217    {
218      int inNr=atoi(nrStr), setNr;
219      cond.getNextToken(p, nrStr, ';'); //then fuzzy set nr
220      setNr=atoi(nrStr);
221      if(!usedInOut[inNr]) //not used yet
222      {
223        if(!first) newInput += ';';
224        first=false;
225        sprintf(tempChar50, "%i;%i", inNr, setNr);
226        newInput += tempChar50;
227        usedInOut[inNr]=true;
228      }
229    }
230    SAFEDELETEARRAY(usedInOut)
231
232    //create output table
233    usedInOut = new bool[outputsNr]; for(i=0;i<outputsNr;i++) usedInOut[i]=false;
234    //create new rule, which omits double outputs
235    p=0; newOutput=""; first=true;
236    while(dec.getNextToken(p, nrStr, ';')) //first: output number
237    {
238      int outNr=atoi(nrStr), setNr;
239      dec.getNextToken(p, nrStr, ';'); //then fuzzy set nr
240      setNr=atoi(nrStr);
241      if(!usedInOut[outNr]) //not used yet
242      {
243        if(!first) newOutput += ';';
244        first=false;
245        sprintf(tempChar50, "%i;%i", outNr, setNr);
246        newOutput += tempChar50;
247        usedInOut[outNr]=true;
248      }
249    }
250    SAFEDELETEARRAY(usedInOut)
251
252    newRules += newInput + ":" + newOutput + "/";
253  }
254
255  rules=newRules;
256
257  return 0;
258}
259
260int Geno_f0Fuzzy::removeExcessiveRules(SString &rules, int setsNr, int &rulesNr)
261{
262  int *rulDef, //for each rule, remembers number of inputs and number of outputs used (in rule)
263      **rulesBody, //for each rule, remembers: nr input, nr fuzzy set ... nr output, nr fuzzy set ...
264      i, j, k, l, nrRulesToRemove, pos, unimpTemp;
265  const int original_rulesNr=rulesNr;
266  bool *rulesToRemove = new bool[original_rulesNr];
267  SString newRules, oneRule;
268
269  for(i=0;i<original_rulesNr;i++) rulesToRemove[i]=false;
270  //create space for rules definition: number of inputs and outputs for each rule
271  rulDef = new int[2*original_rulesNr];
272  if(FuzzyF0String::countInputsOutputs(rules, rulDef, original_rulesNr))
273  {
274    SAFEDELETEARRAY(rulDef)
275    SAFEDELETEARRAY(rulesToRemove)
276    return -1; //error while parsing rules string
277  }
278  //create space for rules
279  rulesBody = new int*[original_rulesNr];   //list of rules that will contain rules body
280  for (i=0;i<original_rulesNr;i++) rulesBody[i] = new int[2*(rulDef[2*i]+rulDef[2*i+1])];  //each rule can have different number of inputs and outputs
281  //get from string rules body into integer variables
282  if(FuzzyF0String::convertStrToRules(rules, rulDef, rulesBody, setsNr, original_rulesNr, unimpTemp))
283  {
284    SAFEDELETEARRAY(rulDef)
285    if(rulesBody) for(i=0;i<original_rulesNr;i++) SAFEDELETEARRAY(rulesBody[i])
286    SAFEDELETEARRAY(rulesBody)
287    SAFEDELETEARRAY(rulesToRemove)
288    return -2; //error while parsing rules string
289  }
290
291  nrRulesToRemove=0;
292  for(i=0;i<original_rulesNr;i++) //for every rule...
293    for(j=i+1;j<original_rulesNr;j++) //...compare with further rule's...
294    {
295      int similarity=0;
296      if(rulDef[2*j]!=rulDef[2*i]) continue;// do not check rules with different number of inputs
297      for(k=0;k<rulDef[2*i];k++) //..conditional part rule i
298        for(l=0;l<rulDef[2*j];l++) //..conditional part rule j
299          if((rulesBody[i][k]==rulesBody[j][l])&&(rulesBody[i][k+1]==rulesBody[j][l+1])) //if inputs nr and fuzzy sets nr are the same
300            similarity++; //increase similarity number
301      //every input and fuzzy set number of rule j equals input and fuzzy set nr of rule i
302      if((similarity==rulDef[2*j])&&(similarity==rulDef[2*i]))
303      {
304        if(!rulesToRemove[j]) nrRulesToRemove++; //because might happen, that rule is mark to remove more than once
305        rulesToRemove[j]=true;
306      }
307    }
308
309  if(nrRulesToRemove>=original_rulesNr) //in fact, it is impossible; but it's safe to protect
310  {
311    SAFEDELETEARRAY(rulDef)
312    if(rulesBody) for(i=0;i<original_rulesNr;i++) SAFEDELETEARRAY(rulesBody[i])
313    SAFEDELETEARRAY(rulesBody)
314    SAFEDELETEARRAY(rulesToRemove)
315    return -3; //error while comparing rules
316  }
317
318  if(nrRulesToRemove>0)
319  {
320    int nrOfRule=0;
321    //copy rules, which are not to be removed
322    pos=0; newRules="";
323    while(rules.getNextToken(pos, oneRule, '/'))
324      if(!rulesToRemove[nrOfRule++]) newRules += oneRule + "/";
325    rulesNr -= nrRulesToRemove;
326    rules = newRules;
327  }
328
329  SAFEDELETEARRAY(rulDef)
330  if(rulesBody) for(i=0;i<original_rulesNr;i++) SAFEDELETEARRAY(rulesBody[i])
331  SAFEDELETEARRAY(rulesBody)
332  SAFEDELETEARRAY(rulesToRemove)
333
334  return 0;
335};
336
337int Geno_f0Fuzzy::sortSet(double set[4])
338{
339  int i,j;
340  double fTemp;
341  for(i=0;i<4;i++)
342  {
343    if(set[i]>1) set[i]=1;
344    if(set[i]<-1) set[i]=-1;
345    for(j=0;j<4;j++)
346      if((i>j)&&(set[i]<set[j]))
347      {fTemp=set[i];set[i]=set[j];set[j]=fTemp;};
348  }
349  return 0;
350}
351
352int Geno_f0Fuzzy::computeSet(double newSet[4])
353{ //parameters: most probably size of support and core
354  double core = min(fabs(0.15+0.25*RndGen.GaussStd()), 2.0), //core can not be bigger 2
355         coreStart = RndGen.Uni(-1,1);
356
357  if(0.5<rnd01)
358  {
359    newSet[0] = coreStart - min(fabs(0.15*RndGen.GaussStd()), 2.0);
360    newSet[1] = coreStart;
361    newSet[2] = newSet[1] + core;
362    newSet[3] = newSet[2] + min(fabs(0.15*RndGen.GaussStd()), 2.0);
363  }
364  else
365  {
366    newSet[2] = coreStart;
367    newSet[3] = newSet[2] + min(fabs(0.15*RndGen.GaussStd()), 2.0);
368    newSet[1] = newSet[2] - core;
369    newSet[0] = newSet[1] - min(fabs(0.15*RndGen.GaussStd()), 2.0);
370  }
371
372  sortSet(newSet);
373
374  return 0;
375}
376
377int Geno_f0Fuzzy::mutate(char *&g, float &chg,int &method)
378{
379  int const maxTrialNr=10; //maximum number of mutating trial, if for some reason drawed mutation can not be done
380  SString fuzzyGeno, finalGenotype, tok, newRulesStr, newSetsStr;
381  int newSetsNr, newRulesNr;
382  int i, pos, genoUsed, genoAdded, genoRemoved, nrTrials;
383  int *transTable;
384  char tempChar50[50];
385  bool mutated;
386
387  Model model(Geno(g, '0')); //create a model from genotype
388  Neuro *fuzzy=findNeuro(&model, Neuro::getClass("Fuzzy"));
389  if (!fuzzy) return GENOPER_OPFAIL; //if not present, fail
390  const int inputsNr=fuzzy->getInputCount(); //get number of inputs
391  const int outputsNr=NI_FuzzyNeuro::countOuts(&model, fuzzy); //count number of outputs
392
393  //get neuron four properties
394  SyntParam pi=fuzzy->classProperties();
395  model.open();
396  const int setsNr=pi.getIntById("ns");
397  const int rulesNr=pi.getIntById("nr");
398  const SString setsStr=pi.getStringById("fs");
399  const SString rulesStr=pi.getStringById("fr");
400
401  if((inputsNr<=0)||(outputsNr<=0)||
402     (setsStr.len()==0)||(rulesStr.len()==0)||(setsNr<=0)||(rulesNr<=0)) return GENOPER_OPFAIL; //ERROR
403
404  //find out the real length of genotype
405  fuzzyGeno = setsStr+", "+rulesStr;
406  genoRemoved=genoAdded=genoUsed=0; //1 geno is i.e. -0.325; but this are 7 characters! so, 1 is used, 6 are unused
407  for(i=0;i<fuzzyGeno.len();i++) //count genes in fuzzy genotype
408    if((fuzzyGeno[i]==';')||(fuzzyGeno[i]=='/')||(fuzzyGeno[i]==':')) genoUsed++;
409
410  //mutation - drawing
411  mutated=false;
412  for(nrTrials=0;(nrTrials<maxTrialNr)&&(!mutated);nrTrials++)
413  {
414    newSetsStr=""; newRulesStr=""; newSetsNr=0; newRulesNr=0;
415    switch(method=roulette(probtab, F0Fuzzy_COUNT))
416    {
417      case F0Fuzzy_ADDSET: //add new fuzzy set
418            if(setsNr>=maximumSetsNr) break;
419            double newSetD[4];
420            computeSet(newSetD); //draw set and rank rising
421            if(sprintf(tempChar50, "%.4lf;%.4lf;%.4lf;%.4lf;", newSetD[0], newSetD[1], newSetD[2], newSetD[3]) != EOF) //in fact, always true
422            {
423              newSetsStr = setsStr + tempChar50;
424              //add new rule, using fresh new created fuzzy set (in premise part) - prevents removing of new fuzzy set
425              if((sprintf(tempChar50, "%i;%i:%i;%i/", randomN(inputsNr), setsNr, randomN(outputsNr), randomN(setsNr+1)) != EOF)&& //in fact, always true; but if not, nothing wrong happens
426                 (rulesNr<maximumRulesNr))
427                { newRulesStr = rulesStr + tempChar50; newRulesNr=rulesNr+1; genoAdded+=4; }
428              newSetsNr=setsNr+1; //one more fuzzy set
429              genoAdded+=4; //four gens added
430              mutated=true;
431            }
432            break;
433      case F0Fuzzy_REMSET:{ //remove existing fuzzy set
434            if(setsNr<=1) break;
435            int setToRemove=randomN(setsNr), foundSetsPartNr=0;
436            pos=0;
437            //copy sets before set to remove
438            while((foundSetsPartNr!=4*setToRemove)&&(setsStr.getNextToken(pos, tok, ';')))
439              { newSetsStr += tok + ";"; foundSetsPartNr++; }
440            double removedSet[4];
441            //omit four numbers - one fuzzy set - and remember parameters of removed set
442            for(int ii=0;(ii<4)&&(setsStr.getNextToken(pos, tok, ';'));ii++) removedSet[ii]=atoi(tok);
443            //copy sets after set to remove
444            while(setsStr.getNextToken(pos, tok, ';'))
445              { newSetsStr += tok + ";"; foundSetsPartNr++; }
446            newSetsNr=setsNr-1;
447            newRulesNr=rulesNr;
448            //find the nearest set to removed one
449            double *newSets = new double[4*setsNr];
450            if(FuzzyF0String::convertStrToSets(newSetsStr, newSets, newSetsNr)!=0)
451              { SAFEDELETEARRAY(newSets) break; }
452            transTable = new int[setsNr];
453            for(int ii=0;ii<setToRemove;ii++) transTable[ii] = ii;
454            for(int ii=setToRemove;ii<setsNr;ii++) transTable[ii] = ii-1; //transformate
455            transTable[setToRemove]=nearestSet(removedSet, newSets, newSetsNr); //in rules, replace removed set with found nearest
456            SAFEDELETEARRAY(newSets)
457            //transformate old fuzzy sets number into new fuzzy sets number, according to transTable table
458            newRulesStr=rulesStr;
459            changeSetsNumeration(newRulesStr, transTable, setsNr);
460            SAFEDELETEARRAY(transTable)
461            //remove inputs/outputs which are unnecessery
462            //remove rules which are unnecessery: conditional part must be unique
463            //CAUTION: rules string and number of rules might change
464            if((removeExcessiveInOut(newRulesStr, inputsNr, outputsNr)<0)||
465               (removeExcessiveRules(newRulesStr, newSetsNr, newRulesNr)<0))
466               break;
467            genoRemoved+=4;
468            mutated=true;
469            break;
470            }
471      case F0Fuzzy_ADDRULE:{ //add new fuzzy rule
472            if(rulesNr>=maximumRulesNr) break;
473            SString tempSString;
474            bool ruleOk=true;
475            int nrIns=1+randomN(inputsNr), //draw number of inputs between {1,..,inputsNr}
476                nrOuts=1+randomN(outputsNr); //draw number of outputs between {1,..,outputsNr}
477            for(i=0;((i<(nrIns+nrOuts))&&(ruleOk));i++)
478              if(sprintf(tempChar50, "%i;%i", (i<nrIns)?randomN(inputsNr):randomN(outputsNr), randomN(setsNr)) != EOF) //write: in/out nr ; fuzzy set nr
479              {
480                tempSString += tempChar50;
481                if(i+1==nrIns) //end of conditional part
482                  tempSString += ':';
483                else if (i+1==nrIns+nrOuts) //end of rule
484                  tempSString += '/';
485                else
486                  tempSString += ';';
487              }
488              else
489                ruleOk = false; //error while transformating, do not add this rule
490            if(ruleOk)
491            {
492              tempSString = tempSString + rulesStr;
493              int temp_newRulesNr = rulesNr+1;
494              if((removeExcessiveInOut(tempSString, inputsNr, outputsNr)<0)||
495                 (removeExcessiveRules(tempSString, setsNr, temp_newRulesNr)<0)||
496                 (temp_newRulesNr != rulesNr+1)) //new added rule was removed, so there was no mutation in fact!
497                break;
498              newSetsStr = setsStr; newSetsNr = setsNr;//do not change sets
499              newRulesStr = tempSString; newRulesNr = temp_newRulesNr; //replace with new one
500              genoAdded+=2*(nrIns+outputsNr); //gens added: input, set, ... , output, set, ...
501              mutated=true;
502            }
503            break;
504            }
505      case F0Fuzzy_REMRULE:{ //remove existing fuzzy rule
506            if(rulesNr<=1) break;
507            int ruleToRemove=randomN(rulesNr), foundRuleNr=0;
508            pos=0;
509            //copy rules before rule to remove
510            while((foundRuleNr!=ruleToRemove)&&(rulesStr.getNextToken(pos, tok, '/')))
511              { newRulesStr += tok + "/"; foundRuleNr++; }
512            //omit this rule
513            rulesStr.getNextToken(pos, tok, '/');
514            for(int ii=0;ii<tok.len();ii++) if((tok[ii]==';')||(tok[ii]==':')||(tok[ii]=='/')) genoRemoved++;
515            //copy rules after rule to remove
516            while(rulesStr.getNextToken(pos, tok, '/'))
517              { newRulesStr += tok + "/"; foundRuleNr++; }
518            newRulesNr = rulesNr-1;
519            newSetsNr = setsNr; newSetsStr = setsStr;
520            // after removing of the rule, an unused fuzzy set(s) may occur
521            //create space for new transformation table
522            int *transTable = new int [newSetsNr];
523            for(int ii=0;ii<newSetsNr;ii++) transTable[ii]=ii; //formula 1:1 - no renumeration needed now
524            int oldSetNr=newSetsNr; //remember number of sets used in new genotype, but before reduction
525            //remove unused sets; if any set was removed, renumeration is needed
526            if(removeUnusedSets(newSetsStr, newRulesStr, newSetsNr, transTable))
527              changeSetsNumeration(newRulesStr, transTable, oldSetNr); //renumerate new sets
528            SAFEDELETEARRAY(transTable);
529            mutated=true;
530            break;
531            }
532      case F0Fuzzy_MODRULE:{ //modify fuzzy rule: add new input/output
533            int ruleToChange=randomN(rulesNr), foundRuleNr=0;
534            SString modRule, cond, dec, tempStr;
535            pos=0;
536            //copy rules before rule to change
537            while((foundRuleNr!=ruleToChange)&&(rulesStr.getNextToken(pos, tok, '/')))
538              { newRulesStr += tok + "/"; foundRuleNr++; }
539            //change this rule
540            rulesStr.getNextToken(pos, modRule, '/');
541            //copy rules after rule to remove
542            while(rulesStr.getNextToken(pos, tok, '/'))
543              { newRulesStr += tok + "/"; foundRuleNr++; }
544            pos=0;
545            modRule.getNextToken(pos, cond, ':');
546            modRule.getNextToken(pos, dec, '/');
547            if(0.5<rnd01) //add input
548            { if(sprintf(tempChar50, ";%i;%i", randomN(inputsNr), randomN(setsNr)) != EOF) //write: in nr ; fuzzy set nr
549                cond += tempChar50;
550              else break;
551            }
552            else //add output
553            { if(sprintf(tempChar50, ";%i;%i", randomN(outputsNr), randomN(setsNr)) != EOF) //write: in nr ; fuzzy set nr
554                dec += tempChar50;
555              else break;
556            }
557            tempStr = newRulesStr + cond + ":" + dec + "/";
558            int temp_rulesNr = rulesNr;
559            if((removeExcessiveInOut(tempStr, inputsNr, outputsNr)<0)||
560               (removeExcessiveRules(tempStr, setsNr, temp_rulesNr)<0)||
561               (temp_rulesNr != rulesNr)) //new added in/out caused duplicated rule, so this mutation is not ok - try other
562              break;
563            newRulesStr = tempStr;
564            newRulesNr = rulesNr; newSetsStr = setsStr; newSetsNr = setsNr;
565            genoAdded+=2;
566            mutated=true;
567            break;
568            }
569      case F0Fuzzy_MOD2RULE:{ //modify fuzzy rule: remove existing input/output
570            int ruleToChange=randomN(rulesNr), foundRuleNr=0;
571            SString modRule, cond, dec, tempStr;
572            pos=0;
573            //copy rules before rule to change
574            while((foundRuleNr!=ruleToChange)&&(rulesStr.getNextToken(pos, tok, '/')))
575              { newRulesStr += tok + "/"; foundRuleNr++; }
576            //change this rule
577            rulesStr.getNextToken(pos, modRule, '/');
578            //copy rules after rule to remove
579            while(rulesStr.getNextToken(pos, tok, '/'))
580              { newRulesStr += tok + "/"; foundRuleNr++; }
581            pos=0;
582            modRule.getNextToken(pos, cond, ':');
583            modRule.getNextToken(pos, dec, '/');
584            pos=0;
585            if(0.5<rnd01) //remove input
586            {
587              int nrIns=0;
588              while(cond.getNextToken(pos, tok, ';'))nrIns++;
589              nrIns = 1 + nrIns/2; //odd number of semicolons, so 1 + ...
590              if(nrIns<=1) break; //can not remove - only one input!
591              int nrInToRem=randomN(nrIns), insFound=0;
592              //copy inputs before one to remove
593              while((insFound<nrInToRem)&&(cond.getNextToken(pos, tok, ';')))
594              {
595                if(insFound>0) tempStr += ";"; //add semic. before input number
596                tempStr += tok + ";"; //input number
597                cond.getNextToken(pos, tok, ';');
598                tempStr += tok; //set number
599                insFound++;
600              }
601              if((!cond.getNextToken(pos, tok, ';'))||(!cond.getNextToken(pos, tok, ';'))) //ommit selected input
602                break; //error
603              //copy inputs after one to remove
604              while(cond.getNextToken(pos, tok, ';'))
605              {
606                tempStr += ";"; tempStr += tok + ";"; //input number
607                cond.getNextToken(pos, tok, ';');
608                tempStr += tok; //set number
609              }
610              modRule = newRulesStr + tempStr + ":" + dec + "/";
611            }
612            else //remove output
613            {
614              int nrOuts=0;
615              while(dec.getNextToken(pos, tok, ';'))nrOuts++;
616              nrOuts = 1 + nrOuts/2; //odd number of semicolons, so 1 + ...
617              if(nrOuts<=1) break; //can not remove - only one input!
618              int nrOutToRem=randomN(nrOuts), outsFound=0;
619              //copy outputs before one to remove
620              while((outsFound<nrOutToRem)&&(dec.getNextToken(pos, tok, ';')))
621              {
622                if(outsFound>0) tempStr += ";"; //add semic. before output number
623                tempStr += tok + ";"; //output number
624                dec.getNextToken(pos, tok, ';');
625                tempStr += tok; //set number
626                outsFound++;
627              }
628              if((!dec.getNextToken(pos, tok, ';'))||(!dec.getNextToken(pos, tok, ';'))) //ommit selected output
629                break; //error
630              //copy outputs after one to remove
631              while(dec.getNextToken(pos, tok, ';'))
632              {
633                tempStr += ";"; tempStr += tok + ";"; //output number
634                dec.getNextToken(pos, tok, ';');
635                tempStr += tok; //set number
636              }
637              modRule = newRulesStr + cond + ":" + tempStr + "/";
638            }
639            tempStr = newRulesStr + modRule;
640            int temp_rulesNr = rulesNr;
641            if((removeExcessiveInOut(tempStr, inputsNr, outputsNr)<0)||
642               (removeExcessiveRules(tempStr, setsNr, temp_rulesNr)<0)||
643               (temp_rulesNr != rulesNr)) //removed in/out caused duplicated rule, so this mutation is not ok - try other
644              break;
645            newRulesStr = tempStr;
646            newRulesNr = rulesNr; newSetsStr = setsStr; newSetsNr = setsNr;
647            genoRemoved+=2;
648            // after removing of an input/output from the rule, an unused fuzzy set may occur
649            //create space for new transformation table
650            int *transTable = new int [newSetsNr];
651            for(int ii=0;ii<newSetsNr;ii++) transTable[ii]=ii; //formula 1:1 - no renumeration needed now
652            int oldSetNr=newSetsNr; //remember number of sets used in new genotype, but before reduction
653            //remove unused sets; if any set was removed, renumeration is needed
654            if(removeUnusedSets(newSetsStr, newRulesStr, newSetsNr, transTable))
655              changeSetsNumeration(newRulesStr, transTable, oldSetNr); //renumerate new sets
656            SAFEDELETEARRAY(transTable);
657            mutated=true;
658            break;
659            }
660    }
661  }
662
663  if(!mutated)
664    return GENOPER_OPFAIL;
665
666  //update new genotype
667  pi.setIntById("ns", newSetsNr);
668  pi.setIntById("nr", newRulesNr);
669  pi.setStringById("fs",newSetsStr);
670  pi.setStringById("fr",newRulesStr);
671  pi.update(); //force commit changes
672  model.close();
673  //get creature whole genotype
674  finalGenotype=model.getF0Geno().getGene();
675
676  //replace old genotype with new one
677  free(g);
678  g=strdup((const char*)finalGenotype);
679
680  chg=(float)(genoAdded+genoRemoved)/(genoAdded+genoRemoved+max(genoUsed-genoRemoved, 0));
681
682  return GENOPER_OK;
683}
684
685int Geno_f0Fuzzy::checkOrValidate(char *&geno, bool repair)
686//checks or validates genotype (depends on repair param)
687{ //all genotype received, but only fuzzy part is to be validated!!!
688  //"Fuzzy: [declarations], [sets], [rules]"
689  SString tok, repairedSets, repairedRules, finalGenotype;
690  char tempChar50[50];
691  int pos=0, i, j, setsFound, rulesFound;
692  double set[4];
693
694  Model model(Geno(geno,'0'));
695  if (!(model.isValid())) { if(repair) return GENOPER_OK; else return 1; } //ERROR
696  Neuro *fuzzy=findNeuro(&model, Neuro::getClass("Fuzzy"));
697  if (!fuzzy) { if(repair) return GENOPER_OK; else return 1; } //ERROR
698  const int inputsDeclared=fuzzy->getInputCount();
699  const int outputsDeclared=NI_FuzzyNeuro::countOuts(&model,fuzzy);
700  if((inputsDeclared<=0)||(outputsDeclared<=0))
701    { if(repair) return GENOPER_OK; else return 1; } //ERROR
702
703  //get neuron four properties
704  SyntParam pi=fuzzy->classProperties();
705  model.open();
706  int setsDeclared=pi.getIntById("ns");
707  int rulesDeclared=pi.getIntById("nr");
708  const SString fuzzySets=pi.getStringById("fs");
709  const SString fuzzyRules=pi.getStringById("fr");
710
711  //unrepairable errors: there must be some string!
712  if((fuzzySets.len()==0)||(fuzzyRules.len()==0))
713    if(repair) return GENOPER_OK; //ERROR
714    else return 2; //ERROR
715
716  if((!repair)&&((setsDeclared<=0)||(rulesDeclared<=0)))
717    return 2; //ERROR
718
719  //repair if corrupted
720  if(setsDeclared<=0)setsDeclared=1;
721  if(rulesDeclared<=0)rulesDeclared=1;
722
723  //now fuzzy sets are defined; each number is separated with semicolon.
724  //acceptables signs are: digits, commas, colons, semicolons.
725  i=j=0; setsFound=0;
726  while (j<fuzzySets.len())
727  {
728    SString acceptSigns; //string with acceptable signs
729    fuzzySets.getNextToken(j,tok,';');
730    if(tok.len()==0) { if(!repair) return j; else continue; }//might happen, when two semicolons stand side by side
731    //copy only acceptable signs
732    for(int ii=0;ii<tok.len();ii++)
733      if(strchr("0123456789.-;", tok[ii])) acceptSigns += tok[ii];
734      else if(!repair) return j;
735    set[i]=atof(acceptSigns);
736    if(set[i]<-1) { if(!repair) return j; else set[i] = -1; }//out of range
737    if(set[i]>1) { if(!repair) return j; else set[i] = 1; }//out of range
738    if(set[i]==HUGE_VAL) { if(!repair) return j; else set[i] = (i>0?set[i-1]:-1); }//sets must not be decreasing
739
740    if(++i==4)
741    {
742      //check if sets are rank rising
743      if((set[0]>set[1])||(set[1]>set[2])||(set[2]>set[3]))
744        { if(!repair) return j; else sortSet(set); }
745      if(sprintf(tempChar50, "%.4lf;%.4lf;%.4lf;%.4lf;", set[0], set[1], set[2], set[3]) != EOF)
746        {i=0; setsFound++; repairedSets += tempChar50;} //copy correct value
747    }
748
749    if((setsFound==setsDeclared)&&(repair))
750      break; //found enough sets - if there were some sets left, omit them
751  }
752  // valitadion: if there were more sets than declares, nothing happens, because pointer is now after comma (end of all sets)
753  // checking: error
754  if((setsFound!=setsDeclared)&&(!repair))
755    return j; //ERROR - wrong number of fuzzy sets in definition or abnormal end of the string
756
757  //now fuzzy rules are defined; each number is separated with semicolon, conditional and decisional part is separated with colon, rules are separated with slash
758  //acceptables signs are: digits, semicolons, colons, slashes.
759  i=0; rulesFound=0; pos=0;
760  while (pos<fuzzyRules.len()) //to the end of string - process loop for each rule
761  {
762    SString ruleSStr, ruleCondisSStr, ruleDecisSStr, nrSStr, acceptSigns;
763    int posRule=0, colons, i, posTemp, inputsUsedNr, outputsUsedNr;
764    int *inoutUsed, posOld;
765    bool firstInput, firstOutput;
766
767    posOld=pos; acceptSigns = "";
768    fuzzyRules.getNextToken(pos,ruleSStr,'/');
769    for(int ii=0;ii<pos-posOld;ii++)
770      if(strchr("0123456789;:/", ruleSStr[ii]))
771        acceptSigns += ruleSStr[ii];
772      else if(!repair) return j+pos; //ERROR - unacceptable sign
773    //cut conditional part
774    acceptSigns.getNextToken(posRule,ruleCondisSStr,':');
775    //cut decisional part
776    acceptSigns.getNextToken(posRule,ruleDecisSStr,'/');
777
778    //check, how many inputs is used:
779    colons=posRule=0;
780    while(++posRule<ruleCondisSStr.len())
781      if(ruleCondisSStr[posRule]==';') colons++;
782    if(!(colons%2)) //nr of colons must be odd. this rule is corrupted
783      {if(!repair) return j+pos; else continue; }//check another rule
784
785    inputsUsedNr=(colons+1)/2; //count nr of inputs
786    if((inputsUsedNr>inputsDeclared)&&(!repair))
787      return j+pos; //ERROR: too many inputs
788    //when repair: if inputsUsedNr > declared, do nothing, because later in loop it is checked whether
789    //there is no duplicate input number (the only possible way of situation where inputsUsedNr > declared)
790
791    //check how many outputs is used:
792    colons=posRule=0;
793    while(++posRule<ruleDecisSStr.len())
794      if(ruleDecisSStr[posRule]==';') colons++;
795    if(!(colons%2)) //nr of colons must be odd. this rule is corrupted - omit one
796      {if(!repair) return j+pos; else continue; }//check another rule
797
798    outputsUsedNr=(colons+1)/2; //count nr of outputs
799    if((outputsUsedNr>outputsDeclared)&&(!repair))
800      return j+pos; //ERROR: too many outputs
801    //when repair: if outputsUsedNr > declared, do nothing, because later in loop it is checked, wether
802    //there is no duplicate output number (the only possible way of situation where outputsUsedNr > declared)
803    inoutUsed = new int[max(inputsDeclared,outputsDeclared)];
804    for(i=0;i<max(inputsDeclared,outputsDeclared);i++) inoutUsed[i]=0; //0=unused, -1 = used by input, +1 used by output
805    firstInput=true; firstOutput=true;
806    //check, whether inputs/outputs or fuzzy set nr is not out of range
807    //and check, whether there is no duplicate input/output number
808    for(i=0,posTemp=0;i<inputsUsedNr+outputsUsedNr;i++)
809    {
810      int tempVal;
811      if(i==inputsUsedNr) posTemp=0; //because in decision string - parse string from begin
812      if(i<inputsUsedNr) //concern inputs
813      {
814        //check input
815        acceptSigns = ""; posOld=posTemp;
816        ruleCondisSStr.getNextToken(posTemp,nrSStr,';');
817        for(int ii=0;ii<nrSStr.len();ii++)
818          if(strchr("0123456789", nrSStr[ii]))
819            acceptSigns += nrSStr[ii];
820          else if(!repair) {SAFEDELETEARRAY(inoutUsed) return j+pos;} //ERROR - out of range
821        tempVal=atoi(acceptSigns);
822        if(tempVal<0)
823          {if(!repair) {SAFEDELETEARRAY(inoutUsed) return j+pos;} else tempVal=0;}
824        if(tempVal>=inputsDeclared)
825          {if(!repair) {SAFEDELETEARRAY(inoutUsed) return j+pos;} else tempVal=inputsDeclared-1; }
826        if(inoutUsed[tempVal]==-1) //input is used
827        {
828          ruleCondisSStr.getNextToken(posTemp,nrSStr,';'); //omit input and fuzzy set
829          if(i+1 == inputsUsedNr) repairedRules += ":"; //the end of conditional part - must be here, because of continue
830          if(!repair) {SAFEDELETEARRAY(inoutUsed) return j+pos;} else continue;//next for loop
831        }
832        else
833          inoutUsed[tempVal]=-1; //used by input
834        if(!firstInput) repairedRules += ";"; //before input there is semicolon, except of begin of the rule
835        firstInput=false;
836        //tempVal now has a correct value
837        sprintf(tempChar50, "%i;", tempVal);
838        //correct input number:
839        repairedRules += tempChar50;
840        //check fuzzy set nr
841        acceptSigns = ""; posOld=posTemp;
842        ruleCondisSStr.getNextToken(posTemp,nrSStr,';');
843        for(int ii=0;ii<nrSStr.len();ii++)
844          if(strchr("0123456789", nrSStr[ii]))
845            acceptSigns += nrSStr[ii];
846          else if(!repair) {SAFEDELETEARRAY(inoutUsed) return j+pos;}
847      }
848      else //concern output
849      {
850        //check output
851        acceptSigns = ""; posOld=posTemp;
852        ruleDecisSStr.getNextToken(posTemp,nrSStr,';');
853        for(int ii=0;ii<nrSStr.len();ii++)
854          if(strchr("0123456789", nrSStr[ii]))
855            acceptSigns += nrSStr[ii];
856          else if(!repair) {SAFEDELETEARRAY(inoutUsed) return j+pos;}
857        tempVal=atoi(acceptSigns);
858        if(tempVal<0)
859          {if(!repair) {SAFEDELETEARRAY(inoutUsed) return j+pos;} else tempVal=0;}
860        if(tempVal>=outputsDeclared)
861          {if(!repair) {SAFEDELETEARRAY(inoutUsed) return j+pos;} else tempVal=outputsDeclared-1; }
862        if(inoutUsed[tempVal]==1) //output is used
863        {
864          ruleDecisSStr.getNextToken(posTemp,nrSStr,';'); //omit output and fuzzy set
865          if (i+1 == inputsUsedNr+outputsUsedNr) repairedRules += "/"; //the end of decisional part - must be here, because of continue
866          if(!repair) {SAFEDELETEARRAY(inoutUsed) return j+pos;} else continue; //next for loop
867        }
868        else
869          inoutUsed[tempVal]=1; //used by output
870        if(!firstOutput) repairedRules += ";"; //before output there is semicolon, except of begin of the decisional part of the rule
871        firstOutput=false;
872        //tempVal now has a correct value
873        sprintf(tempChar50, "%i;", tempVal);
874        //correct output number:
875        repairedRules += tempChar50;
876        //check fuzzy set nr
877        acceptSigns = ""; posOld=posTemp;
878        ruleDecisSStr.getNextToken(posTemp,nrSStr,';');
879        for(int ii=0;ii<nrSStr.len();ii++)
880          if(strchr("0123456789", nrSStr[ii]))
881            acceptSigns += nrSStr[ii];
882          else if(!repair) {SAFEDELETEARRAY(inoutUsed) return j+pos;}
883      }
884      tempVal=atoi(acceptSigns);
885      if(tempVal<0)
886        {if(!repair) {SAFEDELETEARRAY(inoutUsed) return j+pos;} else tempVal=0;}
887      if(tempVal>=setsFound)
888        {if(!repair) {SAFEDELETEARRAY(inoutUsed) return j+pos;} else tempVal=setsFound-1; }
889      //tempVal now has a correct value
890      sprintf(tempChar50, "%i", tempVal);
891      //correct set number:
892      repairedRules += tempChar50;
893      if(i+1 == inputsUsedNr) repairedRules += ":"; //the end of conditional part
894      else if (i+1 == inputsUsedNr+outputsUsedNr) repairedRules += "/"; //the end of decisional part
895    }
896    SAFEDELETEARRAY(inoutUsed)
897    rulesFound++;
898    if ((rulesFound>=rulesDeclared)&&(repair))
899      break; //if there was more rules - omit them by not parsing any more
900    if ((rulesFound>rulesDeclared)&&(!repair))
901      return j+pos; // ERROR - too many rules - stop parsing
902  }
903
904  if ((rulesFound!=rulesDeclared)&&(!repair))
905    return j+pos; // ERROR - wrong number of rules (too few)
906
907  if(rulesFound<1) //could happen, when there is one rule and it is unrepairable
908  {
909    if(sprintf(tempChar50, "%i;%i:%i;%i/", randomN(inputsDeclared), randomN(setsFound), randomN(outputsDeclared), randomN(setsFound)) != EOF)
910      repairedRules += tempChar50; //add simple random rule
911    else //on error - add zeros
912      repairedRules += "0;0:0;0/"; //add the simplies rule, but almost impossible to happen
913    rulesFound=1;
914  }
915
916  //when changing sets numerations, rules might change and equals
917  if((repair)&&(removeExcessiveRules(repairedRules, setsFound, rulesFound)<0))
918    return GENOPER_OPFAIL; //ERROR
919
920  //update new genotype
921  pi.setIntById("ns", setsFound);
922  pi.setIntById("nr", rulesFound);
923  pi.setStringById("fs",repairedSets);
924  pi.setStringById("fr",repairedRules);
925  pi.update(); //force commit changes
926  model.close();
927  //get creature whole genotype
928  finalGenotype=model.getF0Geno().getGene();
929
930  //replace old genotype with new one
931  free(geno);
932  geno=strdup((const char*)finalGenotype);
933
934  return GENOPER_OK;
935};
936
937int Geno_f0Fuzzy::checkValidity(const char *geno)
938{
939  char *genoCopy=strdup(geno);
940  int res=checkOrValidate(genoCopy, false); //false = on errors do not repair but return error position
941  free(genoCopy);
942  return res;
943};
944
945int Geno_f0Fuzzy::validate(char *&geno)
946{
947  checkOrValidate(geno, true); //true = on errors try to repair but might be unrepairable
948  return GENOPER_OK;
949};
950
951int Geno_f0Fuzzy::crossOver(char *&g1, char *&g2, float &chg1,float &chg2)
952{ //both bodies should be the same; the only difference should be in fuzzy neuron
953
954  SString finalGenotype, tok1, tok2;
955  SString fuzzyGeno1, fuzzyGeno2, newSet, sets3, rules3;
956  int setsNr3, rulesNr3;
957  int i, j, k, unimpTemp;
958  int *transTable, *parentsIn, *parentsOut, *parentRules, *rulDef1, *rulDef2, *rulDef3, **rulesBody1, **rulesBody2;
959  int genoUsed1, genoUsed2, copied1, copied2, rulesTaken1, rulesTaken2, rulesUsed3, selectedRule1, selectedRule2;
960  int inputsUsed, outputsUsed;
961  char tempChar50[50];
962  double *fuzzySets1, *fuzzySets2, *fuzzySets3;
963
964  Model model1(Geno(g1,'0'));
965  Model model2(Geno(g2,'0'));
966  Neuro *fuzzy1=findNeuro(&model1, Neuro::getClass("Fuzzy"));
967  Neuro *fuzzy2=findNeuro(&model2, Neuro::getClass("Fuzzy"));
968  if (!fuzzy1 || !fuzzy2) return GENOPER_OPFAIL; //ERROR
969  const int inputsNr1=fuzzy1->getInputCount();
970  const int inputsNr2=fuzzy2->getInputCount();
971  const int outputsNr1=NI_FuzzyNeuro::countOuts(&model1,fuzzy1);
972  const int outputsNr2=NI_FuzzyNeuro::countOuts(&model2,fuzzy2);
973  if((inputsNr1<=0)||(outputsNr1<=0)||(inputsNr2<=0)||(outputsNr2<=0)||
974     (inputsNr1!=inputsNr2)||(outputsNr1!=outputsNr2)) return GENOPER_OPFAIL; //ERROR
975
976  //get neurons four properties
977  SyntParam pi1=fuzzy1->classProperties();
978  SyntParam pi2=fuzzy2->classProperties();
979  model1.open();
980  model2.open();
981  const int setsNr1=pi1.getIntById("ns");
982  const int setsNr2=pi2.getIntById("ns");
983  const int rulesNr1=pi1.getIntById("nr");
984  const int rulesNr2=pi2.getIntById("nr");
985  const SString sets1=pi1.getStringById("fs");
986  const SString sets2=pi2.getStringById("fs");
987  const SString rules1=pi1.getStringById("fr");
988  const SString rules2=pi2.getStringById("fr");
989
990  if((sets1.len()==0)||(rules1.len()==0)||(sets2.len()==0)||(rules2.len()==0)||
991     (setsNr1<=0)||(rulesNr1<=0)||(setsNr2<=0)||(rulesNr2<=0))
992    return GENOPER_OPFAIL; //ERROR
993
994  //find out the real length of genotype - count number of semicolons
995  genoUsed1 = 0; //1 geno is i.e. -0.325; but this are 7 characters! so, 1 is used, 6 are unused
996  fuzzyGeno1 = sets1+", "+rules1;
997  for(i=0;i<fuzzyGeno1.len();i++)
998    if((fuzzyGeno1[i]==';')||(fuzzyGeno1[i]=='/')||(fuzzyGeno1[i]==':')) genoUsed1++;
999  genoUsed2 = 0; //1 geno is i.e. -0.325; but this are 7 characters! so, 1 is used, 6 are unused
1000  fuzzyGeno2 = sets2+", "+rules2;
1001  for(i=0;i<fuzzyGeno2.len();i++)
1002    if((fuzzyGeno2[i]==';')||(fuzzyGeno2[i]=='/')||(fuzzyGeno2[i]==':')) genoUsed2++;
1003
1004
1005  // -------------------------------------
1006  // ------- cross over sets part --------
1007  // -------------------------------------
1008
1009  copied1=copied2=0; //how many gens (in whole rules and whole sets) were copied (without changeing!) from parent 1 / 2 ?
1010
1011  fuzzySets1 = new double[4*setsNr1]; fuzzySets2 = new double[4*setsNr2];
1012  FuzzyF0String::convertStrToSets(sets1, fuzzySets1, setsNr1);
1013  FuzzyF0String::convertStrToSets(sets2, fuzzySets2, setsNr2);
1014
1015  //in fact, there is no crossing over of sets, but copy all parents' sets
1016  //with marking duplicated sets
1017  setsNr3 = setsNr1+setsNr2;
1018  transTable = new int[setsNr3];
1019  for(i=0;i<setsNr1+setsNr2;i++) transTable[i]=-2; //all sets are taken to descendant
1020  if(markDuplicatedSets(fuzzySets1, setsNr1, fuzzySets2, setsNr2, transTable, setsNr3)!=0)
1021    {
1022      SAFEDELETEARRAY(fuzzySets1) SAFEDELETEARRAY(fuzzySets2) SAFEDELETEARRAY(transTable)
1023      return GENOPER_OPFAIL; //ERROR
1024    }
1025
1026  fuzzySets3 = new double[4*setsNr3];
1027  j=0; sets3 = "";
1028  //copy sets from parent 1 and 2
1029  for(i=0;(i<setsNr1+setsNr2)&&(j<setsNr3);i++)
1030    if(transTable[i]==-2) //this set is marked to be taken
1031    {
1032      if(i<setsNr1)
1033      {
1034        fuzzySets3[4*j]=fuzzySets1[4*i]; fuzzySets3[4*j+1]=fuzzySets1[4*i+1];
1035        fuzzySets3[4*j+2]=fuzzySets1[4*i+2]; fuzzySets3[4*j+3]=fuzzySets1[4*i+3];
1036      }
1037      else
1038      {
1039        fuzzySets3[4*j]=fuzzySets2[4*(i-setsNr1)]; fuzzySets3[4*j+1]=fuzzySets2[4*(i-setsNr1)+1];
1040        fuzzySets3[4*j+2]=fuzzySets2[4*(i-setsNr1)+2]; fuzzySets3[4*j+3]=fuzzySets2[4*(i-setsNr1)+3];
1041      };
1042      if(sprintf(tempChar50, "%.4lf;%.4lf;%.4lf;%.4lf;", fuzzySets3[4*j], fuzzySets3[4*j+1], fuzzySets3[4*j+2], fuzzySets3[4*j+3]) != EOF)
1043      {
1044        transTable[i] = j++; //remember, from which set it was copy: [4]=2 means that fuzzy set [4] from parent 1 was copy into descendant fuzzy set [2]. when i>setsNr1, substract setsNr1 from value to obtain number of fuzzy set from parent 2
1045        sets3 += tempChar50;
1046      }
1047      else
1048      {
1049        SAFEDELETEARRAY(fuzzySets1)
1050        SAFEDELETEARRAY(fuzzySets2)
1051        SAFEDELETEARRAY(fuzzySets3)
1052        SAFEDELETEARRAY(transTable)
1053        return GENOPER_OPFAIL; //ERROR
1054      }
1055    }
1056
1057  // -------------------------------------
1058  // ------- cross over rules part -------
1059  // -------------------------------------
1060
1061  rules3="";
1062  //draw number of fuzzy rules for the descendant
1063  rulesNr3 = min(rulesNr1,rulesNr2) + randomN(abs(rulesNr1-rulesNr2)+1);
1064
1065  rulDef1 = new int[2*rulesNr1]; //for each rule, remembers number of inputs and number of outputs used (in rule)
1066  rulDef2 = new int[2*rulesNr2];
1067  rulDef3 = new int[2*rulesNr3]; //it will be filled later, with random values
1068
1069  FuzzyF0String::countInputsOutputs(rules1, rulDef1, rulesNr1);
1070  FuzzyF0String::countInputsOutputs(rules2, rulDef2, rulesNr2);
1071  for(i=0;i<2*rulesNr3;i++) rulDef3[i]=-1; //unknown number of inputs/outputs
1072
1073  //create space for rules from parent 1 and 2
1074  rulesBody1 = new int*[rulesNr1];   //list of rules that will contain rules body
1075  for (i=0;i<rulesNr1;i++) rulesBody1[i] = new int[2*(rulDef1[2*i]+rulDef1[2*i+1])];  //each rule can have different number of inputs and outputs
1076  rulesBody2 = new int*[rulesNr2];   //list of rules that will contain rules body
1077  for (i=0;i<rulesNr2;i++) rulesBody2[i] = new int[2*(rulDef2[2*i]+rulDef2[2*i+1])];  //each rule can have different number of inputs and outputs
1078
1079  FuzzyF0String::convertStrToRules(rules1, rulDef1, rulesBody1, setsNr1, rulesNr1, unimpTemp);
1080  FuzzyF0String::convertStrToRules(rules2, rulDef2, rulesBody2, setsNr2, rulesNr2, unimpTemp);
1081
1082  //draw rules from both parents
1083  parentRules = new int[rulesNr1+rulesNr2];
1084  for(i=0;i<rulesNr1+rulesNr2;i++) parentRules[i]=-1; //any rule is taken yet
1085
1086  rulesTaken1=rulesTaken2=rulesUsed3=0;
1087  while(rulesUsed3<rulesNr3)
1088  {
1089   //draw rule from parent 1
1090   selectedRule1=-1;
1091   if(rulesTaken1<rulesNr1) //if there are some rules left in parent 1
1092   {
1093    //select random rule from parent 1
1094    k=randomN(rulesNr1);
1095    if(parentRules[k]==-1) selectedRule1=k;
1096    else //if rule is taken, search the nearest free
1097      for(j=0;j<rulesNr1;j++)
1098        if(parentRules[(k+j)%rulesNr1]==-1) { selectedRule1=(k+j)%rulesNr1; j=rulesNr1; }
1099        else if(parentRules[abs((k-j)%rulesNr1)]==-1) { selectedRule1=abs((k-j)%rulesNr1); j=rulesNr1; }
1100   }
1101   if (selectedRule1==-1) //all rules are taken from parent 1
1102     break;
1103
1104   //draw rule from parent 2
1105   selectedRule2=-1;
1106   if(rulesTaken2<rulesNr2) //if there are some rules left in parent 2
1107   {
1108    //select random rule from parent 2
1109    k=randomN(rulesNr2);
1110    if(parentRules[rulesNr1+k]==-1) { parentRules[rulesNr1+k]=-2; selectedRule2=k; } //mark as 'taken'
1111    else //if rule is taken, search the nearest free
1112      for(j=0;j<rulesNr2;j++)
1113        if(parentRules[rulesNr1+(k+j)%rulesNr2]==-1) {selectedRule2=(k+j)%rulesNr2; j=rulesNr2; }
1114        else if(parentRules[rulesNr1+abs((k-j)%rulesNr2)]==-1) { selectedRule2=abs((k-j)%rulesNr2); j=rulesNr2; }
1115   }
1116
1117   if (selectedRule2==-1) //all rules are taken from parent 1
1118     break;
1119
1120   parentRules[selectedRule1]=-2;  //mark as 'taken'
1121   parentRules[rulesNr1+selectedRule2]=-2;
1122
1123   //draw number of inputs and outputs in new rule, (created by crossing over of 2 parents)
1124   rulDef3[2*rulesUsed3] = min(rulDef1[2*selectedRule1], rulDef2[2*selectedRule2]) + randomN(abs(rulDef1[2*selectedRule1]-rulDef2[2*selectedRule2])+1); //random number of inputs
1125   rulDef3[2*rulesUsed3+1] = min(rulDef1[2*selectedRule1+1], rulDef2[2*selectedRule2+1]) + randomN(abs(rulDef1[2*selectedRule1+1]-rulDef2[2*selectedRule2+1])+1); //random number of outputs
1126
1127   int nrInputsP1 = rulDef1[2*selectedRule1], nrInputsP2 = rulDef2[2*selectedRule2],       //some variables' names
1128       nrOutputsP1 = rulDef1[2*selectedRule1+1], nrOutputsP2 = rulDef2[2*selectedRule2+1], //become now more understandable
1129       nrInputsP3 = rulDef3[2*rulesUsed3], nrOutputsP3 = rulDef3[2*rulesUsed3+1];
1130
1131   //prepare drawing inputs from parent 1 and 2
1132   int sumParentsInputs = nrInputsP1+nrInputsP2;
1133   parentsIn = new int[sumParentsInputs]; //size: parent's 1 and 2 number of inputs
1134
1135   for(i=0;i<sumParentsInputs;i++) parentsIn[i]=-1; //not taken yet
1136   //search for duplicated output and mark one of them outputs as 'taken'
1137   for(i=0;i<nrInputsP1;i++)
1138     for(j=0;j<nrInputsP2;j++)
1139       if(rulesBody1[selectedRule1][2*i]==rulesBody2[selectedRule2][2*j]) //if inputs numbers are the same,
1140       {
1141         bool takenP1=rnd01<0.5; //draw, which input should be mark as taken
1142         if (takenP1) parentsIn[i]=-2;
1143         else parentsIn[j+nrInputsP1]=-2;
1144       }
1145
1146   //now drawig is well prepared
1147   inputsUsed=0;
1148   while(inputsUsed<nrInputsP3) //loop as long, as inputs taken (from p1&p2) < length of descendant's input part
1149   {
1150     //draw input (which was not used yet) from both parents
1151     do k=randomN(sumParentsInputs);
1152     while (parentsIn[k]!=-1); //draw as long, as input is not taken yet
1153     if(k<nrInputsP1) //concerns input from parent 1
1154       sprintf(tempChar50, "%i;%i", rulesBody1[selectedRule1][2*k], transTable[rulesBody1[selectedRule1][2*k+1]]); //get input and transformated fuzzy set nr
1155     else  //concerns input from parent 2
1156       sprintf(tempChar50, "%i;%i", rulesBody2[selectedRule2][2*(k-nrInputsP1)], transTable[setsNr1+rulesBody2[selectedRule2][2*(k-nrInputsP1)+1]]); //get input and transformated fuzzy set nr. setsNr1+ because transTable is sum of setsNr1+setsNr2
1157     rules3 += tempChar50;
1158     if (inputsUsed+1<nrInputsP3) rules3 += ";";
1159     inputsUsed++; parentsIn[k]=-2; //mark as taken
1160   }
1161   rules3 += ":";
1162
1163   SAFEDELETEARRAY(parentsIn)
1164
1165   //prepare drawing outputs from parent 1 and 2
1166   int sumParentsOutputs = nrOutputsP1+nrOutputsP2;
1167   parentsOut = new int[sumParentsOutputs]; //size: parent's 1 and 2 number of inputs
1168
1169   for(i=0;i<sumParentsOutputs;i++) parentsOut[i]=-1; //not taken yet
1170   //search duplicated output and mark one of them outputs as 'taken'
1171   for(i=0;i<nrOutputsP1;i++)
1172     for(j=0;j<nrOutputsP2;j++)
1173       if(rulesBody1[selectedRule1][2*(i+nrInputsP1)]==rulesBody2[selectedRule2][2*(j+nrInputsP2)]) //if outputs numbers are the same,
1174       {
1175         bool takenP1=rnd01<0.5; //draw, which input should be mark as taken
1176         if (takenP1) parentsOut[i]=-2;
1177         else parentsOut[j+nrOutputsP1]=-2;
1178       }
1179
1180   //now drawig is well prepared
1181   outputsUsed=0;
1182   while(outputsUsed<nrOutputsP3) //loop as long, as outputs taken (from p1&p2) < length of descendant's output part
1183   {
1184     //draw output (which was not used yet) from both parents
1185     do k=randomN(sumParentsOutputs);
1186     while (parentsOut[k]!=-1); //draw as long, as output is not taken yet
1187     if(k<nrOutputsP1) //concerns output from parent 1
1188       sprintf(tempChar50, "%i;%i", rulesBody1[selectedRule1][2*(k+nrInputsP1)], transTable[rulesBody1[selectedRule1][2*(k+nrInputsP1)+1]]); //get output and transformated fuzzy set nr
1189     else  //concerns output from parent 2
1190       sprintf(tempChar50, "%i;%i", rulesBody2[selectedRule2][2*(k-nrOutputsP1+nrInputsP2)], transTable[setsNr1+rulesBody2[selectedRule2][2*(k-nrOutputsP1+nrInputsP2)+1]]); //get output and transformated fuzzy set nr
1191     rules3 += tempChar50;
1192     if (outputsUsed+1<nrOutputsP3) rules3 += ";";
1193     outputsUsed++; parentsOut[k]=-2; //mark as taken
1194   }
1195   rules3 += "/";
1196
1197   SAFEDELETEARRAY(parentsOut)
1198
1199   rulesUsed3++; rulesTaken1++; rulesTaken2++;
1200  }
1201
1202  //if there is no more rules pairs, and descendant needs more rules, copy rules from 'bigger' parent
1203  if(rulesTaken1<rulesNr1)
1204  {
1205    for(j=0;(j<rulesNr1)&&(rulesUsed3<rulesNr3);j++)
1206      if(parentRules[j]==-1) //search for not taken rule
1207      {
1208        parentRules[j]=-2; //taken
1209        rulDef3[2*rulesUsed3] = rulDef1[2*j]; rulDef3[2*rulesUsed3+1] = rulDef1[2*j+1]; //copy whole rule - do not change number of inputs and outputs
1210        for(k=0;k<rulDef3[2*rulesUsed3]+rulDef3[2*rulesUsed3+1];k++) //copy conditional and decisional part
1211        {
1212          sprintf(tempChar50, "%i;%i", rulesBody1[j][2*k], transTable[rulesBody1[j][2*k+1]]);
1213          rules3 += tempChar50;
1214          if(k+1==rulDef3[2*rulesUsed3]) //if end of inputs, put colon
1215            rules3 += ":";
1216          else if(k+1==rulDef3[2*rulesUsed3]+rulDef3[2*rulesUsed3+1]) //if end of outputs, put slash
1217            rules3 += "/";
1218          else
1219            rules3 += ";";
1220        }
1221        rulesUsed3++; rulesTaken1++;
1222        copied1+=2*k; //all inputs, fuzzy sets, ..., all outputs, fuzzy sets
1223      }
1224  }
1225  if(rulesTaken2<rulesNr2)
1226    for(j=0;(j<rulesNr2)&&(rulesUsed3<rulesNr3);j++)
1227      if(parentRules[rulesNr1+j]==-1) //search for not taken rule
1228      {
1229        selectedRule2=j; parentRules[rulesNr1+j]=-2; //taken
1230        rulDef3[2*rulesUsed3] = rulDef2[2*j]; rulDef3[2*rulesUsed3+1] = rulDef2[2*j+1]; //copy whole rule - do not change number of inputs and outputs
1231        for(k=0;k<rulDef3[2*rulesUsed3]+rulDef3[2*rulesUsed3+1];k++) //copy conditional and decisional part
1232        {
1233          sprintf(tempChar50, "%i;%i", rulesBody2[j][2*k], transTable[setsNr1+rulesBody2[j][2*k+1]]);
1234          rules3 += tempChar50;
1235          if(k+1==rulDef3[2*rulesUsed3]) //if end of inputs, put colon
1236            rules3 += ":";
1237          else if(k+1==rulDef3[2*rulesUsed3]+rulDef3[2*rulesUsed3+1]) //if end of outputs, put slash
1238            rules3 += "/";
1239          else
1240            rules3 += ";";
1241        }
1242        rulesUsed3++; rulesTaken2++;
1243        copied2+=2*k; //all outputs, fuzzy sets, ..., all outputs, fuzzy sets
1244      }
1245
1246  //no need to normalize before removing unused sets, because correct (new) number of fuzzy set already written in rules string
1247
1248  //delete 'old' transTable
1249  SAFEDELETEARRAY(transTable)
1250
1251  //create space for new transformation table
1252  transTable=new int [setsNr3];
1253  for(int ii=0;ii<setsNr3;ii++) transTable[ii]=ii; //formula 1:1 - no renumeration needed now
1254
1255  int oldSetNr=setsNr3; //remember number of sets used in new genotype, but before reduction
1256  //remove unused sets; if any set was removed, renumeration is needed
1257  if(removeUnusedSets(sets3, rules3, setsNr3, transTable))
1258    changeSetsNumeration(rules3, transTable, oldSetNr); //renumerate new sets
1259  //after renumeration, excessive rule or input/output may occur
1260  if((removeExcessiveInOut(rules3, inputsNr1, outputsNr1)<0)||
1261     (removeExcessiveRules(rules3, setsNr3, rulesNr3)<0))
1262  { //should not occur
1263    SAFEDELETEARRAY(rulDef1) SAFEDELETEARRAY(rulDef2) SAFEDELETEARRAY(rulDef3)
1264    SAFEDELETEARRAY(transTable) SAFEDELETEARRAY(parentRules) SAFEDELETEARRAY(parentsIn) SAFEDELETEARRAY(parentsOut)
1265    SAFEDELETEARRAY(fuzzySets1) SAFEDELETEARRAY(fuzzySets2) SAFEDELETEARRAY(fuzzySets3)
1266    if(rulesBody1) for(i=0;i<rulesNr1;i++) SAFEDELETEARRAY(rulesBody1[i])
1267    if(rulesBody2) for(i=0;i<rulesNr2;i++) SAFEDELETEARRAY(rulesBody2[i])
1268    SAFEDELETEARRAY(rulesBody1) SAFEDELETEARRAY(rulesBody2)
1269    return GENOPER_OPFAIL; //did not successed
1270  }
1271//---------------------  end of crossing over  --------------------------------
1272
1273  if( (sets3.len()==0)||(rules3.len()==0) ) //shold not occur, but for safety:
1274    {sets3="-1;0;0;1;"; rules3="0;0:0;0/"; setsNr3=1; rulesNr3=1; }
1275
1276  //update new genotype
1277  pi1.setIntById("ns", setsNr3);
1278  pi1.setIntById("nr", rulesNr3);
1279  pi1.setStringById("fs",sets3);
1280  pi1.setStringById("fr",rules3);
1281  pi1.update(); //force commit changes
1282  model1.close();
1283  //get creature whole genotype
1284  finalGenotype=model1.getF0Geno().getGene();
1285
1286  //replace old genotype with new one
1287  free(g1);
1288  g1=strdup((const char*)finalGenotype);
1289
1290  chg1=1-(float)copied1/genoUsed1;
1291  chg2=1-(float)copied2/genoUsed2;
1292
1293  SAFEDELETEARRAY(rulDef1)
1294  SAFEDELETEARRAY(rulDef2)
1295  SAFEDELETEARRAY(rulDef3)
1296  SAFEDELETEARRAY(transTable)
1297  SAFEDELETEARRAY(parentRules)
1298  SAFEDELETEARRAY(parentsIn)
1299  SAFEDELETEARRAY(parentsOut)
1300  SAFEDELETEARRAY(fuzzySets1)
1301  SAFEDELETEARRAY(fuzzySets2)
1302  SAFEDELETEARRAY(fuzzySets3)
1303  if(rulesBody1) for(i=0;i<rulesNr1;i++) SAFEDELETEARRAY(rulesBody1[i])
1304  if(rulesBody2) for(i=0;i<rulesNr2;i++) SAFEDELETEARRAY(rulesBody2[i])
1305  SAFEDELETEARRAY(rulesBody1)
1306  SAFEDELETEARRAY(rulesBody2)
1307
1308  return GENOPER_OK;
1309};
1310
1311
1312
Note: See TracBrowser for help on using the repository browser.